@brandry/claude-jsonl-compressor 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -56
- package/LICENSE +674 -674
- package/NOTICE +8 -8
- package/README.md +666 -611
- package/SKILL.md +230 -345
- package/agents/openai.yaml +7 -7
- package/bin/claude-jsonl-compressor.cjs +4 -4
- package/bin/claude-jsonl-repair-read-pages.cjs +4 -4
- package/bin/run-python.cjs +77 -77
- package/package.json +60 -60
- package/references/claude-jsonl-compression-format.md +635 -578
- package/scripts/claude_session_tools.py +304 -245
- package/scripts/compress_claude_jsonl.py +8608 -8275
- package/scripts/repair_claude_jsonl.py +627 -627
- package/templates/summary_template_en.md +78 -78
|
@@ -1,578 +1,635 @@
|
|
|
1
|
-
# Claude Code JSONL Compression Format Notes
|
|
2
|
-
|
|
3
|
-
This document describes the empirical format handled by
|
|
4
|
-
`@brandry/claude-jsonl-compressor` package `1.
|
|
5
|
-
|
|
6
|
-
Claude Code transcript JSONL is an observed internal format, not a published
|
|
7
|
-
stable storage API. The rules below are deliberately strict where ambiguity
|
|
8
|
-
could restore a rewound branch, break resume topology, or make a tool exchange
|
|
9
|
-
incoherent.
|
|
10
|
-
|
|
11
|
-
## Version Domains
|
|
12
|
-
|
|
13
|
-
The project keeps four independent version domains:
|
|
14
|
-
|
|
15
|
-
| Domain | Current value | Meaning |
|
|
16
|
-
| --- | --- | --- |
|
|
17
|
-
| Package | `1.
|
|
18
|
-
| Compression engine | `v10` | Topology, partition, and rewrite behavior |
|
|
19
|
-
| Model-pack schema | `v11` | Evidence-pack and model-summary binding protocol |
|
|
20
|
-
| Report schema | `1` | Compression and repair report fields |
|
|
21
|
-
|
|
22
|
-
A change to one domain does not imply the other domains changed.
|
|
23
|
-
|
|
24
|
-
## Three Physical and Logical Layers
|
|
25
|
-
|
|
26
|
-
A transcript can contain records that play very different roles:
|
|
27
|
-
|
|
28
|
-
1. **Active API-message chain.** `user` and `assistant` records connected from
|
|
29
|
-
the selected resume leaf through `parentUuid`. This is the history that the
|
|
30
|
-
compressor may summarize or preserve verbatim.
|
|
31
|
-
2. **Control and side records.** `last-prompt`, titles, modes, attachments,
|
|
32
|
-
hooks, and `file-history-snapshot` records may exist physically in the file
|
|
33
|
-
without becoming ordinary API messages. They require explicit projection or
|
|
34
|
-
attribution rules.
|
|
35
|
-
3. **Inactive or unattributed records.** Rewound branches and records that
|
|
36
|
-
cannot be structurally attributed to the active branch remain useful only
|
|
37
|
-
for diagnostics. Engine v10 excludes their content from every Claude-readable
|
|
38
|
-
output layer and from every model-summary evidence channel.
|
|
39
|
-
|
|
40
|
-
Physical line order alone is therefore not a definition of current context.
|
|
41
|
-
|
|
42
|
-
### Physical line accounting
|
|
43
|
-
|
|
44
|
-
The JSONL framer recognizes records only at physical LF boundaries, removes a
|
|
45
|
-
single CR before each LF, and skips blank physical lines. The parser keeps a
|
|
46
|
-
trusted side map from each parsed record to its original 1-based physical line
|
|
47
|
-
number. `validate_jsonl` and the `Read.pages` repair report use that map, so a
|
|
48
|
-
blank line or an excluded branch cannot make an error point at the wrong file
|
|
49
|
-
line. Input `_line`, `_mergedLines`, `_mergedUuids`, and
|
|
50
|
-
`_validationContentLines` fields are untrusted and ignored; validation rebuilds
|
|
51
|
-
record- and content-block provenance in an isolated projection.
|
|
52
|
-
|
|
53
|
-
The model evidence pack uses its own `L<number>` logical nonblank-record
|
|
54
|
-
coordinates because it is a reserialized evidence view; those anchors are not
|
|
55
|
-
claims about physical source-file line numbers. Repair `recordLine`, validator
|
|
56
|
-
diagnostic `line` fields, and the source active-chain preflight used by
|
|
57
|
-
compression/model-pack generation, in contrast, refer to the original file's
|
|
58
|
-
physical lines. The active-chain preflight is a logical projection, so it
|
|
59
|
-
carries source-line provenance separately rather than renumbering the chain.
|
|
60
|
-
|
|
61
|
-
Validation/report counters and `type`/`sessionId`/`subtype` metadata carried
|
|
62
|
-
by validator or system-error diagnostics preserve ordinary short strings.
|
|
63
|
-
Synthetic keys use the collision-safe angle-bracket namespace: `<missing>`,
|
|
64
|
-
`<null>`, and `<invalid:json-type>`. A real string beginning with `<` is
|
|
65
|
-
escaped by adding a second leading `<`; an unusually long real string is
|
|
66
|
-
represented by a bounded `<string:length=...;sha256=...>` label that contains
|
|
67
|
-
no original characters. Complex
|
|
68
|
-
malformed values are labeled by JSON type rather than copied into diagnostics
|
|
69
|
-
or model evidence. The same bound is applied recursively to public validator
|
|
70
|
-
samples, nested diagnostic metadata, identifier-valued dictionary keys, and
|
|
71
|
-
oversized source values embedded in error text. Ordinary error wording and
|
|
72
|
-
physical-line locations remain readable when they contain only normal values.
|
|
73
|
-
|
|
74
|
-
## Common Observed Record Types
|
|
75
|
-
|
|
76
|
-
| `type` | Observed purpose |
|
|
77
|
-
| --- | --- |
|
|
78
|
-
| `user` | User content or user-side `tool_result` blocks |
|
|
79
|
-
| `assistant` | Assistant text, thinking, `tool_use`, model metadata, and usage |
|
|
80
|
-
| `system` | Claude Code events, including `subtype: compact_boundary` |
|
|
81
|
-
| `attachment` | Hook, image, file, or environment attachment metadata |
|
|
82
|
-
| `last-prompt` | UI/session pointer containing the current `leafUuid` |
|
|
83
|
-
| `file-history-snapshot` | File checkpoint metadata, commonly without UUID links |
|
|
84
|
-
| `mode` / `permission-mode` | Session mode state |
|
|
85
|
-
| `ai-title` / `custom-title` | Conversation title metadata |
|
|
86
|
-
| `queue-operation` | Queued-input or editing metadata |
|
|
87
|
-
| `agent-name` | Agent label metadata |
|
|
88
|
-
|
|
89
|
-
Open-schema handling is required: unknown fields are preserved on retained
|
|
90
|
-
records unless the operation explicitly projects a control record.
|
|
91
|
-
|
|
92
|
-
## UUID, Parent, Session, and Resume Relationships
|
|
93
|
-
|
|
94
|
-
### UUID chain
|
|
95
|
-
|
|
96
|
-
Message-like records commonly carry:
|
|
97
|
-
|
|
98
|
-
- `uuid`: record identity;
|
|
99
|
-
- `parentUuid`: preceding record on that branch, or `null` at a root;
|
|
100
|
-
- `sessionId`: session identity.
|
|
101
|
-
|
|
102
|
-
Engine v10 treats duplicate UUIDs anywhere in the input as blocking because a
|
|
103
|
-
UUID index would be ambiguous. A non-null `parentUuid` must be a non-empty
|
|
104
|
-
string; any other value is malformed. A missing parent, malformed parent or loop
|
|
105
|
-
on the selected active chain is blocking. Physical inversion is blocking except
|
|
106
|
-
for same-session `attachment -> attachment` edges on an otherwise complete,
|
|
107
|
-
acyclic chain; accepted attachments are emitted in logical parent order.
|
|
108
|
-
Equivalent non-UUID-ambiguity damage wholly inside an excluded branch does not
|
|
109
|
-
revive that branch.
|
|
110
|
-
|
|
111
|
-
Mixed `sessionId` ancestry is not rejected merely because two IDs occur. A
|
|
112
|
-
lineage is accepted only when its contiguous session runs never return to an
|
|
113
|
-
earlier ID and the final run matches both the selected leaf and authoritative
|
|
114
|
-
pointer. Planning forces every earlier run into `summaryIndexes` and preserves
|
|
115
|
-
only the final run as recent raw records. A tool relationship that would move
|
|
116
|
-
the cut across the lineage transition stops compression. This covers observed
|
|
117
|
-
historical branch/resume files without admitting A-B-A or arbitrary cross-session
|
|
118
|
-
raw chains.
|
|
119
|
-
|
|
120
|
-
### Authoritative `last-prompt`
|
|
121
|
-
|
|
122
|
-
Automatic active-chain mode uses the physically last record whose
|
|
123
|
-
`type` is `last-prompt`. Its `leafUuid` is authoritative. The engine does not
|
|
124
|
-
skip a malformed latest pointer to search for an older usable pointer because
|
|
125
|
-
that could resurrect a state the user already left.
|
|
126
|
-
|
|
127
|
-
Strict topology statuses include:
|
|
128
|
-
|
|
129
|
-
- `absent`
|
|
130
|
-
- `malformed`
|
|
131
|
-
- `malformed-parent`
|
|
132
|
-
- `duplicate-uuid`
|
|
133
|
-
- `dangling`
|
|
134
|
-
- `loop`
|
|
135
|
-
- `non-monotonic`
|
|
136
|
-
- `session-mismatch`
|
|
137
|
-
- `extension-limit`
|
|
138
|
-
- `extension-branch`
|
|
139
|
-
- `extension-unsafe`
|
|
140
|
-
- `valid`
|
|
141
|
-
|
|
142
|
-
`status` is the coarse category. `reasonCode` is the stable, machine-readable
|
|
143
|
-
cause. Current producers emit exactly one of these pairs:
|
|
144
|
-
|
|
145
|
-
| `status` | `reasonCode` | Meaning |
|
|
146
|
-
| --- | --- | --- |
|
|
147
|
-
| `absent` | `last-prompt-absent` | No authoritative `last-prompt` exists |
|
|
148
|
-
| `duplicate-uuid` | `duplicate-uuid` | At least one UUID is ambiguous |
|
|
149
|
-
| `malformed` | `leaf-uuid-malformed` | The authoritative `leafUuid` is absent, empty or not a string |
|
|
150
|
-
| `dangling` | `chain-missing-uuid` | The selected chain references an unknown UUID |
|
|
151
|
-
| `loop` | `chain-loop` | The selected chain contains a parent loop |
|
|
152
|
-
| `malformed-parent` | `chain-malformed-parent` | A selected record has an invalid non-null `parentUuid` |
|
|
153
|
-
| `dangling` | `chain-empty` | Defensive outcome when tracing returns no chain and no more specific error |
|
|
154
|
-
| `non-monotonic` | `chain-non-monotonic` | Physical parent order violates the accepted compatibility rule |
|
|
155
|
-
| `session-mismatch` | `lineage-unsafe` | Session ancestry is not an accepted one-way lineage |
|
|
156
|
-
| `extension-limit` | `extension-limit-exceeded` | Post-pointer records exceed the explicit closure limit |
|
|
157
|
-
| `session-mismatch` | `extension-authority-session-missing` | A requested closure has no usable authority session |
|
|
158
|
-
| `extension-unsafe` | `extension-record-missing-uuid` | A closure record has no usable UUID |
|
|
159
|
-
| `extension-branch` | `extension-record-not-linear-descendant` | A closure record is not the next direct child |
|
|
160
|
-
| `session-mismatch` | `extension-record-session-mismatch` | A closure record does not match the authority session |
|
|
161
|
-
| `extension-unsafe` | `extension-record-not-safe-closure` | A closure record is not a tool-result-only safe closure |
|
|
162
|
-
| `extension-unsafe` | `extension-pending-tool-ids` | The requested closure leaves tool calls unresolved |
|
|
163
|
-
| `valid` | `ok` | Strict topology validation succeeded |
|
|
164
|
-
|
|
165
|
-
For `lineage-unsafe`, `lineageReason` carries the lower-level lineage diagnosis.
|
|
166
|
-
Human-readable `errors` text is diagnostic and is not an enum. Normal
|
|
167
|
-
compression/model-pack/repair failures also include `reasonCode=<value>` in the
|
|
168
|
-
raised CLI error.
|
|
169
|
-
|
|
170
|
-
Report-schema v1 objects and `compactMetadata` are open, additive objects:
|
|
171
|
-
consumers must ignore unknown fields. Stable producers include `reasonCode` on
|
|
172
|
-
every strict topology result. A pre-stable v1 artifact may lack it; readers
|
|
173
|
-
should treat that as legacy/unknown rather than infer `ok`.
|
|
174
|
-
|
|
175
|
-
`--resume-leaf UUID` is an explicit recovery override. It is reported as
|
|
176
|
-
`active-chain-manual-override`, distinct from default strict `active-chain`.
|
|
177
|
-
`--preserve-physical-tail` is a separate legacy compatibility
|
|
178
|
-
mode and does not provide active-branch exclusion guarantees.
|
|
179
|
-
|
|
180
|
-
Strict failures are zero-write outcomes. The CLI does not prompt or retry in a
|
|
181
|
-
different mode. A hosting agent may ask for a new, explicit user confirmation
|
|
182
|
-
when one diagnosed recovery control applies, but the initial compression request
|
|
183
|
-
is not confirmation. Manually spliced or otherwise ambiguous files normally
|
|
184
|
-
require physical-tail compatibility and therefore forfeit branch/rewind
|
|
185
|
-
isolation.
|
|
186
|
-
|
|
187
|
-
### Records after `last-prompt`
|
|
188
|
-
|
|
189
|
-
The default `--max-post-last-prompt-extension 0` excludes all UUID records
|
|
190
|
-
physically after the authoritative pointer. A nonzero value is explicit and
|
|
191
|
-
accepts only a direct, physically later, same-session linear closure consisting
|
|
192
|
-
of tool-result-only user records that close every pending tool ID. Ordinary
|
|
193
|
-
conversation, system/hook records, unrelated results and partial closure are
|
|
194
|
-
rejected as unsafe.
|
|
195
|
-
|
|
196
|
-
## Six-Way Source Partition
|
|
197
|
-
|
|
198
|
-
After strict topology succeeds, every source line belongs to exactly one set:
|
|
199
|
-
|
|
200
|
-
| Set | Meaning | May reach Claude-readable output? |
|
|
201
|
-
| --- | --- | --- |
|
|
202
|
-
| `summaryIndexes` | Older active-chain records selected for semantic summary | Yes, only through the new summary |
|
|
203
|
-
| `rawKeepIndexes` | Recent active-chain records kept byte-semantically as JSON objects | Yes, as recent raw history |
|
|
204
|
-
| `sideKeepIndexes` | Explicitly attributed side/checkpoint records | Yes, as non-chain side records |
|
|
205
|
-
| `controlProjectionIndexes` | Control metadata used to construct the final projected state | Yes, only through controlled projection |
|
|
206
|
-
| `excludedBranchIndexes` | UUID records outside the selected active branch | No |
|
|
207
|
-
| `excludedUnattributedIndexes` | Records with no accepted structural attribution | No |
|
|
208
|
-
|
|
209
|
-
The sets are mutually exclusive and cover every source index. The legacy
|
|
210
|
-
internal/report name `omittedIndexes` is only a compatibility alias for
|
|
211
|
-
`summaryIndexes`; it no longer means every physically discarded record.
|
|
212
|
-
|
|
213
|
-
Before a model pack or candidate is written, the engine copies only the
|
|
214
|
-
authoritative logical active chain, projects its selected leaf into one pointer,
|
|
215
|
-
and runs the shared transcript validator on that source view. Malformed old tool
|
|
216
|
-
exchanges, duplicate tool IDs, or compact metadata on the active chain therefore
|
|
217
|
-
cannot be hidden by summarization. Damage confined to an excluded inactive
|
|
218
|
-
branch remains excluded and does not block or enter the summary.
|
|
219
|
-
|
|
220
|
-
Inactive and unattributed record bodies are absent from:
|
|
221
|
-
|
|
222
|
-
- the model evidence pack;
|
|
223
|
-
- model-authored summary validation input;
|
|
224
|
-
- deterministic fallback summary input;
|
|
225
|
-
- prior-summary verbatim blocks;
|
|
226
|
-
- recent raw records;
|
|
227
|
-
- side records;
|
|
228
|
-
- the final candidate JSONL.
|
|
229
|
-
|
|
230
|
-
Reports may expose only counts and content-free line-set digests for excluded
|
|
231
|
-
sets.
|
|
232
|
-
|
|
233
|
-
## Compact-Style Output Pair
|
|
234
|
-
|
|
235
|
-
The engine emits exactly one current Codex-created compact pair:
|
|
236
|
-
|
|
237
|
-
1. a `system` record with `subtype: "compact_boundary"`;
|
|
238
|
-
2. its direct `user` child with `isCompactSummary: true`.
|
|
239
|
-
|
|
240
|
-
Simplified synthetic shape:
|
|
241
|
-
|
|
242
|
-
```json
|
|
243
|
-
{"type":"system","subtype":"compact_boundary","uuid":"BOUNDARY_UUID","parentUuid":null,"compactMetadata":{"codexOfflineCompression":true,"codexOfflineCompressionVersion":"v10","modelPackSchemaVersion":11,"reportSchemaVersion":1,"summaryUuid":"SUMMARY_UUID","preserveMode":"active-chain","resumeLeafInfo":{"status":"valid","reasonCode":"ok","selectedLeafUuid":"ACTIVE_LEAF"}}}
|
|
244
|
-
{"type":"user","uuid":"SUMMARY_UUID","parentUuid":"BOUNDARY_UUID","isCompactSummary":true,"message":{"role":"user","content":"SUMMARY_TEXT"}}
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
The exact open-schema object contains additional observed metadata. The current
|
|
248
|
-
pair is followed by the recent active suffix. In strict active-chain mode, only
|
|
249
|
-
the first recent record has its parent changed to `SUMMARY_UUID`; every later
|
|
250
|
-
recent parent/session edge must already be coherent. A final `last-prompt` is
|
|
251
|
-
deep-copied from the authoritative source pointer so unknown fields survive,
|
|
252
|
-
then only its projected leaf/session values are updated.
|
|
253
|
-
|
|
254
|
-
Validation requires the final pointer's active chain to contain the exact
|
|
255
|
-
current boundary and summary, not merely an older compact pair.
|
|
256
|
-
|
|
257
|
-
## Model-Assisted Summary Protocol v11
|
|
258
|
-
|
|
259
|
-
Model-assisted semantic summary is the default. Deterministic code owns all
|
|
260
|
-
topology, source partitioning, JSONL construction, UUID generation, parent
|
|
261
|
-
rewrites, and validation. The model receives only the frozen evidence pack and
|
|
262
|
-
writes summary prose.
|
|
263
|
-
|
|
264
|
-
### Evidence binding
|
|
265
|
-
|
|
266
|
-
The generated pack contains:
|
|
267
|
-
|
|
268
|
-
- a generic `SOURCE_JSONL` label, never the original filename or full local path;
|
|
269
|
-
- full source-file SHA-256;
|
|
270
|
-
- SHA-256 of the exact active records selected for summary;
|
|
271
|
-
- the digest of the displayed evidence-anchor set;
|
|
272
|
-
- the digest of all required evidence-coverage groups;
|
|
273
|
-
- the digest of an optional external handoff summary;
|
|
274
|
-
- a canonical request digest binding all selection/budget/policy options and the
|
|
275
|
-
loaded importance/topic/template resource content;
|
|
276
|
-
- a digest of the mandatory claim-source map;
|
|
277
|
-
- a full-text `L<number>` record for every non-empty older active human message
|
|
278
|
-
and every older active assistant `text`/`thinking` message;
|
|
279
|
-
- selected line-numbered source/tool/error evidence;
|
|
280
|
-
- `H<number>` anchors for displayed handoff lines;
|
|
281
|
-
- explicit current-state, chronology, supersession, decision, rationale,
|
|
282
|
-
rejected-option, uncertainty, and recent-boundary instructions.
|
|
283
|
-
|
|
284
|
-
The model summary must begin with the exact comment copied from the pack:
|
|
285
|
-
|
|
286
|
-
```html
|
|
287
|
-
<!-- claude-jsonl-compressor:model-summary v11
|
|
288
|
-
source_sha256: SOURCE_SHA256
|
|
289
|
-
summary_source_sha256: SUMMARY_SOURCE_SHA256
|
|
290
|
-
evidence_anchor_lines_digest: EVIDENCE_ANCHOR_LINES_DIGEST
|
|
291
|
-
required_anchor_groups_digest: REQUIRED_ANCHOR_GROUPS_DIGEST
|
|
292
|
-
handoff_summary_digest: HANDOFF_SUMMARY_DIGEST_OR_NONE
|
|
293
|
-
pack_request_digest: PACK_REQUEST_DIGEST
|
|
294
|
-
required_claim_sources_digest: REQUIRED_CLAIM_SOURCES_DIGEST
|
|
295
|
-
-->
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
Substantive factual lines cite displayed `L<number>` and, when used, `H<number>`
|
|
299
|
-
anchors. The exact whole line `Unknown from provided anchors.` is the only
|
|
300
|
-
unanchored uncertainty placeholder; a longer line containing that text has no
|
|
301
|
-
exemption. Validation rejects wrong digests, invisible or out-of-range anchors,
|
|
302
|
-
unanchored substantive lines, too little evidence coverage, and common
|
|
303
|
-
no-access boilerplate. It requires at least one cited L anchor from each
|
|
304
|
-
generated group. Every non-empty human/assistant semantic record has its own
|
|
305
|
-
required L group, and prior summaries remain independently required. It also
|
|
306
|
-
requires all nine exact semantic sections printed in the pack, each with an L
|
|
307
|
-
or H anchor. A nonempty handoff generates early/middle/late/latest H coverage
|
|
308
|
-
groups that must all be cited. Handoff text is not trusted merely because it
|
|
309
|
-
contains a special phrase; only generated H anchors are accepted.
|
|
310
|
-
|
|
311
|
-
Only the exact leading metadata comment and the exact required headings are
|
|
312
|
-
exempt from line grounding. A second/unclosed HTML comment, an extra Markdown
|
|
313
|
-
heading, duplicate metadata, renamed/reordered sections, or unsupported body
|
|
314
|
-
line is an error. Under `## Evidence and Source Anchors`, the summary must contain
|
|
315
|
-
exactly one `### Mandatory Evidence Coverage` subsection. Every mandatory
|
|
316
|
-
semantic/prior-summary L anchor appears exactly once as:
|
|
317
|
-
|
|
318
|
-
```text
|
|
319
|
-
- L42 support_text_json="exact source substring" disposition=covered
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
The JSON string must decode to a meaningful exact substring of that source
|
|
323
|
-
record. This blocks a content-free anchor dump and leaves a mechanically
|
|
324
|
-
checkable excerpt; it does not prove perfect natural-language interpretation.
|
|
325
|
-
|
|
326
|
-
Every active-chain prior compact summary is inserted as a complete dedicated
|
|
327
|
-
evidence record. An explicitly supplied external handoff is inserted in full,
|
|
328
|
-
one JSON-escaped `H<number> full_text_json` line per source line. Two default
|
|
329
|
-
pack ceilings apply together: 500,000 characters and a conservative 150,000
|
|
330
|
-
local estimated tokens. The latter leaves working space in a typical 200k
|
|
331
|
-
summarizer context. If the complete semantic ledger, prior summaries, handoff,
|
|
332
|
-
and minimum structural coverage do not fit, pack generation stops; it does not
|
|
333
|
-
trim or sample mandatory evidence. Optional source/tool/system/error evidence
|
|
334
|
-
is ranked and added only while both ceilings permit, and truncation is reported.
|
|
335
|
-
The caller should raise `--model-pack-char-budget` or
|
|
336
|
-
`--model-pack-estimated-token-budget` only when the summarizing model can read
|
|
337
|
-
the resulting pack. No external tokenizer is installed. Once a model summary
|
|
338
|
-
passes validation, its text is not truncated to meet `--summary-char-budget`;
|
|
339
|
-
insufficient composition space is a hard error. The summary character budget
|
|
340
|
-
has a hard minimum of 4000, and blank compact summaries are invalid.
|
|
341
|
-
|
|
342
|
-
These controls reduce stale-summary and unsupported-claim risk. They do not
|
|
343
|
-
mathematically prove that a natural-language summary has perfect semantics.
|
|
344
|
-
The deterministic safety appendix and recent raw suffix remain independent
|
|
345
|
-
evidence layers.
|
|
346
|
-
|
|
347
|
-
### Weighting and chronology
|
|
348
|
-
|
|
349
|
-
The evidence pack requires every non-empty older active human message and every
|
|
350
|
-
older active assistant `text`/`thinking` message, regardless of language or
|
|
351
|
-
keyword score. Source-text warnings such as U+FFFD are reported but do not make
|
|
352
|
-
mandatory records optional. Within the remaining optional source/tool capacity it gives
|
|
353
|
-
priority to:
|
|
354
|
-
|
|
355
|
-
1. explicit user constraints and requested outcomes;
|
|
356
|
-
2. final/current decisions and their reasons;
|
|
357
|
-
3. supersessions and chronology needed to avoid reviving old decisions;
|
|
358
|
-
4. model research conclusions, implementation decisions, and rationale;
|
|
359
|
-
5. unresolved risks, exact identifiers, source references, and validation
|
|
360
|
-
results;
|
|
361
|
-
6. file/tool content that materially supports the above;
|
|
362
|
-
7. repetitive logs or mechanically recoverable detail.
|
|
363
|
-
|
|
364
|
-
Important evidence can be Chinese, English, Japanese, Korean, Arabic, Russian,
|
|
365
|
-
Hindi, Greek, Hebrew, Armenian, Thai, Georgian, Ethiopic, Bengali, Tamil,
|
|
366
|
-
Telugu, Malayalam, Spanish, French, German, Portuguese, or another language.
|
|
367
|
-
All assistant thinking is semantic evidence without a language-keyword gate;
|
|
368
|
-
multilingual terms and script detection only improve classification and optional
|
|
369
|
-
weighting. Language is not treated as a proxy for importance.
|
|
370
|
-
|
|
371
|
-
## Token Ceilings
|
|
372
|
-
|
|
373
|
-
`--model-pack-estimated-token-budget N` limits the evidence pack read by the
|
|
374
|
-
summary-authoring model. It defaults to 150,000 and is enforced together with
|
|
375
|
-
the character budget. The same non-default value must be supplied when
|
|
376
|
-
generating the pack and when applying the model summary. Mandatory semantic and
|
|
377
|
-
handoff evidence cannot be dropped to satisfy it; optional evidence can be
|
|
378
|
-
truncated and this state is recorded in the pack, compact metadata, and report.
|
|
379
|
-
|
|
380
|
-
`--target-estimated-tokens N` uses a dependency-free heuristic over complete
|
|
381
|
-
retained structured message payloads, including full thinking,
|
|
382
|
-
`tool_use.input`, `tool_result`, and `toolUseResult` data. ASCII is estimated at
|
|
383
|
-
one token per four characters;
|
|
384
|
-
Han/Kana/Hangul at 1.3 each; non-BMP, symbol and combining-mark code points at
|
|
385
|
-
1.5 each; other non-ASCII at 0.8 each; and each record adds a small allowance.
|
|
386
|
-
It narrows the byte-ratio plan and rejects a generated candidate whose
|
|
387
|
-
estimated message tokens exceed `N`. This candidate-output gate is independent
|
|
388
|
-
of the model-pack reading ceiling.
|
|
389
|
-
|
|
390
|
-
This estimate excludes system prompts, tools, MCP schemas, skills, runtime
|
|
391
|
-
injections, and any Claude-side accounting. It is a reproducible local planning
|
|
392
|
-
gate, not a promise that `/context` or an API relay will report the same total.
|
|
393
|
-
`--target-ratio` is only an approximate byte-ratio planning input and is not a
|
|
394
|
-
hard publication gate.
|
|
395
|
-
|
|
396
|
-
## Tool Use and Tool Result Pairing
|
|
397
|
-
|
|
398
|
-
One API turn may be split across several JSONL records:
|
|
399
|
-
|
|
400
|
-
- multiple `tool_use` blocks in one assistant message;
|
|
401
|
-
- adjacent assistant fragments sharing one `message.id`;
|
|
402
|
-
- split user records carrying `tool_result` blocks;
|
|
403
|
-
- hook or attachment records between result fragments.
|
|
404
|
-
|
|
405
|
-
Validation rebuilds the selected active chain, filters API messages, merges
|
|
406
|
-
compatible assistant and user fragments, and checks tool IDs and order. It
|
|
407
|
-
rejects orphan results, wrong IDs, and out-of-order results. The compression cut
|
|
408
|
-
cannot divide a required tool-use/result relationship.
|
|
409
|
-
|
|
410
|
-
## File-History Checkpoint Policies
|
|
411
|
-
|
|
412
|
-
Conversation topology and file checkpoint metadata are separate planes.
|
|
413
|
-
`file-history-snapshot` records commonly lack `uuid` and `parentUuid`, so they
|
|
414
|
-
cannot be relinked into the API-message chain.
|
|
415
|
-
|
|
416
|
-
Policies:
|
|
417
|
-
|
|
418
|
-
- `active-correlated` (default): retain a bounded set only when structural
|
|
419
|
-
identifiers correlate the snapshot to recent active records;
|
|
420
|
-
- `preserve-recent`: rejected in strict active-chain mode; accepted only with
|
|
421
|
-
explicit `--preserve-physical-tail`, which is labeled compatibility mode and
|
|
422
|
-
has no inactive-branch isolation guarantee;
|
|
423
|
-
- `none`: retain no snapshot side records.
|
|
424
|
-
|
|
425
|
-
Preserved snapshots are emitted as side records before the compact pair. JSONL
|
|
426
|
-
compression alone does not guarantee complete file-state rewind because Claude
|
|
427
|
-
Code checkpoint storage and lifecycle have behavior beyond the message chain.
|
|
428
|
-
|
|
429
|
-
## Repeated Compression
|
|
430
|
-
|
|
431
|
-
Old compact pairs on the active chain are part of `summaryIndexes` when they
|
|
432
|
-
fall before the recent suffix. Normal repeated compression folds their useful
|
|
433
|
-
meaning into one new current summary rather than stacking live compact pairs.
|
|
434
|
-
|
|
435
|
-
`compactMetadata.preservedMessages` and `preservedSegment` describe the raw
|
|
436
|
-
suffix that existed when that compact pair was created. Later work can extend
|
|
437
|
-
that suffix, and a later rewind can leave part of the recorded snapshot on an
|
|
438
|
-
inactive branch. A structurally valid historical divergence is therefore a
|
|
439
|
-
source warning, not authority to restore those UUIDs and not a topology error.
|
|
440
|
-
Selection continues from the current `last-prompt` parent chain. Candidate
|
|
441
|
-
publication is stricter: the newly emitted snapshot must match the candidate's
|
|
442
|
-
current chain exactly or publication stops before writing.
|
|
443
|
-
|
|
444
|
-
`--preserve-prior-summaries-verbatim` is an explicit exception. It attempts to
|
|
445
|
-
embed prior `isCompactSummary.message.content` text verbatim inside the one new
|
|
446
|
-
summary and permits the summary text to grow to `1.5 * --summary-char-budget`.
|
|
447
|
-
If the prior summaries still do not fit, the engine uses the normal folded
|
|
448
|
-
model-summary path and reports the fallback reason. Excluded-branch summaries
|
|
449
|
-
are never eligible for either path.
|
|
450
|
-
|
|
451
|
-
## Branch Session Files
|
|
452
|
-
|
|
453
|
-
Observed `/branch` files are not guaranteed to be full physical copies. They
|
|
454
|
-
may retain source UUIDs, rewrite `sessionId`, add `forkedFrom`, relink parents,
|
|
455
|
-
and omit source history outside the branch-relevant chain.
|
|
456
|
-
|
|
457
|
-
The compressor treats exactly one selected JSONL as authoritative. It does not
|
|
458
|
-
merge a branch file with its source. Compress the branch to continue the branch;
|
|
459
|
-
compress or archive the source separately when its physical history matters.
|
|
460
|
-
|
|
461
|
-
## External References
|
|
462
|
-
|
|
463
|
-
JSONL may contain inline tool results, file excerpts, attachment metadata, or
|
|
464
|
-
paths/references to external artifacts such as tool-result storage. Offline
|
|
465
|
-
compression reads the selected JSONL and an explicitly supplied handoff file
|
|
466
|
-
only. It does not dereference, delete, or rewrite external project files,
|
|
467
|
-
`tool-results`, subagent artifacts, settings, or other sessions.
|
|
468
|
-
|
|
469
|
-
If a referenced artifact's contents are not embedded in the JSONL or handoff,
|
|
470
|
-
the model pack knows only the reference, not the external contents.
|
|
471
|
-
|
|
472
|
-
## `Read.pages` Compatibility Repair
|
|
473
|
-
|
|
474
|
-
Claude Code legitimately uses `Read.input.pages`, including for paged document
|
|
475
|
-
reads. The independent repair command exists only for a known downstream
|
|
476
|
-
compatibility case where historical serialized `pages` members must be removed.
|
|
477
|
-
Compression never invokes this repair implicitly.
|
|
478
|
-
|
|
479
|
-
The repairer:
|
|
480
|
-
|
|
481
|
-
- matches only assistant `tool_use` blocks with exact tool name `Read` and an
|
|
482
|
-
`input` object containing `pages`;
|
|
483
|
-
- requires a nonempty `file_path`, exactly one later matching `tool_result`, the
|
|
484
|
-
same nonempty `sessionId`, and result `sourceToolAssistantUUID` equal to the
|
|
485
|
-
tool-use assistant UUID before automatic repair;
|
|
486
|
-
- reports pending calls without changing them;
|
|
487
|
-
- defaults to the strict active chain; `--scope all` is explicit;
|
|
488
|
-
- deletes the exact JSON member byte span without reserializing other data;
|
|
489
|
-
- blocks duplicate-key or overlapping-span ambiguity;
|
|
490
|
-
- preserves BOM, newline style, Unicode spelling, unknown fields, record count,
|
|
491
|
-
UUID/parent signature, and tool ID sequences;
|
|
492
|
-
- re-reads the actual published candidate, verifies exact expected bytes and
|
|
493
|
-
SHA-256, validates the repair invariants, requires an idempotent second scan
|
|
494
|
-
with zero remaining patches, and runs the shared full-transcript
|
|
495
|
-
UUID/parent/compact/tool validator on the published bytes.
|
|
496
|
-
|
|
497
|
-
Candidate and live replacement modes use the same atomic-write, full-hash,
|
|
498
|
-
numbered-backup, source-race, validation, and rollback principles as compression.
|
|
499
|
-
|
|
500
|
-
## Candidate and Live Replacement Transactions
|
|
501
|
-
|
|
502
|
-
Candidate mode requires distinct input and output paths. Candidate JSONL,
|
|
503
|
-
reports, validation, model packs, summaries and work directories must remain
|
|
504
|
-
outside the entire `.claude` tree.
|
|
505
|
-
|
|
506
|
-
Live replacement mode requires one existing regular `.jsonl` input under
|
|
507
|
-
`.claude/projects`, an external `--work-dir`, and caller acknowledgement
|
|
508
|
-
`--confirm-session-closed`. The acknowledgement is an operational assertion,
|
|
509
|
-
not process-lock detection. It:
|
|
510
|
-
|
|
511
|
-
1. reads and hashes the complete original bytes;
|
|
512
|
-
2. writes and validates a candidate outside `.claude`;
|
|
513
|
-
3. rechecks that the source bytes did not change;
|
|
514
|
-
4. creates an exclusive `.backup`, `.backup1`, and so on;
|
|
515
|
-
5. validates immutable candidate bytes and writes a unique same-directory stage
|
|
516
|
-
with flush/fsync;
|
|
517
|
-
6. captures the actual old target, verifies its full bytes against the frozen
|
|
518
|
-
source, and publishes the staged candidate with an atomic no-clobber claim;
|
|
519
|
-
7. verifies published bytes and structure, restoring the captured original on
|
|
520
|
-
failure. If restoration fails, the numbered verified backup remains and the
|
|
521
|
-
error is promoted.
|
|
522
|
-
|
|
523
|
-
If another process recreates the target after capture begins, the transaction
|
|
524
|
-
does not overwrite the external target. It preserves the verified numbered
|
|
525
|
-
backup and, when necessary, places the captured original in another numbered
|
|
526
|
-
backup, then fails without publishing the candidate.
|
|
527
|
-
|
|
528
|
-
Before any live staging, backup payload publication, or target move, the
|
|
529
|
-
implementation probes file hard-link support in the target directory and, when
|
|
530
|
-
configured, the external backup directory. The probe itself briefly creates
|
|
531
|
-
and removes unique dot-prefixed temporary files. Every unique live-transaction
|
|
532
|
-
temporary path records its observed filesystem identity and frozen bytes.
|
|
533
|
-
Cleanup rechecks both and retains a detected mismatch. A mismatch after commit is reported as
|
|
534
|
-
`committed-cleanup-failed`; a mismatch while an earlier transaction failure is
|
|
535
|
-
already active is appended to that failure. This is a best-effort race check,
|
|
536
|
-
not a portable atomic identity-bound delete: standard Python pathname cleanup
|
|
537
|
-
cannot eliminate a replacement between its final check and `unlink()` across
|
|
538
|
-
Windows, Linux, and macOS. Live operation assumes Claude Code is closed and no
|
|
539
|
-
other writer is manipulating the session directory.
|
|
540
|
-
|
|
541
|
-
Candidate-mode reports are written with the candidate. Live compression delays
|
|
542
|
-
its final sidecar/report until replacement metadata is available, so it does not
|
|
543
|
-
leave a stale pre-commit report. If the JSONL commits and validates but final
|
|
544
|
-
report publication fails, compression returns exit code 3 with
|
|
545
|
-
`operation_state: committed-report-failed`; repair uses the camelCase equivalent
|
|
546
|
-
`operationState`. The receipt includes public artifact labels and frozen,
|
|
547
|
-
candidate, and published hashes. This is a committed state and is not rolled
|
|
548
|
-
back or reported as an ordinary uncommitted failure.
|
|
549
|
-
|
|
550
|
-
Once a numbered backup is created and verified, later failure cleanup never
|
|
551
|
-
deletes that path. This preserves an audit/recovery asset even when publication
|
|
552
|
-
or rollback fails or another process races on a nearby name.
|
|
553
|
-
|
|
554
|
-
Claude Code should be closed for that session during replacement. No other
|
|
555
|
-
session or Claude settings file is part of the transaction. Parent-directory
|
|
556
|
-
fsync is best effort and reported; the project does not promise cross-platform
|
|
557
|
-
power-loss atomicity.
|
|
558
|
-
|
|
559
|
-
## Validation Boundary
|
|
560
|
-
|
|
561
|
-
The validator checks observed-format coherence, including:
|
|
562
|
-
|
|
563
|
-
- parseability and object-per-line structure;
|
|
564
|
-
- unique UUIDs and resolvable parent/session links;
|
|
565
|
-
- exactly one current compact pair;
|
|
566
|
-
- current compact pair reachability from the final pointer;
|
|
567
|
-
- compact preserved-message metadata;
|
|
568
|
-
- non-empty, unique active tool IDs and tool-use/result pairing after fragment
|
|
569
|
-
merging; partial multi-tool ordered subsets are accepted only with an explicit
|
|
570
|
-
compatibility warning/count;
|
|
571
|
-
- absence of internal planning fields in output;
|
|
572
|
-
- source hashes, model-pack metadata, anchor sets, and target estimates where
|
|
573
|
-
applicable.
|
|
574
|
-
|
|
575
|
-
Passing these checks proves coherence under this project's empirical rules. It
|
|
576
|
-
does not make the private transcript format an Anthropic-supported public API.
|
|
577
|
-
When runtime testing is explicitly requested, `/resume`, `/context`, recent
|
|
578
|
-
conversation rewind, and recent file rewind are separate observations.
|
|
1
|
+
# Claude Code JSONL Compression Format Notes
|
|
2
|
+
|
|
3
|
+
This document describes the empirical format handled by
|
|
4
|
+
`@brandry/claude-jsonl-compressor` package `1.1.0` and engine `v10`.
|
|
5
|
+
|
|
6
|
+
Claude Code transcript JSONL is an observed internal format, not a published
|
|
7
|
+
stable storage API. The rules below are deliberately strict where ambiguity
|
|
8
|
+
could restore a rewound branch, break resume topology, or make a tool exchange
|
|
9
|
+
incoherent.
|
|
10
|
+
|
|
11
|
+
## Version Domains
|
|
12
|
+
|
|
13
|
+
The project keeps four independent version domains:
|
|
14
|
+
|
|
15
|
+
| Domain | Current value | Meaning |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| Package | `1.1.0` | GitHub/npm release version |
|
|
18
|
+
| Compression engine | `v10` | Topology, partition, and rewrite behavior |
|
|
19
|
+
| Model-pack schema | `v11` | Evidence-pack and model-summary binding protocol |
|
|
20
|
+
| Report schema | `1` | Compression and repair report fields |
|
|
21
|
+
|
|
22
|
+
A change to one domain does not imply the other domains changed.
|
|
23
|
+
|
|
24
|
+
## Three Physical and Logical Layers
|
|
25
|
+
|
|
26
|
+
A transcript can contain records that play very different roles:
|
|
27
|
+
|
|
28
|
+
1. **Active API-message chain.** `user` and `assistant` records connected from
|
|
29
|
+
the selected resume leaf through `parentUuid`. This is the history that the
|
|
30
|
+
compressor may summarize or preserve verbatim.
|
|
31
|
+
2. **Control and side records.** `last-prompt`, titles, modes, attachments,
|
|
32
|
+
hooks, and `file-history-snapshot` records may exist physically in the file
|
|
33
|
+
without becoming ordinary API messages. They require explicit projection or
|
|
34
|
+
attribution rules.
|
|
35
|
+
3. **Inactive or unattributed records.** Rewound branches and records that
|
|
36
|
+
cannot be structurally attributed to the active branch remain useful only
|
|
37
|
+
for diagnostics. Engine v10 excludes their content from every Claude-readable
|
|
38
|
+
output layer and from every model-summary evidence channel.
|
|
39
|
+
|
|
40
|
+
Physical line order alone is therefore not a definition of current context.
|
|
41
|
+
|
|
42
|
+
### Physical line accounting
|
|
43
|
+
|
|
44
|
+
The JSONL framer recognizes records only at physical LF boundaries, removes a
|
|
45
|
+
single CR before each LF, and skips blank physical lines. The parser keeps a
|
|
46
|
+
trusted side map from each parsed record to its original 1-based physical line
|
|
47
|
+
number. `validate_jsonl` and the `Read.pages` repair report use that map, so a
|
|
48
|
+
blank line or an excluded branch cannot make an error point at the wrong file
|
|
49
|
+
line. Input `_line`, `_mergedLines`, `_mergedUuids`, and
|
|
50
|
+
`_validationContentLines` fields are untrusted and ignored; validation rebuilds
|
|
51
|
+
record- and content-block provenance in an isolated projection.
|
|
52
|
+
|
|
53
|
+
The model evidence pack uses its own `L<number>` logical nonblank-record
|
|
54
|
+
coordinates because it is a reserialized evidence view; those anchors are not
|
|
55
|
+
claims about physical source-file line numbers. Repair `recordLine`, validator
|
|
56
|
+
diagnostic `line` fields, and the source active-chain preflight used by
|
|
57
|
+
compression/model-pack generation, in contrast, refer to the original file's
|
|
58
|
+
physical lines. The active-chain preflight is a logical projection, so it
|
|
59
|
+
carries source-line provenance separately rather than renumbering the chain.
|
|
60
|
+
|
|
61
|
+
Validation/report counters and `type`/`sessionId`/`subtype` metadata carried
|
|
62
|
+
by validator or system-error diagnostics preserve ordinary short strings.
|
|
63
|
+
Synthetic keys use the collision-safe angle-bracket namespace: `<missing>`,
|
|
64
|
+
`<null>`, and `<invalid:json-type>`. A real string beginning with `<` is
|
|
65
|
+
escaped by adding a second leading `<`; an unusually long real string is
|
|
66
|
+
represented by a bounded `<string:length=...;sha256=...>` label that contains
|
|
67
|
+
no original characters. Complex
|
|
68
|
+
malformed values are labeled by JSON type rather than copied into diagnostics
|
|
69
|
+
or model evidence. The same bound is applied recursively to public validator
|
|
70
|
+
samples, nested diagnostic metadata, identifier-valued dictionary keys, and
|
|
71
|
+
oversized source values embedded in error text. Ordinary error wording and
|
|
72
|
+
physical-line locations remain readable when they contain only normal values.
|
|
73
|
+
|
|
74
|
+
## Common Observed Record Types
|
|
75
|
+
|
|
76
|
+
| `type` | Observed purpose |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `user` | User content or user-side `tool_result` blocks |
|
|
79
|
+
| `assistant` | Assistant text, thinking, `tool_use`, model metadata, and usage |
|
|
80
|
+
| `system` | Claude Code events, including `subtype: compact_boundary` |
|
|
81
|
+
| `attachment` | Hook, image, file, or environment attachment metadata |
|
|
82
|
+
| `last-prompt` | UI/session pointer containing the current `leafUuid` |
|
|
83
|
+
| `file-history-snapshot` | File checkpoint metadata, commonly without UUID links |
|
|
84
|
+
| `mode` / `permission-mode` | Session mode state |
|
|
85
|
+
| `ai-title` / `custom-title` | Conversation title metadata |
|
|
86
|
+
| `queue-operation` | Queued-input or editing metadata |
|
|
87
|
+
| `agent-name` | Agent label metadata |
|
|
88
|
+
|
|
89
|
+
Open-schema handling is required: unknown fields are preserved on retained
|
|
90
|
+
records unless the operation explicitly projects a control record.
|
|
91
|
+
|
|
92
|
+
## UUID, Parent, Session, and Resume Relationships
|
|
93
|
+
|
|
94
|
+
### UUID chain
|
|
95
|
+
|
|
96
|
+
Message-like records commonly carry:
|
|
97
|
+
|
|
98
|
+
- `uuid`: record identity;
|
|
99
|
+
- `parentUuid`: preceding record on that branch, or `null` at a root;
|
|
100
|
+
- `sessionId`: session identity.
|
|
101
|
+
|
|
102
|
+
Engine v10 treats duplicate UUIDs anywhere in the input as blocking because a
|
|
103
|
+
UUID index would be ambiguous. A non-null `parentUuid` must be a non-empty
|
|
104
|
+
string; any other value is malformed. A missing parent, malformed parent or loop
|
|
105
|
+
on the selected active chain is blocking. Physical inversion is blocking except
|
|
106
|
+
for same-session `attachment -> attachment` edges on an otherwise complete,
|
|
107
|
+
acyclic chain; accepted attachments are emitted in logical parent order.
|
|
108
|
+
Equivalent non-UUID-ambiguity damage wholly inside an excluded branch does not
|
|
109
|
+
revive that branch.
|
|
110
|
+
|
|
111
|
+
Mixed `sessionId` ancestry is not rejected merely because two IDs occur. A
|
|
112
|
+
lineage is accepted only when its contiguous session runs never return to an
|
|
113
|
+
earlier ID and the final run matches both the selected leaf and authoritative
|
|
114
|
+
pointer. Planning forces every earlier run into `summaryIndexes` and preserves
|
|
115
|
+
only the final run as recent raw records. A tool relationship that would move
|
|
116
|
+
the cut across the lineage transition stops compression. This covers observed
|
|
117
|
+
historical branch/resume files without admitting A-B-A or arbitrary cross-session
|
|
118
|
+
raw chains.
|
|
119
|
+
|
|
120
|
+
### Authoritative `last-prompt`
|
|
121
|
+
|
|
122
|
+
Automatic active-chain mode uses the physically last record whose
|
|
123
|
+
`type` is `last-prompt`. Its `leafUuid` is authoritative. The engine does not
|
|
124
|
+
skip a malformed latest pointer to search for an older usable pointer because
|
|
125
|
+
that could resurrect a state the user already left.
|
|
126
|
+
|
|
127
|
+
Strict topology statuses include:
|
|
128
|
+
|
|
129
|
+
- `absent`
|
|
130
|
+
- `malformed`
|
|
131
|
+
- `malformed-parent`
|
|
132
|
+
- `duplicate-uuid`
|
|
133
|
+
- `dangling`
|
|
134
|
+
- `loop`
|
|
135
|
+
- `non-monotonic`
|
|
136
|
+
- `session-mismatch`
|
|
137
|
+
- `extension-limit`
|
|
138
|
+
- `extension-branch`
|
|
139
|
+
- `extension-unsafe`
|
|
140
|
+
- `valid`
|
|
141
|
+
|
|
142
|
+
`status` is the coarse category. `reasonCode` is the stable, machine-readable
|
|
143
|
+
cause. Current producers emit exactly one of these pairs:
|
|
144
|
+
|
|
145
|
+
| `status` | `reasonCode` | Meaning |
|
|
146
|
+
| --- | --- | --- |
|
|
147
|
+
| `absent` | `last-prompt-absent` | No authoritative `last-prompt` exists |
|
|
148
|
+
| `duplicate-uuid` | `duplicate-uuid` | At least one UUID is ambiguous |
|
|
149
|
+
| `malformed` | `leaf-uuid-malformed` | The authoritative `leafUuid` is absent, empty or not a string |
|
|
150
|
+
| `dangling` | `chain-missing-uuid` | The selected chain references an unknown UUID |
|
|
151
|
+
| `loop` | `chain-loop` | The selected chain contains a parent loop |
|
|
152
|
+
| `malformed-parent` | `chain-malformed-parent` | A selected record has an invalid non-null `parentUuid` |
|
|
153
|
+
| `dangling` | `chain-empty` | Defensive outcome when tracing returns no chain and no more specific error |
|
|
154
|
+
| `non-monotonic` | `chain-non-monotonic` | Physical parent order violates the accepted compatibility rule |
|
|
155
|
+
| `session-mismatch` | `lineage-unsafe` | Session ancestry is not an accepted one-way lineage |
|
|
156
|
+
| `extension-limit` | `extension-limit-exceeded` | Post-pointer records exceed the explicit closure limit |
|
|
157
|
+
| `session-mismatch` | `extension-authority-session-missing` | A requested closure has no usable authority session |
|
|
158
|
+
| `extension-unsafe` | `extension-record-missing-uuid` | A closure record has no usable UUID |
|
|
159
|
+
| `extension-branch` | `extension-record-not-linear-descendant` | A closure record is not the next direct child |
|
|
160
|
+
| `session-mismatch` | `extension-record-session-mismatch` | A closure record does not match the authority session |
|
|
161
|
+
| `extension-unsafe` | `extension-record-not-safe-closure` | A closure record is not a tool-result-only safe closure |
|
|
162
|
+
| `extension-unsafe` | `extension-pending-tool-ids` | The requested closure leaves tool calls unresolved |
|
|
163
|
+
| `valid` | `ok` | Strict topology validation succeeded |
|
|
164
|
+
|
|
165
|
+
For `lineage-unsafe`, `lineageReason` carries the lower-level lineage diagnosis.
|
|
166
|
+
Human-readable `errors` text is diagnostic and is not an enum. Normal
|
|
167
|
+
compression/model-pack/repair failures also include `reasonCode=<value>` in the
|
|
168
|
+
raised CLI error.
|
|
169
|
+
|
|
170
|
+
Report-schema v1 objects and `compactMetadata` are open, additive objects:
|
|
171
|
+
consumers must ignore unknown fields. Stable producers include `reasonCode` on
|
|
172
|
+
every strict topology result. A pre-stable v1 artifact may lack it; readers
|
|
173
|
+
should treat that as legacy/unknown rather than infer `ok`.
|
|
174
|
+
|
|
175
|
+
`--resume-leaf UUID` is an explicit recovery override. It is reported as
|
|
176
|
+
`active-chain-manual-override`, distinct from default strict `active-chain`.
|
|
177
|
+
`--preserve-physical-tail` is a separate legacy compatibility
|
|
178
|
+
mode and does not provide active-branch exclusion guarantees.
|
|
179
|
+
|
|
180
|
+
Strict failures are zero-write outcomes. The CLI does not prompt or retry in a
|
|
181
|
+
different mode. A hosting agent may ask for a new, explicit user confirmation
|
|
182
|
+
when one diagnosed recovery control applies, but the initial compression request
|
|
183
|
+
is not confirmation. Manually spliced or otherwise ambiguous files normally
|
|
184
|
+
require physical-tail compatibility and therefore forfeit branch/rewind
|
|
185
|
+
isolation.
|
|
186
|
+
|
|
187
|
+
### Records after `last-prompt`
|
|
188
|
+
|
|
189
|
+
The default `--max-post-last-prompt-extension 0` excludes all UUID records
|
|
190
|
+
physically after the authoritative pointer. A nonzero value is explicit and
|
|
191
|
+
accepts only a direct, physically later, same-session linear closure consisting
|
|
192
|
+
of tool-result-only user records that close every pending tool ID. Ordinary
|
|
193
|
+
conversation, system/hook records, unrelated results and partial closure are
|
|
194
|
+
rejected as unsafe.
|
|
195
|
+
|
|
196
|
+
## Six-Way Source Partition
|
|
197
|
+
|
|
198
|
+
After strict topology succeeds, every source line belongs to exactly one set:
|
|
199
|
+
|
|
200
|
+
| Set | Meaning | May reach Claude-readable output? |
|
|
201
|
+
| --- | --- | --- |
|
|
202
|
+
| `summaryIndexes` | Older active-chain records selected for semantic summary | Yes, only through the new summary |
|
|
203
|
+
| `rawKeepIndexes` | Recent active-chain records kept byte-semantically as JSON objects | Yes, as recent raw history |
|
|
204
|
+
| `sideKeepIndexes` | Explicitly attributed side/checkpoint records | Yes, as non-chain side records |
|
|
205
|
+
| `controlProjectionIndexes` | Control metadata used to construct the final projected state | Yes, only through controlled projection |
|
|
206
|
+
| `excludedBranchIndexes` | UUID records outside the selected active branch | No |
|
|
207
|
+
| `excludedUnattributedIndexes` | Records with no accepted structural attribution | No |
|
|
208
|
+
|
|
209
|
+
The sets are mutually exclusive and cover every source index. The legacy
|
|
210
|
+
internal/report name `omittedIndexes` is only a compatibility alias for
|
|
211
|
+
`summaryIndexes`; it no longer means every physically discarded record.
|
|
212
|
+
|
|
213
|
+
Before a model pack or candidate is written, the engine copies only the
|
|
214
|
+
authoritative logical active chain, projects its selected leaf into one pointer,
|
|
215
|
+
and runs the shared transcript validator on that source view. Malformed old tool
|
|
216
|
+
exchanges, duplicate tool IDs, or compact metadata on the active chain therefore
|
|
217
|
+
cannot be hidden by summarization. Damage confined to an excluded inactive
|
|
218
|
+
branch remains excluded and does not block or enter the summary.
|
|
219
|
+
|
|
220
|
+
Inactive and unattributed record bodies are absent from:
|
|
221
|
+
|
|
222
|
+
- the model evidence pack;
|
|
223
|
+
- model-authored summary validation input;
|
|
224
|
+
- deterministic fallback summary input;
|
|
225
|
+
- prior-summary verbatim blocks;
|
|
226
|
+
- recent raw records;
|
|
227
|
+
- side records;
|
|
228
|
+
- the final candidate JSONL.
|
|
229
|
+
|
|
230
|
+
Reports may expose only counts and content-free line-set digests for excluded
|
|
231
|
+
sets.
|
|
232
|
+
|
|
233
|
+
## Compact-Style Output Pair
|
|
234
|
+
|
|
235
|
+
The engine emits exactly one current Codex-created compact pair:
|
|
236
|
+
|
|
237
|
+
1. a `system` record with `subtype: "compact_boundary"`;
|
|
238
|
+
2. its direct `user` child with `isCompactSummary: true`.
|
|
239
|
+
|
|
240
|
+
Simplified synthetic shape:
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{"type":"system","subtype":"compact_boundary","uuid":"BOUNDARY_UUID","parentUuid":null,"compactMetadata":{"codexOfflineCompression":true,"codexOfflineCompressionVersion":"v10","modelPackSchemaVersion":11,"reportSchemaVersion":1,"summaryUuid":"SUMMARY_UUID","preserveMode":"active-chain","resumeLeafInfo":{"status":"valid","reasonCode":"ok","selectedLeafUuid":"ACTIVE_LEAF"}}}
|
|
244
|
+
{"type":"user","uuid":"SUMMARY_UUID","parentUuid":"BOUNDARY_UUID","isCompactSummary":true,"message":{"role":"user","content":"SUMMARY_TEXT"}}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The exact open-schema object contains additional observed metadata. The current
|
|
248
|
+
pair is followed by the recent active suffix. In strict active-chain mode, only
|
|
249
|
+
the first recent record has its parent changed to `SUMMARY_UUID`; every later
|
|
250
|
+
recent parent/session edge must already be coherent. A final `last-prompt` is
|
|
251
|
+
deep-copied from the authoritative source pointer so unknown fields survive,
|
|
252
|
+
then only its projected leaf/session values are updated.
|
|
253
|
+
|
|
254
|
+
Validation requires the final pointer's active chain to contain the exact
|
|
255
|
+
current boundary and summary, not merely an older compact pair.
|
|
256
|
+
|
|
257
|
+
## Model-Assisted Summary Protocol v11
|
|
258
|
+
|
|
259
|
+
Model-assisted semantic summary is the default. Deterministic code owns all
|
|
260
|
+
topology, source partitioning, JSONL construction, UUID generation, parent
|
|
261
|
+
rewrites, and validation. The model receives only the frozen evidence pack and
|
|
262
|
+
writes summary prose.
|
|
263
|
+
|
|
264
|
+
### Evidence binding
|
|
265
|
+
|
|
266
|
+
The generated pack contains:
|
|
267
|
+
|
|
268
|
+
- a generic `SOURCE_JSONL` label, never the original filename or full local path;
|
|
269
|
+
- full source-file SHA-256;
|
|
270
|
+
- SHA-256 of the exact active records selected for summary;
|
|
271
|
+
- the digest of the displayed evidence-anchor set;
|
|
272
|
+
- the digest of all required evidence-coverage groups;
|
|
273
|
+
- the digest of an optional external handoff summary;
|
|
274
|
+
- a canonical request digest binding all selection/budget/policy options and the
|
|
275
|
+
loaded importance/topic/template resource content;
|
|
276
|
+
- a digest of the mandatory claim-source map;
|
|
277
|
+
- a full-text `L<number>` record for every non-empty older active human message
|
|
278
|
+
and every older active assistant `text`/`thinking` message;
|
|
279
|
+
- selected line-numbered source/tool/error evidence;
|
|
280
|
+
- `H<number>` anchors for displayed handoff lines;
|
|
281
|
+
- explicit current-state, chronology, supersession, decision, rationale,
|
|
282
|
+
rejected-option, uncertainty, and recent-boundary instructions.
|
|
283
|
+
|
|
284
|
+
The model summary must begin with the exact comment copied from the pack:
|
|
285
|
+
|
|
286
|
+
```html
|
|
287
|
+
<!-- claude-jsonl-compressor:model-summary v11
|
|
288
|
+
source_sha256: SOURCE_SHA256
|
|
289
|
+
summary_source_sha256: SUMMARY_SOURCE_SHA256
|
|
290
|
+
evidence_anchor_lines_digest: EVIDENCE_ANCHOR_LINES_DIGEST
|
|
291
|
+
required_anchor_groups_digest: REQUIRED_ANCHOR_GROUPS_DIGEST
|
|
292
|
+
handoff_summary_digest: HANDOFF_SUMMARY_DIGEST_OR_NONE
|
|
293
|
+
pack_request_digest: PACK_REQUEST_DIGEST
|
|
294
|
+
required_claim_sources_digest: REQUIRED_CLAIM_SOURCES_DIGEST
|
|
295
|
+
-->
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Substantive factual lines cite displayed `L<number>` and, when used, `H<number>`
|
|
299
|
+
anchors. The exact whole line `Unknown from provided anchors.` is the only
|
|
300
|
+
unanchored uncertainty placeholder; a longer line containing that text has no
|
|
301
|
+
exemption. Validation rejects wrong digests, invisible or out-of-range anchors,
|
|
302
|
+
unanchored substantive lines, too little evidence coverage, and common
|
|
303
|
+
no-access boilerplate. It requires at least one cited L anchor from each
|
|
304
|
+
generated group. Every non-empty human/assistant semantic record has its own
|
|
305
|
+
required L group, and prior summaries remain independently required. It also
|
|
306
|
+
requires all nine exact semantic sections printed in the pack, each with an L
|
|
307
|
+
or H anchor. A nonempty handoff generates early/middle/late/latest H coverage
|
|
308
|
+
groups that must all be cited. Handoff text is not trusted merely because it
|
|
309
|
+
contains a special phrase; only generated H anchors are accepted.
|
|
310
|
+
|
|
311
|
+
Only the exact leading metadata comment and the exact required headings are
|
|
312
|
+
exempt from line grounding. A second/unclosed HTML comment, an extra Markdown
|
|
313
|
+
heading, duplicate metadata, renamed/reordered sections, or unsupported body
|
|
314
|
+
line is an error. Under `## Evidence and Source Anchors`, the summary must contain
|
|
315
|
+
exactly one `### Mandatory Evidence Coverage` subsection. Every mandatory
|
|
316
|
+
semantic/prior-summary L anchor appears exactly once as:
|
|
317
|
+
|
|
318
|
+
```text
|
|
319
|
+
- L42 support_text_json="exact source substring" disposition=covered
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
The JSON string must decode to a meaningful exact substring of that source
|
|
323
|
+
record. This blocks a content-free anchor dump and leaves a mechanically
|
|
324
|
+
checkable excerpt; it does not prove perfect natural-language interpretation.
|
|
325
|
+
|
|
326
|
+
Every active-chain prior compact summary is inserted as a complete dedicated
|
|
327
|
+
evidence record. An explicitly supplied external handoff is inserted in full,
|
|
328
|
+
one JSON-escaped `H<number> full_text_json` line per source line. Two default
|
|
329
|
+
pack ceilings apply together: 500,000 characters and a conservative 150,000
|
|
330
|
+
local estimated tokens. The latter leaves working space in a typical 200k
|
|
331
|
+
summarizer context. If the complete semantic ledger, prior summaries, handoff,
|
|
332
|
+
and minimum structural coverage do not fit, pack generation stops; it does not
|
|
333
|
+
trim or sample mandatory evidence. Optional source/tool/system/error evidence
|
|
334
|
+
is ranked and added only while both ceilings permit, and truncation is reported.
|
|
335
|
+
The caller should raise `--model-pack-char-budget` or
|
|
336
|
+
`--model-pack-estimated-token-budget` only when the summarizing model can read
|
|
337
|
+
the resulting pack. No external tokenizer is installed. Once a model summary
|
|
338
|
+
passes validation, its text is not truncated to meet `--summary-char-budget`;
|
|
339
|
+
insufficient composition space is a hard error. The summary character budget
|
|
340
|
+
has a hard minimum of 4000, and blank compact summaries are invalid.
|
|
341
|
+
|
|
342
|
+
These controls reduce stale-summary and unsupported-claim risk. They do not
|
|
343
|
+
mathematically prove that a natural-language summary has perfect semantics.
|
|
344
|
+
The deterministic safety appendix and recent raw suffix remain independent
|
|
345
|
+
evidence layers.
|
|
346
|
+
|
|
347
|
+
### Weighting and chronology
|
|
348
|
+
|
|
349
|
+
The evidence pack requires every non-empty older active human message and every
|
|
350
|
+
older active assistant `text`/`thinking` message, regardless of language or
|
|
351
|
+
keyword score. Source-text warnings such as U+FFFD are reported but do not make
|
|
352
|
+
mandatory records optional. Within the remaining optional source/tool capacity it gives
|
|
353
|
+
priority to:
|
|
354
|
+
|
|
355
|
+
1. explicit user constraints and requested outcomes;
|
|
356
|
+
2. final/current decisions and their reasons;
|
|
357
|
+
3. supersessions and chronology needed to avoid reviving old decisions;
|
|
358
|
+
4. model research conclusions, implementation decisions, and rationale;
|
|
359
|
+
5. unresolved risks, exact identifiers, source references, and validation
|
|
360
|
+
results;
|
|
361
|
+
6. file/tool content that materially supports the above;
|
|
362
|
+
7. repetitive logs or mechanically recoverable detail.
|
|
363
|
+
|
|
364
|
+
Important evidence can be Chinese, English, Japanese, Korean, Arabic, Russian,
|
|
365
|
+
Hindi, Greek, Hebrew, Armenian, Thai, Georgian, Ethiopic, Bengali, Tamil,
|
|
366
|
+
Telugu, Malayalam, Spanish, French, German, Portuguese, or another language.
|
|
367
|
+
All assistant thinking is semantic evidence without a language-keyword gate;
|
|
368
|
+
multilingual terms and script detection only improve classification and optional
|
|
369
|
+
weighting. Language is not treated as a proxy for importance.
|
|
370
|
+
|
|
371
|
+
## Token Ceilings
|
|
372
|
+
|
|
373
|
+
`--model-pack-estimated-token-budget N` limits the evidence pack read by the
|
|
374
|
+
summary-authoring model. It defaults to 150,000 and is enforced together with
|
|
375
|
+
the character budget. The same non-default value must be supplied when
|
|
376
|
+
generating the pack and when applying the model summary. Mandatory semantic and
|
|
377
|
+
handoff evidence cannot be dropped to satisfy it; optional evidence can be
|
|
378
|
+
truncated and this state is recorded in the pack, compact metadata, and report.
|
|
379
|
+
|
|
380
|
+
`--target-estimated-tokens N` uses a dependency-free heuristic over complete
|
|
381
|
+
retained structured message payloads, including full thinking,
|
|
382
|
+
`tool_use.input`, `tool_result`, and `toolUseResult` data. ASCII is estimated at
|
|
383
|
+
one token per four characters;
|
|
384
|
+
Han/Kana/Hangul at 1.3 each; non-BMP, symbol and combining-mark code points at
|
|
385
|
+
1.5 each; other non-ASCII at 0.8 each; and each record adds a small allowance.
|
|
386
|
+
It narrows the byte-ratio plan and rejects a generated candidate whose
|
|
387
|
+
estimated message tokens exceed `N`. This candidate-output gate is independent
|
|
388
|
+
of the model-pack reading ceiling.
|
|
389
|
+
|
|
390
|
+
This estimate excludes system prompts, tools, MCP schemas, skills, runtime
|
|
391
|
+
injections, and any Claude-side accounting. It is a reproducible local planning
|
|
392
|
+
gate, not a promise that `/context` or an API relay will report the same total.
|
|
393
|
+
`--target-ratio` is only an approximate byte-ratio planning input and is not a
|
|
394
|
+
hard publication gate.
|
|
395
|
+
|
|
396
|
+
## Tool Use and Tool Result Pairing
|
|
397
|
+
|
|
398
|
+
One API turn may be split across several JSONL records:
|
|
399
|
+
|
|
400
|
+
- multiple `tool_use` blocks in one assistant message;
|
|
401
|
+
- adjacent assistant fragments sharing one `message.id`;
|
|
402
|
+
- split user records carrying `tool_result` blocks;
|
|
403
|
+
- hook or attachment records between result fragments.
|
|
404
|
+
|
|
405
|
+
Validation rebuilds the selected active chain, filters API messages, merges
|
|
406
|
+
compatible assistant and user fragments, and checks tool IDs and order. It
|
|
407
|
+
rejects orphan results, wrong IDs, and out-of-order results. The compression cut
|
|
408
|
+
cannot divide a required tool-use/result relationship.
|
|
409
|
+
|
|
410
|
+
## File-History Checkpoint Policies
|
|
411
|
+
|
|
412
|
+
Conversation topology and file checkpoint metadata are separate planes.
|
|
413
|
+
`file-history-snapshot` records commonly lack `uuid` and `parentUuid`, so they
|
|
414
|
+
cannot be relinked into the API-message chain.
|
|
415
|
+
|
|
416
|
+
Policies:
|
|
417
|
+
|
|
418
|
+
- `active-correlated` (default): retain a bounded set only when structural
|
|
419
|
+
identifiers correlate the snapshot to recent active records;
|
|
420
|
+
- `preserve-recent`: rejected in strict active-chain mode; accepted only with
|
|
421
|
+
explicit `--preserve-physical-tail`, which is labeled compatibility mode and
|
|
422
|
+
has no inactive-branch isolation guarantee;
|
|
423
|
+
- `none`: retain no snapshot side records.
|
|
424
|
+
|
|
425
|
+
Preserved snapshots are emitted as side records before the compact pair. JSONL
|
|
426
|
+
compression alone does not guarantee complete file-state rewind because Claude
|
|
427
|
+
Code checkpoint storage and lifecycle have behavior beyond the message chain.
|
|
428
|
+
|
|
429
|
+
## Repeated Compression
|
|
430
|
+
|
|
431
|
+
Old compact pairs on the active chain are part of `summaryIndexes` when they
|
|
432
|
+
fall before the recent suffix. Normal repeated compression folds their useful
|
|
433
|
+
meaning into one new current summary rather than stacking live compact pairs.
|
|
434
|
+
|
|
435
|
+
`compactMetadata.preservedMessages` and `preservedSegment` describe the raw
|
|
436
|
+
suffix that existed when that compact pair was created. Later work can extend
|
|
437
|
+
that suffix, and a later rewind can leave part of the recorded snapshot on an
|
|
438
|
+
inactive branch. A structurally valid historical divergence is therefore a
|
|
439
|
+
source warning, not authority to restore those UUIDs and not a topology error.
|
|
440
|
+
Selection continues from the current `last-prompt` parent chain. Candidate
|
|
441
|
+
publication is stricter: the newly emitted snapshot must match the candidate's
|
|
442
|
+
current chain exactly or publication stops before writing.
|
|
443
|
+
|
|
444
|
+
`--preserve-prior-summaries-verbatim` is an explicit exception. It attempts to
|
|
445
|
+
embed prior `isCompactSummary.message.content` text verbatim inside the one new
|
|
446
|
+
summary and permits the summary text to grow to `1.5 * --summary-char-budget`.
|
|
447
|
+
If the prior summaries still do not fit, the engine uses the normal folded
|
|
448
|
+
model-summary path and reports the fallback reason. Excluded-branch summaries
|
|
449
|
+
are never eligible for either path.
|
|
450
|
+
|
|
451
|
+
## Branch Session Files
|
|
452
|
+
|
|
453
|
+
Observed `/branch` files are not guaranteed to be full physical copies. They
|
|
454
|
+
may retain source UUIDs, rewrite `sessionId`, add `forkedFrom`, relink parents,
|
|
455
|
+
and omit source history outside the branch-relevant chain.
|
|
456
|
+
|
|
457
|
+
The compressor treats exactly one selected JSONL as authoritative. It does not
|
|
458
|
+
merge a branch file with its source. Compress the branch to continue the branch;
|
|
459
|
+
compress or archive the source separately when its physical history matters.
|
|
460
|
+
|
|
461
|
+
## External References
|
|
462
|
+
|
|
463
|
+
JSONL may contain inline tool results, file excerpts, attachment metadata, or
|
|
464
|
+
paths/references to external artifacts such as tool-result storage. Offline
|
|
465
|
+
compression reads the selected JSONL and an explicitly supplied handoff file
|
|
466
|
+
only. It does not dereference, delete, or rewrite external project files,
|
|
467
|
+
`tool-results`, subagent artifacts, settings, or other sessions.
|
|
468
|
+
|
|
469
|
+
If a referenced artifact's contents are not embedded in the JSONL or handoff,
|
|
470
|
+
the model pack knows only the reference, not the external contents.
|
|
471
|
+
|
|
472
|
+
## `Read.pages` Compatibility Repair
|
|
473
|
+
|
|
474
|
+
Claude Code legitimately uses `Read.input.pages`, including for paged document
|
|
475
|
+
reads. The independent repair command exists only for a known downstream
|
|
476
|
+
compatibility case where historical serialized `pages` members must be removed.
|
|
477
|
+
Compression never invokes this repair implicitly.
|
|
478
|
+
|
|
479
|
+
The repairer:
|
|
480
|
+
|
|
481
|
+
- matches only assistant `tool_use` blocks with exact tool name `Read` and an
|
|
482
|
+
`input` object containing `pages`;
|
|
483
|
+
- requires a nonempty `file_path`, exactly one later matching `tool_result`, the
|
|
484
|
+
same nonempty `sessionId`, and result `sourceToolAssistantUUID` equal to the
|
|
485
|
+
tool-use assistant UUID before automatic repair;
|
|
486
|
+
- reports pending calls without changing them;
|
|
487
|
+
- defaults to the strict active chain; `--scope all` is explicit;
|
|
488
|
+
- deletes the exact JSON member byte span without reserializing other data;
|
|
489
|
+
- blocks duplicate-key or overlapping-span ambiguity;
|
|
490
|
+
- preserves BOM, newline style, Unicode spelling, unknown fields, record count,
|
|
491
|
+
UUID/parent signature, and tool ID sequences;
|
|
492
|
+
- re-reads the actual published candidate, verifies exact expected bytes and
|
|
493
|
+
SHA-256, validates the repair invariants, requires an idempotent second scan
|
|
494
|
+
with zero remaining patches, and runs the shared full-transcript
|
|
495
|
+
UUID/parent/compact/tool validator on the published bytes.
|
|
496
|
+
|
|
497
|
+
Candidate and live replacement modes use the same atomic-write, full-hash,
|
|
498
|
+
numbered-backup, source-race, validation, and rollback principles as compression.
|
|
499
|
+
|
|
500
|
+
## Candidate and Live Replacement Transactions
|
|
501
|
+
|
|
502
|
+
Candidate mode requires distinct input and output paths. Candidate JSONL,
|
|
503
|
+
reports, validation, model packs, summaries and work directories must remain
|
|
504
|
+
outside the entire `.claude` tree.
|
|
505
|
+
|
|
506
|
+
Live replacement mode requires one existing regular `.jsonl` input under
|
|
507
|
+
`.claude/projects`, an external `--work-dir`, and caller acknowledgement
|
|
508
|
+
`--confirm-session-closed`. The acknowledgement is an operational assertion,
|
|
509
|
+
not process-lock detection. It:
|
|
510
|
+
|
|
511
|
+
1. reads and hashes the complete original bytes;
|
|
512
|
+
2. writes and validates a candidate outside `.claude`;
|
|
513
|
+
3. rechecks that the source bytes did not change;
|
|
514
|
+
4. creates an exclusive `.backup`, `.backup1`, and so on;
|
|
515
|
+
5. validates immutable candidate bytes and writes a unique same-directory stage
|
|
516
|
+
with flush/fsync;
|
|
517
|
+
6. captures the actual old target, verifies its full bytes against the frozen
|
|
518
|
+
source, and publishes the staged candidate with an atomic no-clobber claim;
|
|
519
|
+
7. verifies published bytes and structure, restoring the captured original on
|
|
520
|
+
failure. If restoration fails, the numbered verified backup remains and the
|
|
521
|
+
error is promoted.
|
|
522
|
+
|
|
523
|
+
If another process recreates the target after capture begins, the transaction
|
|
524
|
+
does not overwrite the external target. It preserves the verified numbered
|
|
525
|
+
backup and, when necessary, places the captured original in another numbered
|
|
526
|
+
backup, then fails without publishing the candidate.
|
|
527
|
+
|
|
528
|
+
Before any live staging, backup payload publication, or target move, the
|
|
529
|
+
implementation probes file hard-link support in the target directory and, when
|
|
530
|
+
configured, the external backup directory. The probe itself briefly creates
|
|
531
|
+
and removes unique dot-prefixed temporary files. Every unique live-transaction
|
|
532
|
+
temporary path records its observed filesystem identity and frozen bytes.
|
|
533
|
+
Cleanup rechecks both and retains a detected mismatch. A mismatch after commit is reported as
|
|
534
|
+
`committed-cleanup-failed`; a mismatch while an earlier transaction failure is
|
|
535
|
+
already active is appended to that failure. This is a best-effort race check,
|
|
536
|
+
not a portable atomic identity-bound delete: standard Python pathname cleanup
|
|
537
|
+
cannot eliminate a replacement between its final check and `unlink()` across
|
|
538
|
+
Windows, Linux, and macOS. Live operation assumes Claude Code is closed and no
|
|
539
|
+
other writer is manipulating the session directory.
|
|
540
|
+
|
|
541
|
+
Candidate-mode reports are written with the candidate. Live compression delays
|
|
542
|
+
its final sidecar/report until replacement metadata is available, so it does not
|
|
543
|
+
leave a stale pre-commit report. If the JSONL commits and validates but final
|
|
544
|
+
report publication fails, compression returns exit code 3 with
|
|
545
|
+
`operation_state: committed-report-failed`; repair uses the camelCase equivalent
|
|
546
|
+
`operationState`. The receipt includes public artifact labels and frozen,
|
|
547
|
+
candidate, and published hashes. This is a committed state and is not rolled
|
|
548
|
+
back or reported as an ordinary uncommitted failure.
|
|
549
|
+
|
|
550
|
+
Once a numbered backup is created and verified, later failure cleanup never
|
|
551
|
+
deletes that path. This preserves an audit/recovery asset even when publication
|
|
552
|
+
or rollback fails or another process races on a nearby name.
|
|
553
|
+
|
|
554
|
+
Claude Code should be closed for that session during replacement. No other
|
|
555
|
+
session or Claude settings file is part of the transaction. Parent-directory
|
|
556
|
+
fsync is best effort and reported; the project does not promise cross-platform
|
|
557
|
+
power-loss atomicity.
|
|
558
|
+
|
|
559
|
+
## Validation Boundary
|
|
560
|
+
|
|
561
|
+
The validator checks observed-format coherence, including:
|
|
562
|
+
|
|
563
|
+
- parseability and object-per-line structure;
|
|
564
|
+
- unique UUIDs and resolvable parent/session links;
|
|
565
|
+
- exactly one current compact pair;
|
|
566
|
+
- current compact pair reachability from the final pointer;
|
|
567
|
+
- compact preserved-message metadata;
|
|
568
|
+
- non-empty, unique active tool IDs and tool-use/result pairing after fragment
|
|
569
|
+
merging; partial multi-tool ordered subsets are accepted only with an explicit
|
|
570
|
+
compatibility warning/count;
|
|
571
|
+
- absence of internal planning fields in output;
|
|
572
|
+
- source hashes, model-pack metadata, anchor sets, and target estimates where
|
|
573
|
+
applicable.
|
|
574
|
+
|
|
575
|
+
Passing these checks proves coherence under this project's empirical rules. It
|
|
576
|
+
does not make the private transcript format an Anthropic-supported public API.
|
|
577
|
+
When runtime testing is explicitly requested, `/resume`, `/context`, recent
|
|
578
|
+
conversation rewind, and recent file rewind are separate observations.
|
|
579
|
+
|
|
580
|
+
## Package 1.1.0 additive controls
|
|
581
|
+
|
|
582
|
+
CLI defaults remain `tool_evidence=excerpt`, `citation_style=legacy`,
|
|
583
|
+
`prior_summary_overflow=fold`, `min_recent_turns=0`. Non-default values add
|
|
584
|
+
`toolEvidence`, `citationStyle`, `priorSummaryOverflow`, `minRecentTurns` to the
|
|
585
|
+
v11 request manifest; defaults omit these keys. This preserves the old manifest
|
|
586
|
+
shape, not cross-version evidence bytes: regenerate packs after upgrading.
|
|
587
|
+
|
|
588
|
+
Full tool evidence uses the existing per-record full_text_json/claim-source
|
|
589
|
+
contract. It is a labelled field ledger with complete tool inputs, API results,
|
|
590
|
+
auxiliary toolUseResult and source assistant identity. An exact_string_alias_of
|
|
591
|
+
line refers only to an identical string of at least 80 characters earlier in
|
|
592
|
+
that record. It never deduplicates by path, meaning, or another branch. All
|
|
593
|
+
complete-tool records are mandatory and may not be sampled to fit. Warning
|
|
594
|
+
characters are retained. Plain injected/unknown user-format prose remains
|
|
595
|
+
mandatory too; it is not attributed to a human. Neither full evidence nor
|
|
596
|
+
source excerpts establish that a model interpreted a fact correctly.
|
|
597
|
+
|
|
598
|
+
Scoped prose references are exactly [@L42] / [@H3]. Coverage entries keep the
|
|
599
|
+
printed L prefix; support_text_json contents are excluded from reference scans.
|
|
600
|
+
The chosen style is bound in both passes. Historical source statements about
|
|
601
|
+
unavailable information are allowed; grounding checks still apply.
|
|
602
|
+
|
|
603
|
+
Strict prior-summary overflow uses the existing 1.5x summary character limit.
|
|
604
|
+
Preflight and pack generation reject when the preserved old block and even an
|
|
605
|
+
empty new layer cannot fit. Actual new-layer size is checked in pass 2. Exact
|
|
606
|
+
preserved spans include trailing whitespace and carry SHA-256 and ordered
|
|
607
|
+
offsets. The legacy fold policy still reports fallback-folded on overflow.
|
|
608
|
+
|
|
609
|
+
Recent-turn protection only considers human-started records after the latest
|
|
610
|
+
compact and within the final session. Tool-boundary adjustment must not cross
|
|
611
|
+
that floor. A positive setting is rejected in physical-tail mode. Reports
|
|
612
|
+
count structural human messages and snapshots, not actual rewind menu points.
|
|
613
|
+
|
|
614
|
+
Title selection is shared by locator and compressor: last valid custom title
|
|
615
|
+
in the final session, otherwise last valid automatic title. Supported fields
|
|
616
|
+
are customTitle/aiTitle, title, then message.content. Only UUID-less, parent-less
|
|
617
|
+
control records may be projected; an unowned title is attributable only when
|
|
618
|
+
the source has one nonempty session ID. A rename after the pointer is control
|
|
619
|
+
metadata, not conversation evidence. Selected metadata retains unknown fields
|
|
620
|
+
and is assigned the output session ID. Prior title projections are removed,
|
|
621
|
+
and the final title is written before the sole final last-prompt. Ambiguous
|
|
622
|
+
unowned titles are counted, never used to override a known owner.
|
|
623
|
+
|
|
624
|
+
Preflight is read-only. Its topology, activeChain, partition, estimates and pack
|
|
625
|
+
fields separate structural validity, selected-source validation and capacity.
|
|
626
|
+
Physical-tail diagnostics are not a recovery authorization. It may return
|
|
627
|
+
nothing-to-summarize without building a pack. Exact source bytes are hashed;
|
|
628
|
+
freeze a numbered backup after successful preflight and compare hashes before
|
|
629
|
+
model work. Candidate and live replacement retain their existing write rules.
|
|
630
|
+
|
|
631
|
+
Cost discipline: one authoring pass and focused self-review by default; use
|
|
632
|
+
additional review when requested or needed to resolve a concrete conflict.
|
|
633
|
+
Honor requested reviewer model/effort/scope, and pass only complete relevant
|
|
634
|
+
evidence from the selected branch. No automatic fan-out, budget escalation,
|
|
635
|
+
external document retrieval, or multi-volume pipeline is part of this package.
|