Skip to content

feat(domain): fold contract v0.4 — retraction, CareProfile, raw-access-by-grant - #34

Open
obvious-autobuild[bot] wants to merge 1 commit into
masterfrom
task/contract-v0-4-fold-retraction-careprofil-OalW9ers
Open

obvious-autobuild[bot] wants to merge 1 commit into
masterfrom
task/contract-v0-4-fold-retraction-careprofil-OalW9ers

Conversation

@obvious-autobuild

@obvious-autobuild obvious-autobuild Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

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

Acceptance criteria

  1. Retraction (settlement 1) — published entries gain an append-only retracted state change recorded as a household-visible receipt; retracted content is HIDDEN FROM HOUSEHOLD QUERIES (query-path exclusion filter, not deletion); the original row is retained at the storage layer; operator/lineage reads stay reachable via the receipt.
  2. CareProfile (settlement 2) — a first-class CareProfile contract area scoped to a child (allergy / nap-schedule / emergency), household-visible per existing membership rules, built strictly on explicit caregiver-confirmed information with provenance reusing family-knowledge structures, with NO automatic inference of medical facts.
  3. Raw-access-by-grant (settlement 3) — contract-level visibility default: cross-household viewers get STRUCTURED ENTRIES ONLY; verbatim raw transcripts require an explicit grant; the grant record shape + default-off semantics are defined so slot 20 enforcement binds to schema, not convention.
  4. Dimension separation — publication state, audience permissions, retraction, and raw-access remain independent dimensions; nothing collapses into one fused enum.
  5. Rule-2 discipline — canonical Effect v4 schemas live only in packages/domain; backend Convex validators derive via the tested adapter (PR feat(backend): port thin-path functions onto canonical four-table contract #13 precedent); no domain changes outside the fold.
  6. Coverage — domain round-trip tests + JSON Schema (draft 2020-12) derivation coverage for every new type; stale contract references in .obvious/obvious.md updated.

Why

Gil's three settled product decisions (2026-09-17, pinned in project context) are product law but not yet schema: nothing in the contract distinguishes a retracted entry from a published one, standing care context (allergies, nap schedules, emergency info) has no first-class home for the handoff/digest slots to read, and the raw-transcript boundary for cross-household viewers lives in no record a query can check. Until the contract carries them, slots 20/31 and the agent-query slots would each re-invent these rules as convention. This fold follows the v0.3 precedent (PR #14, merge 00581f5): additive schema areas in packages/domain, backend tables derived, fold pinned by tests.

What

  • retraction.ts (new) — RetractionReceipt is the append-only, household-visible receipt (entryId, retractedBy, retractedAt, optional detail); there is no unretract mutation — reversal is a new contract decision. Entry.retractedAt is its materialized read-model (the same lineage pattern v0.3 established for extractionStatus). RetractionFilter + excludesRetracted are the query-path hook: ABSENT filter or household scope excludes retracted entries — the privacy posture is the default, not an opt-in; operator scope is the only include path. ListEntriesByChildInput embeds the hook as the pattern for the agent-query inputs (slots 15/17/23/24) and timeline reads.
  • careProfile.ts (new) — CareProfile items reuse the family-knowledge structures (source attribution with statedBy/recordedBy/sourceQuote, append-only supersession, confidence partition) with the provenance union NARROWED to caregiver-stated | caregiver-confirmed: model-extracted cannot even encode, and the invariants forbid the extraction model as recorder. The area union is closed to the settled three — no diagnosis/medical area exists. Audience is never stored on the item.
  • rawAccess.ts (new) — RawAccessGrant (grantee, grantedBy, granted/revoked + revokedAt) is a THIRD dimension: it carries no visibility, no audience, and no retraction fields. Default-off is a rule, not a convention: rawTranscriptVisible denies a cross-household viewer unless an active grant exists (absence IS the denial), and StructuredEntryView — derived from EntryFields — is the projection that provably drops rawTranscript (decode through the view schema strips it as an excess key; pinned by a leak-proof test).
  • backend/convex/schema.ts — derives the three new tables (retractions, care_profiles, raw_access_grants) through the tested adapter; no hand-written validators.
  • .obvious/obvious.md — layout + contract references brought to v0.4 reality (security-suite count was stale since PR feat(backend): family-knowledge Convex functions — create, supersede, bounded reads #31 added cases).

Trade-offs / rejected alternatives: an in-place visibility: "retracted" enum value was rejected — it would fuse retraction into publication state (criterion 4) and mutate rather than append. A single-profile-per-child document was rejected — per-item append-only records keep provenance and supersession honest, matching how Knowledge already works.

How to Review

Key files: packages/domain/src/retraction.ts, careProfile.ts, rawAccess.ts (the whole fold), entry.ts (+retractedAt), contracts.ts (+filter hook), backend/convex/convex/schema.ts (derived tables). Tests: packages/domain/test/contract-v04.test.ts (33 tests). Intentionally excluded: no backend function bodies / no UI — those are the slot owners' work (20, 31, 15/17/23/24); no Knowledge changes (its taxonomy stays as merged in PR #16); no entry-row deletion or soft-delete flag — retention is the storage layer's job and the receipt is the only record.

Verification-manifest

{
  "manifestVersion": 1,
  "pr": 34,
  "prUrl": "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/OCPdev25/obv-hackaton/pull/34",
  "testedHeadSha": "ccc1f0cce1b9356af21b27892d3f14b3899a47d4",
  "classification": "backend-only",
  "classificationJustification": "packages/domain contract fold + derived backend schema; no rendered UI changed — visual evidence not applicable",
  "review": { "result": "pass", "reviewer": "independent-review", "reviewedHeadSha": "PENDING", "date": "2026-09-17", "url": "PENDING" },
  "checks": [{ "name": "ci", "status": "green", "headSha": "PENDING", "url": "PENDING" }],
  "evidence": [
    { "kind": "test-run", "name": "domain round-trip + v0.4 fold suite (94 tests, 33 new)", "headSha": "ccc1f0c", "result": "pass", "url": "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/OCPdev25/obv-hackaton/pull/34" },
    { "kind": "suite-run", "name": "pnpm typecheck + test + build (turbo, uncached)", "headSha": "ccc1f0c", "result": "pass", "url": "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/OCPdev25/obv-hackaton/pull/34" }
  ],
  "suites": {
    "security":   { "ran": true, "result": "pass", "headSha": "ccc1f0c", "url": "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/OCPdev25/obv-hackaton/pull/34" },
    "evaluation": { "ran": true, "result": "pass", "headSha": "ccc1f0c", "negativeControl": "fail-as-expected", "url": "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/OCPdev25/obv-hackaton/pull/34" }
  },
  "notes": "month-history journeys 28/28 at ccc1f0c; local verification run in the assigned repo sandbox worktree"
}

🔗 Obvious Project · 🧵 Obvious Thread

…s-by-grant

Contract v0.4 fold (Gil settlements 1-3, 2026-09-17), following the v0.3
fold precedent (00581f5):

- retraction.ts: append-only RetractionReceipt (the household-visible
  receipt: entry, retractedBy, retractedAt, optional detail) — the entry
  row is retained at the storage layer; no "unretract" mutation exists.
  Entry gains retractedAt as its materialized read-model (the lineage
  pattern v0.3 established for extractionStatus). RetractionFilter +
  excludesRetracted are the query-path exclusion hook: ABSENT filter or
  household scope EXCLUDE retracted entries (the settled privacy posture
  is the default, not an opt-in); operator scope is the only include
  path. ListEntriesByChildInput embeds the hook as the pattern for
  household-facing query inputs (agent queries slots 15/17/23/24,
  timeline reads).
- careProfile.ts: first-class CareProfile area — standing care context
  per child (allergy | nap-schedule | emergency), scoped to a child,
  household-visible per existing membership rules (audience never
  stored). Reuses the family-knowledge structures: source attribution
  (statedBy/recordedBy, KnowledgeSourceType/Span, sourceQuote),
  append-only supersession (supersedes/status/validFrom/validUntil),
  and the confidence partition. Caregiver-confirmed only binds at the
  SCHEMA level: CareProfileProvenance omits model-extracted (a
  model-proposed item cannot even encode) and the invariants forbid the
  extraction model as recorder — no automatic inference of medical
  facts. The area union is closed to the settled three.
- rawAccess.ts: RawAccessGrant record (grantee, grantedBy, granted /
  revoked + revokedAt) with default-off semantics — a cross-household
  viewer sees STRUCTURED ENTRIES ONLY; the absence of an active grant
  IS the denial (rawTranscriptVisible is the rule slot 20 binds to).
  StructuredEntryView is the entry projection without rawTranscript,
  derived from EntryFields and stripping the verbatim field by
  construction (decode through the view schema). The grant is a THIRD
  dimension: it carries no visibility, no audience, and no retraction
  fields — publication state, audience, retraction, and raw-access
  never fuse into one enum.
- backend/convex/schema.ts derives the three new tables (retractions,
  care_profiles, raw_access_grants) via the tested adapter — no
  hand-written validators (PR #13 precedent).
- contract-v04.test.ts: 33 tests — round-trips, receipt state on Entry,
  filter semantics, closed unions, invariants (supersession lifecycle,
  confidence partition, source attribution, grant revocation pairing
  and ordering), default-off matrix, projection-leak proof, adapter
  mapping for every new table, and JSON Schema (draft 2020-12)
  derivation for every new type.
- .obvious/obvious.md: layout + contract references updated (v0.4
  areas, security-suite count unpinned to current reality).

Verified locally (worktree at this commit): turbo typecheck 10/10,
test 7/7, build green; domain suite 94/94 (33 new); security 29/0;
evaluation corpus 6/6 + negative control exits 0; month-history
journeys 28/28.

Human author: Gilbert Polanco (gilbertpolanco42@gmail.com)
Co-authored-by: Gilbert Polanco <gilbertpolanco42@gmail.com>
@obvious-autobuild
obvious-autobuild Bot marked this pull request as ready for review September 17, 2026 20:19
@obvious-autobuild

Copy link
Copy Markdown
Contributor Author

CI failure diagnosis — pre-existing on master, fix inbound via #35 (not this diff)

The failing Typecheck, test, build check runs on the merge ref = master 9ea7e73 + this branch. 9ea7e73 (PR #15) introduced packages/capture-recovery written against the pre-v0.3 domain API — it uses ExtractionAttempt as the numeric attempt counter (v0.3 renamed that to AttemptNumber; ExtractionAttempt now names the lineage record) and assigns plain-string capture ids into the branded CaptureId field.

Verified independently of this PR: the same typecheck fails on pristine master 9ea7e73 (no changes from this branch applied). This PR's diff is additive to packages/domain and does not touch the names capture-recovery consumes.

Fix ownership: #35 (same lane that owns capture-recovery) carries the domain adaptation with green CI. To avoid duplicating the fix and generating conflict churn for the sweep owner, this PR carries no capture-recovery changes. Plan: once #35 merges, rebase this branch onto the new master, re-run the full local verification table at the new head, refresh the verification-manifest (testedHeadSha + evidence), and let CI re-run green.

Domain gates re-verified at the current rebased head 6d4432a: domain suite 94/94 (33 new v0.4 tests).

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