contextBreakdown kept one entry per retained surface node, so its
checkpoint grew with the message count (7.13 MB across 836 local Sessions,
up to 103 KB for one) and every cached Session listing validated it. The
state now holds the surviving system prompts, one surface total, and at
most one shadow-price claim. Appends add their price; a replacement
subtracts the adjacent compaction/summary or compaction/prune price and
drops the system prompts its shadowedSeqs name; a system-prompt rewrite
subtracts the retained prompt price. Other unmetered replacements fold at
zero delta, as in contextPressure. State version 6 discards positional
rows. Folding all 836 local logs with both versions gives identical
figures after every event; retained state drops to 110 KB.
Represent tool results as tool-role messages and migrate released wrappers
without losing outer own JSON fields, call identity, error state, or writer
field order. Refuse nested or wrapper-only information that has no lossless
current representation before successor publication.
Validate current event relationships directly instead of projecting V4 data
back into V3. Keep lifecycle, PTC, title/command, compaction, system-field and
retired-syntax checks on catalog restoration and ordinary JSONL opens. The
Worker JSON equality helper must inspect own keys so it cannot admit PTC
arguments that Node rejects.
Keep the source role change, required native admission and consumer fixture
updates in one complete review layer. Explain shared-type changes in the
persistence record and the native reader rationale in its existing note.
Use checked branded fixture identities and discriminant narrowing instead
of unknown double casts; fixture values and assertions remain intact.
This recomposes the original tool-role work by _Kerman with the independently
validated migration and admission repairs by Tianyi Cui. Frozen generations
and snapshot input version selection are retained.
Co-authored-by: Tianyi Cui <[email protected]>
Drop the image/offload event and every session change with it. An adapter's
IMAGE_OFFLOAD_REQUIRED failure now makes dsh-llm-retry replace the surface
nodes carrying the named oldest images with copies whose blocks are marked
offloaded, through the same surfaceOp: replace compaction uses, then retry the
step. ImageBlock.offloaded becomes a durable field the routes project and the
token meter prices; the session core, its event map, derivation, and
validation return to master.
The parent representation fix now correctly invalidates header-based caches with scalar state version3. The dependent in-history projection has a different compact live-surface schema and must not reuse that version. Advance it to4 and prove that a lower-layer version3 cache is discarded and refolded, alongside the existing version2 regression. No historical Session migration or compatibility mechanism is added.
Addresses ds-review-bot cache-version thread3921300994 across the stack. Validation:62 focused projection, adapter and admission tests passed; context.ts and breakdown-projection.ts each have100% exact-source coverage; paired README record updated.
Scalar shadow prices cannot restore an earlier effective prompt when compaction removes the newest system node: subtracting that price from messages can permanently make the published bucket negative. Reuse the positional measurement planner over compact current surface entries and choose the last nonempty system by surface order, not event sequence or provenance citations.
Explicitly trade the scalar checkpoint for O(current retained surface) state, dropping shadowed entries and message bodies. Version 3 invalidates old scalar checkpoints; pure transitions preserve wire identity for same-price rewrites. Cover newest/middle removal, reversed sequence ranges, extra sources, empty fallback nodes, replay and late registration, cache version rejection, and route-independent heuristic totals. Document the bounded-state exception and rejected prompt-only ancestry approach in both languages.
Consolidate the existing in-history capability, loop, UI and artifacts into one baseline. Preserve the reviewed tree so each independently verified correction has a subsequent rationale-rich commit.
Address ds-review-bot thread 3921300994 (PRRT_kwDOS3Pfcs6eyLsu). contextBreakdown now folds system/message instead of request/header.system, so version-2 checkpoints have different semantics even though their numeric fields still pass the current schema. Bump the lower projection to stateVersion 3 so cache-only reads omit old values and restore replays the full log; derived caches are not covered by the Session-log persistence compatibility waiver. No migration or fallback is added.
Regression seeds a schema-valid v2 row at the current watermark with stale system/message prices. Before the bump, cache views returned it, restoreFloor selected seq 2 rather than 0, and restore retained system=0/message=17 instead of system=8/message=9. After the bump, the 13-test owning suite passes and exact src/breakdown-projection.ts coverage is 100% statements, branches, functions, and lines; refreshed rows equal a fresh fold at version 3. Existing token-meter README prose documents the current system/message fold without a version literal, so it needs no edit.
Propagation requirement: the upper layer already uses version 3 for a different compact cache representation. Advance that layer to version 4 when propagating this fix to avoid assigning one version to two schemas.
The loop appends step/start before system/message and the entered user
messages. Capturing nodes at step/start therefore omits inputs already
included in the provider's successful usage, then adds those inputs back
as a positive surface delta. Prompt replacement can also incorrectly add
or subtract the difference from the prior prompt on a completed call.
Snapshot the current priced surface immediately before assistant/message
commits. Keep provider output separate from the durable assistant node so
listener rewrites retain their signed delta. The invariant is zero delta
immediately after an unchanged successful output: provider usage already
includes every admitted prompt input. Later appends/replacements still
produce signed deltas, and low or absent usage keeps heuristic fallback.
Delete stepStart.nodes rather than adding prompt-specific corrections or
another request snapshot: the existing transactional surface fold already
contains the successful request inputs, including replacements made during
same-step retry recovery. Keep turn/step state and all overlap, mismatch,
and late-assistant lifecycle validation. Retry attempts are log-only and
request middleware changes configuration; injected messages remain queued
until admission. No loop, event format, projection, or retry policy changes.
Exercise the real loop with reported usage and initial, growing, shrinking,
and empty prompts; same-step failed attempt plus retry prompt replacement;
request middleware; eager observation and fresh seeded replay. The two
regressions fail before the fix with spurious deltas of +48 and +18 tokens.
Retain existing durable-output rewrite, route repricing, missing/low usage,
transactional failure, and lifecycle tests. Update README EN/ZH and the
existing system-prompt surface-node Agent Note, including pairing records.
Validation (dedicated worktree, no full unit suite):
- pnpm exec vitest run packages/llm/token-meter/tests packages/compaction/compaction-basic/tests/compaction-loop-repro.spec.ts --coverage --coverage.include='packages/llm/token-meter/src/index.ts'
118 passed; exact changed runtime file 100% statements/branches/functions/lines.
- pnpm exec vitest run packages/core/agent-loop/tests/request-reconstruction.spec.ts packages/compaction/compaction-basic/tests/compaction-basic.spec.ts packages/compaction/compaction-basic/tests/loader-composition.spec.ts
118 passed, including retry reconstruction and real Loader composition.
- pnpm run doc-sync: 33 gates passed.
- pnpm run test:docs: 15 gates passed.
- pnpm run lint: passed, 0 warnings/errors.
- git diff --cached --check: passed.
Baseline normalize.ts comment conflict marker is intentionally untouched.
Consolidate the representation-change PR and its rebase reconciliations into one baseline. Preserve the exact tree and keep the in-history feature in the dependent PR. Follow-up fixes remain separate.
Session format v2 embeds each attempt's compact stream in
assistant/message and assistant/attempt, but Host and client consumers
still expanded it into per-member TimedStreamChunk arrays and did
per-member work; expandAssistantStream materializes the full array before
find/toReversed/break can answer. Session Stats (the projection phase of
every Session open), the token meter's usage and provider-assembly folds,
the subagent output fold, and the Session Controller image lookup still
paid O(members) allocation and time per settlement.
The Chat and Trajectory definitions were already settled from
message.content on master; the remaining per-member folds stay.
dsh-llm now exports record-level readers (first token, visible content,
visible text, last raw chunk of a type, raw chunks of a type, joined
text, run-aware assembly, per-run first-token/first-visible times) that
scan the compact records once with early exit. Session Stats reads
assistantStreamFirstTokenTime, the token meter reads
lastAssistantStreamChunk(stream, 'usage') and assembles through
assembleAssistantStream, the subagent output fold appends
joinAssistantStreamText, and the Session Controller scans
assistantStreamChunks(stream, 'block-end').
expandAssistantStream is deliberately not memoized: retaining expansions
costs roughly ten times the compact stream for the Session's lifetime.
It remains the validating path at durable boundaries.
Synthetic 200-turn v0 migration benchmark, median of five: first-open
projection 28.0 ms -> 5.4 ms, first-open total 76.9 -> 50.0 ms, peak RSS
137.2 -> 94.9 MB; reopen projection 17.8 -> 5.6 ms; all phase budgets and
the 128 MB heap constraint keep passing.
Record the image offload point as the core image/offload session event so the
derived surface, every adapter, and the token meter share one offloaded set.
The agent loop plans the advance from the route's declared request-image
budget before dispatch; an adapter whose exact accounting still overflows
fails with IMAGE_OFFLOAD_REQUIRED and the loop advances by the named count.
- permission-presets: register the permissions unit synchronously before the
existing-session sweep, so a remount reads folded knob state instead of
treating every session as fresh; add a regression test for that path
- sandbox-policy/terminal-bash: mount the projection registry in the 5 pwsh
terminal tests, the sdk-minimal bundle, and the e2b fixture composition;
declare the new package dependency in both manifests
- plan-mode: restore .strict() on the plan unit state schema and drop the
deleted foldPlanMode from the bilingual READMEs
- session-title/session-projection: sync bilingual READMEs to the mandatory
projection seam and re-record translation pairing
- docs: turnBoundary reader contract, subagent schema comment, token-meter
import comment, sandbox-policy module docstring
foldSurfaceTokens rebuilt the priced surface on every surface event: an
append allocated [...nodes, node] and a replacement copied the whole
array before splicing, charging every well-formed event O(surface) for
an atomicity property only malformed events need. Benchmarks put the
copy at ~99.9% of an append's cost (100µs at a 50k-node surface vs
0.1µs for pricing) with O(S²) accumulation over a session, inside the
synchronous session/event publication path.
Split the fold into the session core's planSurfaceEvent/applySurfacePlan
shape: planSurfaceTokens performs every fallible step against the
read-only surface, commitSurfaceTokens applies the plan in place and is
infallible by construction. _foldEvent plans first, runs the remaining
fallible anchor validation, and only then commits, so retry identity is
preserved by ordering instead of by allocation. Appends drop to
amortized O(1) (100.3µs -> 1.9µs at 50k nodes); replacements keep their
O(surface) findIndex but stop paying the extra full copy (21µs -> 4.2µs).
A new regression test pins the one hazard this introduces: an event
whose surface plan is valid but whose later anchor validation throws
must leave the priced surface and running total uncommitted across
repeated failures.
Reconcile the base's persist removal and later master content with the
migration branch: keep 2742's wireOnly read options, the host-inclusive
snapshot/viewCheckpoint/restore defaults, and the drive's late-event
replay (applyToCell) that bare-session reads rely on.
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.
Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.
The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.
Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.