Skip to content

Rate Scanner Dev

  • The new MBR business, described in D:\FSS\KB\MBR\02_Strategy\Executive-Summary.md, at its foundation depends on a system that scans rates on savings products, and later debt products.
  • The Rate Intelligence Engine (Big Rock 1) is the core product. Without reliable, current rate data, the Hassle Threshold algorithm cannot function, the Money Minute has no content, and the 1-Click transfer has no “where to” destination. This is the data substrate that everything else sits on.
  • You misinterpreted that I suggested that this results in an AI based tool. To clarify, I simply meant that AI can help develop this tool.
    • Rate data is structured (name, rate, minimum balance, promo expiry, account type)
    • The logic is deterministic (sort by rate, filter by category, flag by change)
    • A Python or Deno script running on a cron job is orders of magnitude more reliable and cheaper
    • Note that unless There is a strong reason for otherwise, my preferred language for such backend and/or utility developments is Python.
  • Deeply brainstorm the architecture needed to meet short and medium-term objectives for such a back-end scanning tool.
  • Research ALL viable sources for this data
    • Ratehub.ca, highinterestsavings.ca, EQ Bank, Oaken, Wealthsimple, …
  • First research from the existing rate comparison sites the different types of categories for savings products and debt products. Fundamentally, my crude categorization for Savings products would be based on features/functionality, then perhaps account types (only if different)
    • can write cheques
    • cashable (HISA, cashable GICs, …)
    • non-cashable, locked for various terms (60 days, 1/2/3/5 yrs, etc.)
  • Can we include MMF in Savings alternatives, or does that get into the securities world where business risks are increased?
  • Explore the pros and cons of different database solutions, or is as simple YAML or JSON rate manifest sufficient?
  • Do the same for the basic debt products, starting from biggest to smallest
    • mortgages (insured, uninsured)
    • HELOCs
    • Personal LOC
    • auto loans
    • credit cards (normal, low rate)
  • Data needed (minimum?)
    • institution name, product name, current rate, promo flag (Y/N), promo expiry, minimum balance, account opening URL.
  • Address any other issue you identify as important

  • Researched all viable data sources — tiered by accessibility and reliability
  • Confirmed Bank of Canada Valet API: free, public, no scraping needed for prime/overnight rate
  • Confirmed highinterestsavings.ca: simple HTML table, scrapeable with requests+BeautifulSoup
  • Confirmed Ratehub.ca: Next.js SPA with internal API URLs — requires Playwright for full data; not publicly accessible via simple REST calls
  • Confirmed EQ Bank: static HTML, scrapeable (rates visible)
  • Defined complete savings product taxonomy (5 categories + 1 informational)
  • Defined debt product taxonomy (6 categories, priority-ranked)
  • Answered MMF question: informational only, never executed through MBR
  • Recommended database stack: YAML (Phase 1) → SQLite (Phase 2) → Postgres (Phase 3+)
  • Designed full Rate Intelligence Engine architecture: schema, scraper structure, CLI, cron
  • Mapped 4-phase technical roadmap aligned with A→B→Z plan

The Rate Intelligence Engine is a Python-based data pipeline that:

  1. Collects rate data from multiple sources (manual → scrapers → Open Banking APIs)
  2. Stores rates with full history in SQLite (never update, only insert — time-series)
  3. Detects changes and feeds alerts to the Hassle Threshold Engine
  4. Exposes a simple CLI for manual inspection and validation
  • Python 3.12+ managed by uv (per project standard)
  • requests + BeautifulSoup4 — static HTML scrapers
  • Playwright-python — JS-rendered pages (Ratehub, Wealthsimple)
  • pyyaml — Phase 1 YAML manifest
  • sqlite3 (built-in) + SQLAlchemy (optional ORM) — database layer
  • pydantic — data validation / schema enforcement
  • schedule or system cron — daily runner

SourceWhat It ProvidesStatus
Bank of Canada Valet APIPrime rate (V80691311), Overnight rate (V39079), Policy rate✅ Confirmed public, free, structured JSON

Live test result:

GET https://www.bankofcanada.ca/valet/observations/V80691311,V39079/json?recent=1
→ Prime rate: 4.45% (2026-04-01)
→ Overnight target: 2.25% (2026-04-01)

This is the anchor for all variable-rate debt products (“Prime + X%”). Fetch daily.

Tier 2 — Simple HTML Scraping (requests + BeautifulSoup)

Section titled “Tier 2 — Simple HTML Scraping (requests + BeautifulSoup)”
SourceWhat It ProvidesNotes
highinterestsavings.caHISA rates (personal + TFSA), 15–18 institutions✅ Confirmed — clean HTML table, no JS required
EQ Bank (direct)Personal Account, TFSA, GIC, FHSA rates✅ Confirmed static HTML; rates visible
Oaken Financial (direct)GIC and HISA ratesNeeds investigation — curl returned empty
Achieva Financial (direct)HISA, GICLikely static HTML
AcceleRate Financial (direct)HISA, GICLikely static HTML
Motive Financial (direct)HISA, GICLikely static HTML
Saven Financial (direct)HISAON-only, clean site
Tangerine (direct)HISA, GICSimple pages

highinterestsavings.ca table structure confirmed:

Brand | Account | Rate | TFSA rate | Province restrictions
Achieva Financial | Achieva Savings | 1.80% | 1.95% | MB
Saven Financial | High Interest Savings | 2.85% | 2.85% | ON
EQ Bank | Personal Account | 1.00% | 1.50% | —
...

Note: rates appear stale on this site (EQ Bank at 1.00% is well below current). Use as a supplementary source, not sole authority. Always cross-reference with direct institution pages.

Tier 3 — JS-Rendered (Playwright Required)

Section titled “Tier 3 — JS-Rendered (Playwright Required)”
SourceWhat It ProvidesNotes
Ratehub.caHISA, GICs, chequing, mortgages, personal loansNext.js SPA — internal APIs discovered but not publicly exposed. Playwright needed.
WealthsimpleCash account rateReact app, 167-byte response to curl
Neo FinancialNeo SavingsLikely JS-rendered
Big 6 bank pagesSavings, GICs, mortgagesMostly JS-rendered, complex DOM

Ratehub internal API URLs (discovered in NEXT_DATA — useful for Phase 2 Playwright extraction):

SAVINGS_API_URL: https://api.ratehub.ca/savings-accounts-service
GICS_API_URL: https://api.ratehub.ca/gics-rates-service
MORTGAGE_RATES_API_URL: https://api.ratehub.ca/mortgage-rates
CHEQUING_API_URL: https://api.ratehub.ca/chequing-accounts-service
LOANS_API_URL: https://api.ratehub.ca/loans-service

