Skip to content

plan: A4 compaction — phase 4 — plan-level test hardening (source #552) #951

Description

@btipling

Plan header

Field Value
Status HANDOFF-READY
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 — no Production data, schema, environment, or secret mutation
Living docs N/A this phase (parent Phase 5 / #952 owns the timeless docs)

Review notes (2026-09-06)

# Finding Severity Resolution
1 The gate row made the parent-required npm run build optional (“where feasible”) and omitted it from the test matrix. A hardening phase cannot waive the parent build gate. Major Require npm run build in the cloud agent workspace or CI. If the workspace lacks the existing Wasm artifact or authorized artifact access, obtain it through the established cloud/CI path; do not waive the gate.
2 The phase had no caps table despite exercising the compaction carrier and its bounded checkpoint/span paths. Minor Add a baseline caps table: Phase 4 changes no cap; all listed limits remain at their current values.
3 “Rows 4–8” was imprecise: parent row 4 (honesty label) belongs to Phase 1, while this phase hardens rows 5–8 and re-proves the checkpoint-preferred route seed from parent row 3. Minor Correct parent mapping and lock observable assertions for each fallback case.

Verdict: HANDOFF-READY — no blockers remain. Parent dependency Phase 3 is merged (PR #955); Phase 2 is merged (PR #954). Scope is backend test hardening only, stays within the parent, introduces no Production mutate, and leaves timeless documentation to Phase 5. No existing cap is raised or lowered; no human cap decision is required.

Intent lock

In scope: land the parent test-matrix contracts not sufficiently proven by the Phase 1–3 focused tests — copy-forward, confused-deputy rejection, planted/stale checkpoint fallback and re-pairing, checkpoint-preferred route seeding, and fail-open compaction — so the whole parent DoD is provable. This is a hardening phase that closes the parent’s remaining “Minimum locked” coverage.

Out of scope: product behavior changes, new caps, Production data/schema/env/secret changes, and docs (Phase 5 / #952). Test-only helpers may expose already-shipped behavior; if a test discovers a behavior defect, fix or re-plan that defect explicitly rather than weakening the contract.

Forbidden: treating this phase as optional; skipping the copy-forward/confused-deputy cases; waiving the build gate; changing any existing cap.

Depends on

Phase 3 is merged (PR #955): trigger, summarizer, checkpoint writer, and seeding exist to test end-to-end at the route/workflow seam. Phase 2 is merged (PR #954): the persisted checkpoint carrier and route read/fallback chain exist.

Current baseline (live code @ main)

Claim Path / symbol Notes
Test framework direct vitest run (no wrapper) required by repository guidance
Checkpoint pointer copy-forward lib/sessions/sessionStore.ts (upsertEnvelope, copyForwardCompactionPointer) shipped by Phase 2
Route seed chain app/api/turns/route.ts checkpoint → modelMessages → legacy sidecar; read is scope-bound and checkpoint tail is rebuilt/re-paired
Compaction fail-open lib/workflows/compactionStep.ts, lib/workflows/turnWorkflow.ts shipped by Phase 3; failed summary must not prevent a turn
Existing route adversarial-test idioms app/api/turns route tests use bound/unbound Blob fixtures rather than a synthetic bypass

Design

Close out the parent testing matrix with observable, contract-level tests:

  • Copy-forward (parent row 5): a host flatten envelope PUT that omits compactionPointer preserves the worker checkpoint through upsertEnvelope; an intentional worker-authored value still wins. The test must exercise the LWW read/merge path, not merely the helper in isolation.
  • Confused-deputy rejection (parent row 6): supply a checkpoint object id that is not bound to the requesting session scope; assert the route neither reads nor seeds it and instead uses the valid modelMessagesPointer fallback (or the legacy sidecar if that pointer is unavailable).
  • Planted/stale/malformed checkpoint (parent row 8): for a bound but invalid JSON/shape checkpoint and for a tail that needs repair, assert the route rejects/re-pairs safely and follows checkpoint → modelMessages → legacy fallback without emitting orphan tool results to the model seed.
  • Checkpoint-preferred seed (parent row 3 re-proof): with valid, session-bound checkpoint and model-messages objects, assert the workflow start receives [summaryRow, ...retainedTail] rather than the full model-messages projection; assert the summary is the existing honest user-role row.
  • Summarizer fail-open (parent row 7): force the summary step to fail and assert the turn still starts from the full route-trimmed projection, with no partial/fabricated checkpoint substituted.
  • Gates (parent row 9): run direct focused Vitest tests during iteration, then npm run typecheck, npm test, and npm run build. The build runs in the cloud agent workspace or CI; a missing generated Wasm artifact/access is remediated using the existing cloud artifact/CI path, never treated as a waiver.

Caps table

Phase 4 adds and changes no cap. The tests use bounded fixtures and must not alter these existing limits.

Cap / ceiling Current value Rationale Code location
COMPACTION_RESERVE_TOKENS 16,384 tokens Existing trigger completion reserve lib/sessionCloudCaps.ts
COMPACTION_SUMMARY_MAX_CHARS 8,000 chars Existing bounded checkpoint summary lib/sessionCloudCaps.ts
COMPACTION_FILES_TOUCHED_MAX 256 paths Existing bounded checkpoint file list lib/sessionCloudCaps.ts
COMPACTION_CHECKPOINT_MAX_BYTES MODEL_MSG_SEED_MAX_BYTES + 256 KiB (2.25 MiB) Existing checkpoint-object ceiling, sized for the legal retained tail plus summary metadata lib/sessionCloudCaps.ts
COMPACTION_SPAN_MAX_BYTES 2 MiB Existing summarizer-input ceiling lib/sessionCloudCaps.ts
Function-body / model-seed transport ceilings unchanged Tests must not introduce a larger Function-carried payload existing transport + session cap seams

Cap governance: no existing value changes in this phase; no human cap decision is needed.

Implementation order

  1. Add/extend lib/sessions/sessionStore.test.ts for host-flatten PUT copy-forward, including worker-value precedence.
  2. Add/extend the app/api/turns route tests for valid checkpoint preference, unbound pointer rejection, malformed/stale fallback, legacy fallback, and strict re-pairing of the resulting seed.
  3. Add/extend lib/workflows/compactionStep.test.ts and/or the owning workflow test for a rejected/failed summary step that still starts the turn from the full trimmed projection. Keep the assertion at the workflow boundary where fail-open is implemented.
  4. Run focused direct Vitest commands while iterating, then the required typecheck, full test, and build gates. Record the passed matrix rows and all three gate results in the PR body.

Testing

# Case Layer Type Command / method
1 Host-flatten envelope PUT copy-forwards compactionPointer; worker-authored explicit value wins backend unit vitest run lib/sessions/sessionStore.test.ts
2 Unbound checkpoint id is rejected; route falls back without cross-session read backend route unit vitest run app/api/turns
3 Bound malformed/stale checkpoint and unrepaired tail safely follow checkpoint → modelMessages → legacy fallback; seeded messages have no orphan tool results backend route unit vitest run app/api/turns
4 Valid bound checkpoint is preferred over modelMessages and produces the honest summary-row + retained-tail workflow seed backend route integration vitest run app/api/turns
5 Summary-step failure fail-opens to the full trimmed projection and still starts the turn backend workflow unit vitest run lib/workflows/compactionStep.test.ts (plus owning workflow test if needed)
6 Required gates all gate npm run typecheck, npm test, npm run build in cloud agent workspace or CI

Minimum locked for DoD: all rows.

Definition of done

  • Parent test rows 5–8 are proven; parent row 3’s checkpoint-preferred seed is re-proven at the route/workflow boundary
  • Focused tests prove copy-forward, scope binding, malformed/stale fallback, re-pairing, valid preference, and summary-step fail-open without weakening shipped behavior
  • npm run typecheck, npm test, and npm run build are green in the cloud agent workspace or CI, and results/matrix rows are recorded in the PR body
  • No existing cap value changed; no human cap decision required
  • Cloud ops: N/A — no Production mutate
  • Living docs: N/A this phase; Phase 5 / plan: A4 compaction — phase 5 — living docs (source #552) #952 owns the parent’s timeless documentation changes

Corrections / refinements vs parent

Topic Parent said This phase locks
Parent testing matrix Rows 1–9 Phase 4 hardens rows 5–8 and re-proves checkpoint-preferred seeding from row 3; Phase 1 owns honesty (row 4)
Build gate Parent row 9 requires npm run build Build is mandatory in the cloud agent workspace or CI; artifact/access setup is not a waiver
Cap governance Parent owns the compaction cap definitions This phase changes none; baseline values are listed for test-fixture discipline

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions