fix: cap the consolidation response, and stop reading a store too large to read (#346) - #347
Merged
Merged
Conversation
recent.md reached 6.4GB and archive.md 1.8GB in a reporter's store, freezing every session start. Nothing appends to either file — the only writer is the wholesale `cp` in run-consolidation.sh. The defect is that consolidate() refuses to SEND a prompt over consolidate_max_bytes but nothing bounded what it WRITES back, and recent.md is part of the input that cap is measured on, so one oversized write froze the store permanently: it never grew again and never shrank either, which reads from outside as append-only. - consolidate(): refuse a response over the cap as non-conforming (ConsolidationSkipped, not ConsolidationTooLarge — retrying would not help) - cmd_consolidate(): stat the store before reading it, so an oversized store is not loaded into RAM to discover it cannot be sent; archive rotation moves ahead of the read and is undone on every path that does not go through - session-start: a memory file over thresholds.memory_inject_max_bytes (new, default 200000) is named with its size instead of cat'd, so an already broken store no longer hangs the launch Co-Authored-By: Max <noreply>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #346
The reporter's root cause is wrong, and the way it is wrong is the bug
The report says
recent.mdandarchive.md"only ever get appended to". They have never been appended to:run-consolidation.sh:159-160cps both wholesale from the model's response, and those two lines are unchanged since the initial commit. There is exactly one writer in the tree.Consolidation caps its input and never caps its output.
pipeline/consolidate.py:315-322refuses to send a prompt overconsolidate_max_bytes(default 600000).pipeline/haiku.py:686runs the CLI withcapture_output=True, timeout=timeout— bounded by a wall clock, not by bytes. The size of a response was never a quantity anything downstream measured.pipeline/shell.pywritesresult.recentto a temp file verbatim andrun-consolidation.sh:159copies it overrecent.md. No size check on that path.Measured on a stub: one round wrote 52,428,825 bytes — 87× the cap the same function had refused to send seconds earlier.
One oversized write is permanent, and that is what produces the reported symptom.
recent.mdis part of the input the cap is measured on, so the round after an oversized write assembles an oversized prompt, raisesConsolidationTooLarge, and skips — and so does every round after it._rotate_archiveis no escape when the bulk isrecent.md. The file then never grows again and never shrinks either, which from outside is indistinguishable from a file that is only ever appended to. The observation was right; the mechanism was inside out.What this changes
Refuse an oversized response (
consolidate()). Deliberately a plainConsolidationSkipped, notConsolidationTooLarge: that subclass means "the input was too big, shrink it and retry", and the caller acts on it by rotatingarchive.md. Nothing about the input was wrong here, so a retry would spend another model call to be handed another oversized response and would rotate away a healthy archive for nothing.statthe store before reading it (cmd_consolidate()). The cap was enforced on the assembled prompt, so a 6.4 GBrecent.mdhad to be read into memory and a prompt built around it before the pipeline was allowed to notice it was too large to send. That is the allocation that took the reporter's machine down, from a script that runs disowned beside a live session. It cannot produce a false skip: the assembled prompt is the template plus per-file labels plus these bytes, so it is strictly larger than their sum.Name, do not inject, an oversized memory file (
session-start-hook.sh). Nothing above helps the 6.4 GB file someone already has on disk, and that file is what froze everyclaudelaunch in that project. Overthresholds.memory_inject_max_bytes(new, default 200000) the file is listed with its size instead ofcat'd — the same "kept but not injected" trade Recall should read rotatedarchive-<date>.mdsiblings #124 makes for rotated archives, reached by size rather than by filename. The bytes stay on disk and stay greppable.Not fixed here
now.md/today-*.mdare the genuinely append-only files —staging_appendis a literal>>with no cap, and five documented branches append a duplicate span without rolling it back. Different bug, different files, filed separately.recent.md~2 KB/round; measured hitting the cap at round 298. Bounded by the cap by construction, so it cannot reach a gigabyte on its own — it is the slow grower, not the multiplier. Noted in the CHANGELOG.Verification
TDD: the test file was written first and failed 5/6 (the pass is the control — a normal response must still be written). Representative RED:
GREEN, full suite:
An existing test caught a real defect in the first attempt: the up-front rotation was not undone when the model call raised. Fixed with a trailing
except Exception: _restore_rotation(); raise.