These endpoints return “Cannot GET /” directly — they require authenticated session cookies from the SPA. With Playwright, we can let the page load, intercept network traffic, and capture the JSON responses directly.

SourceNotes
CANNEXIndustry-standard rate data used by banks and advisors. Subscription required. Best data quality. Evaluate at Phase 3+.
Open Banking / CDF APIsCanada’s Consumer-Directed Finance rollout (2026-2027). Will replace most scraping for participating institutions. First-mover advantage.

Can write cheques, use debit, send e-transfers. Functions as daily banking.

  • Examples: EQ Bank Personal Account, Wealthsimple Cash
  • Key attributes: can_write_cheques: true, cashable: true, term_days: null
  • Distinction from pure HISA: full transactional access at high yield

Category 2: Pure HISA (High-Interest Savings Account)

Section titled “Category 2: Pure HISA (High-Interest Savings Account)”

Instant liquidity, no term, no chequing. Sub-types by account wrapper:

  • personal — non-registered HISA
  • tfsa — Tax-Free Savings Account wrapper
  • rrsp — Registered Retirement Savings Plan wrapper
  • fhsa — First Home Savings Account wrapper
  • business — Business savings account

Most institutions offer the same underlying product across multiple wrappers at the same or slightly different rates. Track each rate separately.

Category 3: Cashable GICs / Short-Term Deposits

Section titled “Category 3: Cashable GICs / Short-Term Deposits”

Fixed term but redeemable before maturity (usually after minimum hold period, often 30 days). Lower rate than non-cashable but higher than HISA.

  • Terms: 30d, 60d, 90d, 180d, 1yr (cashable)
  • Key flag: is_cashable: true, min_hold_days: 30 (or similar)

Category 4: Non-Cashable Term Deposits / GICs

Section titled “Category 4: Non-Cashable Term Deposits / GICs”

Cannot redeem before maturity (or only with substantial penalty / institution discretion).

  • Terms: 30d, 60d, 90d, 180d, 1yr, 2yr, 3yr, 4yr, 5yr
  • Highest rates in the savings universe for equivalent institution risk
  • Same wrapper variants as HISA (TFSA, RRSP, RRIF, FHSA, non-registered)

Category 5: Promotional / Bonus Rate (Flag, Not Separate Category)

Section titled “Category 5: Promotional / Bonus Rate (Flag, Not Separate Category)”

Not a separate category — a flag applied across Category 1–4.

  • promo: true, promo_expiry: YYYY-MM-DD, new_money_required: true/false
  • This is the Rate Expiry Engine’s primary input: track expiry date, alert 30 days before reversion.

Informational Only (Not CDIC-Insured — Display With Prominent Disclaimer)

Section titled “Informational Only (Not CDIC-Insured — Display With Prominent Disclaimer)”

Category 6: Cash-Equivalent ETFs and Money Market Funds

  • HISA ETFs: CI CSHI (formerly CSAV), Purpose PSA, Horizons CASH, BMO ZMMK
  • Reason to include: yields often match or exceed HISA rates; relevant to users asking “is this worth switching for?”
  • Reason NOT to execute: securities, not deposits; requires securities dealer registration to broker
  • Implementation: display as comparison context with disclaimer. Never include in alert triggers or transfer flow.

Debt Product Taxonomy (Sorted by MBR Revenue Priority)

Section titled “Debt Product Taxonomy (Sorted by MBR Revenue Priority)”

1. Mortgages (Highest Priority — 9x Revenue vs. Savings)

Section titled “1. Mortgages (Highest Priority — 9x Revenue vs. Savings)”

Sub-types (each tracked separately):

  • Fixed: 1yr, 2yr, 3yr, 4yr, 5yr, 7yr, 10yr (5yr is 90% of the market)
  • Variable: Prime − spread (e.g., Prime − 0.70%) → rate updates when Prime changes
  • Adjustable-rate: similar to variable but payments adjust (not just amortization period)
  • Insured: CMHC-insured, <20% down, max purchase price $1.5M (post-2024 rules)
  • Uninsured: ≥20% equity / purchase price >$1M
  • High-ratio vs. conventional: overlaps with insured/uninsured but distinct fee structure

Key attributes: rate_type: fixed|variable|adjustable, term_years: 5, insured: true|false, open: false

Rate Expiry Engine analogy for mortgages: renewal date tracking is the equivalent of promo_expiry. A user’s 5yr fixed mortgage coming up for renewal in 6 months is the highest-value alert MBR can send.

Sources: Ratehub.ca (comprehensive), ratesupermarket.ca, direct broker networks

  • Typically Prime + 0% to Prime + 0.5%
  • Rate = BoC Prime + spread (spreads are institution-specific)
  • Track spread, not absolute rate — the BoC API feeds the calculation in real time
  • Limited public comparison data; primarily broker-channel information
  • Similar structure to HELOC but not necessarily secured against home equity
  • Prime + 1% to Prime + 3% typical range
  • Prime + 2% to Prime + 8%
  • Highly individual (credit score dependent); limited public comparison data
  • Lower priority for MBR Phase 1-2
  • Fixed rate; manufacturer promotions common (0.99%, 1.99%)
  • Less standardized, harder to compare systematically
  • Recommend Phase 3+ only
  • Standard: 19.99% purchase, 22.99% cash advance (nearly universal in Canada)
  • Low-rate: 8.99%–12.99%
  • Little actionable variation → minimal alert opportunity
  • Lowest priority: include as reference data only, no alert logic needed

Database Recommendation: YAML → SQLite → Postgres

Section titled “Database Recommendation: YAML → SQLite → Postgres”

Best for: human-maintained, version-controlled, quick to bootstrap

data/rates.yaml
meta:
schema_version: 1
last_updated: "2026-04-02"
institutions:
- id: eq_bank
name: EQ Bank
cdic_member: true
province_restrictions: []
url: https://www.eqbank.ca
products:
- id: eq_hisa_personal
institution_id: eq_bank
name: Personal Account
category: chequable # Category 1 — can write cheques
account_types: [personal]
can_write_cheques: true
is_cashable: true
term_days: null
apply_url: https://www.eqbank.ca/personal-banking/savings
rates:
- rate: 3.50
rate_type: variable
promo: false
promo_expiry: null
min_balance: 0
max_balance: null
source: direct
fetched_at: "2026-04-02"
- id: oaken_gic_1yr
institution_id: oaken
name: 1-Year GIC
category: gic_term # Category 4 — non-cashable term
account_types: [personal, tfsa, rrsp, rrif]
is_cashable: false
term_days: 365
rates:
- rate: 4.10
rate_type: fixed
promo: false
min_balance: 1000
source: direct
fetched_at: "2026-04-02"

