Skip to content

plan: A4 compaction — phase 5 — living docs (source #552) #952

Description

@btipling

Plan header

Field Value
Status IMPLEMENTED — PR #957 (open, not merged)
Date 2026-09-05
Type phase 5
Parent #947#947
Source issue #552#552 (A4 compaction engine)
Layers Living docs only
Reusability impact none — describe the existing per-session, selected-model behavior without origin-specific configuration
Production mutate? no — documentation only; no schema, Redis, Blob data, environment, secret, or deployed-runtime change
Cloud ops path N/A — no Production mutate
Living docs docs/session-model.md, docs/harness-limits.md, docs/feature-divide.md, AGENTS.md; README / SECURITY / .env.example reviewed N/A below

Review notes (2026-09-07)

# Finding Severity Resolution
1 The limits list omitted the shipped combined start() compact-argument ceiling, and did not distinguish the 2.25 MiB checkpoint object ceiling from the 2 MiB span/input ceiling. Major Document all six existing compaction limits, including COMPACTION_START_MAX_BYTES; lock their current values and carriers in the caps table. No value changes.
2 The proposed simple seed order “checkpoint → modelMessages → legacy sidecar” would be inaccurate after a successful compact: a valid live model-messages projection beginning with the honesty row is preferred so a later non-compacting turn retains post-compact work. Major Lock the exact selector: honest live model-messages projection → valid checkpoint → ordinary model-messages projection → legacy promptHistory; all Blob ids are session-bound and reads re-validate/re-pair.
3 “Markdown renders; links resolve” was not an implementable verification plan, and did not require the repository gates. Minor Add source-to-doc semantic review, link/diff review, and the required cloud-workspace/CI typecheck, full test, and build gates.

Verdict: HANDOFF-READY — all findings are resolved in this issue. Phase 4 is merged through PR #956, so this phase documents shipped behavior only. No cap is added, raised, or lowered; no human cap decision is required.

Intent lock

In scope: capture the shipped compaction behavior in the four living-document surfaces assigned by the parent. The text must be timeless product/agent truth: it explains what the current system does, its ownership boundaries, data safety, and existing limits without phase/issue history.

Out of scope: application code, tests, migrations, deployment configuration, schema/Redis/Blob data changes, cap changes, and visitor-front-door or secret-policy changes.

Forbidden: phase/issue theater in product docs; “see issue #NN” as an explanation; a simplified seed-order statement that loses the honest-live-projection preference; laptop-primary ops notes; describing compaction as deleting transcript or model-history objects; suggesting that the Wasm harness or DOM host runs the summarizer.

Depends on

Phase 4 is merged (PR #956), following merged Phases 1–3. The documentation therefore describes current main behavior, not an intended or speculative design.

Current baseline (live code @ main)

Claim Path / symbol Notes
Trigger and seed selection occur before durable workflow start app/api/turns/route.ts Reads bound checkpoint/model-message objects, applies the pre-trim trigger, and passes serializable compact args only
Compaction is a server-side first workflow step lib/workflows/compactionStep.ts, lib/workflows/turnLoop.ts Same selected model, BYOK re-resolved in-step, tools off; no DOM/Wasm summarizer
Checkpoint shape, honesty row, cut/re-pair, and payload rails lib/agent/compaction.ts {summary, filesTouched, retainedTail}; user-role honesty row; logical compaction does not delete Blob history
Pointer carrier, validation, and host-omit copy-forward lib/sessions/sessionStore.ts meta.compactionPointer is a reserved session-bound Blob pointer, copied forward by envelope upsert when the host omits it
Current compaction caps lib/sessionCloudCaps.ts Six existing values in the caps table below; no value changes in this phase
Current session/Blob and host responsibilities docs/session-model.md, docs/feature-divide.md, AGENTS.md These docs currently cover the model-messages projection and its rails but need compaction’s exact durable semantics

Documentation design

docs/session-model.md — new timeless Compaction section

Document the model-facing compaction lifecycle alongside the existing durable-turn model-messages section:

  1. Checkpoint carrier and durability. meta.compactionPointer is only a Redis-safe, session-bound object id. Its Blob object holds { summary, filesTouched, retainedTail }; the checkpoint body never rides envelope meta. A host flatten envelope PUT omits this worker-authored key, and the store copy-forwards the existing valid value; a new successful compaction replaces it. The transcript and earlier model-messages objects remain retained in Blob — compaction changes the model seed, not stored history.
  2. Trigger and cut. At POST /api/turns, the backend resolves the selected model’s joined catalog window and its existing fold budget, evaluates the pre-trim seed, and compacts only when that seed exceeds the budget and a safe user-turn boundary exists. The cut is re-paired so an assistant tool call cannot be separated from its tool result. If there is no legal cut, the established route trim remains the fail-open fallback; no turn is blocked.
  3. Server-only summary. The Workflow runs one tools-off summarizer step before the first normal model round, with the selected model and in-step authorization. The Wasm harness and DOM host do not summarize, receive credentials, or gain a new bridge/protocol surface. A failed, empty, or unusable summary fails open to the ordinary bounded seed and must not create a fabricated checkpoint.
  4. Exact next-turn seed selection. Validate every pointer against the requesting {tenantId, userId, sessionId} and re-validate/re-pair decoded rows. Prefer a valid model-messages object when its first row is the labeled compaction honesty row (the post-compact live warehouse, preserving work done after compaction); otherwise prefer a valid checkpoint rendered as [summaryRow, ...retainedTail]; then use an ordinary valid model-messages projection; finally fall back to the host’s legacy promptHistory sidecar. Unbound, missing, malformed, or invalid objects do not seed another session and fall through safely.
  5. Honesty. The summary is a user-role row beginning exactly Summary of earlier session (compacted, not live assistant prose):; it is context, never a claim that the assistant just said it live. filesTouched supplies the bounded Files read/modified: context.

Update the reserved-meta/key table and full-replace exception text to include compactionPointer with the other worker-authored pointers, including its clear/copy-forward behavior. Keep explanations timeless; do not mention plans, phases, PRs, or issue numbers.

docs/harness-limits.md — compaction limits rows

Add a Compaction limits row/table near the existing durable model-message rails. State units, carrier, and behavior, not only constant names. Distinguish a Blob-object ceiling from workflow-start-argument and summarizer-input ceilings. Cross-reference the existing model window/fold-budget and model-seed rails rather than duplicating their values.

docs/feature-divide.md — ownership table

Add a durable-turn/compaction ownership row, or extend the current durable-turn row, that makes the split explicit: Vercel backend reads the bound seed, decides/cuts, runs the server-side workflow summary, and writes the checkpoint; DOM remains the thin submit/bridge host; Wasm remains the primary transcript/composer and never runs the summary or accesses Blob/Redis/Gateway credentials. Preserve the no-dual-chat rule.

AGENTS.md — timeless “Where to change” entry

Add one compact, durable table row covering the compaction seam: lib/agent/compaction*.ts, app/api/turns/route.ts, lib/workflows/{compactionStep,turnLoop}.ts, lib/agent/turnPersistSeam.ts, and lib/sessions/sessionStore.ts. State the pre-trim selected-model trigger, server-only tools-off step, session-bound meta.compactionPointer, honest summary row, copy-forward, and logical-not-physical deletion rules. Reference the docs by name, not phase/issue history. Do not duplicate the full implementation map already present elsewhere in AGENTS.

Other durable surfaces reviewed

Surface Decision Rationale
README.md N/A Visitor entry, setup, and top-level feature taxonomy do not change; the compaction mechanism is an internal durable-turn continuity detail covered by session and architecture guides.
SECURITY.md N/A No new secret, client exposure, endpoint authorization class, or trust boundary: the checkpoint uses the existing session-bound Blob/envelope pattern. Existing session security language already covers server-only, bound object reads.
.env.example N/A No environment variable or configuration seam is introduced.

Caps table

This documentation phase adds and changes no cap. It documents these already-shipped values exactly; the existing CONTEXT_* fold-budget and MODEL_MSG_SEED_* rails remain documented at their own locations and are not redefined here.

Existing cap / ceiling Current value Rationale / carrier Code location
COMPACTION_RESERVE_TOKENS 16,384 tokens Name for the existing completion reserve already accounted for by foldBudgetTokens; the trigger must not subtract it twice lib/sessionCloudCaps.ts, lib/agent/compactionBudget.ts
COMPACTION_SUMMARY_MAX_CHARS 8,000 characters Bounded persisted summary with explicit truncation marker lib/sessionCloudCaps.ts, lib/agent/compaction.ts
COMPACTION_FILES_TOUCHED_MAX 256 paths Bounded newest-first checkpoint file list with an honest omitted-count marker lib/sessionCloudCaps.ts, lib/agent/compaction.ts
COMPACTION_CHECKPOINT_MAX_BYTES MODEL_MSG_SEED_MAX_BYTES + 256 KiB = 2.25 MiB Own session-bound checkpoint Blob ceiling; it accommodates the legal retained tail plus summary/file metadata and is not envelope meta or a Function body lib/sessionCloudCaps.ts, lib/agent/turnPersistSeam.ts
COMPACTION_SPAN_MAX_BYTES 2 MiB Serialized input ceiling for the pre-loop summarizer; cut walk can move to an older boundary or prefix-clip rather than send an unbounded span lib/sessionCloudCaps.ts, lib/agent/compaction.ts
COMPACTION_START_MAX_BYTES 3 MiB Combined serialized compact start() arguments ceiling (span + retained tail + metadata), leaving margin under the Vercel Function wire lib/sessionCloudCaps.ts, app/api/turns/route.ts

Cap governance: all values above already exist on main. This plan only documents them; it raises, lowers, adds, and removes none. No human cap decision is requested.

Implementation order

  1. Update docs/session-model.md with the exact durable checkpoint, trigger, fail-open, seed-selection, honesty, and copy-forward semantics.
  2. Add the six existing compaction-cap rows to docs/harness-limits.md, cross-linking existing model-window/seed rails instead of duplicating or changing them.
  3. Update the docs/feature-divide.md ownership table to place compaction fully on the Vercel backend and explicitly exclude Wasm/DOM summarization.
  4. Add one concise timeless compaction-seam entry to the AGENTS “Where to change” table.
  5. Review the complete documentation diff for source accuracy, relative-link correctness, no phase/issue/process language, and consistency across all four surfaces; then run the required repository gates in a cloud agent workspace or CI.

Testing / verification

# Case Layer Type Command / method
1 Every lifecycle claim matches the current route, loop, compaction helper, session-store, and cap source; exact honest-live-model-messages preference is preserved docs source-to-doc review Read and compare app/api/turns/route.ts, lib/workflows/{compactionStep,turnLoop}.ts, lib/agent/compaction*.ts, lib/sessions/sessionStore.ts, and lib/sessionCloudCaps.ts
2 Docs state server-only ownership, session-bound reads, no secrets/client/Wasm summary, logical-not-physical deletion, and all six limits with correct units/carriers docs content review Review the four edited rendered Markdown files together
3 All new/changed relative Markdown links resolve and no new text refers to phase/issue/PR process history docs diff/link review Inspect rendered relative links and run git diff --check
4 Required repository gates all gate npm run typecheck, npm test, npm run build in a cloud agent workspace or CI

Definition of done

  • docs/session-model.md accurately documents checkpoint carrier, session binding, pre-trim trigger, safe/re-paired cut, fail-open behavior, honest summary row, exact seed selector, and logical compaction without physical deletion
  • docs/harness-limits.md documents all six existing compaction limits with units, code locations, and Blob/workflow carrier distinction; no cap value changed
  • docs/feature-divide.md assigns compaction entirely to the Vercel backend and preserves Wasm-primary/no-dual-chat ownership
  • AGENTS.md has one concise, timeless compaction seam entry including meta.compactionPointer and copy-forward rules
  • The documentation contains no phase/issue/PR narrative; README.md, SECURITY.md, and .env.example remain N/A for the reasons above
  • Source-to-doc review, link/diff review, npm run typecheck, npm test, and npm run build are green in a cloud agent workspace or CI and recorded in the PR
  • Parent Phase 5 and parent living-doc DoD items can be checked off after the merged documentation PR
  • Cloud ops: N/A — no Production mutate

Parent adherence

Parent Phase 5 deliverable This phase locks
docs/session-model.md Timeless lifecycle and exact selector documentation
docs/harness-limits.md Existing compaction caps, including the combined-start rail omitted from the initial draft
docs/feature-divide.md Backend-only summary/seed ownership; Wasm remains display/composer only
AGENTS.md Timeless source-of-truth change map and pointer ownership guidance
No code/test work Documentation only; verification is source review plus standard repository gates

Corrections / refinements vs parent

Topic Parent said This phase locks
Checkpoint seed wording “checkpoint + retained tail” / fallback to model messages Exact current selector: honest live model-messages projection first; otherwise checkpoint; then ordinary model messages; then legacy sidecar. This preserves post-compact work without weakening scope binding.
Checkpoint object ceiling Parent cap index retained an early 1 MiB value Current main value is the existing 2.25 MiB expression (MODEL_MSG_SEED_MAX_BYTES + 256 KiB); docs correct the description only, not the cap.
Transport documentation Parent names transport safety generally Document the existing 3 MiB combined compact-start rail in addition to the separate 2 MiB span and 2.25 MiB Blob checkpoint rails.
Documentation style Four surfaces plus N/A rows Identical ownership; all new prose is timeless and contains no phase/issue/PR narrative.

IMPLEMENTED (2026-09-07) — PR #957: #957

All locked doc rows shipped in the four parent surfaces: docs/session-model.md (timeless Compaction section + compactionPointer reserved-key carrier), docs/harness-limits.md (all six existing caps incl. COMPACTION_START_MAX_BYTES), docs/feature-divide.md (backend-only ownership), AGENTS.md (one compaction-seam row). Source-to-doc review done against live main (seed preference route.ts:498–505, caps sessionCloudCaps.ts:631–721, fail-closed checkpoint write, fail-open loop). Gates: typecheck clean, full vitest 177 files / 3527 tests green, npm run build green in this cloud workspace; git diff --check clean; all new relative links resolve. No caps changed; no Production mutate. Awaiting adversarial review.

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