Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9b10729
perf: batch patch-chain reads through one log stream per chain
flyingrobots Aug 15, 2026
fecdc11
fix: address review findings on batched patch discovery
flyingrobots Aug 18, 2026
9f4f035
fix: constrain bulk chain reads to first-parent traversal
flyingrobots Aug 18, 2026
781f747
fix: honour firstParent in the in-memory persistence
flyingrobots Aug 18, 2026
61c740b
fix: bound the bulk chain read to the walked range
flyingrobots Aug 18, 2026
d3ee489
test: cover the fallback, cycle and non-ancestor stopAt paths
flyingrobots Aug 21, 2026
706db08
test: hold every adapter to the log traversal contract
flyingrobots Aug 21, 2026
a105704
perf: gate the v19 benchmark on Git command counts
flyingrobots Aug 21, 2026
a320611
fix: make an incomplete bulk chain read observable
flyingrobots Aug 21, 2026
d9d82c3
refactor: validate benchmark evidence instead of asserting its shape
flyingrobots Aug 21, 2026
23de781
perf: tighten Git-command ceilings to reference-runner evidence
flyingrobots Aug 21, 2026
e9de9a1
fix: version the policy format and gate ceilings on CI evidence
flyingrobots Aug 21, 2026
acfc7d9
perf: consume git-cas 6.5.7 session reads
flyingrobots Aug 23, 2026
270bca3
test: ratchet line coverage to 93.03 percent
flyingrobots Aug 23, 2026
6fd42cc
perf: preserve Git sessions in benchmark plumbing
flyingrobots Aug 23, 2026
e5c4bc9
perf: recalibrate session-aware Git command gates
flyingrobots Aug 23, 2026
954bff8
perf: preserve page batches in benchmark workspaces
flyingrobots Aug 23, 2026
d9ca354
refactor: split performance workspace recorder
flyingrobots Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,75 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
### Performance

- Patch-chain traversal (`PatchDiscovery.loadPatchChainFromSha`,
`PatchDiscovery.discoverTicks`) now reads chain metadata with a single bulk
`logNodesStream` history read per chain instead of one `getNodeInfo` call per
commit. On the Git adapter every `getNodeInfo` call is a `git show`
subprocess, so materializing a graph previously spawned one subprocess per
patch commit, serially — O(history × spawn latency) for every read. Patch
payload reads now run with bounded concurrency (8) while preserving
chronological order and read-error behavior. When several payload reads fail,
the error raised is the one belonging to the earliest patch in chain order
rather than whichever rejected first in wall-clock time, so the failure a
caller observes is deterministic. Persistences without a usable bulk log
surface (or commits missing from the bulk read) fall back to the legacy
per-commit walk and its error surface. Both degradations are logged — a bulk
read that throws, and a bulk read that succeeds while omitting commits — so a
silent return to per-commit cost is observable rather than merely correct. Measured as an A/B on two
fresh copies of one real graph whose largest writer chain holds 745 patch
commits, three reads and two captures each: median read time went from
80.0 s to 9.3 s, and median capture from 59.0 s to 17.1 s. Upgrading the
runtime dependency from `@git-stunts/git-cas` 6.5.5 to 6.5.7 also completes
the payload half of the fix: on twin disposable copies of the same current
Think mind, a consumer-level spawn census on this branch fell from 3,205 Git
child starts to 27. All 3,179 one-shot `git cat-file blob` children became
zero; two bounded persistent `git cat-file --batch-command` sessions covered
the object-read path instead. The 54 emitted JSON events had the same semantic
digest after removing only their per-run timestamps. This is process-topology
and output-equivalence evidence, not a claim that arbitrary large payloads
are buffered or that every Git process has been eliminated.

### Changed

- The minimum `@git-stunts/git-cas` runtime dependency is now 6.5.7. Because
git-cas includes its package version in newly written manifest metadata, the
verified v17 migration-reading fixture's content handle advances with the
dependency while its legacy equivalence facts remain unchanged.
- `LogNodesOptions` gains `firstParent` and `stopAt`. Chain readers advance by
first parent and stop at a known boundary, so the history read is now
constrained the same way: a merge's side branch is never streamed, and the
read is bounded to `stopAt..ref` rather than running to the root of history.
Both options are opt-in and default to the previous behaviour.

### Added