Phase 2: SQLite with Rate History (Month 1–3)

Section titled “Phase 2: SQLite with Rate History (Month 1–3)”

Best for: automated scraping, change detection, Hassle Threshold Engine integration

Minimum schema:

CREATE TABLE institutions (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
url TEXT,
cdic_member BOOLEAN DEFAULT TRUE,
province_restrictions TEXT, -- JSON array: '["QC"]'
notes TEXT
);
CREATE TABLE products (
id TEXT PRIMARY KEY,
institution_id TEXT REFERENCES institutions(id),
name TEXT NOT NULL,
category TEXT NOT NULL, -- 'hisa', 'gic_term', 'gic_cashable', 'chequable',
-- 'mortgage_fixed_5yr', 'heloc', etc.
account_types TEXT, -- JSON: '["personal","tfsa","rrsp","fhsa"]'
can_write_cheques BOOLEAN DEFAULT FALSE,
is_cashable BOOLEAN,
term_days INTEGER, -- NULL for variable products
apply_url TEXT,
active BOOLEAN DEFAULT TRUE,
notes TEXT
);
-- Never UPDATE rates — only INSERT. Full time-series history.
CREATE TABLE rates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id TEXT REFERENCES products(id),
rate REAL NOT NULL, -- Annual rate, e.g., 3.50 for 3.50%
rate_type TEXT DEFAULT 'fixed', -- 'fixed' | 'variable' | 'prime_plus'
prime_spread REAL, -- For "Prime + X%" products; effective_rate = prime + spread
promo BOOLEAN DEFAULT FALSE,
promo_expiry DATE,
min_balance REAL DEFAULT 0,
max_balance REAL, -- NULL = no cap
fetched_at DATETIME DEFAULT CURRENT_TIMESTAMP,
source TEXT, -- 'manual' | 'scraper:highinterestsavings' | 'api:boc'
source_url TEXT
);
-- Change log — populated by diff.py after each scraper run
CREATE TABLE rate_changes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id TEXT REFERENCES products(id),
prev_rate REAL,
new_rate REAL,
change_bps REAL, -- (new - prev) * 100; positive = rate went up
detected_at DATETIME DEFAULT CURRENT_TIMESTAMP,
alert_queued BOOLEAN DEFAULT FALSE
);

Key design decision: rates are insert-only. This gives MBR the historical dataset needed for “Your savings rate has increased 3x since you joined” and the Canadian Financial Health Index. Every scraper run produces a new row — never modifies an existing one.

Only when: hosted deployment, multiple scrapers running in parallel, or B2B Rate Intelligence API requires multi-tenant isolation. Not needed for Phase 1-2.


rate-scanner/ # Standalone Python project
├── pyproject.toml # uv-managed
├── uv.lock
├── data/
│ └── rates.yaml # Phase 1: manually maintained manifest
├── rate_scanner/
│ ├── __init__.py
│ ├── db.py # SQLite setup, schema creation, migrations
│ ├── models.py # Pydantic: RateRecord, ProductRecord, etc.
│ ├── loader.py # YAML → SQLite: validates, deduplicates, inserts
│ ├── diff.py # Change detection: compare latest rate vs. prior
│ ├── runner.py # Orchestrates all scrapers; logs run summary
│ ├── cli.py # typer CLI: list, run, diff, validate
│ └── scrapers/
│ ├── __init__.py
│ ├── base.py # Abstract BaseScraper: fetch(), normalize(), validate()
│ ├── boc_api.py # Bank of Canada Valet API (prime + overnight rate)
│ ├── highinterestsavings.py # HTML table scraper — Priority 1
│ ├── eq_bank.py # Direct institution scraper — Priority 2
│ ├── oaken.py # Direct institution scraper
│ └── ratehub.py # Playwright-based — Phase 2
└── tests/
├── test_models.py
├── test_loader.py
└── test_scrapers/
└── test_boc_api.py # Can test against live API

CLI commands:

Terminal window
rate-scanner list # Show all current rates, sorted by rate desc
rate-scanner list --category hisa --account-type tfsa
rate-scanner list --category gic_term --term 365
rate-scanner run # Execute all scrapers, write to SQLite
rate-scanner run --scraper boc_api # Run single scraper
rate-scanner diff # Show rate changes since last run
rate-scanner validate # Schema-validate YAML manifest
rate-scanner export --format json # Export current rates as JSON (for Hassle Threshold Engine)

Short answer: Include as informational only. Never execute through MBR.

The regulatory line: MBR’s business model depends on staying in the “information and referral” category, not the “securities dealer” category. Executing HISA ETF or MMF purchases would require registration as a mutual fund dealer or exempt market dealer. This is a business risk that far outweighs any product benefit.

What MBR CAN do:

  • Display current ETF yields (CASH, PSA, CSAV, HSAV, ZMMK) as a comparison column
  • Label them clearly: “Investment Alternative — Not CDIC-insured. Not available through MBR.”
  • Show the yield comparison: “HISA best rate: 3.50% | HISA ETF yields: up to 4.10%”
  • Link to the user’s brokerage for execution (no referral fee, just information)

Why include them at all: A user with $50k in a HISA at 3.50% who could be in CASH.TO at 4.10% is leaving ~$300/year on the table. MBR’s job is to surface this. Not acting on it because of regulatory complexity would mean MBR is hiding material information from users — which contradicts the mission.

Implementation note: Add a category: 'investment_alt' flag and an is_cdic_insured: false field. Filter these out of all alert and transfer logic. Display in a separate “For Your Information” section with a single-line disclaimer.


Phase 1: Manual YAML Manifest (Weeks 1–4)

Section titled “Phase 1: Manual YAML Manifest (Weeks 1–4)”

Zero infrastructure. Immediately useful.

  • Build data/rates.yaml with 15–20 products:
    • EQ Bank: Personal Account (chequable), TFSA HISA, 1-year GIC
    • Oaken: HISA, GICs (1yr, 2yr, 3yr, 5yr)
    • Achieva: HISA, TFSA HISA
    • AcceleRate, Motive, Saven: HISA
    • Tangerine: HISA, GICs
    • Wealthsimple Cash: chequable/HISA
    • Neo Savings: HISA
  • BoC prime rate fetcher (10 lines of Python, live API)
  • CLI: rate-scanner list, rate-scanner validate
  • Git-committed: YAML is the SSOT, version-controlled, diffable

