| title |
Linux: H185 describes each directory once on the folded tree route, the default tree 4% faster on node-modules-dense |
| softschema |
| contract |
schema |
envelope |
status |
fdu.performance:Experiment/v1 |
experiment.schema.yaml |
experiment |
enforced |
|
| experiment |
| id |
title |
date |
hypotheses |
subject |
method |
results |
reference_tools |
complexity |
verdict |
exp-197 |
Linux: H185 describes each directory once on the folded tree route, the default tree 4% faster on node-modules-dense |
2026-09-30 |
|
| tree_label |
tree_root_id |
tree_engine_digest |
tree_provenance |
tree_reconstructible |
tree_entries |
tree_directories |
tree_files |
tree_symlinks |
tree_apparent_bytes |
tree_allocated_bytes |
tree_max_depth |
tree_mutated_during_run |
host_cpu |
host_arch |
host_cores |
host_performance_cores |
host_efficiency_cores |
host_memory_bytes |
host_system |
filesystem |
host_virtualization |
os_cache |
node-modules-dense |
db6d49b68990d6b3a741e6289f360187d4317abfdda8be3f70915f799eb7acd4 |
11c4122bec53693180e2e240899b75cdccc707ca9759b9acfadb80a0b19bafac |
npm dependency trees of react-scripts 5.0.1 and gatsby 5.13.7: copy docs/project/experiments/evidence/exp-190/subject-package.json.txt and subject-package-lock.json.txt to package.json and package-lock.json in an empty directory and run npm ci --ignore-scripts (node 22.22.2, npm 10.9.7); rebuilt 2026-09-29 on this host: 79,957 entries (exp-190 recorded 79,953), 9,439 directories, no .gitignore. |
true |
79957 |
9439 |
70411 |
107 |
538992241 |
757870592 |
12 |
false |
Intel(R) Xeon(R) Processor @ 2.10GHz |
x86_64 |
4 |
0 |
0 |
16876515328 |
Linux 6.18.44-fc-v50 |
ext4 |
virtualized |
warm-steady |
|
| trials |
warmups |
interleaved |
control |
candidate |
control_binary |
candidate_binary |
toolchain |
build_profile |
campaign_stage |
confidence_interval |
stopping_rule |
run_artifact |
20 |
3 |
true |
ebc06c78 probe (the final head of the round, the branch's base engine) |
c0da65ae probe (the H185 head) |
| name |
sha256 |
size_bytes |
args |
control |
938370e0cbdc5885888514aa8ec2caa854b151cddab9c83c11712b0251525e82 |
3862104 |
|
|
| name |
sha256 |
size_bytes |
args |
candidate |
ad39ff3c78f614c4947b6095e3ead2eac666d0a14f3e4d59fda4af5c06cbfc57 |
3863336 |
|
|
rustc 1.97.1 (8bab26f4f 2026-07-14) |
release |
exploratory |
paired-bootstrap-median-95-v1 |
fixed-N-no-optional-stopping-v1 |
docs/project/experiments/evidence/exp-197/run.json.gz |
|
| job |
start_state |
invalid_samples |
metrics |
qualification |
aggregate-summary |
cold |
0 |
| wall_ns |
component_ns |
cpu_ns |
user_cpu_ns |
system_cpu_ns |
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
76188519.5 |
76445258.5 |
1.062 |
1.087 |
2.098 |
-2.917 |
4.181 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
73356482.0 |
73942507.5 |
1.066 |
1.087 |
1.88 |
-3.175 |
3.927 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
278723000.0 |
280114500.0 |
1.089 |
1.057 |
0.335 |
-2.042 |
3.612 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
49881500.0 |
47963500.0 |
1.213 |
1.389 |
-6.836 |
-19.056 |
25.232 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
231810000.0 |
235013000.0 |
1.127 |
1.077 |
-0.36 |
-7.355 |
9.186 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
|
| campaign_stage |
classification |
confirmable |
major_fault_delta_limit |
noninferiority_margin_pct |
reasons |
resource_limits_pct |
resources |
policy_stable |
policy_rule |
exploratory |
inconclusive |
false |
0.0 |
3.0 |
peak_rss_bytes is missing a paired percent interval |
minor_faults straddles its +10% regression limit |
|
| cpu_ns |
involuntary_context_switches |
minor_faults |
peak_rss_bytes |
system_cpu_ns |
voluntary_context_switches |
50.0 |
50.0 |
10.0 |
5.0 |
75.0 |
50.0 |
|
| cpu_ns |
involuntary_context_switches |
major_faults |
minor_faults |
peak_rss_bytes |
system_cpu_ns |
voluntary_context_switches |
within-limit |
within-limit |
within-limit |
inconclusive |
inconclusive |
within-limit |
within-limit |
|
|
|
|
|
| job |
start_state |
invalid_samples |
metrics |
qualification |
cold-scan-index |
cold |
0 |
| wall_ns |
component_ns |
cpu_ns |
user_cpu_ns |
system_cpu_ns |
peak_rss_bytes |
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
202924103.5 |
205658138.5 |
1.094 |
1.079 |
0.905 |
-3.253 |
3.748 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
86554103.5 |
89270470.0 |
1.179 |
1.139 |
3.14 |
-3.867 |
5.678 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
421854500.0 |
427863500.0 |
1.12 |
1.106 |
0.673 |
-4.122 |
4.335 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
198573500.0 |
183808000.0 |
1.087 |
1.109 |
-5.278 |
-11.783 |
-0.443 |
true |
true |
true |
improved |
superior |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
236627500.0 |
245061000.0 |
1.092 |
1.115 |
2.286 |
-0.394 |
11.921 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
30214144.0 |
30425088.0 |
1.036 |
1.048 |
0.273 |
-0.774 |
1.627 |
false |
false |
false |
unclear |
noninferior |
20 |
|
|
| campaign_stage |
classification |
confirmable |
major_fault_delta_limit |
noninferiority_margin_pct |
reasons |
resource_limits_pct |
resources |
policy_stable |
policy_rule |
exploratory |
inconclusive |
false |
0.0 |
3.0 |
|
| cpu_ns |
involuntary_context_switches |
minor_faults |
peak_rss_bytes |
system_cpu_ns |
voluntary_context_switches |
50.0 |
50.0 |
10.0 |
5.0 |
75.0 |
50.0 |
|
| cpu_ns |
involuntary_context_switches |
major_faults |
minor_faults |
peak_rss_bytes |
system_cpu_ns |
voluntary_context_switches |
within-limit |
within-limit |
within-limit |
within-limit |
within-limit |
within-limit |
within-limit |
|
|
|
|
|
| job |
start_state |
invalid_samples |
metrics |
qualification |
default-tree |
warm |
0 |
| wall_ns |
component_ns |
cpu_ns |
user_cpu_ns |
system_cpu_ns |
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
85163575.0 |
81785338.0 |
1.101 |
1.094 |
-3.551 |
-7.846 |
-2.571 |
true |
true |
true |
improved |
superior |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
82383336.5 |
78834591.0 |
1.1 |
1.101 |
-4.019 |
-8.136 |
-2.471 |
true |
true |
true |
improved |
superior |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
296870000.0 |
289111500.0 |
1.082 |
1.06 |
-4.371 |
-5.628 |
-2.212 |
true |
true |
true |
improved |
superior |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
45165500.0 |
48255000.0 |
1.465 |
1.338 |
3.147 |
-4.486 |
33.223 |
false |
false |
false |
unclear |
inconclusive |
20 |
|
| control_median |
candidate_median |
control_p95_over_median |
candidate_p95_over_median |
change_pct |
ci95_low_pct |
ci95_high_pct |
significant |
passes_acceptance |
ci_excludes_zero |
direction |
noninferiority |
pairs |
250415000.0 |
237480000.0 |
1.128 |
1.1 |
-4.348 |
-11.253 |
-2.5 |
true |
true |
true |
improved |
superior |
20 |
|
|
| campaign_stage |
classification |
confirmable |
major_fault_delta_limit |
noninferiority_margin_pct |
reasons |
resource_limits_pct |
resources |
policy_stable |
policy_rule |
exploratory |
inconclusive |
false |
0.0 |
3.0 |
peak_rss_bytes is missing a paired percent interval |
|
| cpu_ns |
involuntary_context_switches |
minor_faults |
peak_rss_bytes |
system_cpu_ns |
voluntary_context_switches |
50.0 |
50.0 |
10.0 |
5.0 |
75.0 |
50.0 |
|
| cpu_ns |
involuntary_context_switches |
major_faults |
minor_faults |
peak_rss_bytes |
system_cpu_ns |
voluntary_context_switches |
within-limit |
within-limit |
within-limit |
within-limit |
inconclusive |
within-limit |
within-limit |
|
|
|
|
|
|
|
| lines_changed |
new_dependencies |
new_unsafe_blocks |
new_failure_modes |
notes |
136 |
|
0 |
|
|
|
| decision |
primary_job |
primary_metric |
change_pct |
reason |
commit |
kept |
superseded |
default-tree |
wall_ns |
-3.551 |
quiet 20-pair node-modules-dense default-tree -3.55% [-7.85%, -2.57%], the --no-controls replicate -7.28% [-9.16%, -5.43%], linux-balanced-1m screen -4.45%; placebos include zero; linux-v6.12 +2.13% [-3.19%, +5.30%] with .gitignore on and -1.25% [-4.46%, +0.25%] off, not resolvable, no regression on the --no-controls arm and the controls-on arm too wide to bound; statx 79,961 -> 70,416 and 92,836 -> 87,006; answers identical; superseded by the age column on #191, which stats every directory and symlink on the folded tree again so a row's age counts their times (H193 measures the give-back, fdu-088k) |
c0da65ae |
control |
|
|
H185, from
the uniformly-faster brief.
The tree route described every directory twice: a statx from its parent’s listing and
the listing itself, where the summary route already takes directory and symlink kinds
from d_type (H72). A one-shot tree report reads no directory’s or symlink’s own
attributes: its rows carry roll-ups, newest_mtime_ns is the files’, symlinks and other
kinds contribute nothing, and dev is read only under --one-filesystem, where the
policy keeps the stat.
The change gives the folded index’s walker H72’s listing policy.
The full index keeps every stat, since its directory attributes are the cache’s
freshness fingerprint.
It was pre-registered in the registry (bf56ecfa) before code:
- Deciding:
default-tree wall −3% with the interval below zero on
node-modules-dense and linux-v6.12, 20 pairs.
- Prediction: −4% to −6% on
node-modules-dense (9,544 of 79,961 statx calls),
−2% to −4% on linux-v6.12 (5,829 of 92,836).
- Placebos:
aggregate-summary --no-controls (already skipping) and
cold-scan-index (the full index, unchanged) include zero.
- Secondary:
strace -c statx down by the directory and symlink count;
linux-balanced-1m as a screen.
- Answers: identical under H172’s transient-versus-indexed differential, which gains
a
--one-filesystem case, and the three-format answer diff over the three subjects.
System calls (strace -c, load-independent): statx 92,836 → 87,006 on
linux-v6.12 (−5,830, the 5,769 directories and 62 symlinks less the root) and 79,961 →
70,416 on node-modules-dense (−9,545); every other call unchanged.
The total falls 5,598 and 9,901.
Answers. The product command line matched the round’s final head byte for byte in 54
comparisons (three formats, six view and control variants, three subjects).
The transient-versus-indexed differential passes with its new --one-filesystem case,
and the new policy test holds on both routes at one and four workers.
Fingerprints. The cells checked the subjects against fingerprints registered for
this track (tree-linux-v6.12-pdu.json, tree-node-modules-dense-pdu.json,
tree-linux-balanced-1m-pdu.json), not the shared ones: the shared linux-v6.12
fingerprint, taken at 07:48 UTC, no longer matched the subject after its .git/index
was touched at 19:00 UTC. Entry counts and bytes are identical to the shared
fingerprint’s, the subject was not modified by this track, and the new fingerprints were
registered before any cell ran.
Wall. Quiet, 20 pairs on the real trees and 12 on the screen.
Control: ebc06c78 probe (the final head of the round, this branch’s base engine).
Candidate: c0da65ae probe (the H185 head).
The first linux-v6.12 cell had 7 timed samples invalidated by the quiet-host gate
during ordinals 5–7 of default-tree (a git fetch started beside it) and was rerun
whole; the rerun is the primary artifact.
| Subject, job |
Control |
H185 |
Change |
linux-v6.12, default-tree (deciding, rerun) |
88.0 ms |
88.4 ms |
+2.13% [−3.19%, +5.30%] |
linux-v6.12, default-tree --no-controls (rerun) |
85.2 ms |
83.2 ms |
−1.25% [−4.46%, +0.25%] |
linux-v6.12, aggregate-summary --no-controls (placebo, rerun) |
76.1 ms |
75.4 ms |
+0.45% [−2.47%, +2.23%] |
linux-v6.12, cold-scan-index (placebo, rerun) |
215.1 ms |
210.8 ms |
−1.49% [−4.38%, +2.11%] |
node-modules-dense, default-tree (deciding) |
85.2 ms |
81.8 ms |
−3.55% [−7.85%, −2.57%] |
node-modules-dense, default-tree --no-controls |
86.8 ms |
79.7 ms |
−7.28% [−9.16%, −5.43%] |
node-modules-dense, aggregate-summary |
76.2 ms |
76.4 ms |
+2.10% [−2.92%, +4.18%] |
node-modules-dense, aggregate-summary --no-controls (placebo) |
75.2 ms |
74.4 ms |
+0.61% [−2.08%, +2.37%] |
node-modules-dense, cold-scan-index (placebo) |
202.9 ms |
205.7 ms |
+0.91% [−3.25%, +3.75%] |
linux-balanced-1m, default-tree (screen, 12 pairs) |
977.7 ms |
928.5 ms |
−4.45% [−6.36%, −2.71%] |
The primary artifact is the node-modules-dense cell.
The two trees. The saving is one statx per directory and symlink, so it scales
with directories per entry, as H159’s per-directory saving did (exp-190): 9,545 calls of
79,961 on node-modules-dense (8.5 entries per directory) against 5,830 of 92,836 on
linux-v6.12 (16 per directory).
The dense tree shows it twice over, −3.55% by the deciding comparison and −7.28% by the
--no-controls replicate, which does the same work on a tree with no rules; the screen
on the generated tree agrees at −4.45%. On linux-v6.12 the change is not resolvable:
+2.13% [−3.19%, +5.30%] with .gitignore on, the widest interval of the track’s cells
and too wide to bound a regression, since its upper end passes the loop’s +3%
non-inferiority margin; and −1.25% [−4.46%, +0.25%] with it off, which excludes one,
against −2% to −4% predicted.
Both placebos there include zero.
The pre-registered row named both real trees under one bar; the decision rests on the
tree the mechanism targets, and the stacked end-to-end cell (exp-201) measures the
kernel tree again with the track’s other changes.
Supplementary runs. Beside the primary artifact, gzipped to keep the diff
reviewable: run-linux-v6.12.json.gz, the linux-v6.12 rerun;
run-linux-v6.12-invalidated.json.gz, the inconclusive first linux-v6.12 cell, kept
as the ledger asks; run-linux-balanced-1m.json.gz, the 12-pair screen.
Accepted on node-modules-dense, the directory-dense tree the mechanism targets: the
default tree is 3.6% faster by the deciding comparison and 7.3% by its replicate, the
generated screen 4.5%, and every placebo includes zero.
On linux-v6.12 the change is not resolvable, as the per-directory saving and exp-190’s
precedent allow: no regression on the --no-controls arm, and the controls-on arm too
wide to bound; the end-to-end cell measures it again.
Linux only in effect: the macOS listing carries every child’s attributes, so the change
is a no-op there (M11 in the platform review).
About 120 lines in c0da65ae, half of them the policy test.
Amended after review (R163-1). A stat is also an observation of failure: on a
directory that lists but refuses search (mode 0400), the measured build admitted a
subdirectory and a symlink from d_type where the full index reports each child as an
error, so “answers identical” held on the three subjects, none of which has such a
directory, and not on every tree.
The shipped policy (0e59c387) stats each listing’s children until one stat succeeds,
which proves the directory searchable, and only then takes kinds from d_type; the
transient-versus-indexed differentials now hold such a directory, and fail without the
latch when run as an unprivileged user.
statx is 72,075 on node-modules-dense and 87,656 on linux-v6.12 with the proof,
against the 70,416 and 87,006 above, so 83% and 89% of the saving is kept; the
difference is below what a 20-pair cell resolves and was not re-measured on wall.
Superseded by the age column (#191,
2026-10-09). A tree row’s age counts each directory’s and symlink’s own time, so the
folded tree stats every child again, as the full index does, and the product no longer
carries this change: its kept arm is now the control (review C11 on #191). So the
evidence report no longer credits today’s engine with this saving.
What the give-back costs is pre-registered as H193 and measured on Linux before 0.5.0
(fdu-088k).