diff --git a/.design-sync/NOTES.md b/.design-sync/NOTES.md index 4b8c0b3ff..ba955101b 100644 --- a/.design-sync/NOTES.md +++ b/.design-sync/NOTES.md @@ -46,7 +46,36 @@ repo defects — re-flag to the design agent instead of restructuring CSS: ## Known render warns -- None — 10/10 render clean, no thin/blank/variantsIdentical flags. +- Renders themselves stay clean: 10/10, no thin/blank/variantsIdentical flags + (re-confirmed 2026-07-30). +- `[TOKENS_MISSING]` 7 CSS custom properties — triaged 2026-07-30, all seven + are **expected in the bundle**, so the warn line itself is known. Four are + benign by construction (runtime-set or scan artifacts); three are undefined + references in repo code that the bundle merely carries along (tracked as + `#141` in `docs/outstanding-issues.md`, not a sync defect): + - `--mobile-composer-reserve` — set at runtime by + `clinical-dashboard/mobile-composer-reserve.ts` and always read through a + `var(…, 0rem)` fallback. Never in a static stylesheet. Do not "fix". + - `--x` — Tailwind v4 scans the whole repo, found the literal string + `bg-[color:var(--x)]` in `docs/redesign/03-decision-log.md` prose, and + emitted a class for it. An artifact of documenting a class name; nothing + renders it. + - `--med-accent`, `--med-accent-border` — also runtime-set, not defects. + `medicationAccentStyle()` in + `clinical-dashboard/medication-record-page.tsx:88-94` assigns both, and + that style object is applied to the ancestor that contains every + referenced class (`:393`). A stylesheet-only missing-token scan cannot + see React `style` assignments; do not "fix" these. + - `--clinical-accent-strong` + (`clinical-dashboard/answer-status.tsx:252`) — genuinely undefined + production reference, no stylesheet or React `style` definition and no + fallback, so the declaration is dropped at parse time. Same defect + family as the dead `--text-4xs` classes repaired on 2026-07-30. + - `--primary-hover`, `--success-hover` — + `favourites-page-mockups/favourites-library-redesign-page.tsx`, which is + gate-exempt design scratch. Lowest priority. +- If a future sync sees a **different** var in the `[TOKENS_MISSING]` warn, that + one is new — look at it before recording it. ## Re-sync risks @@ -64,3 +93,17 @@ repo defects — re-flag to the design agent instead of restructuring CSS: components, but prop renames need preview edits. - The `prompt-for-codex-medical-knowledge-base` import specifier in previews is the package.json `name`; if the repo is renamed, update previews + config. +- `conventions.md` drifts silently when the token set moves. The 2026-07-30 + re-sync caught two dead claims after the Clinical Sky port: a `-solid` / + `-solid-contrast` pair claimed for every status family when only `danger` + has one, and `controlBase` listed as module-private when + `ui-primitives.tsx:34` exports it. Re-validate every enumerated token/class/ + icon against `ds-bundle/_ds_bundle.css` (definitions only — match + `--name\s*:`, not bare `var(--name)`, or referenced-but-undefined vars read + as defined) and the bundle's export list on every re-sync. A helper lives at + `.design-sync/.cache/validate-conventions.mjs` (gitignored, cheap to rewrite). +- The driver reports the token port as `changed: []` with `sourceKeys` + unchanged: `sourceKeys` track the authored preview + preview-affecting config, + NOT component source. A component-source or token change surfaces instead as + render churn (`canary`/`[SPOT_CHECK]`) plus `styling: true`. Grade the + spot-check sheets — the churn is real even though nothing is listed "changed". diff --git a/.design-sync/conventions.md b/.design-sync/conventions.md index bb6eaa361..136f9e754 100644 --- a/.design-sync/conventions.md +++ b/.design-sync/conventions.md @@ -17,8 +17,11 @@ arbitrary-value form — never hardcoded colours: - Borders: `border-[color:var(--border)]`, `--border-strong`, `--border-lux` - Accent (primary action colour): `--clinical-accent`, `--clinical-accent-hover`, `--clinical-accent-active`, `--clinical-accent-soft`, `--clinical-accent-border`, `--clinical-accent-contrast` - Command (primary buttons): `--command`, `--command-hover`, `--command-contrast` -- Status: `--danger-text/-bg/-border/-solid/-solid-contrast`, plus the same - families for `success`, `warning`, `info` (e.g. `--success-text`) +- Status: `success`, `warning`, `info` and `danger` each define + `-text`, `-bg`, `-border`, `-soft` (e.g. `--success-text`, `--warning-soft`). + The solid pair `--danger-solid` / `--danger-solid-contrast` exists for + `danger` only — there is no `--success-solid`, `--warning-solid` or + `--info-solid`. For a filled non-danger status use `-bg` + `-text`. - Elevation: the `--e0` … `--e4` ladder — `shadow-[var(--e2)]`, `hover:shadow-[var(--e3)]`. `--e0` flush · `--e1` resting hairline · `--e2` cards/popovers · `--e3` hover/lifted chrome · `--e4` modals/sheets/drawers. The role names are aliases onto tiers: @@ -42,13 +45,15 @@ re-deriving surfaces: `panel`, `panelSubtle`, `raisedCard`, `sourceCard`, `navPill`, `metadataPill`, `subtleStatusPill`, `shellChip`, `fieldLabel`, `fieldControl`, `fieldControlWithIcon`, `fieldControlPlain`, `fieldIcon`, `eyebrowText`, `textMuted`, `proseMeasure`, `codeText`, `iconTilePremium`, -`clinicalDivider`, `tableCard`, `tableCardHeader`, plus the chat/search -composer and tone recipes documented in +`clinicalDivider`, `tableCard`, `tableCardHeader`, `controlBase` (the shared +control shell the button recipes build on — prefer `primaryControl` / +`floatingControl` / `toolbarButton` unless composing a new control), plus the +chat/search composer and tone recipes documented in `docs/redesign/09-ui-primitives-recipes.md`. Join with the exported `cn(...)` helper. Module-private helpers (`insetCard`, `iconTile`, `compactMetadataRow`, -`toneWarningQuiet`, `controlBase`, `statusDotBase`, `chatComposerShellDelta`) +`toneWarningQuiet`, `statusDotBase`, `chatComposerShellDelta`) power components inside `ui-primitives.tsx` and are **not** part of the import surface — use the exported components (`LoadingPanel`, `PanelHeading`, `SourceProvenance`, `SourceStatusBadge`, …) or the exported recipes above. diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index 45af638ec..f071550bc 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -82,7 +82,7 @@ removed after current-main verification; it is not missing recommended work. | 34 | `#105` | Optional | High — browser/UI verification | When the heavy-run lock is free | 20–40 minutes | Run `verify:ui` over the ten `LoadingPanel` fallbacks and confirm the Supabase `preconnect` reaches `
` on a live page. Implementation already shipped; this row is the outstanding verification only. | | 35 | `#126` | Optional | Standard — repository hygiene | Once per UTC calendar quarter, or when the live ledger grows large | 5–15 minutes | Run `npm run ledger:rotate -- --dry-run`, then `npm run ledger:rotate` if the preview looks right; commit the live+archive diff. Stop if dry-run shows unexpected mass moves or archive path collisions. | - + ## Open items @@ -142,7 +142,6 @@ removed after current-main verification; it is not missing recommended work. | #105 | P3 | task | Verify the `#017`-exempt client latency wins in a browser | **Outcome:** the two zero-payload client fixes are confirmed in a real browser. `#017` gates _payload_ decisions (#012/#013/#016 are all byte-count items); a `loading` fallback ships zero bytes and a resource hint ships ~60, so neither can be justified or refuted by a Lighthouse number — that is why these were not held behind #017. **Implementation shipped 2026-07-29; browser verification still PENDING:** 10 of 11 `ssr:false` dashboard surfaces had NO `loading` fallback and rendered nothing between HTML arrival and chunk execution — all now use the shared `LoadingPanel` (`role="status"` + accessible label); Supabase `preconnect`/`dns-prefetch` added, since `AuthProvider` awaits a cross-origin `getUser()` on mount that every auth-gated fetch queues behind and there were no resource hints anywhere in `src/`. Shipped with `verify:cheap` + `verify:pr-local` only. **Next:** run `npm run verify:ui` once the heavy-run lock is free, and confirm the preconnect appears in `` on a live page. **Stop:** the two sidebar dialogs are intentionally excluded — they mount on open, so a fallback would render into a closed dialog. | `docs/audit/latency-audit-2026-07-28.md` L3-4/L3-5; `src/components/clinical-dashboard/clinical-dashboard-lazy.tsx` | 2026-07-29 | | #106 | P2 | rec | Ingestion worker and indexing agent are verified by grepping their own source | **Outcome:** the ingestion worker and indexing agent are verified by executing code, not by asserting on their own source text. **Detail:** measured 2026-07-29 via `npm run test:coverage` — `worker/main.ts` (2,015 lines) and `supabase/functions/indexing-v3-agent/index.ts` (1,966 lines) each report **0% executed lines**; no test imports either module. Both are covered only by `readFileSync` + `toContain` assertions in `worker-safe-logging.test.ts`, `worker-visual-capture.test.ts` and `document-metadata-merge.test.ts`, which pass whenever a string is present and break on harmless refactors; `document-metadata-merge.test.ts` additionally reimplements the SQL deep-merge in TypeScript and tests the reimplementation rather than the worker. Area totals: `worker/` 18.6% lines, `supabase/functions/` 4.5%. **Next:** continue the extraction pattern that already works here — `indexing-v3-agent/behavior.ts` (167 lines, 96%) and `ingestion-worker/auth.ts` (30 lines, 90%) — pulling the highest-risk decision points out of `worker/main.ts` (job claim/retry, generation commit, failure classification) into importable modules with executing tests, retiring the matching source-text assertion as each lands. Roughly cost-neutral: each extracted test replaces a grep assertion. **Stop:** do not try to make the 2,000-line entrypoint importable in one pass; extract incrementally and keep each step green. | session 2026-07-29 test-coverage analysis | 2026-07-29 | | #107 | P2 | rec | Component state matrices are the largest untested surface | **Outcome:** loading / empty / error / disabled states on interactive components are covered by executing tests, not only by E2E happy paths. **Detail:** measured 2026-07-29 — production components (excluding mockups) sit at **38.2% lines / 22.8% branch** across 12,602 lines, with **83 of 208 files at zero executed lines**; there are 51 `.dom.test.tsx` files against 195 components. Playwright does visit these routes, so they are smoke-covered, but branch coverage is where the state matrix lives and smoke journeys rarely reach it. Worst by uncovered lines: `global-search-shell.tsx` (7%), `mode-action-popup.tsx` (21%), `answer-content.tsx` (27%), `document-search-results.tsx` (32%), `universal-search-command-surface.tsx` (39%), `master-search-header.tsx` (43%). A concrete first target with clinical meaning: `calculator-ui.tsx` now covers all exported scoring logic, but `seedCheckboxDefaults`, `toggleCheckboxAnswer` and `selectOptionAnswer` stay uncovered because they are module-private and only reachable through React event handlers — `seedCheckboxDefaults` is what makes an all-negative CAGE / SAD PERSONS screen read as a valid 0 rather than incomplete, so a regression there is a false-negative risk. **Next:** treat as a per-PR convention rather than a backfill push — `docs/testing.md` already prescribes the state matrix, so the gap is enforcement. Start with `global-search-shell.tsx`, which `docs/search-chrome-behaviour.md` treats as a contract surface. Keep additions in the jsdom tier (measured ~0.54s per file) instead of new Playwright journeys (~231 production journeys already run serially at `workers: 1` against a 45-minute CI budget). **Stop:** do not chase the coverage percentage by backfilling low-risk components; the re-ratcheted broad floor in `vitest.config.mts` holds the line. | session 2026-07-29 test-coverage analysis | 2026-07-29 | -| #110 | P3 | task | Design-system project token manifest lags its stylesheet | **Outcome:** the claude.ai/design token panel matches the shipped stylesheet. **Detail:** PR #1375 pushed a recompiled `_ds_bundle.css` (Clinical Sky, `--e0`–`--e4`, 4px radius grid, `--tracking-eyebrow`/`--leading-display`/`--leading-prose`) plus the four changed guideline docs to project `08d6f126`, but `_ds_manifest.json` is converter-generated and still advertises `--text-4xs: 0.5rem`, the old `--radius-lg/xl/2xl` values, and `--tw-leading`/`--tw-tracking` entries scoped to the retired `.leading-[…]` / `.tracking-[0.08em]` utilities. Rendering is correct; only the token inventory lags. Hand-editing was rejected — `kind`/`scope`/`annotation` are converter heuristics and a wrong panel is worse than a stale one. **Next:** in a session with the `/design-sync` skill, `npm ci`, then `npm install --prefix .ds-sync --no-save --package-lock=false esbuild ts-morph @types/react @tailwindcss/cli geist`, read `.design-sync/NOTES.md`, and run `resync.mjs --remote` so bundle and manifest regenerate together. **Stop:** do not hand-author `_ds_manifest.json`; the converter is not a published npm package and ships with the skill. | PR #1375; `.design-sync/NOTES.md`; project `08d6f126` (`_ds_needs_recompile` marker present) | 2026-07-29 | | #120 | P2 | issue | `verify:phone-chrome` exits 0 while reporting failed browser tests | **Outcome:** the phone-chrome gate cannot report success when no test executed. **Evidence 2026-07-30 (PR #1396):** `npm run verify:phone-chrome` finished with **exit code 0** while its own output ended `13 failed`. Every one of the 13 failed at browser launch (`browserType.launch: Executable doesn't exist ... chrome-headless-shell`), so zero assertions ran, yet the gate returned success. This is the green-when-broken case `AGENTS.md` warns about ("Exit code 0 alone is not proof") realised in a gate that is supposed to be the proof. **Next:** make the runner propagate the Playwright exit status, and fail loudly on a launch error rather than treating a zero-test run as a pass. Stop: do not paper over it by grepping output in the caller — the runner owns the status. | `scripts/verify-phone-chrome.mjs`; `scripts/run-playwright.mjs` | 2026-07-30 | | #121 | P3 | issue | Container Playwright browser build lags the pinned client | **Outcome:** browser gates run in remote sessions without hand-patching. **Evidence 2026-07-30:** the repo's Playwright client resolves headless-shell build `1234`; the container image provides `1194` at `/opt/pw-browsers`, so every browser test fails at launch. Worked around in-session by symlinking `chromium_headless_shell-1234/chrome-headless-shell-linux64/chrome-headless-shell` to the `1194` `headless_shell` binary plus its sibling resources — container-local, nothing committed, and it disappears with the session. `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1` means the mismatch cannot self-heal. **Next:** decide whether the image pins the browser build or the repo pins a client matching the image; until then any remote session claiming browser proof must state which it used. | `docs/testing.md`; container `/opt/pw-browsers` | 2026-07-30 | | #122 | P2 | issue | `ci/circleci: verify` fails on every branch and its log needs operator access | **Outcome:** the CircleCI status is trustworthy signal again, or it stops reporting. **Evidence 2026-07-30:** `ci/circleci: verify` was `failure` on every open PR sampled — #1396, #1407, #1405, and #1400, which is a **docs-only** `AGENTS.md` change — plus #1403's head. It is sharply bounded in time: #1393's head **passed** at build 638 (03:57), and builds 645 (04:09) onward all failed. The job's entire contents were mirrored locally on PR #1396's exact tip and every part is green — `format:check` clean, `lint` exit 0, `typecheck` exit 0, `npm run test` `432 passed (432)` / `4473 passed \| 4 skipped`, and the PyMuPDF-gated `tests/pdf-extractor.test.ts` (the repo's only `process.env.CI`-gated tests) `6 passed (6)` under a locally built `PyMuPDF==1.28.0` venv with `PYTHON_BIN` set exactly as `.circleci/config.yml` does. So the failure is in the job's **environment**, not repo code. Around 40 builds fired in ~40 minutes across 8 open PRs in that window, so credit/quota exhaustion is the leading hypothesis — **explicitly unverified**: the CircleCI project is private and no CircleCI token is available to any agent session, and `api/v1.1/project/gh/BigSimmo/Database/