Phase 2: Automated Scraping + SQLite (Month 1–2)

Section titled “Phase 2: Automated Scraping + SQLite (Month 1–2)”

Rate data becomes live and historical.

  • highinterestsavings.ca scraper (easy win — confirmed HTML table)
  • EQ Bank direct scraper
  • BoC API integrated into daily run
  • SQLite schema deployed, YAML loader → SQLite
  • Change detection (diff.py) → populates rate_changes table
  • Daily cron: 0 6 * * * rate-scanner run
  • Alert hook: when rate_changes has new rows, Hassle Threshold Engine evaluates

Phase 3: Full Coverage + Debt Products (Month 2–4)

Section titled “Phase 3: Full Coverage + Debt Products (Month 2–4)”

Ratehub coverage, mortgage data, broker integration.

  • Ratehub Playwright scraper (intercept network calls to internal APIs)
  • Mortgage rates (5yr fixed as first priority)
  • Rate Expiry Engine: promo tracking, 30-day pre-alert
  • Mortgage renewal date tracking (separate table: user_mortgage_renewals)
  • B2B Rate Intelligence API: FastAPI wrapper over SQLite queries

Replace scrapers with authoritative bank APIs.

  • Consumer-Directed Finance (CDF) framework integration
  • Real-time or near-real-time rate feeds
  • Scraper modules deprecated for participating institutions
  • First-mover advantage window: be in market now, infrastructure ready before CDF goes live

  • Approve the architecture direction — YAML → SQLite → Postgres progression; Python throughout 1.
  • Approve the savings product taxonomy (5 categories + informational ETF section) 1.
  • Confirm: should rate-scanner live inside the MBR monorepo, or as a standalone utility (like web-deploy)?
    1. If it served more than one project or utility, I think it would belong in \\wsl$\Ubuntu-24.04\home\ta\projects\, so it could be consumed by multiple projects. But at this point, I see no valid reason that it would serve anything other than MBR. Anything related to this data would appropriately be under the domain of MBR. So it should go into a dedicated mbr folder.
    2. Yes, the monorepo will hold the MyBetterRates.com website. But I don’t think that the Related rates engine needs to be here. Agree? I like to keep separate concerns as much as possible and the mono repo already will do lots.
    3. MBR will require many databases, automation scripts and more. Separately think through all of the tasks that we identified as big rocks and suggest an architecture to handle what is knowable, perhaps leaning towards keeping the website content separate in the monorepo and structuring everything else external to it.
    4. Under \\wsl$\Ubuntu-24.04\home\ta\projects\mbr\?
  • Confirm: should Phase 1 YAML manifest be built first (manually by Claude) before any scraper code is written?
    1. sure
  • MMF decision — informational-only column confirmed, or exclude entirely for now?
    1. info column
  • Strategic Better-Quantified data
    • While we clearly are most interested in the best savings rate and debt rate for every category, it might also be useful to know what the opposite is, so that we could quantify the full difference that some people Who have currently the worst products might experience. Unfortunately, often the worst products are those that are most used, due to inertia and lack of, and hassle Factor Etc. I think this is a good additional piece of data to capture and perhaps use for marketing purposes. Agreed?


  • Confirmed architecture location: mbr/ under /home/ta/projects/ — rate-scanner and all non-website MBR backend lives here, website stays in monorepo
  • Designed full MBR project architecture — 10 service directories, all created
  • Built Phase 1 YAML manifest at mbr/rate-scanner/data/rates.yaml
    • 18 institutions, 23 products (7 verified, 16 flagged for Playwright verification)
    • Includes benchmark/worst-rate infrastructure for Big 6 baseline comparison
  • Built models.py (Pydantic validation), loader.py (YAML → models), cli.py (typer CLI)
  • Built scrapers/boc_api.py — Bank of Canada Valet API integration
  • Installed with uv and tested all commands — all passing
  • Answered “worst rate” question: YES — implemented via institution_type: national_bank and needs_verification flags for Big 6

Architecture location: Rate-scanner and all backend services in /home/ta/projects/mbr/. Website (MBR.com) stays in monorepo. Correct separation. No exceptions.

Phase 1 YAML first: Done. Manifest is built, installed, and tested.

MMF/investment_alt: category: investment_alt added to schema. Two HISA ETFs (CSHI, PSA) included with no rate (needs data feed) and notes: "INFORMATIONAL ONLY. Not available through MBR." They’re in the manifest, excluded from verified products unless rates are populated.


/home/ta/projects/mbr/
├── README.md # Architecture overview
├── rate-scanner/ # ✅ Built (Phase A→B — NOW)
├── cancer50pledge/ # Phase A→B — GWWC-modeled pledge platform (SvelteKit)
├── benefit-snapshots/ # Phase A→B — embeddable rate calculator widgets
├── hassle-engine/ # Phase B→Next — Hassle Threshold + Alert Dispatcher
├── split-cart/ # Phase B→Next — Stripe + CanadaHelps split payment
├── wealthcare50-portal/ # Phase B→Next — Employer/charity HR portal + CSR dashboard
├── financial-iq/ # Phase C — Financial IQ Score + Net Worth Thermometer
├── concierge/ # Phase C — 1-Click Transfer: KYC, form gen, DocuSign
├── notifications/ # Phase C — Email + push notification delivery
└── browser-extension/ # Phase D — Passive rate surveillance overlay

Website (MyBetterRates.com) → monorepo at /home/ta/projects/monorepo/sites/mbr/ Everything else/home/ta/projects/mbr/

Each service is standalone: its own pyproject.toml (Python) or package.json (Svelte). Communication in Phase 1–2 is via file export (YAML/JSON/SQLite); Phase 3+ is via internal API.


Location: \\wsl$\Ubuntu-24.04\home\ta\projects\mbr\rate-scanner\

Test results (all passing):

rate-scanner validate
→ ✓ Manifest valid
→ Institutions: 18, Products: 23
→ Verified rates: 7 (all EQ Bank — confirmed from their website today)
→ Needs verification: 16 (aggregator-sourced or TBD)
rate-scanner benchmarks (live Bank of Canada API call)
→ Prime Rate: 4.45%
→ Overnight Target: 2.25%
rate-scanner list (verified products only, sorted by rate)
→ EQ Bank GIC 15-month: 3.25%
→ EQ Bank GIC 1-year: 3.20%
→ EQ Bank GIC 6-month: 2.75%
→ ...

CLI commands available:

