docs: close QA-B0-04 (@ts-nocheck 38->8) in QA plan + CODE_STANDARDS

Cycle Log row 3·typecheck; B0 counter steady state now <=8 with a
regression guard; CODE_STANDARDS records that all routes/server.cts are
checked and the 8 intentional exceptions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
null 2026-07-11 07:20:13 -05:00
parent 7ce5fb66f5
commit 8075b4e1e1
2 changed files with 18 additions and 7 deletions

View File

@ -12,7 +12,15 @@ rolled out. Update this doc when a standard changes.
(react-hooks on the client; `js/recommended` + TS-unused on the server). Errors block CI;
warnings are advisory (ratchet down over time).
- **Typecheck:** `npm run typecheck` (client, strict + `noUncheckedIndexedAccess`) and
`npm run typecheck:server` (server). Both run in CI.
`npm run typecheck:server` (server). Both run in CI. **All routes, middleware,
workers, `server.cts`, and most services are fully type-checked.** Only 8
files keep `@ts-nocheck` — 4 db migration/seed factories + 4 dynamic parsers
(spreadsheet/userDbImport/subscription/oidc) that parse inherently-`unknown`
input or mutate arbitrary historical schemas; each carries an `INTENTIONAL`
rationale header. A **new** bare `@ts-nocheck` on a route or handler is a
regression (B0 recon counts them; steady state ≤ 8). Dynamic DB rows stay
`any` by design (see `types/db.d.ts`); annotate params/callbacks rather than
suppressing whole files.
- **Local hooks (lefthook):** pre-commit auto-formats staged files + lints; pre-push
typechecks. Installed by `npm install` (the `prepare` script).
- **Dead code:** `npm run knip` (advisory) for unused exports/deps.

View File

