Skip to content

feat(catch-up): since-last-seen caregiver catch-up — contract delta v0.1 + deterministic acceptance cases - #33

Open
obvious-autobuild[bot] wants to merge 2 commits into
masterfrom
spike/agent-experience-catchup
Open

obvious-autobuild[bot] wants to merge 2 commits into
masterfrom
spike/agent-experience-catchup

Conversation

@obvious-autobuild

Copy link
Copy Markdown
Contributor

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

Acceptance criteria

All 14 cases are fixture-driven (synthetic two-household history, grants, per-case expectations) and green locally on HEAD a54cd90aae18197421eb18d1ab8573d869ab647f:

  • AC-01: first-time reader over 20d history clips the window to now−14d (horizonClipped), every item new/late, raw transcripts verbatim, coverage + confirmation present.
  • AC-02: strictly-after-watermark rule — the entry with createdAt === W is excluded, entries after W are included.
  • AC-03: event recorded 2 days after capture yields kind "late", daysLate 2, occurredAt = event timestamp.
  • AC-04: revision after W surfaces a corrected item on the original entry (originalEventId, revisionIds, correctedBy, revised events, original source).
  • AC-05: the same revision before W surfaces NO corrected item and its ids appear nowhere in the output.
  • AC-06: draft entries never appear as items or sources, and do not perturb the published set.
  • AC-07: a reader with no grant on the child's household gets { _tag: "UnauthorizedReader" } and nothing else — no partial output, no coverage leak.
  • AC-08: cross-household entries in history appear nowhere in the output; every source.entryId resolves to a reader-visible entry.
  • AC-09: zero-entry days are counted (gapDays), listed in coverageDays, and disclosed with the exact string "No entries recorded for …"; output never contains "no care" / "nothing happened".
  • AC-10: DST fall-back — 05:00Z and 06:00Z bucket to one local day under the injected offset policy; a single coverage bucket, no 23/25h skew.
  • AC-11: nothing after W → items [], allCaughtUp true, coverageDays still non-empty.
  • AC-12: advanceReadState never moves backwards (older at stays at the watermark; a same-value advance is a no-op).
  • AC-13: a watermark older than the horizon clips windowStart to now−horizon and suppresses corrections to pre-window events.
  • AC-14: report → Schema.encodeSync(CatchUpReport) → decodeUnknownSync → deep-equal (contract round-trip lossless).

Local verification on HEAD a54cd90aae18197421eb18d1ab8573d869ab647f: pnpm typecheck (10/10 turbo tasks), pnpm test (14 AC tests + retrieval suite green), pnpm build (5/5), bun test ./security (29 pass / 0 fail), evaluation harness 6/6 + negative control --expect-failure exit 0, month-history journeys 28/28.

Design summary

  1. Effect v4 schemas in packages/domain/src/catchup.ts are the single contract source (annotated via convexId, decoded with Schema.Schema.Type; no Date.now/Math.random in domain).
  2. computeCatchUp is a pure reducer over (input, history, grants, dayKeyOf): fail-closed authorization first, horizon clip, strict-after-watermark new items, late projection, corrected projection from revisions, per-day coverage, confidence counts, exact gap disclosure.
  3. Convex backend: additive caregiverReadState table + getCatchUp query / advanceReadState mutation (monotonic clamp), validators derived through the existing convexFields adapter; rows decode through the *Document contracts.
  4. Authorization placeholder: master has no membership table (slot 19), so grants are a named knownReaders allowlist that defaults to DENY — replaced by the real membership check when slot 19 lands.
  5. The mobile surface is a presentational CatchUpView prototype taking a validated CatchUpReport; disclosure discipline (exact gap string, confidence markers, correction lineage) lives in the domain, not the view.

Evidence labels

  • LOCAL-REAL: deterministic reducer + CI (no wall clock or randomness in domain code; all 14 acceptance cases are reproducible).
  • DETERMINISTIC DOUBLE: synthetic fixtures only (evaluation/fixtures/agent-experience/catchup/), no LLM in the loop.
  • Mobile NOT device-verified (typecheck-verified prototype only; not wired into navigation).
  • Corrected-path persistence PENDING v0.3 fold/slot 10 (no eventRevisions table on master; the query passes empty revisions and the corrected surface is exercised at the domain level).

Design artifact: art_6qhBut41 (contract proposal, v0.4 fold target). The EventRevision shape there is a proposal for the fold owner — this PR consumes it fixture-level only and creates no table.

Deviations (one line each)

  • Branch base is the current origin/master tip fd7a6ab (the brief's 241ffe6 is stale — master moved), branched -B from origin as required.
  • apps/mobile/package.json links @journal/domain (workspace:*) so the view can take the domain CatchUpReport type — lockfile importers entry only (3 lines), no new npm dependencies.
  • CatchUpRevision adds a fixture-level revision identity so corrected items can cite revisionIds (the EventRevision proposal has no persisted id).

Coordination note

Per the execution coordinator: no namespace-manifest registration or evaluation/src changes are included here — the catch-up fixtures stay plain bun-test-loadable data. A manifest entry for the catchup area will be added and this branch rebased after the namespace-loader PR (task todo_l5QeXI2q) merges.

How to review

Start at packages/domain/src/catchup.ts (contracts + reducer, the heart of the change), then packages/domain/test/catchup.test.ts (AC-01…AC-14 against evaluation/fixtures/agent-experience/catchup/). The backend sketch (backend/convex/convex/catchup.ts, schema table) and the prototype view (apps/mobile/src/catchup/CatchUpView.tsx) are thin consumers. Intentionally excluded: membership authorization (slot 19), eventRevisions persistence (slot 10), device QA, and any evaluation-harness registration (loader PR owns the seam).

No device evidence, live-model runs, or medical/clinical validity are claimed anywhere in this change.

🔗 Obvious Project · 🧵 Obvious Thread

@obvious-autobuild
obvious-autobuild Bot marked this pull request as ready for review September 17, 2026 19:49
ObviousApp and others added 2 commits September 17, 2026 20:20
…0.1 + deterministic acceptance cases

Implements the catch-up slice per the published design (art_6qhBut41):
- packages/domain: additive Effect v4 contracts (CaregiverReadStateFields,
  CatchUpQueryInput/Source/Item, CoverageDay, CatchUpReport,
  AdvanceReadStateInput, EventRevision proposal) + deterministic
  computeCatchUp reducer (fail-closed grants, horizon clip, strict-after
  watermark, late/corrected projection, coverage days, gap disclosure,
  confirmation counts) + monotonic advanceReadState + utcDayKey.
- backend/convex: additive caregiverReadState table with by_caregiver_child
  index, getCatchUp query and advanceReadState mutation (fail-closed
  allowlist placeholder pending membership slot 19; corrected path TODO
  pending eventRevisions slot 10). Regenerated _generated/api.d.ts.
- apps/mobile: presentational CatchUpView prototype (typecheck-verified
  only, not device-verified); links @journal/domain (lockfile importers
  entry only — no new npm dependencies).
- evaluation/fixtures/agent-experience/catchup: synthetic two-household
  fixtures + AC-01..AC-14 cases (no real names/ids/medical content).

Co-authored-by: Gilbert Polanco <gilbertpolanco42@gmail.com>
Register the catch-up scenario-and-authorization area (cases.json,
grants.json, history.json) in the fixture-area manifest with the
loader-legal binding pair (bun-test-data), making it visible to the
fail-fast registration path and listed by corpus runs. Update the
manifest self-check's committed-shape pin to two areas (seed corpus +
registered scenario area); all fail-fast rejection checks unchanged.

Co-authored-by: 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