Terminal window
rate-scanner validate # Schema check
rate-scanner list # Verified products, sorted by rate
rate-scanner list --category hisa # Filter by category
rate-scanner list --account-type tfsa # Filter by account wrapper
rate-scanner list --all # Include unverified (shows ? flag)
rate-scanner benchmarks # Live BoC API: current Prime rate

“Worst Rate” / Benchmark Data: Confirmed — Great Strategic Idea

Section titled ““Worst Rate” / Benchmark Data: Confirmed — Great Strategic Idea”

Short answer: Yes. Do this. It is the marketing data that makes the Benefit Snapshot compelling.

The value isn’t just “best available rate: 3.25%.” The value is the delta: “Most Canadians at a major bank are earning [X%]. The best available rate today is 3.25%. On $100,000 that is $[X-3.25 × 1,000] per year you are leaving on the table.”

How it’s implemented without adversarial framing:

The YAML manifest uses institution_type: national_bank for the Big 6. TD and RBC are already in the manifest with needs_verification: true (their pages require Playwright to scrape). Once populated:

  • rate-scanner list --category hisa will show all HISA rates including national bank rates
  • The CLI will not label them “offenders” — it just sorts by rate
  • The data tells the story without editorial judgment

The “Canadian Savings Rate Tracker” (not “Loyalty Penalty Report”):

  • Average national bank HISA rate = factual, from their own public pages
  • Best challenger bank / credit union rate = factual
  • Delta = factual math
  • “X% of Canadians are leaving an estimated $Y/year on the table” = aggregate calculation from data
  • This is exactly what MoneySense, Globe and Mail, and CBC do annually — standard financial journalism

Implementation in the manifest:

- id: td_savings_standard
institution_id: td_bank
name: TD eSavings Account (Standard)
institution_type: national_bank # ← triggers "benchmark" treatment in UI
notes: "Standard non-promotional rate. Used as Big 6 market baseline."
rates:
- rate: null # Playwright scraper populates this
needs_verification: true

When the Benefit Snapshot widget calculates “your potential gain,” it uses:

  • user_current_rate (what user enters or we detect)
  • best_available_rate (top verified challenger bank rate)
  • national_bank_average (average of Big 6 verified rates)

The delta between those three numbers is the core of MBR’s value proposition made visual.


16 products need Playwright scraping or manual verification before going live. Priority order:

Tier 1 — Manual check this week (5 min each, just visit their website):

  1. oaken_hisa — Oaken Financial HISA (their rates page loads but needs JS)
  2. wealthsimple_cash — Wealthsimple current Cash/Chequing rate
  3. neo_savings — Neo Financial current savings rate
  4. td_savings_standard — TD eSavings standard rate (the benchmark)
  5. rbc_savings_standard — RBC High Interest eSavings standard rate

Tier 2 — Next scraper sprint:

  • Remaining challenger banks (Achieva, Saven, Wealth One, Canadian Tire)
  • HISA ETF yields (CSHI, PSA — available from TMX or Yahoo Finance)
  • Mortgage best rates (Ratehub Playwright scraper)

  • Confirm the MBR project structure at /home/ta/projects/mbr/ — any services to add, rename, or remove?
    1. Good. Done. You are the senior architectural expert. I trust you.
  • Manually verify 5 priority rates (30 min total): Oaken HISA, Wealthsimple Cash, Neo Savings, TD standard HISA, RBC standard HISA
    1. Not clear what you need here …
  • Decide: initialize mbr/ as its own git repo, or part of the broader projects structure?
    1. own repo
  • Ready to build cancer50pledge/ next (Phase A→B priority), or continue with rate-scanner first?
    1. Continue with as many next steps as you are confident with, only asking for confirmation when you need strategic input.


  • Initialized mbr/ as its own git repo — first commit made, Phase 1 history committed
  • Built and tested scrapers/highinterestsavings.ca — confirmed 17 institutions scraped from clean HTML table, no Playwright needed
  • Built and tested scrapers/eq_bank.py — direct scraper for EQ Bank static HTML (10 products)
    • Found 3 additional GIC terms not in YAML: 2-Year (3.50%), 3-Year (3.65%), 5-Year (3.20%)
    • Added all to rates.yaml and DB
  • Built db.py — SQLite schema with insert-only time-series design; WAL mode
  • Built diff.py — change detection, populates rate_changes for Hassle Threshold Engine
  • Built runner.py — full orchestration pipeline
  • Added run and diff CLI commands — all tested and passing
  • Phase 2 committed to git

“Not clear what you need here” — understood. Here is what that means precisely:

The 16 products flagged needs_verification: true have rates sourced from highinterestsavings.ca, which is an aggregator that can be stale by days or weeks. This was confirmed: EQ Bank appears as 1.00% on that site while their actual rate (from their own website) is 2.75%.

The verification question was: which of those remaining rates should be trusted, and which need to be corrected?

Here’s what I’ve determined autonomously:

  • The highinterestsavings.ca data for non-EQ-Bank institutions (Oaken, Saven, Neo, Achieva, etc.) is likely within range but may be slightly low
  • EQ Bank’s aggregator data (1.00%) is demonstrably stale — the direct scraper now handles EQ Bank
  • Big 6 bank benchmark rates (TD, RBC) are still null because those sites require Playwright

The one thing I can’t do without Playwright or Talbot’s help:

The 5 rates where I’m still blocked are the Big 6 benchmark rates (TD, RBC standard HISA rates). These are the “inertia baseline” — the rates that make the Canadian Savings Rate Tracker comparison compelling. Without them, the widget can still function with “your current rate vs. best available,” but we can’t show the “national bank average” automatically.

Two options — Talbot’s call:

  1. Playwright approach (I build it): Playwright is a browser automation tool. I can set it up in WSL and build a TD/RBC scraper that renders the JS page and extracts the rates. More infrastructure, fully automated going forward.
  2. Manual YAML entry (5 min for Talbot): Visit these two URLs, find the standard HISA rate, update rates.yaml:
    • TD eSavings: td.com → Personal Banking → Savings → eSavings Account → Interest Rates
    • RBC High Interest: rbc.com → Savings → High Interest eSavings → Rates Then run rate-scanner run and the data is in the DB.

Current rate-scanner state (as of this commit)

