Bump actions/setup-node from 4 to 6 - #2
Closed
dependabot[bot] wants to merge 1 commit into
Closed
Conversation
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](actions/setup-node@v4...v6) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
ContributorAuthor
Looks like actions/setup-node is up-to-date now, so this is no longer needed. |
13 tasks
This was referenced Jul 2, 2026
BigSimmo pushed a commit
that referenced
this pull request
Jul 20, 2026
…idence (A-PR-2 part 3) lithium-therapy-monitoring was the only golden case with no document expectation, making its rr@10 a hardcoded 0.00 — measurement noise that masked real ordering headroom (live top-5: Lithium Clinical Guideline (EMHS) #1, Lithium Therapy Initiation (FSH) #2, Lithium (CAMHS) #3). expectedDocumentSubstrings gains ["Lithium"]: deliberately broad because the corpus carries multiple legitimate lithium guidelines (same pattern as the agitation pair) — the gate asserts subject precision in the top 5, not a single pinned title that would flake between equally-correct docs. Measured mrr@10 rises ~+0.028 from de-noising alone. Snapshot rebuilt from the same run-29763761133 artifact with the updated expectation so fixture and snapshot stay in lockstep (ranks 1-4 now grade as relevant; the psychotropic-generic rank 5 and the wrong-medication hard negative stay 0). Clinical sign-off note: this changes eval ground truth only — no runtime ranking behavior. Flagged in the PR for review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXsJcLrbZUXwnBeG91cVo9
This was referenced Jul 20, 2026
BigSimmo added a commit
that referenced
this pull request
Jul 21, 2026
#1046) Against current main (post-#1033, which already resolved#2/#3): - Capture the still-untracked auth DB-connection allocation debt as #11: operator-only Supabase dashboard action (percentage-based allocation before compute scale-up), not settable via SQL/MCP. next-id -> 012. - Fix#5 Source path src/lib/rag/clinical-search.ts:1362 -> src/lib/clinical-search.ts:1735 (the rag/ path does not exist; it was failing docs:check-links on main) and note ordering already sorts by the unbounded pre-clamp rankScore, so the clamp bounds only reported confidence. Docs-only. No code/protected-surface edits, no provider/CI/dashboard action. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
8 tasks
BigSimmo added a commit
that referenced
this pull request
Jul 22, 2026
5 tasks
14 tasks
This was referenced Aug 18, 2026
BigSimmo added a commit
that referenced
this pull request
Aug 24, 2026
…pty state, overlay commit contract (#2350) * docs(caring-contacts): correct the retired-branch records, close the browser gate, capture the deferred findings Phase 2A was squash-merged to main as e4cbe8d (#2279) on 2026-08-23, but the handoff, the ledger and the continuation prompt all still named the feature branch as the source of truth and told the next session to build a worktree from it. Corrected in place rather than deleted, because the reasoning about durability and about measuring a moving tree still holds -- and holds harder on main, which far more sessions touch. - Browser gate re-run on main: 32 passed, exit 0, no ECONNRESET. The test that failed on 2026-08-23 (the 1440px condensed-bar pin) ran and passed, so the residual failure was load, not a defect. Also records that :822 was the test's declaration line, never the failing statement -- the dropped connection was in the setup POST at line 672, before any pin assertion ran. - Seven deferred findings captured as immutable issues-inbox requests, so they no longer survive only in the build record. - copy-decisions-recommended.md is new: the copy recommendations existed only in a previous session's conversation and did not survive it. Also corrects the count -- the records said seven items need the owner, the copy review actually raises thirteen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): correct the self-contradicting handoff, and record the mutation proofs The entry-point handoff said on line 7 that the branch had never been pushed and in section 4 that it was pushed to origin. Both were true when written and neither was updated when the other changed; both are now superseded by the merge. Records mutation proof A for the condensed bar: top-full -> top-0 turns 32/0 into 13 failed / 19 passed, and the 1440px failure is the pin assertion itself at line 877 (barBox.top 64 -> 0) with the two preceding assertions passing first, so the assertion is reached and discriminating rather than merely present. Also records the trap that nearly produced a false proof: the first mutation-B anchor matched two elements, a uniqueness assertion refused the edit, and the script ran the full gate anyway on an unmutated tree -- reporting 32 passed, exit 0. Read without the abort line that is a real, green, strongest-looking gate run supporting exactly the wrong conclusion. A mutation proof therefore has two results, not one: prove the mutation is in the tree before believing the gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): both mutation proofs run, and the Phase 2B plan Mutation B (dark-mode colour): 1 failed / 31 passed. The single failure is the scheme-comparison at line 931 and names the injected literal, so it is attributable by value and not merely by timing; the display guard before it passed, so the assertion is reached. A blast radius matching the mutation's intent is itself evidence the assertion measures what it claims. With mutation A already proven, both closing proofs the final review recorded as UNRUN are discharged and the condensed bar's fix round is closed. Adds the Phase 2B implementation plan. It follows the owner's stated order and is grounded in a measured reading of what Phase 2A actually left: one real route, thirteen stub destinations, zero of twenty-four overlays wired to a trigger, no empty-state component, and no read API for patients, schedule or team. Two gaps the plan surfaces rather than hides: message templates have a full governance lifecycle but only ONE hard-coded message, so a template library cannot show per-version content that does not exist; and 'workload and coverage' has an approved design only at roster-table depth, which is the single most likely place the plan under-delivers against what the owner means. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): record the owner's approval of all thirteen copy decisions The owner answered 'go ahead with your recommendations' to all thirteen items on 2026-08-24. Recorded as the decision of record, with two qualifications that approval alone does not settle: A9 (add Lifeline 13 11 14) is approved in principle but BLOCKED. The recommendation was conditional -- add Lifeline and drop the Fictional Support Line once a real crisis number is chosen -- because the message sits about nine characters from its two-segment maximum, so nothing can be added until something comes out. No real number exists, and the owner was explicitly asked to name what goes. An implementer must not pick the removal itself. A4 (the closing message) is approved as a deferral, not as text: the refusal path is buildable now, the wording waits for a lived-experience representative. Patient-visible copy is no longer frozen, but every change must cite its item number and still live only in the sealed domain's message-copy module. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): remove the freeze line the approval banner contradicts The approval banner lifted the copy freeze, but the line directly beneath it still said wording stays frozen until the owner answers. That is the same self-contradiction this session just criticised in phase-2a-handoff.md, created the same way -- a true sentence left in place when the thing it described changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): open the Phase 2B ledger, run the pre-flight scan, add Task C The pre-flight scan found one real defect in the plan before any dispatch: the design-corrections table routed correction #2 to 'Group 3, Task 11', but Task 11 is Group 1's overlay wiring and Group 3 is Tasks 15-16. An implementer would have received a requirement it had no surface for. Fixed as Ruling 73. Adds Task C -- the owner's six approved copy changes, batched into one dispatch per the method's rule about small same-shape work. A9 (add Lifeline) is deliberately excluded: it is approved in principle but conditional on a real crisis number existing, and dispatching it would force an implementer to choose which patient-facing sentence to delete. Rulings 73-78 recorded, each with what it costs if wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): Task C brief, and the two rulings its conflicts forced Ruling 79: the owner's approved 'refuse any message containing Fictional' cannot be implemented as a prohibited term, because both approved patient messages contain 'Fictional Support Line' -- every existing message would be invalid and the check would have to be disabled to ship. Implemented instead as a validator issue plus an explicit synthetic-acknowledgement flag on each call site, so a real send path has to opt in deliberately rather than fail silently. Ruling 80: A3's 'something automatic comes back' fits only in the reply message. Message A is 252 septets against a two-segment ceiling. Measured with the repo's own calculateGsm7 rather than estimated -- the proposed reply is 210 septets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): Task 1 brief -- the shared empty-state component Carries Ruling 81: EmptyState is its own component and does not render AutomatedState internally. The two have different triggers -- AutomatedState is for the system acting on its own, an empty list is usually the user's own filter or simply nothing existing yet -- and AutomatedState's alert icon and state-name aria-label are both wrong for 'no patients yet'. The filtered variant reuses its why/what-changes-it wording shape so a clinician learns one pattern. The brief models the two emptinesses as a discriminated union rather than optional strings, because an optional reason is a reason that will be omitted, and a filtered-empty list that says only 'nothing to show' is indistinguishable from an empty caseload. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(caring-contacts): drop the unverifiable storage claim from the automated reply (A2 + A3) Owner-approved 2026-08-24. The reply's first sentence claimed replies "had not been seen by anyone and had not been kept" -- a firm storage claim about a system with no telephony provider yet, so nobody could currently know if it was true (A2). It also left a patient who had just been told "no one reads this" unable to tell a reply was automatic rather than human (A3). Replaces the sentence with wording that states only what the system can actually know and names the reply as automatic. Verified 210 septets / 2 segments / GSM-7 valid (was 218). EXACT_PATIENT_VISIBLE_MESSAGE is untouched -- it has no segment headroom left, so the "reply is automatic" fact lives only here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(caring-contacts): refuse an unacknowledged fictional contact detail (A1 / Ruling 79) Both approved patient-visible messages name the reserved fictional crisis number on purpose, so a bare prohibition on the word "Fictional" would make every existing message invalid and the check would have to be disabled to ship -- worse than no check. Instead validateGovernedMessage now always reports fictional-contact-detail-present when a message contains the marker (derived from message-rules.ts's crisisSupportContact, not hard-coded a second time), unless the caller passes the new, explicit syntheticFictionalContactsAcknowledged: true. Existing tests that build compliant first/closing messages from the crisis contact are updated to pass the acknowledgement, since they were never testing this rule. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(caring-contacts): refuse loudly when a closing contact has no authored body (A4) No closing message has ever been written -- that wording is a clinical decision deferred to a lived-experience representative, not an implementation gap. resolveClosingContactMessageBody is the refusal only: it never returns an empty string, never falls back to another message's text, and never silently drops the contact when no authored body exists. No closing-message wording is drafted here. No existing seam resolved a contact's message body anywhere in this domain (checked schedule.ts, simulation.ts, repository.ts, model.ts): PlannedContact carries a messageType but no body content, and nothing supplies one yet. This function is the mechanism a future sender will call once that seam exists; it is deliberately not wired into schedule.ts/simulation.ts here, since doing so would require inventing where an authored closing body comes from -- exactly the decision this task defers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(caring-contacts): narrow "lead" to its commercial sense only (B2) lowerText.includes("lead") also matched the ordinary English "the incident lead" and "the clinical programme lead" -- job titles that appear in the service-stop wording -- so a message using the word correctly would be rejected. Word-boundary matching alone would not have fixed this (both job titles contain "lead" as a whole word too), so "lead" is narrowed to a commercial-specific form instead: a marketing-word modifier ("sales lead", "a new lead") or companion ("lead generation", "lead conversion"). The narrowing lives as a per-term pattern override in message-rules.ts (prohibitedTermPatternOverrides), keeping message-policy.ts's mechanism generic. Every other prohibited term keeps its exact substring behaviour -- one covering test per term proves it, since narrowing one term is precisely the change most likely to quietly widen what the rest of the list allows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(caring-contacts): scan interface string literals for prohibited vocabulary (B3) Until now the prohibited-word ban ran only against outgoing messages (message-policy.ts) and the 24 frozen overlay definition rows (caring-contacts-overlay-definitions.test.ts) -- nothing checked the words on a screen, so it was policy held by people rather than software. This scans every string/template literal under src/components/caring-contacts/ workspace/** and src/app/caring-contacts/** against the existing wider CARING_CONTACTS_PROHIBITED_LANGUAGE vocabulary. src/components/caring-contacts/mockups/** is out of scope by construction (not one of the two scan roots) -- it is frozen design scratch that 404s in production and knowingly contains one prohibited phrase the owner ruled (B4) to leave alone. Extraction uses a small character-by-character scan rather than a regex over the raw source: a naive quote-matching regex treats JSDoc inline-code backticks (`` `useSearchParams` ``) as template-literal delimiters, and an odd count across a comment pairs unrelated spans into one giant fake literal spanning most of the file. className attribute values are excluded before extraction -- narrowing which literals reach the scan, not adding a file to an ignore list -- because they carry CSS custom-property names (var(--safe-area-bottom)) that contain "safe" as a substring unrelated to interface prose. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(caring-contacts): bound the B3 fixture cleanup's rmSync retries npm run test's repo-wide test-runner-safety.test.ts requires every recursive rmSync in a test fixture to pass maxRetries/retryDelay, guarding against Windows file-lock flakiness on cleanup. The B3 fixture cleanup added in the previous commit was missing them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): Task C report -- six copy/policy changes, mutation-proven Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task C evidence, and the zero-caller finding Verified the two full-suite failures myself rather than accepting the report: both are gate-receipts file-mode tests failing in chmodSync, on a Windows drive that cannot represent file modes. Environmental, and a third known local failure. Records the consequential finding: validateGovernedMessage has zero production callers. The brief assumed callers to update and there are none. The checks are real but guard a send path that does not exist yet, so 'the validator refuses this' must not be read as 'the system refuses this'. Captured as a P2 issue. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task C review verdict and fix round 1 Spec passed. Three Important findings, four Minor. Two lessons recorded that generalise beyond this task: An allowlist cannot close an open-ended set. B2 narrowed the 'lead' prohibition by enumerating commercial phrasings, so everything unenumerated is now permitted -- 'lead magnet', 'qualify this lead' and others all pass and all previously failed. Enumerate the safe set, never the dangerous one. A guard on a chokepoint fires; a guard beside one does not. A1 and A4 both look 'unwired' and have opposite futures: A1 sits inside validateGovernedMessage which any sender must pass, while A4 is a standalone function nothing obliges anyone to call. Ruling 83 therefore refuses to record A4 as closed. Ruling 82 promotes the A1 marker finding from Minor: it matches the label 'Fictional Support Line', not the reserved number, and the number is the artefact that would actually reach a patient. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(caring-contacts): fix round 1 -- seven review findings (B2, A1, B3, comment) Fix round 1 against Task C, six of seven fixable findings (the seventh, A4's standalone resolveClosingContactMessageBody, was recorded and reported to the owner instead of changed -- it rides no chokepoint yet, and inventing one is out of this task's scope). Important 1+2 (B2): the first "lead" override was an ALLOWLIST of nine commercial modifiers/companions, and commercial vocabulary is open-ended, so anything not enumerated passed silently -- verified newly permitted "lead nurturing", "lead magnet", "lead source", "leads database", "lead gen", "qualify this lead", "convert the lead", "this lead is hot", "your lead". Inverted: COMMERCIAL_LEAD_PATTERN now refuses "lead"/"leads" as a whole word BY DEFAULT via a negative lookbehind, exempting only the closed set of job titles this domain's own wording uses -- incident lead, programme lead, clinical lead, team lead, service lead. The "scoring?" typo (matched "lead scoring" but not "lead score") disappears with the allowlist it lived in; confirmed via a dedicated "lead score" test. Promoted Important (A1): the marker was `crisisSupportContact.split(":") [0]`, i.e. the LABEL "Fictional Support Line" only -- a message carrying the bare reserved NUMBER with no label raised nothing, which is the shape that would actually reach a sender. fictionalContactMarkerPattern is now `/Fictional/i` plus every reserved number in synthetic-contacts.ts (escaped), so relabelling, reordering, or dropping the label entirely are all still caught. One pre-existing rule-6 test (contains-patient-mobile) used +61 491 570 006 -- itself one of the four reserved numbers -- as its example patient mobile; its expectation is updated (not loosened) to the now-correct two-issue result. Minor 5: pins prohibitedTermPatternOverrides to exactly {"lead"} so a future override for another term cannot land unnoticed by this regression suite. Important 3 (B3): the interface-vocabulary scan only saw quoted/template strings, missing the plain-JSX-text form this tree actually writes copy in (shell.tsx, loading.tsx). Added a second raw-prose pass (comments and className values stripped, everything else scanned as-is) and a fixture test proving it catches a word planted as bare JSX text between tags, not just inside quotes. Minor 7 (B3): the real-tree scan now asserts filesScanned > 0, closing the vacuous-pass hole a root with no matching files would otherwise leave open. Minor 6: reworded the AUTOMATED_REPLY_RESPONSE comment claiming content "is discarded... nothing is stored" as a design INTENT/contract rather than settled fact, so it no longer contradicts the very next paragraph explaining that no telephony provider exists yet to make that claim true or false. Every fixable finding mutation-proven: B2 mutated back to the old allowlist (the CRM test goes red) and to a bare `\bleads?\b` with no exemption (the job-title test goes red); A1 mutated to drop the number half of the pattern (the bare-number and four-numbers tests go red); B3's raw-prose pass and floor assertion each mutated out and confirmed red. All mutations confirmed present in the tree via direct file inspection before trusting the red result. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): Task C fix-round-1 report Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task C fix round 1, with the B2 inversion verified independently Executed the new negative-lookbehind pattern against 18 cases rather than accepting the report. All ten previously-leaking commercial phrasings are now refused -- including 'lead score', the case the scoring? typo let through, so that finding is genuinely moot rather than relocated. All eight job-title and ordinary-English cases still pass. Records the rule the inversion confirms: when a check must separate a safe set from a dangerous one, enumerate whichever set is CLOSED. Five job titles are closed; commercial vocabulary is not. That test now applies to every allowlist, ignore list and exemption the rest of this plan adds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task C COMPLETE -- all seven findings addressed Re-review re-derived every claim by execution rather than reading assertions. Two mechanism-level checks worth keeping: the A1/patient-mobile double report is benign because the patient-mobile check is independent of the acknowledgement flag, so acknowledging silences the noisy code and keeps the safety-critical one; and the global-regex handling is correct, with the non-global copy used for .test() and the global copy only with matchAll. B2's mutation proof is two-directional as requested -- reverting to the allowlist reddens the refusal test, widening to a bare pattern reddens the exemption test. Those bracket the behaviour rather than being two views of one assertion. Six minors deferred to the final whole-branch review, including a new one: the job-title exemption needs whitespace adjacency but this domain writes 'team-lead'. Inert today -- outside the scan roots, absent from both messages, and the validator has no production callers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): reading the API layer cut one task and corrected two Went to write Task 2's brief, read the code it was meant to extract a pattern from, and found the pattern already there. Two more premises fell the same way. Ruling 84 cuts Task 2: readHandler already is the list-read pattern, used by eight routes, four of them sharing the collection objectId convention. One requirement survives into the first list route -- a contract test pinning that an empty list is 200 with an empty array, never a 404, since auditedRead maps a null release to denied and an empty array is neither. Ruling 85: Task 5 builds no API. GET /api/caring-contacts/plans already lists team plans. The patientDirectory object type is not an unwired gap -- the referrals route already uses it, for patients who may not yet have a plan. Ruling 86: design correction 1 is already in the domain. schedule.ts takes and validates firstContactDate and the plans schema accepts it; only the screen control is missing. All three came from recon reports that were factually correct and whose implications I carried too far. Before a brief says build this, open the file. The cost of skipping that is not a wasted task, it is a second implementation of something that already works, sitting beside the first, both maintained. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(caring-contacts): add the shared EmptyState component (Phase 2B Task 1) Adds src/components/caring-contacts/workspace/empty-state.tsx, exporting EmptyState -- the one shared empty-list surface the four Phase 2B list screens (patients, schedule, templates, team) will use, so each does not invent its own. Modelled as a discriminated union on `kind`: "no-data" (nothing exists yet) and "filtered" (a filter/search is hiding existing records) cannot be confused with each other, because "filtered" requires its `because` and `changedBy` at the type level -- there is no shared optional field a caller could omit. The "filtered" branch reuses AutomatedState's "Why: .../What changes it: ..." wording shape without rendering AutomatedState itself (Ruling 81): the two have different triggers, and AutomatedState's CircleAlert icon and state-name aria-label are wrong for "no patients yet". A Server Component with no hooks (Ruling 13): the optional `action` slot takes an already-built ReactNode (a <Link>, a form-submit button, or an UnavailableDestination) rather than raw onClick/href props, the same way ServiceStateBanner hosts UnavailableDestination as a child without becoming a Client Component itself. The icon started as lucide-react's Inbox and had to change to FolderOpen: tests/caring-contacts-interface-vocabulary.test.ts's raw-prose scan caught the bare identifier "Inbox" as the prohibited reply-monitoring/marketing term "inbox" (CARING_CONTACTS_PROHIBITED_LANGUAGE), even though it was never in a string literal -- a real catch by that guard, not a false positive. tests/caring-contacts-empty-state.dom.test.tsx: 9 tests covering both kinds' required copy, the absence of the other kind's wording, the optional action (rendered vs. omitted, and genuinely actionable), a type-level compile check that "filtered" cannot omit because/changedBy, a 320px-container render, and the forced-colors override class. Mutation-tested: forcing the "filtered" branch to always render the "no-data" JSX (dropping the reason and remedy) reddened exactly the two tests that read that content; reverted and confirmed green again. docs/design-system/adoption-manifest.json regenerated via `npm run design-system:adoption:update` -- the only change is the new test file being recorded against ui-primitives.tsx's testFiles array. Not wired into any screen (later tasks' job). Does not modify automated-state.tsx, shell.tsx, or any route. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): Ruling 87 -- Task 3 cannot ship a trigger without the commit contract Verified in code before writing the brief. openWorkspaceOverlay already exists, is exported and is DOM-tested, so Task 3 was never going to build an opening mechanism. Reading it exposed the thing that matters instead. WorkspaceOverlays' commit callback closes the overlay and records nothing, with an honest comment noting this is safe because nothing in the workspace opens an overlay yet, so no control advertises an action it does not perform. Task 3 is precisely what would break that clause: the moment a screen can open an overlay, its confirm button becomes a control that advertises an action the system does not perform, which is what the button-wiring gate forbids. So the trigger and the commit contract ship together, and the trigger requires a commit handler rather than defaulting to a no-op. A screen must be unable to open an overlay it has not wired, and the compiler is what finds the omissions rather than a later sweep. The general shape, worth keeping: a mechanism that is safe only because nothing reaches it is not safe, it is unreached. Before making something reachable, check what its arrival makes true. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): Task 3 brief -- trigger plus commit contract Carries Ruling 87 into the brief, and tells the implementer plainly that the overlay opening mechanism already exists so it does not rebuild one. The task is the small client control plus the type-level requirement that a screen cannot open an overlay it has not wired. Leaves one genuinely open design question to the implementer with instructions to choose deliberately and record what it rejected: WorkspaceOverlays is rendered once by the shell rather than per screen, so a screen's commit handler has to reach it somehow, and the obvious answers each carry costs. If the honest answer is that it needs a decision above its level, it is told to say so rather than pick silently. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): Task 1 report -- shared EmptyState component Records the build of src/components/caring-contacts/workspace/empty-state.tsx, the TDD red/green proof, the mutation proof, the interface-vocabulary catch (Inbox -> FolderOpen), and the full verification chain (vitest, full test suite, typecheck, lint -- including the two bounded lock-contention retries before typecheck acquired the repo's heavy-run lease). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task 1 built, and the lock incident that corrected the briefs The implementer paused mid-task on the heavy-run lease with its work uncommitted, on a machine that has destroyed four working directories mid-session. Resumed with an explicit ordering -- commit first, then retry the gate, bounded -- which is now standing for every remaining brief. Machine health was measured rather than assumed: node --version in 0.083s, so ordinary lease contention. Records that Task C's interface-vocabulary scan caught a defect in Task 1 one task after being built: a lucide Inbox icon, rejected because inbox is banned as reply-monitoring language. It fired on a bare identifier rather than prose, which is exactly the deferred concern Task C's re-review raised -- so that concern is real and will recur. Whether it was a false positive is put to the reviewer rather than settled here, with the note not to narrow the scan merely because it was inconvenient once. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task 1 review -- Ruling 88 renames the component, and my brief caused the collision The reviewer re-ran both mutations rather than reading the report, and found the described mutation does not produce the reported numbers: mutating the filtered branch gives 1 failed, not 2, because with the guard hardcoded true that branch is dead code. The evidence is real, the account of which branch was mutated is not. Second time on this programme that re-deriving a self-reported mutation changed the answer. Ruling 88 renames to ListEmptyState. ui-primitives.tsx already exports an EmptyState and the adoption-manifest generator matches tests to components by a bare name regex with no import awareness, so the caring-contacts test now falsely counts as coverage for a shared primitive it never imports. False evidence about test coverage in a governance artifact. My brief mandated the colliding name. Also settles two open questions: action: ReactNode is correct because an onClick prop cannot cross a Server-to-Client boundary; and the vocabulary scan will not be narrowed after firing on an identifier, closing Task C deferred item 2 as decided rather than deferred. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(caring-contacts): Task 1 fix round 1 -- rename collision, accessible group, mutation-proof correction Three review findings addressed: 1. Renamed EmptyState -> ListEmptyState (file, exports, test imports/usages). src/components/ui-primitives.tsx already exports a registered design-system primitive called EmptyState, used across 43 files. scripts/generate-design-system-adoption.mjs credits test coverage by matching \bName\b against raw test-file text with no import-path awareness, so the bare name in this component's test file was crediting tests/caring-contacts-empty-state.dom.test.tsx as coverage for the unrelated ui-primitives EmptyState in the generated adoption manifest -- false evidence in a governance artifact. ListEmptyState does not match \bEmptyState\b, so it cannot recreate the collision. Manifest regenerated; the false testFiles line is confirmed gone from the ui-primitives EmptyState entry (see report for the diff). 2. Wrapped the whole component in role="group" aria-label={props.heading}, reusing automated-state.tsx's accessible grouping (Ruling 81 forbade rendering AutomatedState, not reusing its structure): a screen reader that reaches the state enters a named group and finds "Why:"/"What changes it:" without hunting elsewhere. Applied to both kinds, not only "filtered", for one consistent grouping pattern. Uses the same aria-label (not aria-labelledby) technique automated-state.tsx already proves hook-free. Two new tests assert the group and its name for each kind. 3. Re-ran the brief's named mutation correctly. The prior report described mutating the "filtered" branch but had actually hardcoded the ternary's guard to `true` AND replaced the no-data branch's real content with a placeholder string -- coarser than specified, and it broke both kinds equally rather than leaving no-data's real output intact. This round's mutation touches only the guard (hardcoded true) plus a necessary type-safe cast, reusing the actual no-data code path rather than a placeholder: for a genuine no-data instance the cast is a no-op (identical output); for a genuine filtered instance, reading a field that does not exist on it renders nothing. Result: exactly 2 of 11 tests reddened, both in the "filtered" describe block; all "no-data" tests stayed green throughout. Reverted and confirmed 11 passed again. Report rewritten to describe this accurately. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): Ruling 89 merges Task 4 into Task 5 Task 4 would have created the patients page rendering the empty state before Task 5 gave it data -- a caseload screen saying 'No patients yet' whether or not patients exist. That is precisely the defect Task 1's component was built to prevent, and the orphan-route gate would have forced an inbound link at the same moment, making the false state reachable rather than merely present. Its real deliverables travel with the screen that has real data: the href, the sitemap update, the codebase-index entry and the reachability assertion. Same shape as Ruling 87: before making something reachable, ask what its arrival makes true. There it was confirm buttons that do nothing; here a caseload screen that says empty when it is not. Both invisible while unreachable. Also records what already exists: caring-contacts-routes.ts declares all fifteen destinations plus typed helpers for every dynamic route, and shell.tsx's own comment says lighting one up is exactly adding an href. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): correct Task 1 report -- mutation proof, plus fix round 1 Rewrites the "Mutation proof" section: the original described mutating the "filtered" branch but the edit actually applied hardcoded the ternary guard AND replaced the no-data branch's real content with a placeholder string -- coarser than the brief specified, breaking both kinds equally instead of leaving no-data's real output intact. The section now describes the corrected mutation (guard hardcoded true, plus a type-safe cast reusing no-data's real render path rather than a placeholder) and its actual result: 2 failed | 9 passed (11), both failures in the filtered describe block only. Adds the fix-round-1 record: the EmptyState -> ListEmptyState rename (with the adoption-manifest diff proving the false test-coverage attribution to ui-primitives.tsx's EmptyState is gone), and the role=group accessible grouping added to both kinds. Updates the verification-chain section with this round's fresh typecheck/lint/full-test-suite results. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): Task 5 brief -- the Patients directory, absorbing Task 4 The first real screen of Phase 2B. Carries Rulings 85 and 89: no data source to build because GET /api/caring-contacts/plans and listPlans already exist, and the navigation link ships with the real screen rather than ahead of it so the page is never reachable in a state where it can say 'No patients yet' untruthfully. Points the implementer at the Today page as the established server-read pattern rather than describing it, and names the exact access identities to reuse so the access trail does not grow a second vocabulary for the same read. Carries the one requirement that survived cutting Task 2: a test pinning that an empty caseload renders the empty state on a success path and never a 404, since auditedRead maps a null release to denied and an empty array is neither. Forbids getEpisode, which is the only read releasing patient name, mobile, identifiers and cultural identity, and tells the implementer to report rather than decide if the approved design appears to need it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task 1 COMPLETE -- all three findings addressed The re-reviewer traced the corrected mutation through all eleven tests from the code rather than accepting the count, and explained why exactly two fail rather than three: the action slot sits outside the mutated ternary. That detail is what separates a re-derivation from a re-reading. Rename verified end to end -- no bare EmptyState word survives in the test file, the move is a real rename, and the manifest diff is exactly the one deleted line. The surviving mentions in the component's comments are safe because the generator builds its testFiles list from a tests-only walk, checked in the generator source. Task 3 goes to opus rather than the default implementer tier: it carries a real architectural decision about how a screen's commit handler reaches an overlay host the shell renders once, and every obvious answer costs something different against the client-payload limit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(caring-contacts): Task 3 -- overlay trigger and the commit contract it must ship with Ruling 87: making an overlay reachable makes its confirm control a control that advertises an action the system does not perform, so the trigger and the commit contract land together. - overlay-commits.ts: WorkspaceOverlayCommit (record | unavailable) and a single-slot handoff the opening control writes, with the rejected alternatives (context provider, per-screen host, mount-time registry) recorded in the file. - overlay-trigger.tsx: the required-commit client control; an unknown overlay id throws at render rather than opening nothing. - OverlayHost gains a required commitUnavailableReason, refusing the action whatever the row's mutatesState says. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(caring-contacts): Task 3 -- trigger and commit-contract proofs Covers: the trigger opens what it names and Back closes it; an id no frozen row carries throws at render; `commit` is required (`@ts-expect-error`, enforced by tsc); the record path reaches the shell-mounted host through the fresh-authentication checkpoint; the unavailable path renders the aria-disabled shape with its reason reachable via aria-describedby and not in a title; a read-only row is refused too; an overlay reached by address is refused; and one overlay's staged commit is never offered to another. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): Task 3 report -- the handoff decision, its rejects, and the gates Records the architectural choice (single-slot commit handoff staged at the moment of opening), the three rejected alternatives with the reason each fails, the deep-link refusal as the change with the widest blast radius, six mutation proofs, and the gates -- including the one that did not run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * plan(caring-contacts): the owner's three answers, and formatting Push authorised, so Ruling 78 is superseded -- it forbade pushing precisely because he had not been asked. Team screen confirmed at roster-table depth, so Ruling 74 is now his decision rather than my inference, which is what flagging it was for. Guidance and Reports are IN this phase, REVERSING Ruling 75. Worth recording about the reversal rather than just the reversal: Ruling 75's reasoning was sound on its own terms and still wrong, because it optimised against a constraint -- protect the four groups he asked for -- that he never expressed as a constraint. Ruling rather than stalling is right, and this is its cost: a ruling made in the owner's absence is a guess with reasoning attached. Where a ruling is cheap to un-make and the owner is reachable, ask. Also formats 16 files that prettier flagged, which the push guard checks against the pushed commit rather than the working tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task 3 review -- Ruling 90 overrules the blanket refusal Eight of the 24 overlay rows have mutatesState: false and their controls are exits, not confirmations -- 'Sign in again', 'Try connecting again', 'Back to the plan'. None records anything, so Ruling 87 never reached them, and refusing them renders a sentence that is false about the control it points at. On session-expiry and offline-banner it is actively harmful: both are recovery-only, so Escape and backdrop are deliberately inert, and their only control is now aria-disabled. That is the one overlay a person must not be able to walk away from, and it offers them nothing. Live today, since the shell renders the host and any deep link reaches it. The lesson generalises: a rule derived from a real defect was applied uniformly to a set whose members differ in exactly the property the rule depends on. The rule was right; its domain was assumed rather than checked. The frozen matrix already carried the flag that answers it row by row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): browser gate green at Task 3 head -- 32 passed Closes Task 3's concern 2 by measurement rather than inference. The implementer declined to claim it passed and the reviewer judged the risk real but its size understated; the margin held. 32 passed, exit 0, no failures. States plainly what the result does not cover: it was taken before fix round 1, and Ruling 90 changes which rows render the paragraph at all while the confirm- sequence fix changes what renders at commit time. This green must be re-taken after the fixes. A browser result names the commit it ran against or it means nothing -- the rule this branch learned when a concurrent session invented both a phantom failure and a phantom pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(caring-contacts): Task 3 fix round 1 -- Ruling 90, the confirm flash, entry-bound commits, async signature Important 1 (Ruling 90): the no-staged-commit refusal now carries scope recording-rows-only and is withheld from the 8 mutatesState:false rows, whose controls are exits rather than confirmations -- and two of which are recovery-only, so refusing their single control left a person with nothing to do. A caller-stated unavailable refusal still reaches every row. Important 2: the slot is no longer cleared inside the confirm handler, which emptied it while the URL still named the overlay and flashed the refusal in the frame just after a withdrawal was confirmed. Important 3: the staged commit is bound to a one-shot token carried in the pushed history entry, not to the overlay id, and is reconciled in one effect. That closes Back (which never calls onClose), a commit outliving its screen, and one list row's commit answering another row's overlay. Important 4: record widened to (overlayId) => void | Promise<void>; a rejection is re-raised during render so it reaches the route error boundary. The policy for what a failed write should do to the interface still defers. M-3: the trigger ships a default token-based surface. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): Task 3 fix round 1 -- record the four fixes and correct two claims Corrects the section that argued for the blanket refusal (now OVERRULED, Ruling 90) and the M-4 length estimate: NO_STAGED_COMMIT_REASON is 126 characters, roughly 4-5 lines at 390px, not 'one extra short paragraph'. Adds the fix-round mutation table and reports one chained run that short-circuited and never happened. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): Task 3 fix round 1 gates -- 9823 passed, typecheck and lint clean Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(caring-contacts): Task 3 -- the browser green predates fix round 1 and is owed a re-take The coordinator's 32-passed result in 9cc7fa5 ran against the pre-fix head. Ruling 90 changed which rows render the refusal and the confirm-sequence fix changed what renders at commit time, so that evidence does not name this head. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task 3 fix round 1, and a fifth check that could not fail Records two corrections the implementer made to my framing. My suggested remedy for the flashing refusal -- close before clearing -- would not have worked, since both are synchronous while the URL change is not. A controller's suggested remedy is a hypothesis like any other, and this one was falsified by someone reading the code more carefully than I did. The valuable part is a gate it caught not running: grep -c chained with && before the test, where the mutation had stripped the very classes being counted, so grep exited non-zero on a legitimate no-match and the test never ran. No summary line, and it reads as 'confirm the mutation landed, then test it'. Fifth member of a family this repo keeps meeting. The tell that unites them: ask what the check prints when it fails, and confirm you have seen that output once. Four of the five produce no output at all in the failing case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): browser gate re-taken post-fix -- 32 passed at 1306c0b The earlier green was correctly declared stale: Ruling 90 changed which rows render the refusal paragraph and the confirm-sequence fix changed what renders at commit time, so neither the input nor the output of the assertion that mattered was the same thing twice. Both greens read 32 passed, which is why the rule matters rather than why it does not. Identical numbers across two different trees are two separate measurements that happen to agree, and only one describes the code that now exists. Had the fix broken the viewport assertion, the stale green would have said 32 passed about a tree nobody was shipping. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger(caring-contacts): Task 3 COMPLETE -- Group 0 finished All five findings addressed. The re-reviewer checked Ruling 90 against definitions.ts itself: exactly 8 non-mutating rows, the withholding reads the frozen flag, and definitions.ts is untouched across the task range, so the flag was consulted rather than edited. It corrected one of my claims. I described the fix as a one-shot token; it is two mechanisms -- the token and a reconciliation effect -- and neither alone closes the set. A mechanism described as one thing that is actually two is a description under which a later maintainer can delete half and still believe the comment. The generated manifest line is a different problem from Ruling 88 despite the same weak generator: there the attribution was false, here it is true. Same mechanism, opposite verdicts, which is why 'we saw this before' is not itself an answer. Group 0 done: Task 2 cut, Task 4 merged forward, leaving ListEmptyState and the overlay trigger with its commit contract. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps actions/setup-node from 4 to 6.
Release notes
Sourced from actions/setup-node's releases.
... (truncated)
Commits
48b55a0Update Node.js versions in versions.yml and bump package to v6.4.0 (#1533)ab72c7eUpgrade@actionsdependencies (#1525)53b8394Bump minimatch from 3.1.2 to 3.1.5 (#1498)54045abScope test lockfiles by package manager and update cache tests (#1495)c882bffReplace uuid with crypto.randomUUID() (#1378)774c1d6feat(node-version-file): support parsingdevEnginesfield (#1283)efcb663fix: remove hardcoded bearer (#1467)d02c89dFix npm audit issues (#1491)6044e13Docs: bump actions/checkout from v5 to v6 (#1468)8e49463Fix README typo (#1226)Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)