@ -3,7 +3,9 @@
**Version target:** v0.42.x · **Executor:** Claude (active) · **Last updated:** 2026-07-10
**Cycle 1: COMPLETE ✅** — all 18 batches (B0→B16 + B-UI) run; **15 findings fixed**, verified & archived (3× S2); automated re-run of existing batches clean (0 new); the added **B16** (migrations/secrets/deploy) surfaced + fixed 1 (version-check opt-out). Guard suite green. External-infra items (live TOTP/OIDC, SMTP delivery, cross-browser, PWA-offline, load, container build) carried to Cycle 2 as non-blocking.
**2026-07-10 blind-spot recon + fix pass: COMPLETE ✅** — a dedicated deps/dead-code/coverage audit logged 6 findings (1× S2) + 4 IMP; **all fixed, verified & archived** to `HISTORY.md` v0.41.1/v0.42.0 except the `@ts-nocheck` burn-down (QA-B0-04, a tracked program). Highlights: the WebAuthn ghost feature now **ships end to end** (passkey UI + CDP virtual-authenticator e2e — no longer "needs a human"); every route emits errors through the enforced throw-pattern; every dependency major is current (0 vulns, audit gate raised to high, weekly deps-audit workflow + renovate.json); knip is clean and blocking; Appendix E is automated (`census` e2e project). See Cycle Log rows 2·recon / 2·fix.
**2026-07-11 `@ts-nocheck` burn-down: COMPLETE ✅** (branch `chore/typecheck-routes`) — QA-B0-04 closed. All 29 routes **and** `server.cts` are now type-checked (38 → 8); the 8 remaining files are documented intentional exceptions (dynamic parsers + migration factories). The checker caught two shared-type gaps (fixed) and forced two small correctness touch-ups; the /code-review over this branch found nothing further of note beyond the earlier cycle. Steady-state counter now guards ≤ 8.
**2026-07-10 blind-spot recon + fix pass: COMPLETE ✅** — a dedicated deps/dead-code/coverage audit logged 6 findings (1× S2) + 4 IMP; **all fixed, verified & archived** to `HISTORY.md` v0.41.1/v0.42.0 (the `@ts-nocheck` burn-down QA-B0-04 was carried as a tracked program and is now closed — see above). Highlights: the WebAuthn ghost feature now **ships end to end** (passkey UI + CDP virtual-authenticator e2e — no longer "needs a human"); every route emits errors through the enforced throw-pattern; every dependency major is current (0 vulns, audit gate raised to high, weekly deps-audit workflow + renovate.json); knip is clean and blocking; Appendix E is automated (`census` e2e project). See Cycle Log rows 2·recon / 2·fix.
This is a **living, operational** QA document, not a static spec. Claude runs it,
in **batches**, actively hunting for bugs/errors/rough edges, **fixing** them, and
@ -165,6 +167,7 @@ until you get a clean cycle.
| 1·data-overhaul | 2026-07-03 | `78ad63d`→`d53a64b` (dev) | **0 defects** (feature work) | — | ✅ **Data page overhaul, 7 batches, all green.** Two-pane goal layout + 5-state connection hero + `?section=` deep-linking + nav badges/health dots + lazy panes (B0B2); **new features** OFX/QFX import (B3), richer export JSON + date-range (B4), "Erase my data" danger zone (B5). Verified: server 139 tests, client 46, build; **axe on `/data` zero critical/serious** (added to `a11y.authed`); full probe suite 17/17. Section internals + the 7 SimpleFIN buttons untouched. |
| 2·recon | 2026-07-10 | `d9545d6` (dev) | **6** (1× S2, 4× S3, 1× S4) + 4 IMP | — (find-only) | 🔁 **Blind-spot recon** (deps/dead-code/coverage audit, no UI batches). Logged: high-vuln deps invisible to the critical-only CI gate (QA-B0-02) · package.json 0.40.0 vs HISTORY v0.41.0 drift (QA-B0-03) · **WebAuthn ghost feature** — full backend + api wrappers, zero UI, and a login fall-through that 500-locked any user who enabled it (QA-B1-01, S2) · 38 `@ts-nocheck` files ⇒ vacuous server typecheck (QA-B0-04) · raw `err.message` 5xx leaks (QA-B13-02) · dead duplicate admin routes incl. an unauthenticated `/api/auth/has-users` (QA-B17-01). Verified-clean along the way: SQL building (whitelists+params), no `dangerouslySetInnerHTML`/`as any` in client, ICS feed token-gated, git hygiene, all 29 route files mounted. |
| 2·fix | 2026-07-10 | `3c82c30`→HEAD (dev), tags `v0.41.1` | all 6 + 4 IMP fixed | **9 archived** (v0.41.1 + v0.42.0); QA-B0-04 continues as a program (38→29) | ✅ **Fix pass complete, ~30 commits.** Phases: bug fixes (lockout, 401-mid-session redirect, version sync + guard test, 20 err.message leak sites) → **standards unification: all 29 routes on the throw-pattern, eslint-enforced** (no-console + errorFormatter ban; exceptions documented in CODE_STANDARDS) → **passkey UI shipped** (+ virtual-authenticator e2e, WEBAUTHN_RP_ID deploy guard) → tag v0.41.1 → **full dependency modernization** (vite 8 · tailwind 4 · router 7 · openid-client 6 · eslint 10 · nodemailer 9 · SheetJS dist; 0 vulns; audit gate → high; prod-smoke caught & fixed 3 upgrade breakages: send absolute-path, CSP inline script, manualChunks; TS7 deferred on typescript-eslint peer cap) → dead-code sweep (knip clean + blocking; `doingmypart.jpg` kept after user catch — markdown-content lesson added to B0) → @ts-nocheck starter batch (38→29) → **automated control census** (own `census` project) → deploy checklist + renovate.json + weekly deps-audit workflow. Gates at close: ci green (252 server / 52 client), e2e 27, census+probe 33/33 ×3, OIDC smoke 44/44, PROD SMOKE PASS. **Closing /code-review (8 finder angles + library-verified) surfaced and fixed 8 more:** tailwind-4 codemod killed the row-status tints (fractional bare opacity emits no CSS; invisible to the login-only screenshot baseline — `a00013d`) · session-expiry redirect falsely fired on /profile/change-password wrong-password (now keyed off requireAuth's distinct `AUTH_REQUIRED` code, not a path prefix) · OIDC v6 dropped the RFC 9207 `iss` param (every authentik login would fail) · v6 https-only discovery breaks internal http providers (`OIDC_ALLOW_INSECURE_HTTP` opt-in) · 2FA silently downgraded to password on any challenge error (now only the stale-flag case) · burned single-use 2FA challenges left a dead retry button (WebAuthn AND pre-existing TOTP — both reset to sign-in) · three multi-write handlers `db.transaction()`-wrapped (`2a07e76`, `a17ce13`). Larger refactors → IMP-CODE-08…11, IMP-UX-03. |
| 3·typecheck | 2026-07-11 | `chore/typecheck-routes` off `25404ec` | 0 defects (2 latent touch-ups) | — | ✅ **`@ts-nocheck` burn-down (QA-B0-04 CLOSED), 6 commits.** All 20 remaining routes + `server.cts` type-checked in 5 batches (easy tail → transactions' 116-error monster), 38 → 8 files. Mostly mechanical annotation, but the checker earned it: fixed the `res.download`/`res.redirect` shared-type overloads it exposed from the v0.42.0 changes, deleted dead `clampDay`, tightened the bills end-date guard, `Date - Date``.getTime()`; `throwStandardized(): never` cleared 16 false "possibly undefined". The 8 remaining files got INTENTIONAL rationale headers. Also hardened the control census against count-driven plural churn (was flaking under parallel load). Verified: ci green, server 252/252, client 52/52, real `server.cts` boot smoke, census+probe 33/33 ×2. Closing /code-review over the branch: nothing of note. |
**Result key:** 🔄 in progress · 🔁 findings fixed, re-run required · ✅ clean (zero findings — QA complete)
@ -181,10 +184,10 @@ fixing. Keep only **Open / Fixing / Fixed** rows here. Once a finding is
**Severity:** S1 Critical · S2 Major · S3 Minor · S4 Cosmetic · IMP Improvement (see [Appendix A](#appendix-a--severity-definitions)).
**Status:** 🔴 Open → 🟡 Fixing → 🟢 Fixed (verified, awaiting archive) → then remove on 📦 Archive.
| ID | Sev | Area (`file:line`) | Summary | Status | Notes / repro |
| ------------------------------------------------------------------------------------------------------------------------------ | --- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| QA-B0-04 | S3 | 29 server files (`grep -rl @ts-nocheck`) | **`@ts-nocheck` burn-down (program, in progress):** typecheck:server is vacuous over these files. Starter batch done (38 → **29**: the 9 smallest routes fully checked, `db53954`). The B0 recon counter must only go down. | 🟡 Fixing (program) | Remaining: 20 routes + server.cts + 4 db + 4 mega services. Convert opportunistically when touching a file; oidcService partially cleaned during the v6 rewrite. |
| _(all other 2026-07-10 recon findings fixed & archived — QA-B0-02 → v0.42.0, QA-B0-03/QA-B1-01/QA-B13-02/QA-B17-01 → v0.41.1)_ | | | | | |
| ID | Sev | Area (`file:line`) | Summary | Status | Notes / repro |
| ------------------------------------------------------------------------------------------------------------------------------ | --- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| QA-B0-04 | S3 | 8 dynamic files (documented) | **CLOSED (2026-07-11, branch `chore/typecheck-routes`):** `typecheck:server` was vacuous over 38 files; now all 29 routes **and** `server.cts` are type-checked (38 → **8**). The 8 remaining `@ts-nocheck` files (4 db migration/seed factories + 4 dynamic parsers: spreadsheet/userDbImport/subscription/oidc) carry an **INTENTIONAL** rationale header — they parse inherently-`unknown` input or mutate arbitrary historical schemas, where full typing yields `any` anyway or adds risk to boot-critical code. The B0 counter now guards the steady state (must stay ≤ 8). | 🟢 Closed | Two shared-type gaps the checker caught were fixed in `types/http.d.ts` (`res.download`/`res.redirect` overloads for the v0.42.0 root-option + status-redirect forms). Real bugs it forced: bills end-date guard tightened, `Date - Date``.getTime()`. |
| _(all other 2026-07-10 recon findings fixed & archived — QA-B0-02 → v0.42.0, QA-B0-03/QA-B1-01/QA-B13-02/QA-B17-01 → v0.41.1)_ | | | | | |
**Finding template** (paste a new row above; keep the full write-up here until archived):
@ -396,7 +399,7 @@ Run these, then compare the output to the batch playbooks (§7) and the [route m
- [ ] **What changed since last cycle** — skim `git log`/`HISTORY.md` since the previous cycle's commit (see [Cycle Log](#11-qa-cycle-log)) for new features/pages.
- [ ] **Dependency freshness (added 2026-07-10)** — run `npm outdated` and `npm audit` (full, not just the CI gate). Log every **high+ vulnerability** and every **major lag on a security-relevant dep** (auth, crypto, parsers of untrusted input) as a finding. Standing guards: weekly `deps-audit` workflow (fails on high+), `renovate.json`. Known cap: typescript <7 until typescript-eslint supports it.
- [ ] **Dead-code scan (added 2026-07-10)**`npx knip` is a **blocking CI step**; any new unused file/export/dep fails. Also grep for **API wrappers with no client callers** (how the WebAuthn ghost hid for 4 cycles) and remember: asset-reference sweeps must include **rendered markdown content** (HISTORY.md images are served by the release-notes renderer — the `doingmypart.jpg` near-miss).
- [ ] **Type-check debt census (added 2026-07-10)**`grep -rl "@ts-nocheck" routes services db workers middleware utils server.cts | wc -l` and record it in the Cycle Log. It must be **≤ last cycle's** (baseline after the starter batch: **29**; was 38 — see QA-B0-04).
- [ ] **Type-check debt census (added 2026-07-10)**`grep -rl "@ts-nocheck" routes services db workers middleware utils server.cts | wc -l` and record it in the Cycle Log. Steady state is **8** (all routes + server.cts checked; 8 intentional-exception files remain, each with a rationale header — see QA-B0-04, CLOSED). It must stay **≤ 8**; a new bare `@ts-nocheck` on a route/handler is a regression.
- [ ] **Version coherence (added 2026-07-10)**`package.json` version == top `HISTORY.md` heading; `tests/versionSync.test.js` enforces it, this check is the reminder to bump both when releasing.
**Update the plan (do this now, not later)** — for anything the recon surfaced that isn't already covered: