Repository navigation
fix(tldr): one invalid TLDR/Goal record no longer breaks TLDR and Goal for every agent (#1247) - #1257
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he whole store One record that fails validation, such as an over-limit text from a newer build before a downgrade (the owner's real file already has one AT the 400-char limit) or a half-written completion, made every read and write of the store throw. Every agent's tldr_update and goal_set failed, the peeks and Agent Activity went empty, and the enforcement hooks threw. The validator itself threw instead of returning false. Invalid records are now set aside per identity, the original bytes are preserved beside the file (named by digest, one copy), and a malformed container still refuses. Closes #1247 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y, carry revisions - A crash mid-copy left a partial file under the final name, and its existence was taken as proof the evidence was safe. Copies are now published with temp + rename, and an existing copy counts only if its bytes are identical. - One unreadable history entry read as an empty history, so the next report replaced that identity's whole timeline. The raw file is now preserved (without a .json name, so eviction never counts or deletes it) and every entry that still validates is kept. - An identity reporting again after its record was set aside restarted at revision 1, which every reader discards as stale. It now continues above the set-aside revision. - The copy's 0600 mode is pinned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ait for it Review B: preservation failing (a read-only directory, a full disk) made every READ of a store with one set-aside record throw again, which is #1247's symptom. Reads now succeed; the copy is owed before the first write, which retries it and is refused if it still cannot be made, so nothing is dropped unpreserved. Pinned: an over-limit completion note, an over-limit history entry, and reads never answering an inherited property name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05
added a commit
that referenced
this pull request
Sep 25, 2026
…ptional fields, owed copy Both reviewers: an object without a `workspaces` list (a typo'd key, a top-level list) loaded as zero workspaces, and the next save erased it with no copy. Every file this store writes carries the list, so its absence now refuses like any malformed container. Review A: mistyped optional fields passed through (a `description` object threw in the command palette's text helper, taking the picker down). They are now dropped per field; a mistyped title becomes the file's basename, and a mistyped attachedAt becomes the workspace's createdAt. A copy that cannot be made no longer fails the load (same rule as #1257): it is owed before the next save, which retries it and is refused while it fails. Review B: preserveInvalidBytes gets its own tests (exact bytes once, 0600, digest name, forks a fresh name over foreign bytes, no temp leftovers on failure). The status repair is asserted as stale, and the remaining row guards are pinned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…versized ones move aside unread Review A (round 2): when even the raw read failed, the history fell back to empty and the next report replaced the file uncopied; it now throws (the report still succeeds, and history failures stay non-fatal) and leaves the file untouched. Salvage also bypassed the reader's 512 KiB cap by loading the whole file; an oversized history is now renamed aside without being read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…istory; C's surviving mutants pinned After a salvage the file on disk was still damaged, and an unchanged re-post returned early, so the history view kept failing. It now rewrites the salvaged rows. Tests pin continuing above a revision-32 set-aside record, the identity check in salvage, and a set-aside revision below 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Final disposition (pre-merge), head 5362ee6. Three reviewers: A and B (two rounds each) and C (third reviewer per steering q37, on the final head).
Findings and dispositions: Round 2
Round 1
Caveats / residuals:
Reviewer C (q37), on the final head: MERGE-READY with four minors. All four are fixed in this head's parent commit:
The body now describes every review follow-up. 🤖 Generated with Claude Code |
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 #1247.
Verified failure
On the owner's real
tldr.json(328 records, one exactly at the 400-char limit), one over-limit record made every store call throwTLDR must contain 1–400 characters.The validator threw instead of returning false. The result:tldr_updateandgoal_setfailed;A half-written goal completion did the same. Plan:
docs/plans/2026-09-25-tldr-store-invalid-record.md(plan-only commit first).Fix
<file>.invalid-<digest>.jsonbefore any write can drop the record; one copy per content.Review follow-ups (in this PR)
.jsonextension, so history eviction never counts it;Evidence
testing/fixtures/tldr-store/real-records-2026-09-25.json.tsc -bis clean;src/main/tldrpasses (65 tests).🤖 Generated with Claude Code