- The v19 performance gate now blocks on Git command counts as well as CPU.
`benchmarks/v19/policy.json` gains `absolute.gitCommandMedian` per scenario and
`relative.gitCommandRegressionRatio`, and the gate summary reports head and base
counts. The benchmark plumbing delegates and counts persistent `cat-file`,
`mktree`, and `fast-import` sessions, so instrumentation preserves the same
session topology as production instead of degrading a session-capable adapter
into one-shot commands. Command counts are structural: they are decided by
which code paths run, not by how fast the runner is. This is measured rather
than assumed: the ubuntu-24.04 reference runner and a local arm64 machine report
identical counts per scenario (1521 / 30 / 1409) despite differing in
architecture, OS, Node version, and Git version, while their CPU medians differ
materially. Five measured runs on each machine returned the same count every
time (MAD 0). The checks therefore carry no noise floor, and the absolute
ceilings sit about 1.15x above the observed count — tight enough to force review
of a structural change to the storage path, loose enough to absorb a small
legitimate addition. On the reference runner, the dependency and benchmark
plumbing change reduced cold/warm/incremental Git commands from
2758 / 543 / 2788 to 1521 / 30 / 1409 and CPU medians by
28.4% / 59.0% / 33.5%. Together the gates catch a subprocess-count regression
that leaves the CPU envelope untouched.
Scope, stated plainly: the current corpus writes each segment as a single
patch, so every scenario replays a one-patch chain. These counts therefore
gate object and payload traffic, not chain-traversal depth, and they would not
by themselves have caught the per-commit walk fixed above. Giving the fixture a
multi-patch chain is tracked separately.
- `intent.entity.add({ subject, properties })` creates one entity occurrence and
its initial payload in a single patch. The lowered patch declares an empty
read set and exactly one subject write. That declaration describes the
Expand Down
101 changes: 61 additions & 40 deletions benchmarks/v19/calibration.json
Original file line number Diff line number Diff line change
@@ -1,52 +1,58 @@
{
"schemaVersion": 1,
"sourceCommit": "490ffc8c047033531281c58d4b431aa21a52877d",
"generatedAt": "2026-07-26T03:30:11.485Z",
"sourceCommit": "6fd42cc7ae33b02a4370236010a67cde08a655e4",
"generatedAt": "2026-08-23T18:22:04.400Z",
"evidence": {
"artifact": "v19-performance-a166926815bd73e78b546095a4d142db17b2fd1b",
"run": "https://github.com/git-stunts/git-warp/actions/runs/30186045644"
"artifact": "v19-performance-cbf17fc96555c9799043a24f0af522718c378caa",
"run": "https://github.com/git-stunts/git-warp/actions/runs/32657452817"
},
"environment": {
"architecture": "x64",
"cpuCount": 4,
"cpuModel": "AMD EPYC 7763 64-Core Processor",
"git": "git version 2.54.0",
"gitCas": "6.5.3",
"node": "v22.23.1",
"git": "git version 2.55.0",
"gitCas": "6.5.7",
"node": "v22.23.2",
"platform": "linux",
"runner": "github-hosted ubuntu-24.04"
"runner": "github-hosted"
},
"corpus": {
"baseNodeCount": 25,
"suffixNodeCount": 5,
"propertyBytesPerNode": 256,
"measuredRuns": 3,
"measuredRuns": 5,
"warmupRuns": 1
},
"observed": {
"cold-materialize": {
"cpuTotalMedianMs": 11440.000000000002,
"cpuTotalMadMs": 300.0000000000018,
"maximumRssBytes": 149114880,
"maximumHeapUsedBytes": 55814856
"cpuTotalMedianMs": 7020,
"cpuTotalMadMs": 70,
"maximumRssBytes": 147722240,
"maximumHeapUsedBytes": 53719200,
"gitCommandMedian": 1521,
"gitCommandMadCount": 0
},
"warm-materialize": {
"cpuTotalMedianMs": 2889.9999999999995,
"cpuTotalMadMs": 90.00000000000045,
"maximumRssBytes": 129462272,
"maximumHeapUsedBytes": 44256456
"cpuTotalMedianMs": 980,
"cpuTotalMadMs": 30,
"maximumRssBytes": 128880640,
"maximumHeapUsedBytes": 39450024,
"gitCommandMedian": 30,
"gitCommandMadCount": 0
},
"incremental-materialize": {
"cpuTotalMedianMs": 11240,
"cpuTotalMadMs": 320,
"maximumRssBytes": 151187456,
"maximumHeapUsedBytes": 57289656
"cpuTotalMedianMs": 6550.000000000001,
"cpuTotalMadMs": 49.99999999999909,
"maximumRssBytes": 147767296,
"maximumHeapUsedBytes": 54754208,
"gitCommandMedian": 1409,
"gitCommandMadCount": 0
},
"streaming": {
"generationMaximumRssBytes": 196218880,
"generationPeakHeapUsedBytes": 52742016,
"maximumRssBytes": 145403904,
"peakHeapUsedBytes": 38016568
"generationMaximumRssBytes": 204263424,
"generationPeakHeapUsedBytes": 61427008,
"maximumRssBytes": 150323200,
"peakHeapUsedBytes": 37747672
}
},
"localCalibration": {
Expand All @@ -55,30 +61,38 @@
"cpuCount": 10,
"cpuModel": "Apple M1 Pro",
"git": "git version 2.50.1 (Apple Git-155)",
"gitCas": "6.5.3",
"gitCas": "6.5.7",
"node": "v26.0.0",
"platform": "darwin"
},
"observed": {
"cold-materialize": {
"cpuTotalMedianMs": 3993.154,
"cpuTotalMadMs": 11.974,
"maximumRssBytes": 152158208,
"maximumHeapUsedBytes": 57703656
"cpuTotalMedianMs": 2543.928,
"cpuTotalMadMs": 21.105000000000018,
"maximumRssBytes": 161824768,
"maximumHeapUsedBytes": 59778136,
"gitCommandMedian": 1521,
"gitCommandMadCount": 0
},
"warm-materialize": {
"cpuTotalMedianMs": 834.786,
"cpuTotalMadMs": 4.831,
"maximumRssBytes": 120930304,
"maximumHeapUsedBytes": 39929144
"cpuTotalMedianMs": 142.252,
"cpuTotalMadMs": 1.6859999999999786,
"maximumRssBytes": 118980608,
"maximumHeapUsedBytes": 37857744,
"gitCommandMedian": 30,
"gitCommandMadCount": 0
},
"incremental-materialize": {
"cpuTotalMedianMs": 4276.35,
"cpuTotalMadMs": 89.092,
"maximumRssBytes": 152928256,
"maximumHeapUsedBytes": 58384360
"cpuTotalMedianMs": 2359.879,
"cpuTotalMadMs": 12.159000000000106,
"maximumRssBytes": 159940608,
"maximumHeapUsedBytes": 58520568,
"gitCommandMedian": 1409,
"gitCommandMadCount": 0
}
}
},
"measuredRuns": 5,
"warmupRuns": 1
},
"rejectedProfiles": [
{
Expand All @@ -95,6 +109,13 @@
},
"streamingMaxRssBytes": 268435456,
"streamingPeakHeapUsedBytes": 100663296,
"note": "CI-runner measurements are primary. Noise floors cover hosted-runner MAD; absolute materialization and streaming ceilings retain reviewed headroom while blocking gross regressions."
"note": "CI-runner measurements are primary. Noise floors cover hosted-runner MAD; absolute materialization and streaming ceilings retain reviewed headroom while blocking gross regressions.",
"gitCommandRegressionRatio": 1.05,
"gitCommandMedian": {
"cold-materialize": 1750,
"warm-materialize": 35,
"incremental-materialize": 1625
},
"gitCommandNote": "Git command counts are structural, not timing. The reference runner and a local arm64 machine report identical session-aware counts per scenario (1521 / 30 / 1409) despite differing in architecture, OS, Node version (v22.23.2 vs v26.0.0), and Git version (2.55.0 vs 2.50.1), while their CPU medians differ materially. Five measured runs on each machine returned the same count every time (MAD 0). Machine independence is therefore measured, not assumed, which is why the relative ratio carries no noise floor. Absolute ceilings sit about 1.15x above the observed count \u2014 tight enough that a structural change to the storage path must be reviewed, loose enough to absorb a small legitimate addition. Evidence: https://github.com/git-stunts/git-warp/actions/runs/32657452817"
}
}
10 changes: 8 additions & 2 deletions benchmarks/v19/policy.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
{
"schemaVersion": 1,
"schemaVersion": 2,
"wallTime": "diagnostic",
"absolute": {
"cpuTotalMedianMs": {
"cold-materialize": 30000,
"warm-materialize": 10000,
"incremental-materialize": 30000
},
"gitCommandMedian": {
"cold-materialize": 1750,
"warm-materialize": 35,
"incremental-materialize": 1625
},
"maxRssBytes": {
"cold-materialize": 402653184,
"warm-materialize": 268435456,
Expand All @@ -24,7 +29,8 @@
"warm-materialize": 50,
"incremental-materialize": 250
},
"cpuRegressionRatio": 1.15
"cpuRegressionRatio": 1.15,
"gitCommandRegressionRatio": 1.05
},
"streaming": {
"maxRssBytes": 268435456,
Expand Down
93 changes: 21 additions & 72 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
"@flyingrobots/bijou-node": "^7.2.0",
"@flyingrobots/bijou-tui": "^7.2.0",
"@git-stunts/alfred": "^0.10.4",
"@git-stunts/git-cas": "^6.5.5",
"@git-stunts/git-cas": "^6.5.7",
"@git-stunts/plumbing": "^3.2.0",
"@git-stunts/trailer-codec": "^2.1.1",
"@noble/hashes": "^2.2.0",
Expand Down
Loading
Loading