You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Status: Research; the feature's time cost has never been measured — that is the gap this issue fills. Filed 2026-09-20 from the #205/#190 attribution round (ledger L53).
Related:#190 (retained-history read/scale) · #186 (the feature) · #205 (where the cost surfaced).
The question
LAYERFS_HISTORY_CHUNK_PREDECESSORS was introduced by 795fb1a2f ("C1 chunk cursor, C2 persisted similarity index, lean row grammar", closes #186) and defaults ON because it was measured and it wins on space. What was never measured is what it costs in time, on any row. This issue measures both axes across all three strides and then states a judgement.
What is already established — do not re-derive
The feature is a space feature, and it is a large win. From 795fb1a2f's own record, against the v0.1.6 reference:
row
states
apparent
v0.1.6
ratio
history-stride10
17
49,053,696
49,315,840
0.99468
history-stride3
53
61,767,680
64,000,000
0.96512
history-stride1
157
80,273,408
82,685,952
0.97082
All three PASS and all three are below the v0.1.6 reference; the registered lane fell 128,864,256 → 49,053,696, a 61.9 % reduction (2.6130× → 0.99468×). Its switch documentation records the enabling measurement: 51,347,456 → 49,672,192 B apparent (−1,675,264), the native lane falling to 3,957,829 B — 228 B below v0.1.6's own 3,958,057 B — with the selection becoming byte-identical to v0.1.6's (448 FULL / 650 PREFIX). delta.trials rose 37,886 → 38,538, the first chunk trials on this lane.
And the commit is explicit that time was not part of the claim:
"No timing claim is made anywhere in this commit. The machine was not quiet (load ~5) for the lane runs; bytes and RSS are load-independent and stand."
The time cost, measured this round on stride10 alone: operation 16.296 s (predecessors ON) against 10.882 s (OFF, LAYERFS_HISTORY_CHUNK_PREDECESSORS=0). Same workload, same 17 states, same 52,032 objects, same build. content 1.585 → 1.039 s, filesystem 5.146 → 3.490 s, accept_loop 8.820 → 5.847 s.
Store cost of the same control arm, measured: apparent 49,324,032 → 51,040,256 B (+1,716,224, +3.48 %); allocated 50,249,728 → 51,298,304 B (+1,048,576, +2.09 %); pack BLOB bytes 45,297,954 → 47,036,475 (+3.84 %); packs 255 → 262; objects 52,032 → 52,032 (unchanged); value groups 1,737 → 1,737 (unchanged).
The correction this issue records
An earlier reading of the stride10 control — reported in this lane as "declining prior-state bases cut the operation 33 %, at the cost of a larger Store" — had the causality backwards. The control does not remove a cost; it removes a feature. CHUNK_PREDECESSORS=0 reproduces the arm every earlier measurement was taken on, byte for byte, so:
ON = the shipped feature, 3.5 % smaller Store, slower.
So the trade under examination is the reverse of how it was first stated: how much time does the space win cost, and is that price worth paying?
The experiment
One switch, two arms, three strides, time and space on both axes for every row:
row
states
arm
switch
history-stride10
17
ON (shipped)
default
history-stride10
17
OFF
LAYERFS_HISTORY_CHUNK_PREDECESSORS=0
history-stride3
53
ON
default
history-stride3
53
OFF
LAYERFS_HISTORY_CHUNK_PREDECESSORS=0
history-stride1
157
ON
default
history-stride1
157
OFF
LAYERFS_HISTORY_CHUNK_PREDECESSORS=0
Reported per row: operation ns, content / filesystem / accept_loop node ns, apparent bytes, allocated bytes, pack BLOB bytes, packs created, object count, and the harness's own gate outcome.
Why stride1 matters most. Reuse volume dominates there — 121,301 reuse occurrences, 16.544 s, 34.6 % of scope — so if the predecessor cursor's per-chunk base resolution grows with history, stride1 is where it shows. The space cost should also be largest there. A stride10-only verdict would be the wrong basis for a policy that ships on all three rows.
Two limits this experiment cannot remove
The switch is confounded by construction.LAYERFS_HISTORY_CHUNK_PREDECESSORS=0 disables both the predecessor offering and the chunked-construction path that consumes it. The measured delta is therefore the cost of the whole v0.1.7: Stage 6 - retained history storage families (C1+C2, stride 10/3/1) #186 chunk-cursor mechanism, not of base resolution alone. Separating them needs a narrower switch, which is not proposed here.
The OFF arm's Store is not byte-identical to the recorded constant, by declaration. Byte-identity is not a criterion for the OFF arm and its absence is not a defect.
What a judgement would need
The time price per row (this experiment).
The space saving per row (this experiment, plus 795fb1a2f's v0.1.6 comparison).
Whether the time cost grows with history faster than the space saving does. If the cost is flat while the saving grows, ON is comfortable; if the cost grows, there is a history length beyond which the trade inverts.
Whether the space win is still needed. It took the registered lane from 2.61× v0.1.6 to 0.99× — i.e. it is the reason the lane now sits below the v0.1.6 reference. If that standing is a requirement, the time price is not optional regardless of its size.
Owner rulings that apply
One second of stride10 operation reduction is worthwhile. If the time price is ≥ 1 s on stride10, it is not a rounding error and needs an explicit ruling.
A small allocated-storage overage is acceptable when accompanied by good time reduction. Here the axes point in opposite directions — time up, space down — so the ruling's premise does not directly apply and an explicit decision is required rather than an inference.
No automatic cache growth; no invented cold stance; no pre-touched inputs; no shrunk selection.
Report both axes; never relabel a historical miss as a pass.
Measurement protocol
One sample per case per arm; fresh --output per run; receipts append-only; failures and deferrals retained. Both global flocks held for every resource command; a held lock defers and never waits. Quiet preflight — no named cargo/rustc/fs-bench competitor and ≥ 70 % CPU idle on the second of two one-second observations; a busy preflight consumes no sample. Rust 1.85.1, --locked, one construction worker. Diagnostic caps unchanged: 120 s / 240 s / 720 s.
All history.* rows are diagnostics — admission INELIGIBLE, O3 INCOMPLETE, every budget class NOT_RUN. Nothing here is admission evidence, and no pin may be hand-edited.
Deliverable
A three-row, two-axis table with the mechanism's time price stated per row, a judgement on whether the shipped default is right, and — if the price grows with history — the crossover point stated as a finding rather than left implicit. #186, #190 and #205 are not closed by this.
Status: Research; the feature's time cost has never been measured — that is the gap this issue fills. Filed 2026-09-20 from the #205/#190 attribution round (ledger L53).
Related: #190 (retained-history read/scale) · #186 (the feature) · #205 (where the cost surfaced).
The question
LAYERFS_HISTORY_CHUNK_PREDECESSORSwas introduced by795fb1a2f("C1 chunk cursor, C2 persisted similarity index, lean row grammar", closes #186) and defaults ON because it was measured and it wins on space. What was never measured is what it costs in time, on any row. This issue measures both axes across all three strides and then states a judgement.What is already established — do not re-derive
The feature is a space feature, and it is a large win. From
795fb1a2f's own record, against the v0.1.6 reference:history-stride10history-stride3history-stride1All three PASS and all three are below the v0.1.6 reference; the registered lane fell 128,864,256 → 49,053,696, a 61.9 % reduction (2.6130× → 0.99468×). Its switch documentation records the enabling measurement: 51,347,456 → 49,672,192 B apparent (−1,675,264), the native lane falling to 3,957,829 B — 228 B below v0.1.6's own 3,958,057 B — with the selection becoming byte-identical to v0.1.6's (448 FULL / 650 PREFIX).
delta.trialsrose 37,886 → 38,538, the first chunk trials on this lane.And the commit is explicit that time was not part of the claim:
The time cost, measured this round on stride10 alone: operation 16.296 s (predecessors ON) against 10.882 s (OFF,
LAYERFS_HISTORY_CHUNK_PREDECESSORS=0). Same workload, same 17 states, same 52,032 objects, same build.content1.585 → 1.039 s,filesystem5.146 → 3.490 s,accept_loop8.820 → 5.847 s.Store cost of the same control arm, measured: apparent 49,324,032 → 51,040,256 B (+1,716,224, +3.48 %); allocated 50,249,728 → 51,298,304 B (+1,048,576, +2.09 %); pack BLOB bytes 45,297,954 → 47,036,475 (+3.84 %); packs 255 → 262; objects 52,032 → 52,032 (unchanged); value groups 1,737 → 1,737 (unchanged).
The correction this issue records
An earlier reading of the stride10 control — reported in this lane as "declining prior-state bases cut the operation 33 %, at the cost of a larger Store" — had the causality backwards. The control does not remove a cost; it removes a feature.
CHUNK_PREDECESSORS=0reproduces the arm every earlier measurement was taken on, byte for byte, so:So the trade under examination is the reverse of how it was first stated: how much time does the space win cost, and is that price worth paying?
The experiment
One switch, two arms, three strides, time and space on both axes for every row:
history-stride10history-stride10LAYERFS_HISTORY_CHUNK_PREDECESSORS=0history-stride3history-stride3LAYERFS_HISTORY_CHUNK_PREDECESSORS=0history-stride1history-stride1LAYERFS_HISTORY_CHUNK_PREDECESSORS=0Reported per row: operation ns,
content/filesystem/accept_loopnode ns, apparent bytes, allocated bytes, pack BLOB bytes, packs created, object count, and the harness's own gate outcome.Why stride1 matters most. Reuse volume dominates there — 121,301 reuse occurrences, 16.544 s, 34.6 % of scope — so if the predecessor cursor's per-chunk base resolution grows with history, stride1 is where it shows. The space cost should also be largest there. A stride10-only verdict would be the wrong basis for a policy that ships on all three rows.
Two limits this experiment cannot remove
LAYERFS_HISTORY_CHUNK_PREDECESSORS=0disables both the predecessor offering and the chunked-construction path that consumes it. The measured delta is therefore the cost of the whole v0.1.7: Stage 6 - retained history storage families (C1+C2, stride 10/3/1) #186 chunk-cursor mechanism, not of base resolution alone. Separating them needs a narrower switch, which is not proposed here.What a judgement would need
795fb1a2f's v0.1.6 comparison).Owner rulings that apply
Measurement protocol
One sample per case per arm; fresh
--outputper run; receipts append-only; failures and deferrals retained. Both global flocks held for every resource command; a held lock defers and never waits. Quiet preflight — no namedcargo/rustc/fs-benchcompetitor and ≥ 70 % CPU idle on the second of two one-second observations; a busy preflight consumes no sample. Rust 1.85.1,--locked, one construction worker. Diagnostic caps unchanged: 120 s / 240 s / 720 s.All
history.*rows are diagnostics — admissionINELIGIBLE, O3INCOMPLETE, every budget classNOT_RUN. Nothing here is admission evidence, and no pin may be hand-edited.Deliverable
A three-row, two-axis table with the mechanism's time price stated per row, a judgement on whether the shipped default is right, and — if the price grows with history — the crossover point stated as a finding rather than left implicit. #186, #190 and #205 are not closed by this.