diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 9ee914b9a..7b51dd458 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -660,3 +660,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-20 | claude/clinical-kb-pwa-review-asi3wb (PR: RAG memory + safeguards) | see PR head | User-directed close-out: durable RAG behaviour memory (docs/rag-behaviour/, 4 files) + AGENTS.md standing protection rules + ENFORCED safeguards — pr-policy blocking `RAG impact:` gate on protected surfaces (self-tested: undeclared/vague blocked, no-change/canary declarations pass) + source-pin contract test on imputation formulas and release comparator key order (red-proven vs a mutated constant). Confirmation canary #56 (29774459706, reverted main 0a498e6): SUCCESS — 36/36 restored, closing the #55-regression→revert→restore arc live. Phase D complete (D-1 ref input #1003, D-2 eval:trend #1006, D-3 policy §3.1 #1006, D-4 latency in trend rows); remaining documented plans: word-boundary matcher (own PR), irrelevant@10 labeling audit, Phase E (separate approval). Spend ≈$5-10 of ≤$20. | pr-policy self-test + workflow guard PASS; contract test 4/4 + red-proof; npm run test 3025 passed / 1 known container pdf-budget artifact; lint+typecheck+prettier clean; docs:check-links 1030 refs PASS; check:github-actions PASS | | 2026-07-20 | claude/clinical-kb-pwa-review-asi3wb (PR: matcher + artifact follow-ups) | ab145f6 | Remaining documented improvements implemented: word-boundary textContainsClinicalTerm + top-10 canary artifact rows | Matcher: boundaries + internal separators widened to any non-alphanumeric run — PROVEN strict superset by artifact replay on canary #53 (1,126 term×alias×result comparisons, 0 lost matches, 7 gained = exactly the previously-documented punctuation-joined occurrences: treatment,/mood,/(opioid/ptsd.[35]/ciwa-ar ×3). More-tolerant measurement cannot fail a passing case → weekly scheduled canary = free live confirmation. Exported + 3 direct unit-test groups (superset preservation, audit classes incl. line-broken 'ciwa- ar' and 'full-blood-count', substring-inside-word rejections). Artifact: topResultSummary 5→10 rows so rr@10/irrelevant@10 metrics' actual inputs are captured — unblocks the offline irrelevant@10 labeling audit next artifact. docs/rag-behaviour updated to implemented state. Phase E remains gated on separate approval. | Targeted vitest 59/59; npm run test 3028 passed / 1 known container pdf-budget artifact; lint+typecheck+prettier clean; audit script run recorded above; no provider calls | | 2026-07-20 | claude/clinical-kb-pwa-review-asi3wb (PR: DB easy wins) | see PR head | User-requested database + process easy-wins pass: read-only Supabase advisor sweep (user-authorized) → canary-liveness probe + advisor-disposition docs; live mutations withheld for per-item confirmation | Advisors (live, read-only): security = 1 INFO (document_title_words RLS-no-policy = the deliberate fail-closed pattern — now comment-documented at the schema block so it is never 'fixed'); performance = ~33 unused-index INFOs + auth connection-strategy note → docs/db-maintenance.md TRIAGE list with retrieval-surface trgm indexes flagged RAG-protected (dropping = full canary protocol), owner-scoped indexes retained for multi-tenant design, operational candidates deferred (negligible benefit at corpus size). Implemented: ci.yml static-pr warn-only eval-canary staleness probe (actions:read, github-script pinned, >8 days → warning; never fails) — needed because #923 (2026-07-19) moved the canary cadence from daily to weekly Sunday 18:00 UTC, where a dropped fire would go unnoticed for a week (the failure-issue step only reacts to runs that happen). CORRECTION (CodeRabbit review on this PR): the initially recorded "2026-07-20 dropped Sunday fire" incident did not occur — 2026-07-20 is a Monday; the Sunday 2026-07-19 slot fired as scheduled run #48 (19:03 UTC, success), and under the weekly cron no 2026-07-20 slot existed. Probe stands as proactive hardening, staleness now measured from updated_at with a finite-timestamp guard. Presented for confirmation (NOT implemented): scheduled telemetry retention (purge:query-logs is owner-scoped + unscheduled; needs owner/window/policy decision), auth percentage connection strategy (dashboard config), any index drops. | check:github-actions PASS; check:ci-scope PASS; check:function-grants 28/28 PASS; docs:check-links 1034 PASS; supabase-schema vitest 66/66; lint+typecheck+prettier clean; Supabase access read-only only | +| 2026-07-20 | claude/clinical-kb-pwa-review-asi3wb (restarted from e6cd6cb; PR: telemetry-retention correction) | 01368ff (+0144e69 main merge-in) | User-directed "implement your recommendation for all decisions" close-out: the scheduled-retention recommendation is RETRACTED as founded on a false premise — telemetry retention is ALREADY ACTIVE inside the database via pg_cron; docs corrected, nothing built, no live mutations | Fresh read-only cron.job verification (2026-07-20) matches docs/privacy-impact-assessment.md §6 exactly: jobid 11 purge-expired-rag-queries daily 03:30 (30d), jobid 12 purge-rag-retrieval-logs daily 03:00 (90d), jobid 13 purge-rag-query-misses daily 03:45 (90d), jobid 16 purge-rag-response-cache hourly (bounded 1000); v3 worker jobs present-inactive under backlog auto-toggle (jobid 10); obsolete unbounded cache job absent; audit_logs indefinite by design. db-maintenance.md "open decision" section replaced with the resolved state; purge:query-logs clarified as the MANUAL owner-scoped tool (not the retention mechanism). A GitHub-side weekly deleter would have duplicated pg_cron with window drift (a 90d rag_queries sweep can never out-delete the live 30d job). Remaining decisions stand as documented no-action: auth percentage connection strategy deferred to next instance resize; operational index drops not recommended. | prettier + docs:check-links PASS; Supabase access read-only (single cron.job SELECT, user-authorized read-only envelope); no workflow/schema/config changes | diff --git a/docs/db-maintenance.md b/docs/db-maintenance.md index 232f5f8ef..5fe22e930 100644 --- a/docs/db-maintenance.md +++ b/docs/db-maintenance.md @@ -37,15 +37,32 @@ replay + (for retrieval tables) canary pair — never a bulk advisor-driven swee (magic-link/OAuth only). Revisit at the next instance-size change (dashboard config — confirmation-required). -## Telemetry retention — open decision (2026-07-20) - -`rag_queries` / `rag_retrieval_logs` telemetry grows with live and eval traffic. -`npm run purge:query-logs` exists (owner-scoped, `--older-than-days`, `--dry-run`, -fails loudly on unknown flags) but is **scheduled nowhere** — retention is currently manual -and unbounded. Wiring a schedule is deliberately NOT done unilaterally because it is a -recurring live-deletion job needing an explicit policy: which owner scope, what retention -window (script default 90 days), and where it runs (a small weekly workflow with the -service-role secret is the natural home). Decision recorded here when made. +## Telemetry retention — RESOLVED: already active in pg_cron (verified live 2026-07-20) + +An earlier revision of this section called retention "manual and unbounded" after finding +`npm run purge:query-logs` scheduled nowhere. That premise was wrong: retention runs INSIDE +the database via pg_cron, not in CI. Read-only `cron.job` verification (2026-07-20) matches +`docs/privacy-impact-assessment.md` §6 exactly: + +| jobid | Job | Schedule (UTC) | Window / mechanism | +| ----- | --------------------------- | -------------- | -------------------------------------------------- | +| 11 | `purge-expired-rag-queries` | daily 03:30 | `purge_expired_rag_queries(30)` — 30 days | +| 12 | `purge-rag-retrieval-logs` | daily 03:00 | raw delete where `created_at` older than 90 days | +| 13 | `purge-rag-query-misses` | daily 03:45 | `purge_expired_rag_query_misses(90)` — 90 days | +| 16 | `purge-rag-response-cache` | hourly at :15 | `purge_expired_rag_response_cache(1000)` (bounded) | + +All four are active; the obsolete unbounded cache job remains absent; `audit_logs` retention +is indefinite BY DESIGN (compliance note in migration `20260702120000` — do not add a purge +without compliance review). **No GitHub-side retention workflow is needed, and none was +added**: a second scheduled deleter would duplicate pg_cron and invite window drift — the +once-proposed weekly 90-day sweep of `rag_queries` could never delete anything the 30-day +job had not already removed. Retention windows are PIA-governed privacy decisions; change +them via migration + PIA update, never ad hoc. + +`npm run purge:query-logs` is the MANUAL owner-scoped deletion tool (privacy requests, +targeted eval-owner cleanup; requires `--owner-email`, supports `--dry-run`, default 90 +days). It is deliberately unscheduled — it is not the retention mechanism, and its absence +from cron is not a gap. ## Cross-references