Section titled “Current rate-scanner state (as of this commit)”
Confirmed live rates (direct source, no caveats):
EQ Bank GIC 3-Year: 3.65%
EQ Bank GIC 2-Year: 3.50%
EQ Bank GIC 15-Month: 3.25%
EQ Bank GIC 1-Year: 3.20%
EQ Bank GIC 5-Year: 3.20%
EQ Bank GIC 6-Month: 2.75%
EQ Bank Personal: 2.75% (with direct deposit)
EQ Bank Notice 30d: 2.75%
EQ Bank GIC 3-Month: 2.60%
EQ Bank Notice 10d: 2.35%
Aggregator-sourced (may be slightly stale, flagged):
Saven Financial HISA: 2.85%
Oaken Financial HISA: 2.80%
Wealth One HISA: 2.60%
Canadian Tire HISA: 2.40%
Hubert Financial HISA: 2.30%
Neo Financial HISA: 2.25%
Achieva TFSA HISA: 1.95%
Achieva HISA: 1.80%
Manulife Advantage: 1.50%
Wealthsimple Cash: 1.25%
Still null (need Playwright or manual entry):
TD standard HISA: null
RBC standard HISA: null
Mortgage rates: null (need Ratehub Playwright)
HISA ETF yields: null (need TMX data feed)
HELOC best spread: null (need broker data)
BoC (live, API):
Prime Rate: 4.45%
Overnight: 2.25%

Current git log:

04ded89 feat(rate-scanner): Phase 2 complete — SQLite pipeline, 3 scrapers, change detection
bf9036c feat: initialize MBR project — rate-scanner Phase 1 complete

  • Rate verification decision: Playwright (I build it, more automation) or manual YAML entry for TD + RBC standard HISA rates?
    1. Everything needs to be automated, and verified as true. There is way too much at stake to operate on false data on anything, including rates.
  • Next build priority: Benefit Snapshots widget (embeddable calculator) — the most immediate marketing asset that can go live before the full app exists. Ready to start?
    1. yes
  • cancer50pledge/ or benefit-snapshots/ first? Both are Phase A→B. Benefit Snapshots is simpler to ship; cancer50pledge is higher strategic value.
    1. keep going on all task you have enough context on


  • Re-ran rate-scanner run — 27 products synced, TD confirmed rates (0.010% + 0.450%) now in SQLite from YAML
  • Built scrapers/td_bank.py — Playwright-based scraper for TD Every Day Savings (0.010%) and TD ePremium (0.450%); fixed networkidle timeout by switching to wait_for_selector("table") — confirmed 2 new rows on run
  • Added run_td_scraper() and run_eq_scraper() to runner.py — all direct scrapers now automated; daily run covers BoC API + highinterestsavings.ca + TD Bank + EQ Bank
  • Added rate-scanner export command — produces data/rates.json with inertia_baseline, best_by_category, BoC benchmarks, and full verified product list
  • Built Benefit Snapshot widget (benefit-snapshots/) — pure HTML/JS/CSS, no framework, no build step
    • src/widget.js: fetches rates.json, renders inertia vs best HISA vs best GIC, live recalculation on balance change
    • src/widget.css: MBR-branded responsive design (F.A.S.T.)
    • build.py: compiles dist/benefit-snapshot.html — 19KB self-contained, rates embedded inline, iframe/CDN-deployable
  • All changes committed: b9bf1d5 feat: Phase 3 — TD/EQ scrapers automated, export command, Benefit Snapshot widget

Current state of the Rate Intelligence Engine

Section titled “Current state of the Rate Intelligence Engine”
Daily automated pipeline:
1. rate-scanner run
├── BoC Valet API (Prime 4.45%, Overnight 2.25%)
├── highinterestsavings.ca (16 aggregator products, flagged)
├── TD Bank via Playwright (0.010%, 0.450% — confirmed direct)
└── EQ Bank via requests (10 products — confirmed direct)
2. rate-scanner export → data/rates.json
3. python3 build.py → dist/benefit-snapshot.html
Widget headline (live data):
TD Every Day Savings: 0.010% ← Canadian inertia baseline
EQ Bank 30-Day Notice: 2.75% ← Best liquid savings
Delta: +$2,740/yr per $100,000
Remaining null (need future scrapers):
- RBC standard HISA (blocked by anti-bot)
- BMO, CIBC, Scotiabank (ERR_HTTP2 / timeout)
- Mortgage rates (need Ratehub Playwright — Phase B)
- HELOC / LOC (need broker data — Phase B)
- HISA ETF yields (need TMX feed — Phase B)
b9bf1d5 feat: Phase 3 — TD/EQ scrapers automated, export command, Benefit Snapshot widget
04ded89 feat(rate-scanner): Phase 2 complete — SQLite pipeline, 3 scrapers, change detection
bf9036c feat: initialize MBR project — rate-scanner Phase 1 complete
  • Deploy the Benefit Snapshot widget — it’s ready to go live. Options: (a) add to MBR landing page as <iframe>, (b) deploy to Cloudflare Pages as benefit-snapshots.mybetterrates.com, (c) both. What’s the target URL?
    1. go
  • Set up daily cron for the full pipelinerate-scanner run && rate-scanner export && python3 build.py — should run at 06:00 ET. Run on the WSL machine or a Cloudflare Worker/cron trigger? 1.
  • Remaining Big 6 banks — RBC, BMO, CIBC, Scotiabank all block Playwright. Options: (a) use a stealth Playwright plugin (playwright-stealth), (b) use a rotating proxy, (c) manually verify quarterly and update YAML. Recommendation: start with (c) since TD is the strategic inertia benchmark and the others are less critical for Phase A.
    1. Never manual. Violates automation objective. Use playwright-stealth, “or better”
  • Cancer50Pledge.ca — Phase A→B priority you flagged. Ready to scaffold when you are. This is a standalone Svelte app per the MBR stack. 1.


  • Widget deployed to Cloudflare Pages — https://benefit-snapshots.pages.dev

    • Created Cloudflare Pages project benefit-snapshots
    • build.py now outputs dist/index.html + dist/benefit-snapshot.html
    • 15 verified products embedded, 19.6KB self-contained
    • Deployed twice: initial build, then updated after Big 6 data was added
  • Big 6 bank scrapers — implemented using curl_cffi (better than playwright-stealth for TLS fingerprint)

    • curl_cffi is the “or better”: Chrome TLS/HTTP2 fingerprint without a browser — ~5s for 3 banks vs ~20s+ for Playwright
    • RBC: rbcroyalbank.com/bank-accounts/high-interest-savings-account.html0.550% standard rate confirmed
    • BMO: bmo.com/en-ca/main/personal/bank-accounts/savings-accounts/0.010% Premium Rate Savings confirmed
    • Scotiabank: scotiabank.com/ca/en/...momentum-plus-savings-account.html0.400% regular rate confirmed
    • CIBC: ERR_HTTP2_PROTOCOL_ERROR from Playwright, SSR HTML has zero rate data — Akamai blocks both. Flagged needs_verification: true
    • runner.py: added generic _run_curl_scraper() + run_rbc/bmo/scotiabank_scraper() functions; added try/finally to prevent DB lock on scraper errors
  • Added BMO, Scotiabank, CIBC as institutions in rates.yaml

  • All Big 6 scrapers running in daily rate-scanner run pipeline

  • Exported updated rates.json (15 verified products) + rebuilt widget

  • Committed: 61cd20c feat: Phase 4 — Big 6 bank scrapers, widget deployed

