Skip to content

feat(handoff): since-last-seen digest + grounded follow-up prototypes - #17

Merged
obvious-autobuild[bot] merged 1 commit into
masterfrom
feat/handoff-expansion
Sep 17, 2026
Merged

obvious-autobuild[bot] merged 1 commit into
masterfrom
feat/handoff-expansion

Conversation

@obvious-autobuild

Copy link
Copy Markdown
Contributor

Acceptance criteria

  • Codebase areas for slots 23/24 (caregiver handoff) are implemented as graftable prototypes: since-last-seen summary for an invited caregiver, unresolved questions, routine context, coverage with source links.
  • Both interaction shapes prototyped on one input model: static digest (composeSinceLastSeen) and interactive follow-up (answerFollowUp); renderers for both.
  • Hard rules enforced in code: no medical conclusions; absence of logs never reads as absence of care (care-neutral gap disclosure is first-class data); every claim links to its source (structurally, NonEmptyArray of source refs); unpublished capture content never leaks.
  • Synthetic data only; expected-behavior fixtures schema-checked; tests green locally and CI green on the exact head SHA.

Why

An invited caregiver (a grandparent, a nanny) currently has no way to catch up on a child's window without paging through raw captures — or worse, trusting an unsourced summary. Slots 23/24 call for a handoff that is reviewable instead of impressive: what was logged, where each claim came from, what the journal could not see, and explicit refusals where a summary would otherwise start interpreting. Absence of logs is the failure mode that hurts families most — a summary that reads a quiet day as a bad day is worse than no summary.

What

New workspace package @journal/handoff (Effect v4 contracts + pure composition; no model call, no Convex call — deterministic so fixtures pin exact behavior):

Shape Entry point Notes
Static digest composeSinceLastSeen(input) Per-event claims with verbatim-quote source refs; routine context attributed to the child profile; unresolved questions for draft/pending/failed/low-confidence captures; per-category coverage rows; care-neutral GapDisclosure per capture-free local day; source index; suggested follow-ups (the bridge into the interactive shape).
Interactive follow-up answerFollowUp(question, input) Same DigestInput. Citation-bearing answers; explicit refused-medical and refused-out-of-window; care-neutral not-logged statements. Classification is deliberately heuristic keyword matching — the refusals and citation invariants are the part meant to survive; the matcher is replaceable.
Renderers digestToText / answerToText Plain-text layout for ticket/print surfaces; pure.

Decisions worth a reviewer's attention:

  • Wire-level taxonomy duplication (mirrors evaluation/src/adapter.ts precedent): handoff duplicates the six-category union rather than reach into domain internals, so the package grafts cleanly without a domain value export. Keep-both-in-sync comment marks the seam.
  • Authorization is upstream by contract — the package summarizes exactly what it is given (slot 20 owns authorization, 23/24 own presentation). No tenancy re-check inside.
  • Guard scoping: assertCareNeutral (word-anchored, suffix-tolerant) applies to system-GENERATED language only. Verbatim transcript snippets are exempt — quoting a human source is not drawing a conclusion. Family-profile notes ARE guarded (inclusion is endorsement).
  • Window semantics: [lastSeenAt, generatedAt) in caller's IANA timezone; hourly day-walk handles DST without fixed-24h assumptions; events at lastSeenAt in, entries at generatedAt out.
  • Alternatives considered: an LLM-composed narrative (rejected — nondeterministic, unsourced by default, harder to keep care-neutral under test) and a domain-contract change (rejected — conflicts with the in-flight v0.3 fold; this package is the graft point instead).

How to Review

  • Contracts first: packages/handoff/src/contracts.ts — the hard rules are structural (SourceRefs is NonEmptyArray; there is no field for severity/comparison/normality anywhere in HandoffDigest).
  • Guard: src/gaps.ts — word-anchored matching so stems catch inflections ("diagnos" → "diagnosed") while "still" never trips "ill".
  • Composer: src/compose.ts — published+structured filter, question escalation, gap disclosure, coverage.
  • Fixtures: packages/handoff/fixtures/*.json (six, all syn-* ids) + generator scripts/gen-handoff-fixtures.mjs (epochs verified against America/New_York via Intl).
  • Intentionally excluded: no UI screens, no Convex functions, no model integration — this is the contract + composition layer slots 23/24 consume.

Test Evidence

Full local verification table, run against HEAD 8b7c7ee (post-rebase onto master 00581f5):

  • pnpm turbo run typecheck — 8/8 packages
  • pnpm turbo run test — all workspaces; @journal/handoff: 21 tests / 156 assertions (invariants + schema-checked acceptance fixtures)
  • pnpm turbo run build — 4/4
  • bun test ./security — 17/17 fail-closed access cases
  • cd evaluation && bun src/run.ts — 6/6 corpus fixtures; negative control (broken-adapter --expect-failure) fails as designed

CI is the final gate for merge; no human approval is required by repo policy.

Human author: Gilbert Polanco (gilbertpolanco42@gmail.com)

🔗 Obvious Project · 🧵 Obvious Thread

@journal/handoff prototypes for delivery slots 23/24 — two interaction
shapes over one input model:

- composeSinceLastSeen: static digest with per-event claims (every claim
  carries a NonEmptyArray of source refs), verbatim routine context,
  unresolved questions for draft/pending/failed/low-confidence captures,
  per-category coverage, and care-neutral gap disclosures for every
  capture-free day in the window.
- answerFollowUp: interactive surface over the same DigestInput —
  citation-bearing answers, explicit refusals for medical questions and
  out-of-window spans, care-neutral not-logged statements.

Hard rules enforced in code, not comments: no medical conclusions (a
word-anchored guard rejects interpreting vocabulary in all system-
generated language, while verbatim human quotes stay exempt as sources);
absence of logs never reads as absence of care (gap disclosures are
first-class data); unpublished capture content never leaks (draft/
pending/failed captures are cited, never quoted); window semantics
[lastSeenAt, generatedAt) rendered in the caller's IANA timezone.

Six schema-checked synthetic fixtures (all ids syn-*) + 21 Bun tests
(invariants + fixture-driven acceptance). scripts/gen-handoff-fixtures.mjs
regenerates the fixtures from verified epoch constants.

Co-authored-by: Gilbert Polanco <gilbertpolanco42@gmail.com>
@obvious-autobuild
obvious-autobuild Bot marked this pull request as ready for review September 17, 2026 18:33
@obvious-autobuild
obvious-autobuild Bot merged commit 652ace5 into master Sep 17, 2026
1 check passed
@obvious-autobuild

Copy link
Copy Markdown
Contributor Author

Evidence receipt

Field Value
PR #17
Tested head SHA 8b7c7ee (branch head reviewed and locally verified; re-verified after rebase onto 00581f5)
Review result pass — acceptance-criteria diff inspection per repo workflow (no required human approvals per .obvious policy), obvious worker, 2026-09-17
Checks all green — ci.yml run on the same SHA (1/1 checks passed, 0 pending)
Merge commit 652ace5 (squash)
Post-merge smoke on 652ace5: pnpm turbo run typecheck test build --force — 12/12 tasks uncached; bun test ./security — 17/17 fail-closed cases; packages/handoff suite — 21 tests / 156 assertions, 0 fail
Unlocked tasks slots 23/24 implementation lanes (todo_aZRC3b5p, todo_ikGk2iqI) and the remember-and-retrieve catch-up consumers

Remote branch feat/handoff-expansion was left on origin after merge (no --delete-branch used); delete at will.

Human author: Gilbert Polanco (gilbertpolanco42@gmail.com)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants