live · updated 2026-07-19 12:23:13 MDT · auto-refreshes every 20s
branch harden/marathon-2026-07-19 · base 1534ba22 · one commit per fix, splittable · rolling PR ↗
Visible fixes a beta user experiences directly
Invisible robustness / privacy / security wins
| # | Fix | Severity | User value | Dev value | What it means for you | What it means for the codebase | Tests | Commit |
|---|---|---|---|---|---|---|---|---|
| 1 | Weather widget survives partial Open-Meteo data Weather | high | High | High | The Weather widget no longer goes blank where Open-Meteo omits a value — e.g. polar sunrise/sunset, or precipitation past the forecast horizon. Before, one missing value wiped current + hourly + daily. | The Open-Meteo Codable arrays (precip / sunrise / sunset / UV) now accept null elements; a null sun event is skipped and a null precip/UV reads as 0. +2 tests including a null-laden decode that threw before the fix. | +2 | 68a90028CI (macOS) |
| 2 | Recently Played shows “X minutes ago” again Music · Recently Played | high | High | Medium | The “X minutes ago” line is back on every Recently Played row. Real Spotify timestamps include milliseconds the app couldn’t parse, so the relative time silently disappeared for everyone. | played_at now parses both fractional- and whole-second ISO8601 (with fallback); the new regression test uses a real millisecond payload that would have failed before. Also capped a previously-unbounded 401 retry loop in search(). | +3 (incl. fractional fixture) | 0315f65eCI (macOS) |
| 3 | Crash reports stop leaking your username Feedback · crash reports | high | High (privacy) | High | Crash reports sent from the beta no longer expose your Mac username. The old redaction missed bare home-folder paths and could even leak a second username by “bridging” across text. | redact() rewritten to match a single username segment (no whitespace/newline bridging), handle no-trailing-slash paths, and preserve the real /Users/Shared folder. | +3 | abd2a5e7CI (macOS) |
| 4 | Nothing is sent before you’ve seen the disclosure Feedback · telemetry consent | high | High (consent) | High | A crash that happened before you finished onboarding can no longer be transmitted early. Nothing about a crash leaves your Mac until you’ve actually seen the telemetry disclosure and had the chance to opt out. | CrashReportHarvester now requires the TelemetryConsent watermark AND the opt-out toggle, matching the heartbeat gate. The old code checked only the toggle, so a pre-onboarding report could flush on the next launch. | +1 new, 8 adapted | d77e275dCI (macOS) |
| 5 | Feedback dashboard auth bypass closed Feedback backend (Cloudflare Worker) | critical | High (PII) | Critical | Your submitted feedback, screenshots, and install ID can no longer be read by a stranger. The ops dashboard trusted a header that anyone could fake on the default deployment. | isDashboardAuthorized no longer trusts the spoofable Cf-Access-Authenticated-User-Email header unless CF_ACCESS_ENABLED is explicitly set; otherwise it requires the signed session cookie. Fully verified locally. | +2 (npm 74/74 green) | 3cb2c61enpm 74/74 (local, full) |
| # | Target (surface) | User value | Severity | Conf | Cost | Score | Status |
|---|---|---|---|---|---|---|---|
| 1 | Spotify Recently-Played timestamp parse + bounded search retry (Music) — bare ISO8601DateFormatter drops fractional played_at → "Xm ago" vanishes every row | High | High | High | S | 78 | LANDED — 0315f65e |
| 2 | Worker dashboard auth bypass via spoofable Cf-Access-Authenticated-User-Email (feedback-worker src/index.js:909-917) — any request with that header reads all beta-tester PII; default deploy has no Access app in front | High (PII) | Critical (security) | High | S | 96 | LANDED — 3cb2c61e (npm test 74/74, fully verified) |
| 3 | Crash-report redaction leaks usernames (CrashReportParser.swift:155-159) — regex misses /Users/x w/o trailing slash and greedy-bridges across text/newlines, leaking a second username | High (PII) | High (security) | High | S | 90 | LANDED — abd2a5e7 (build + test-target compile green; full run on CI) |
| 4 | Crash harvester ignores consent watermark (CrashReportHarvester.swift:68-71) — can transmit a crash summary before onboarding/opt-out (heartbeat gates on both; harvester doesn't) | High (consent) | High (privacy) | High | S | 88 | LANDED — d77e275d (build + test-target compile green; full run on CI) |
| 5 | Weather: non-optional Open-Meteo arrays (WeatherManager.swift:176,200-203) — one null (polar sunrise/sunset, null precip) fails decode → entire forecast blanks | High (widget dead) | High | High | S | 84 | LANDED — 68a90028 (build + test-target compile green; full run on CI) |
| 6 | FeedbackService flushPending re-entrancy (FeedbackService.swift:191-205) — boot + harvest drains overlap → duplicate sends / lost queue items | Med-High | Med | High | M | 72 | Planned (seamed async) |
| 7 | Spotify queue decode fails on podcast episode (SpotifyAPI.swift:44-59) — a podcast in the queue throws → whole "Up Next" blanks | Med | Med | Med-High | M | 70 | Planned (decodable test) |
| 8 | Calendar isVideoConferenceURL substring match (CalendarEventParsing.swift:48-57) — lookalike/redirect URLs classified as meetings and auto-opened at start | Med | Med (auto-open) | High | S | 68 | Planned (pure test) |
| 9 | Lyrics multi-timestamp LRC lines (LyricsService.swift:392,399-406) — compressed chorus tags render raw [mm:ss] text and only highlight once | Med | Low-Med | Med | S | 60 | Planned (pure test) |
| 10 | Lyrics updateCurrentIndex non-monotonic freeze (LyricsService.swift:435-442) — early break freezes highlight after any out-of-order timestamp | Med | Low-Med | Med | S | 58 | Planned (pure test) |
| 11 | Worker /beta/heartbeat unbounded (src/index.js:222-281) — no rate limit, unbounded install_id + uptime → D1 growth / metric pollution / 64-bit overflow | Med (dev) | Med | High | S | 56 | Planned (local test) |
| 12 | Worker malformed cookie/path → unauth 500 (src/index.js:982-991,66) — decodeURIComponent throws → 500 instead of fail-closed 302; add safeDecode | Low-Med (dev) | Med | High | S | 50 | Planned (local test) |
| 13 | Calendar meet regex misses hyphenated vanity subdomains + case (CalendarEventParsing.swift:72-79) | Low-Med | Low | High | S | 48 | Planned (pure test) |
| 14 | Worker /submit no idempotency → duplicate rows/blobs/emails on client retry (src/index.js:151-209) | Low-Med | Low-Med | High | M | 44 | Planned (local test) |
| Round | Target | Plan file | Commit | Verify | Cycles | Files | Notes |
|---|---|---|---|---|---|---|---|
| 0 | Assess + prioritize + plan | this ledger + spotify-recently-played-timestamp-2026-07-19.md | — | — | — | — | Seeded from latent-bugs-2026-07-19.md; 4 explore agents verified against current tree; most of snapshot already landed; new backlog built |
| 1 | Spotify played_at parse + bounded search retry | spotify-recently-played-timestamp-2026-07-19.md | 0315f65e | Host build gate + test-target compile GREEN; full test+coverage deferred to CI/VM | 1 | SpotifyAPI+Library.swift, SpotifyLibraryFetchTests.swift | 3 tests added incl. fractional fixture that would have failed pre-fix |
| 2 | Fresh bug-hunt (4 parallel explore agents) | this ledger | — | — | — | — | Beta-visible seed exhausted; surfaced 14 new targets (security/privacy on top): worker auth bypass, crash-report PII leak, consent gate, Weather null-decode, etc. |
| 2 | Worker Cf-Access auth-bypass fix | (from bug-hunt) | 3cb2c61e | npm test 74/74 GREEN (full gate, local) | 1 | feedback-worker/{src/index.js,test/dashboard-auth.test.js,README.md,.dev.vars.example} | Bypass closed by default; Access honored only when CF_ACCESS_ENABLED="true" |
| 3 | Crash-report redaction PII leak fix | (from bug-hunt) | abd2a5e7 | Build + test-target compile GREEN; full run on CI | 1 | CrashReportParser.swift, CrashReportParserTests.swift | Username no longer leaks (bare path + whitespace-bridge); /Users/Shared preserved; +3 tests |
| 4 | Crash harvester consent-watermark gate | (from bug-hunt) | d77e275d | Build + test-target compile GREEN; full run on CI | 1 | CrashReportHarvester.swift, CrashReportHarvesterTests.swift | Requires consent watermark AND opt-out toggle (mirrors heartbeat); +1 new test, 8 adapted |
| 5 | Weather null-element decode tolerance | (from bug-hunt) | 68a90028 | Build + test-target compile GREEN; full run on CI | 1 | WeatherManager.swift, WeatherModelTests.swift, WeatherManagerTests.swift | 5 Open-Meteo arrays accept null elements; +2 tests |
| PR | Checkpoint: push + full critical review of PR #147 | — | (push) | pending review | — | git diff main...HEAD | Every-5-fixes gate: review whole PR, fix blockers, check CI |
fe370122docs(marathon): log round 5 (weather null-decode) + PR checkpoint2026-07-19 12:2368a90028fix(weather): tolerate null Open-Meteo array elements so a forecast still renders2026-07-19 12:221da1de35docs(marathon): enrich tracker with user/dev impact cards + ranked impact log; log round 42026-07-19 12:17d77e275dfix(feedback): gate crash harvesting on the consent watermark, not just the opt-out toggle2026-07-19 12:1576679bbcchore(marathon): link rolling PR from the live tracker2026-07-19 12:09de111f90docs(marathon): add Phase H (rolling PR + critical review every 5 fixes); log round 32026-07-19 12:08abd2a5e7fix(feedback): redact bare and adjacent /Users home paths without leaking usernames2026-07-19 12:073387aab2docs(marathon): log round 2 (worker auth bypass landed)2026-07-19 12:013cb2c61efix(worker): require CF_ACCESS_ENABLED to trust Cf-Access header (close dashboard auth bypass)2026-07-19 12:009a4bd0c7docs(marathon): record round-2 bug-hunt (14 ranked targets)2026-07-19 11:57c4132abbchore(marathon): add live Cloudflare Pages tracker (generator + publisher)2026-07-19 11:552ebf9c4bdocs(marathon): log round 1 landing, pivot round 2 to fresh bug-hunt2026-07-19 11:380315f65efix(spotify): parse fractional-second played_at timestamps and bound search 401 retry2026-07-19 11:379eb6b8e9docs(marathon): seed harden-marathon ledger and round-1 plan2026-07-19 11:29b30b6abachore(skills): add harden-marathon skill and protocol rule2026-07-19 11:29Generated by the harden-marathon tracker · impact data: .cursor/skills/harden-marathon/landed.json · ledger: .cursor/plans/harden-marathon-2026-07-19.md