Big 6 Benchmark Summary (confirmed live rates, 2026-04-02)

Section titled “Big 6 Benchmark Summary (confirmed live rates, 2026-04-02)”
BankProductRateSource
TD BankEvery Day Savings Account0.010%Playwright
BMOPremium Rate Savings Account0.010%curl_cffi
RBCHigh Interest eSavings Account0.550%curl_cffi
ScotiabankMomentum Plus Savings Account0.400%curl_cffi
CIBCeAdvantage Savings Accountpendingblocked

The narrative is confirmed: TD and BMO both pay 0.010% on standard savings. EQ Bank pays 2.75%. Delta on $100k = +$2,740/yr. This is the core Benefit Snapshot claim, now backed by live automated data from 4 of 5 reachable Big 6 banks.

rate-scanner run (daily, 06:00 ET)
├── BoC Valet API → prime 4.45%, overnight 2.25%
├── highinterestsavings.ca → 16 aggregator products (flagged)
├── TD Bank (Playwright) → 0.010%, 0.450%
├── EQ Bank (curl) → 10 products, 2.35%-3.65%
├── RBC (curl_cffi) → 0.550%
├── BMO (curl_cffi) → 0.010%
└── Scotiabank (curl_cffi) → 0.400%
rate-scanner export → data/rates.json (15 verified products)
python3 build.py → dist/index.html (deployed to Cloudflare Pages)
  • Custom domain for widget — currently at benefit-snapshots.pages.dev. Connect snapshot.mybetterrates.com or rate.mybetterrates.com as custom domain in Cloudflare dashboard? 1.
  • Set up daily cron — the pipeline now covers 7 sources and takes ~15s. Run as WSL cron job at 06:00 ET: rate-scanner run && rate-scanner export && python3 ~/projects/mbr/benefit-snapshots/build.py && wrangler pages deploy ... — confirm and I’ll write the crontab entry.
    1. go
  • CIBC scraping — Akamai-hardened, blocks both curl_cffi and Playwright. Options: (a) investigate Akamai bypass techniques (adds complexity), (b) accept CIBC as needs_verification for now since TD + BMO already confirm the 0.010% inertia narrative. CIBC rate is unlikely to be materially different.
    1. b) Let’s recognize that the rates That absolutely must be confirmed as true are the better rates that could end up being recommended to clients for upgrading. In this case we could tag the bank account rate as “unimportant” or “reference-only”, as we would never recommend clients move to one of the worst rates. Make sense?
  • Cancer50Pledge.ca scaffold — you flagged this as Phase A→B priority. Ready to build when you say go.
    1. Detail what is involved here


  • Daily cron — already complete from Phase 4b. daily-run.sh + crontab entry 0 10 * * * (06:00 ET) both in place. No action needed.

  • reference_only flag implemented — Big 6 standard savings are now tagged as “benchmark-only; never recommended to clients”

    • Added reference_only: bool = False to Product model in models.py
    • Marked all 6 Big 6 savings products in rates.yaml: td_savings_standard, td_savings_epremium, rbc_savings_standard, bmo_savings_standard, scotiabank_savings_standard, cibc_savings_standard
    • Export logic updated in cli.py:
      • best_by_category now excludes reference_only products — Big 6 standard savings can never surface as a recommendation
      • inertia_baseline now pulls specifically from reference_only products — the baseline is always the Big 6 worst rate, not a challenger accidentally being the lowest
      • products list includes reference_only: true/false for the widget to display benchmarks differently
    • Verified: Best HISA = EQ Bank 2.75% (not Big 6), Inertia baseline = TD Bank 0.010%
    • Committed: 794775e
    • Yes, your framing is exactly right. CIBC’s rate doesn’t matter — we already have two Big 6 banks confirmed at 0.010% (TD + BMO). The inertia narrative is proven. CIBC is now reference_only + needs_verification: true and the scraper will keep trying, but it will never block anything.
  • Cancer50Pledge.ca — current state detailed below

Cancer50Pledge.ca — What’s Already Done

Section titled “Cancer50Pledge.ca — What’s Already Done”

The site was scaffolded and deployed in Phase 4b (previous session). Here’s what exists:

Live URL: https://cancer50pledge.pages.dev

Stack: SvelteKit + adapter-static + Tailwind CSS v4 — deploys as a fully static site to Cloudflare Pages.

Pages built (all 4 routes):

RoutePurposeContent
/ (home)Hero + pledge numbers”He survived cancer. He made a pledge.” — 50% / Forever / Public stats, link to /pledge and /about
/pledgeIndividual + corporate pledge textPledge verbiage for individuals and companies; action buttons
/impactThe mathRevenue loop visual: Canadian saves more → MBR earns referral → 50% → cancer research → compound projections
/aboutFounder storyCancer diagnosis (2022), survival, the 50% commitment, GWWC model reference

What the site does NOT yet have:

  • Email/name capture on the pledge form (no backend — just static pledge text right now)
  • Custom domain (cancer50pledge.ca not yet connected — domain likely needs to be registered/pointed)
  • Donation tracker / running total widget (showing cumulative $ sent to cancer research)
  • Google/meta analytics
  • SEO sitemap

What “Phase B” would involve to call this production-ready:

  1. Custom domain — register cancer50pledge.ca (if not owned), point DNS to cancer50pledge.pages.dev via Cloudflare
  2. Pledge form with email capture — form action to a Google Sheet (simplest no-backend approach) or a simple serverless function; shows the pledge count publicly
  3. Donation tracker — a running total section on /impact showing total $ distributed to cancer research (manually updated or pulled from a public Google Sheet)
  4. Analytics — Fathom or Plausible (privacy-first, no cookie banner needed)

Effort estimate by item:

  • Custom domain: 30 minutes (DNS + CF Pages config)
  • Pledge form (Google Sheets): 1-2 hours (form POST to a Google Apps Script endpoint)
  • Donation tracker: 1 hour (static embed from a Google Sheet cell, or manual update per year)
  • Analytics: 30 minutes (Fathom/Plausible script tag in layout)

