Plan header
| Field |
Value |
| Status |
DRAFT |
| Date |
2026-09-05 |
| Type |
phase 4 |
| Parent |
#947 — #947 |
| Source issue |
#552 — #552 (A4 compaction engine) |
| Layers |
Vercel backend (tests) |
| Reusability impact |
none |
| Production mutate? |
no |
| Cloud ops path |
N/A |
| Living docs |
N/A this phase (parent Phase 5 owns docs) |
Intent lock
In scope: land the parent test matrix rows that are not covered by Phases 1–3 unit tests — the copy-forward, confused-deputy, planted/stale checkpoint, and fail-open contracts — so the whole parent DoD is provable. This is a hardening phase; it closes out the "Minimum locked" test rows for the parent.
Out of scope: new product code beyond test scaffolding (only the exports already shipped in Phases 1–3), and docs (Phase 5).
Forbidden: treating this phase as optional; skipping the copy-forward/confused-deputy rows.
Depends on
Phase 3 merged (trigger + summarizer + seeding exist to test end-to-end).
Current baseline (live code @ main)
| Claim |
Path / symbol |
Notes |
| Test framework |
vitest run direct (no wrapper) |
verified @ main |
#944/#937 adversarial test idioms for pointer reads |
app/api/turns route tests |
verified @ main |
Design
Close out the parent Testing matrix:
- Row: copy-forward — a host flatten envelope PUT omitting
compactionPointer must not delete the worker's checkpoint (copyForwardCompactionPointer inside upsertEnvelope). Covered in lib/sessions/sessionStore.test.ts.
- Row: confused-deputy read — an unbound
compactionPointer id is rejected on the route's seed read (revert to modelMessagesPointer / legacy).
- Row: planted/stale checkpoint — the route re-validates + re-pairs on read; a malformed checkpoint Blob falls back safely.
- Row: summarizer fail-open —
compactionStep failure seeds from the full (trimmed) projection; turn still starts.
- Row: end-to-end seed — checkpoint preferred over
modelMessagesPointer when bound + valid.
- Row: gates —
npm run typecheck, npm test, and a npm run build smoke where feasible in the agent workspace.
Implementation order
- Add/extend
lib/sessions/sessionStore.test.ts (copy-forward).
- Add/extend the
app/api/turns route tests (confused-deputy, planted/stale, optional-historical fallback chain).
- Add
lib/workflows/compactionStep.test.ts fail-open cases as needed.
- Run
npm run typecheck, npm test and list the passing rows in the PR body.
Testing
| # |
Case |
Layer |
Type |
Command / method |
| 1 |
Copy-forward on envelope PUT |
backend |
unit |
vitest run lib/sessions/sessionStore.test.ts |
| 2 |
Confused-deputy read rejected |
backend |
unit |
vitest run app/api/turns |
| 3 |
Planted/stale/malformed checkpoint → fallback chain |
backend |
unit |
vitest run app/api/turns |
| 4 |
Summarizer fail-open |
backend |
unit |
vitest run lib/workflows/compactionStep.test.ts |
| 5 |
End-to-end checkpoint-preferred seed |
backend |
integration |
vitest run app/api/turns |
| 6 |
Gates |
all |
gate |
npm run typecheck, npm test |
Minimum locked for DoD: all rows.
Definition of done
Corrections / refinements vs parent
| Topic |
Parent said |
This phase locks |
| Parent Testing matrix |
Rows 1–8 |
This phase proves rows 4–8 (copy-forward, confused-deputy, planted/stale, fail-open, seed-chain) as the hardening gate |
Plan header
Intent lock
In scope: land the parent test matrix rows that are not covered by Phases 1–3 unit tests — the copy-forward, confused-deputy, planted/stale checkpoint, and fail-open contracts — so the whole parent DoD is provable. This is a hardening phase; it closes out the "Minimum locked" test rows for the parent.
Out of scope: new product code beyond test scaffolding (only the exports already shipped in Phases 1–3), and docs (Phase 5).
Forbidden: treating this phase as optional; skipping the copy-forward/confused-deputy rows.
Depends on
Phase 3 merged (trigger + summarizer + seeding exist to test end-to-end).
Current baseline (live code @ main)
vitest rundirect (no wrapper)#944/#937adversarial test idioms for pointer readsapp/api/turnsroute testsDesign
Close out the parent Testing matrix:
compactionPointermust not delete the worker's checkpoint (copyForwardCompactionPointerinsideupsertEnvelope). Covered inlib/sessions/sessionStore.test.ts.compactionPointerid is rejected on the route's seed read (revert tomodelMessagesPointer/ legacy).compactionStepfailure seeds from the full (trimmed) projection; turn still starts.modelMessagesPointerwhen bound + valid.npm run typecheck,npm test, and anpm run buildsmoke where feasible in the agent workspace.Implementation order
lib/sessions/sessionStore.test.ts(copy-forward).app/api/turnsroute tests (confused-deputy, planted/stale, optional-historical fallback chain).lib/workflows/compactionStep.test.tsfail-open cases as needed.npm run typecheck,npm testand list the passing rows in the PR body.Testing
vitest run lib/sessions/sessionStore.test.tsvitest run app/api/turnsvitest run app/api/turnsvitest run lib/workflows/compactionStep.test.tsvitest run app/api/turnsnpm run typecheck,npm testMinimum locked for DoD: all rows.
Definition of done
Corrections / refinements vs parent