journal: detect and recover collapse shape C, bare opening field tags with no closers - #1013
Merged
Merged
Conversation
… with no closers Found in a real store 2026-08-26: the emitter dropped EVERY closing tag, so sibling fields arrived as bare opening tags inside the unclosed value. Two consecutive writes, one a clean three-parameter call; done and decisions both empty, next_steps carrying <decisions>... and <done>... items. Shapes A and B never fire on it: no closing tag, no parameter marker. Detection: a bare <focus|done|decisions|next_steps> opener is a signature. Recovery: the value is split at each bare opener and each piece goes to the field it names. v2, after the r2 read on v1: recover_collapsed parsed a swallowed <done> correctly and repair_journal then dropped it, building the corrective entry with only the contaminated marker in done, so the report counted a field the entry never carried. Now every recovered field lands on the corrective entry for that field: done keeps the contaminated values first and verbatim (the loop-breaking marker) followed by the clean recovered done values; recovered focus is appended to the repair focus as a scalar suffix. The new witness asserts the SERVED output end to end; reverting only the done concatenation reds that witness and nothing else (33 -> 32 pass). Co-Authored-By: Claude <noreply@anthropic.com>
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
What was wrong
A third collapse shape, found in a real store on 2026-08-26: the emitter dropped every closing tag, so sibling fields arrived as bare opening tags inside the unclosed value. Two consecutive writes, one of them a clean three-parameter call;
doneanddecisionsboth empty,next_stepscarrying<decisions>...and<done>...items. Shapes A and B never fire on it: there is no closing tag and no parameter marker anywhere.What changed
<focus|done|decisions|next_steps>opener is now a signature, so the write guard refuses it, the serving filter hides it, and carry-forward does not propagate it.donekeeps the contaminated values first and verbatim, because they are the loop-breaking marker, followed by the clean recovereddonevalues; recoveredfocusis appended to the repair's focus as a scalar suffix.v2, after the r2 read on v1
The v1 body said the swallowed tail is split "so repair can put the content back where it belongs." That was false for a swallowed
<done>:recover_collapsedparsed it correctly andrepair_journalthen built the corrective entry with only the contaminated marker indone, so the report counted a field the entry never carried. Parsing a field is not recovering it. The same omission existed for a swallowed<focus>. Both are fixed in this version and the claim above is now true.Witnesses
test_bare_opening_tags_are_detected/test_clean_prose_with_angle_brackets_still_not_flaggedtest_recovery_splits_on_bare_openers/test_recovery_never_loses_content_shape_ctest_guard_refuses_shape_c_and_names_the_fieldtest_serving_never_shows_a_shape_c_steptest_repair_serves_a_swallowed_done_and_focus(v2)doneandfocuspresent in the latest entry and in the session-start rendering, no opener in the served textUnder mutation: reverting only the
doneconcatenation inrepair_journalredstest_repair_serves_a_swallowed_done_and_focusand nothing else (33 to 32 pass); restore verified by grep.Verification
tests/recall/test_journal_collapse.py: 33 passed, import path pinned and printed as the branch'ssrc/synapt/recall/journal.py.Premium boundary: recall is OSS because this is the journal store's own write guard, serving filter, and append-only repair. No identity, no org state.