Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-09-02 | claude/caring-contacts-rules-r7r2ih-4 | 3e7d010575ece57266be7bd0864e5e60de874d58 | PR #2535 (#PAMATF): model.ts planSendingHold relocation and load-time invariant, both repository implementations' listSendableContacts, message-policy.ts plan-not-dispatchable, schedule-view.ts, simulation.ts, repository.ts port contract, plan-activation.ts, the phase-2b build record and HANDOVER, and their tests | MERGED 2026-09-02 into its base branch (claude/caring-contacts-rules-r7r2ih-3), not into main directly, so it reached main inside 2631782a3. Branch since deleted — but note it was accidentally RE-PUSHED after the merge and could not be deleted again from the cloud container (git push --delete returns 'the remote end hung up unexpectedly' then 'Everything up-to-date'); it is stale and must not be reused. This PR overturns Ruling 129 as Ruling 129A by explicit owner decision, recorded in the build record with the HANDOVER entry closed. Two pinned assertions were changed deliberately, not incidentally: the readmission test now expects zero sendable contacts (it had been pinning the defect) while additionally asserting all ten contacts still exist and are still scheduled, and the simulation's paused-plan case now sees the refusal at the read rather than the write. A review round found a third — the death-correction case would have passed from the plan gate alone — and it gained a per-contact state assertion. | LOCAL OFFLINE GATES, run in this container: typecheck exit 0; full offline unit suite 949 files / 12293 passed \| 1 skipped; lint exit 0; prettier --check clean; cc-guards 42 files / 1069 passed; caring-contacts db suite 217 passed against a disposable local Postgres 16 (not the live Supabase project); mutation checks — removing the in-memory plan gate turns two contract assertions red, and making planSendingHold admit a paused plan turns the new Ruling 129A read/write agreement assertion red. HOSTED CI: none ran on this PR — repo CI is scoped to branches [main, release/**], so a PR whose base is another feature branch gets no pipeline at all. Its hosted proof is therefore the CI that ran on the main-based head AFTER this merged through into it (see the claude/caring-contacts-rules-r7r2ih-3 record at 2631782a3), not anything observed on this PR. Hosted CI results named here were OBSERVED, not inherited: this Claude Code session read them directly from the GitHub check runs via the GitHub MCP tools, under Josh's standing instruction to babysit these PRs, which is the explicit confirmation the provider boundary requires for that read. Provider-backed gates NOT run: no eval:* retrieval canary, no verify:release, no check:supabase-project, no live Supabase or OpenAI test:live path, and no live-drift dispatch. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-09-02 | claude/caring-contacts-rules-r7r2ih | 94a14a829312ab317b64064fe520a38481930db7 | PR #2532 (#59JT7W + #RZVMPD, squashed to main): src/lib/caring-contacts/message-policy.ts, db/postgres-repository.ts, schedule-view.ts and their tests | MERGED to main 2026-09-02. Closing-message refusal routed through the validateGovernedMessage chokepoint and widened to every message type; caseload list read narrowed to PLAN_LIST_COLUMNS. A clinical-governance review round caught the first draft granting a NEW permission (validateGovernedMessage returned valid:true for a standard message with no body at all) and masking the more serious record-level refusal behind 'write a body'; both fixed before merge. Bugbot reviewed and rated Low Risk. | LOCAL OFFLINE GATES, run in this container: typecheck exit 0; full offline unit suite 949 files / 12293 passed \| 1 skipped; lint --max-warnings 0 exit 0; prettier --check clean; caring-contacts db suite 218 passed against a disposable local Postgres 16 (not the live Supabase project; assertNotClinicalKbProject refuses that ref by construction); cc-guards 1069 passed. HOSTED CI: green on the main-based head — PR required, Unit coverage, Build, Static PR checks, Safety and config, Caring Contacts database, Lighthouse budget, Semgrep, Gitleaks, GitGuardian, PR policy, PR mergeability. Hosted CI results named here were OBSERVED, not inherited: this Claude Code session read them directly from the GitHub check runs via the GitHub MCP tools, under Josh's standing instruction to babysit these PRs, which is the explicit confirmation the provider boundary requires for that read. Provider-backed gates NOT run: no eval:* retrieval canary, no verify:release, no check:supabase-project, no live Supabase or OpenAI test:live path, and no live-drift dispatch. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-09-02 | claude/caring-contacts-rules-r7r2ih-2 | bdf300188da5ac7ac7f0b36eea1aab2d266cdc48 | PR #2533 (#RZVMPD): db/postgres-repository.ts PLAN_LIST_COLUMNS, schedule-view.ts doc comment, tests/caring-contacts-domain-isolation.test.ts and the wire-level listPlans test | MERGED 2026-09-02 into its base branch (claude/caring-contacts-rules-r7r2ih), not into main directly, so it reached main inside 94a14a829. Branch since deleted. Two guards shipped with the fix and both were confirmed red against the pre-fix code: a static scan of the constant and its wiring, and a wire-level test recording every statement listPlans issues. Bugbot reviewed the final head and rated Low Risk. Clinical Governance Preflight completed voluntarily — the pr-policy classifier returns clinicalRisk:false for these paths, which is a substring accident rather than a judgement about patient mobile numbers and identifiers. | LOCAL OFFLINE GATES, run in this container: typecheck exit 0; full offline unit suite 949 files / 12293 passed \| 1 skipped; lint exit 0; prettier --check clean; caring-contacts db suite 214 passed against a disposable local Postgres 16 (up from 213 by the new wire-level guard); domain-isolation 12 passed; mutation check — reverting listPlans to PLAN_COLUMNS turns both new guards red. HOSTED CI: none ran on this PR — repo CI is scoped to branches [main, release/**], so a PR whose base is another feature branch gets no pipeline at all. Its hosted proof is therefore the CI that ran on the main-based head AFTER this merged into it (see the claude/caring-contacts-rules-r7r2ih record at 94a14a829), not anything observed on this PR. Hosted CI results named here were OBSERVED, not inherited: this Claude Code session read them directly from the GitHub check runs via the GitHub MCP tools, under Josh's standing instruction to babysit these PRs, which is the explicit confirmation the provider boundary requires for that read. Provider-backed gates NOT run: no eval:* retrieval canary, no verify:release, no check:supabase-project, no live Supabase or OpenAI test:live path, and no live-drift dispatch. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-09-02 | claude/caring-contacts-rules-r7r2ih-3 | 2631782a39ce277f055b53bce8a0418d43b66ac9 | PR #2534 (#J7PZQP + #PAMATF, squashed to main): episode.ts, model.ts, repository.ts, schedule-view.ts, simulation.ts, message-policy.ts, both repository implementations, patient-overview.tsx, plan-activation.ts, the schedule route, the shared contract helper and their tests | MERGED to main 2026-09-02. Episode carries patientDetailClearedAt instead of the screen inferring a clearance from a blank name; listSendableContacts gates on the owning plan in both stores, overturning Ruling 129 as Ruling 129A by explicit owner decision. Codex review found a genuine P2: under READ COMMITTED a clearance committing mid-getEpisode produced an episode reporting a completed clearance while still releasing name and mobile number — the fix reintroducing the defect class it exists to remove. Reproduced, fixed by reading every clearance-touched field in one statement, and pinned by a database contract test that pauses the read between statements. Merged with NO Bugbot or Cursor approval-agent review: both returned neutral because the Cursor account was at its spend limit (recorded as a separate ledger item). | LOCAL OFFLINE GATES, run in this container: typecheck exit 0; cc-guards 42 files / 1069 passed; caring-contacts db suite 2 files / 218 passed against a disposable local Postgres 16 (not the live Supabase project); message-policy + model + simulation + diff-integrity + interface-vocabulary 181 passed \| 1 skipped; prettier --check clean on all files changed vs main; phantom-revert check clean (21 files, +904/-121, nothing outside caring-contacts). HOSTED CI: green on the main-based head — Production UI critical, Build, Static PR checks, Safety and config, Caring Contacts database, Semgrep, Gitleaks, GitGuardian, PR policy, PR mergeability. Hosted CI results named here were OBSERVED, not inherited: this Claude Code session read them directly from the GitHub check runs via the GitHub MCP tools, under Josh's standing instruction to babysit these PRs, which is the explicit confirmation the provider boundary requires for that read. Provider-backed gates NOT run: no eval:* retrieval canary, no verify:release, no check:supabase-project, no live Supabase or OpenAI test:live path, and no live-drift dispatch. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 2,
"id": "00e5a4b0-11fa-46c4-a101-e75d0ce3cc35",
"createdOn": "2026-09-02",
"action": "add",
"payload": {
"pri": "P3",
"type": "issue",
"summary": "Caring Contacts createPlan accepts a blank patient name in both stores, so '' remains a legal stored value",
"issueUlid": "01M1HW3N65V6CDEVZETMC62AXS"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": 2,
"id": "354ac34b-c146-489c-a2c5-341988cbe3cf",
"createdOn": "2026-09-02",
"action": "done",
"payload": {
"id": "#RZVMPD",
"outcome": "FIXED AND MERGED to main in 94a14a829 (PR #2532), 2026-09-02. listPlans now selects a narrower PLAN_LIST_COLUMNS that drops patient_name, patient_mobile_number and patient_identifiers, so a caseload render no longer pulls every patient's name, mobile number and identifier list for the whole team into the process. PLAN_COLUMNS is unchanged for readPlanRecord and selectPlanForUpdate, whose callers (getEpisode, markRetentionCleared) genuinely need that detail — narrowing the shared constant would have made getEpisode project undefined for three fields, which no type would catch. patient_name was dropped alongside the two columns the issue named because names have their own separately audited read (listPatientNames, patientNameDirectory object type, Ruling 91), so fetching them inside a read audited as plan under-counted that trail. Evidence read off origin/main: PLAN_LIST_COLUMNS appears 3x in src/lib/caring-contacts/db/postgres-repository.ts at 94a14a829. Two guards ship with it — a static scan asserting the constant excludes the patient columns AND is actually wired into listPlans, and a wire-level Postgres test recording every statement listPlans issues; both were confirmed red against the pre-fix code. Nothing was ever released: PlanRecord excludes patientDetail structurally and that held throughout; the narrowing has moved from the mapping into the query.",
"baseRowFingerprint": "2448dd4735678e1775d81b6e3b9e44b500ec9ee7cdcfcb89428b69f015bfb3e1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 2,
"id": "42f4e905-cce5-41f0-9a8a-7678eaad9895",
"createdOn": "2026-09-02",
"action": "add",
"payload": {
"pri": "P2",
"type": "issue",
"summary": "Two clinical-risk Caring Contacts fixes merged with no automated review, because the Cursor spend limit silently downgraded the approval agent and Bugbot to neutral",
"issueUlid": "01M1HW41T6ACWXN6TRZTKCGMG6"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 2,
"id": "74f5d2b4-02bb-43ae-9fd5-2e78c5a717d9",
"createdOn": "2026-09-02",
"action": "add",
"payload": {
"pri": "P3",
"type": "issue",
"summary": "Two test suites fail on a shallow clone, and the failure names a manifest rather than the clone depth",
"issueUlid": "01M1HW3BVC77NJE2ZG49Q2E7FR"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": 2,
"id": "a3d9c842-724b-4b1c-b564-7c3be4ec8ba2",
"createdOn": "2026-09-02",
"action": "done",
"payload": {
"id": "#PAMATF",
"outcome": "FIXED AND MERGED to main in 2631782a3 (PR #2534), 2026-09-02. listSendableContacts now gates on the owning plan before the contact, in BOTH stores, so a draft plan nobody has started and a plan a coordinator has paused no longer present their contacts as work about to go out. planSendingHold moved from schedule-view.ts to model.ts beside contactSendability and is re-exported so existing imports still resolve; no second predicate was written. Evidence read off origin/main: planSendingHold appears 2x in src/lib/caring-contacts/model.ts at 2631782a3. validateGovernedMessage also gained a plan-not-dispatchable issue covering the draft and paused plans that previously passed the chokepoint, and a load-time invariant ties planSendingHold to TERMINAL_PLAN_STATES beside the two that already guard contactSendability. Neither store needed a query or a join, and a read racing an activation resolves fail-closed. THIS OVERTURNS RULING 129, which considered exactly this change and declined it on the grounds that it would duplicate an existing gate. Every fact in that ruling was re-verified and still holds; what changed is the weighing of the residual it named itself — a rename or a sibling leaves the misleading behaviour reachable and merely relabelled, which is the same shape as #59JT7W. Recorded as Ruling 129A in docs/caring-contacts/phase-2b-build-record.md with the HANDOVER entry closed, taken as an explicit owner decision rather than a drive-by consequence. The duplication cost Ruling 129 predicted is now pinned rather than accepted: the shared contract asserts the read gate and the write gate (requiresActivePlan) agree for every plan state where the plan is what decides. Two pinned assertions changed deliberately and are documented in the PR body. NOTE: this was never a live send hole — there is no dispatcher or SMS provider in the tree.",
"baseRowFingerprint": "d05c5812c06f1cb856402507488d12b896b150385ae41fbb6cbeccfc3190732b"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": 2,
"id": "d0cd358b-2b92-456f-8bd3-525341f1cf4b",
"createdOn": "2026-09-02",
"action": "done",
"payload": {
"id": "#J7PZQP",
"outcome": "FIXED AND MERGED to main in 2631782a3 (PR #2534), 2026-09-02. Episode now carries patientDetailClearedAt: Date | null, so the patient overview stops deducing 'a retention clearance removed this' from episode.patientName === ''. That inference was only ever held up by z.string().min(1) at the HTTP edge: patient_name is not null with no CHECK against the empty string and neither store's createPlan validates non-blank, so a blank name reaching a store any other way made the screen state three things falsely about a live record. Evidence read off origin/main: patientDetailClearedAt appears in src/lib/caring-contacts/episode.ts at 2631782a3. No migration — retention_state.cleared_at already existed and both stores already wrote it in the same transaction as the de-identification, so there is no backfill gap either. The field is named for what was cleared, not the policy that ordered it, because Ruling 26 keeps that vocabulary inside the storage layer and forbids widening its allowlist to make a diff pass. DeidentifiedEpisode is unchanged: it is built by construction from a named field list, so the new field is absent from it automatically. A Codex review round found the first fix reintroducing its own defect class — under READ COMMITTED a clearance committing mid-getEpisode produced an episode reporting a completed clearance while still releasing the name and mobile number. Fixed by reading every field a clearance touches in one statement, and pinned by a database contract test that pauses the read between statements (present on main; fails against the pre-fix code with expected 'Rowan Delacroix' to be ''). This does not overturn the ''-as-cleared convention, which is correct wherever a non-blank write is enforced. NOT DONE, deliberately, and worth filing separately: createPlan still accepts a blank patient name.",
"baseRowFingerprint": "540928de1bb3a5c74d5fd6bda6302e2625e1c7756bd316db26620ec25a733588"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": 2,
"id": "d7e85095-3340-470c-9674-1481fc9b0930",
"createdOn": "2026-09-02",
"action": "done",
"payload": {
"id": "#59JT7W",
"outcome": "FIXED AND MERGED to main in 94a14a829 (PR #2532), 2026-09-02. The refusal no longer lives only in resolveClosingContactMessageBody: validateGovernedMessage — the chokepoint every future sender must pass — now returns closing-message-body-not-authored via an early return when no body was authored, and message-body-not-authored for standard/first, so no message type can be sent with no body. resolveClosingContactMessageBody is a thin adapter over it; its signature is unchanged. Evidence read off origin/main, not inferred: closing-message-body-not-authored appears 8x in src/lib/caring-contacts/message-policy.ts at 94a14a829. Record-level refusals (terminal contact, ended plan) are shared by both exits via appendStateIssues, so a missing body cannot mask an unrecoverable plan state. NOTE for whoever reads this row next: the earlier done request c862828e claimed this was fixed when it was not, which is why this closure cites the merge commit and a grep-verifiable fact rather than a file name. No closing-message wording was authored — approved-copy item A4 remains open.",
"baseRowFingerprint": "8e298119ee409dfa362d10036e14ee8f66b41094b1c8b39efbf8394560fc0b75"
}
}
Loading