Ready to build any of these when you say go.

  • reference_only confirmed? — Does the framing make sense as described? Any other products that should be reference_only: true (e.g., Tangerine, which may be too low-rate to recommend)?
    1. yes
  • Cancer50Pledge.ca — which Phase B items to build? — The site is live at cancer50pledge.pages.dev. Custom domain + pledge form are the two highest-leverage items. Which do you want next? 1.
  • Custom domain for benefit-snapshots widget — still unaddressed from last session. snapshot.mybetterrates.com or rate.mybetterrates.com? 1.
  • Where is Phase 4b outlined? Where is the Strategic Plan or ROADMAP?
    • D:\FSS\KB\MBR\02_Strategy\Strategic Plan.md is empty
  • Identify several medium-sized tasks that you can work on in the next hour.


  • reference_only confirmed — Tangerine noted as a candidate; addressed in Next Steps below.

  • Where is Phase 4b outlined? — It lives in git commit messages and README.md only. There is no formal ROADMAP, STATUS.md, or Strategic Plan capturing the MBR project state. The D:\FSS\KB\MBR\02_Strategy\Strategic Plan.md is an empty scaffold. The MBR monorepo README.md (/home/ta/projects/mbr/README.md) has the project map and phase labels (A→B, B→Next, Phase C, Phase D) — that’s the closest thing to a strategic document right now.

    What exists as “planning”:

    • README.md — project map + phase labels + architecture diagram
    • Git log — phase-by-phase commit history with detailed descriptions
    • This task file — rolling session log with decisions
    • Nothing in the KB Strategic Plan
  • Medium-sized tasks for next hour — detailed below

Ranked by strategic leverage:


Task A — Write the MBR Strategic Plan (~45 min) Fill D:\FSS\KB\MBR\02_Strategy\Strategic Plan.md with real content:

  • Mission / narrative (better rates → referrals → 50% to cancer research)
  • Phase map: A (rate intel + widget) → B (hassle-engine + alerts) → C (concierge + financial IQ) → D (browser extension)
  • Current position: Phase A→B, rate scanner live, widget deployed
  • Key decisions made: Python/uv, SQLite, curl_cffi, reference_only distinction, CF Pages This turns scattered git history into a navigable strategic document.

Task B — Create rate-scanner STATUS.md (~30 min) The project has no formal STATUS.md in the SMTM sense. Create _WorkingOn/Projects/rate-scanner/STATUS.md:

  • Completed: Phases 1–4 (manifest → SQLite → scrapers → Big 6 → widget deployed)
  • Active: Phase 4 complete, cron running
  • Next: hassle-engine scaffold, custom domains, Cancer50Pledge Phase B
  • Feedback section This gives any future session an immediate read on where things are.

Task C — Update benefit-snapshots widget to use reference_only (~45 min) The export now tags products with reference_only: true, but the widget doesn’t use it yet. Update widget.js + build.py to:

  • Show recommended products (EQ Bank, Tangerine, etc.) as the primary comparison set
  • Show Big 6 standard savings in a separate “Market Average” callout (not as alternatives)
  • Sharpen the narrative: “This is what most Canadians earn. Here’s what you could earn instead.” This makes the widget’s Benefit Snapshot story cleaner and more persuasive.

Task D — Cancer50Pledge.ca: custom domain + analytics (~1 hr) Two items, each ~30 min:

  • Connect cancer50pledge.ca DNS to cancer50pledge.pages.dev (assumes domain is registered or can be)
  • Add Fathom or Plausible analytics script to +layout.svelte Makes the site production-ready for sharing/linking from MBR.

Task E — Mark Tangerine as reference_only (~15 min) Tangerine’s 0.700% is better than TD/BMO inertia but still not a product MBR would recommend clients move to (challenger banks like EQ Bank at 2.75% are far superior). If the principle is “reference_only = never recommend to clients,” Tangerine qualifies. One YAML flag + export re-run + commit.


  • Which task(s) to run this session? — Pick from A–E above (or any combination; A+B are pure KB writing, C+D are code, E is trivial).
    1. A, B, C, E
  • Tangerine reference_only — Should Tangerine (0.70%) be marked reference_only: true? Or do you see scenarios where it might be a legitimate recommendation? 1.
  • cancer50pledge.ca domain — Do you own this domain, or does it need to be registered first?
    1. soon


  • Task E — Tangerine marked reference_only: truerates.yaml updated, export re-run. Confirmed: 10 recommendable products (EQ Bank only), 6 reference-only (Big 6 + Tangerine).

  • Task A — MBR Strategic Plan written (D:\FSS\KB\MBR\02_Strategy\Strategic Plan.md)

    • Mission + the revenue loop (inertia → switch → referral → 50% cancer research)
    • Positioning, constraints
    • Full phase map: A (complete) → A→B (now) → B → C → D
    • Key technology decisions table
    • Cancer50Pledge integration rationale
    • Committed to MBR KB (6c752f7)
  • Task B — rate-scanner STATUS.md created (D:\FSS\KB\MBR\_WorkingOn\Projects\rate-scanner\STATUS.md)

    • SMTM-format: completed phases 1–4 with checkboxes, current metrics, Phase B priority queue, architecture decisions locked
    • Any future session on rate-scanner reads this first — full context in one file
    • Committed to MBR KB (6c752f7)
  • Task C — Widget updated to use reference_only flag

    • widget.js: getDisplayRows() now filters reference_only: true products before selecting recommendations — EQ Bank is always the best HISA candidate, never Tangerine or Big 6
    • Inertia row label updated: “Typical Big 6 bank rate” (was “What most Canadians earn”)
    • Rebuilt and deployed to Cloudflare Pages
    • Committed to MBR monorepo (6ea4935)
  • Review the Strategic PlanD:\FSS\KB\MBR\02_Strategy\Strategic Plan.md. Any corrections to the phase map, positioning, or Cancer50Pledge description? 1.
  • Phase A→B priority — The STATUS.md lists Phase B in order: (1) hassle-engine, (2) Cancer50Pledge Phase B, (3) custom domains, (4) mybetterrates.com site. Does this match your priorities, or should the consumer site come first? 1.
  • cancer50pledge.ca domain — answered “soon.” When ready, the CF Pages custom domain connection is 30 min. Flag here when the domain is registered.
    1. Cancer50Pledge.com and Cancer50Pledge.ca domains registered via Canadian Web Hosting