test(graph): make the fixture diagnostic see the object store, and git's own stderr - #98
Merged
Merged
Conversation
…t's own stderr
Seven occurrences of the e2e fixture fault produced no root cause, and this is
why: describeRepoState checked HEAD, refs and index.lock — all of which are
intact in every observed failure — and never looked at the object store, which
is what every observed failure is actually about. Its catch handler also took
.split("\n")[0], keeping the "Command failed: <argv>" line we already know and
discarding the stderr underneath, where git says WHAT it could not read.
Adds fsck, cat-file -t HEAD, the loose-object-directory count, the pack list,
and df — enough to say which object is gone and whether the store was emptied
or has one bad member — plus the real stderr on every probe.
Established while trying to reproduce this locally (2026-08-13):
- deleting HEAD's tree object reproduces `error: bad tree object HEAD`
byte-exactly on git 2.39 (Linux) and 2.50 (macOS), so that message means a
missing tree and nothing else;
- but rev-list SURVIVES a missing tree, and CI's rev-list failed too, so CI
lost commit objects as well — a chunk of the store, not one object;
- a full filesystem is NOT the mechanism: forcing ENOSPC fails loudly, names
"Out of diskspace", and leaves fsck clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
arozumenko
added a commit
that referenced
this pull request
Aug 13, 2026
First VSIX since 0.0.47 (2026-07-31), which shipped pack v36. Everything since
lands in this one:
- octograph, the git-history architecture graph, plus its Install/Rebuild
Graph commands and the bundled CLI payload;
- knowledge-explorer, the fifth pack skill — the knowledge vault is
obligatory, octograph enriches it where installed;
- a mission may now hold several workflows, one per execution loop
(implementation / testing / fixing), with the doctrine to choose between
them (#99, closing #60);
- the product-management SDLC bundle showing a real label instead of a bare
slug (#97);
- fixture diagnostics that can finally see the object store (#98).
Packaging also refreshed both model price tables, which is the only point
either can be updated — 2026-07-31 to 2026-08-13.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Seven occurrences of the
packages/graphe2e fixture fault have produced no root cause. This PR fixes the reason why, and records what a day of local experiments eliminated.The diagnostic was blind to the only thing that was ever wrong
describeRepoStatecheckedHEAD,refs/headsandindex.lock— all of which are intact in every observed failure — and never looked at the object store, which is what every observed failure is actually about. Its catch handler also did.split("\n")[0], keeping Node'sCommand failed: <argv>line (which we already know) and discarding git's stderr underneath it, where git says what it could not read.The one occurrence that named its own cause got there through the separate two-line slice in
step, not through the diagnostic.Now added:
fsck --connectivity-only,cat-file -t HEAD, the loose-object-directory count, the pack list,df, and the real stderr on every probe — enough to say which object is gone and whether the store was emptied or has one bad member.What the experiments established
The message means exactly one thing. Deleting HEAD's tree object reproduces
error: bad tree object HEADbyte-for-byte on git 2.39 (Linux, container) and git 2.50 (macOS). It is a missing tree, not a corrupt one and not a ref problem.CI's damage is bigger than one object. In that simulation
git rev-list --count --allsurvived — rev-list walks commits, not trees. On CI it failed. So CI lost commit objects as well: a chunk of the store went missing, which is why the "one transient hiccup" model never fit.Disk exhaustion is not the mechanism. Forcing ENOSPC on a size-capped filesystem makes git fail loudly (
fatal: … write error. Out of diskspace) and leaves the store healthy —fsckclean,rev-parse HEADandcat-file -t HEADboth fine. That is the opposite of the flake. The prior note ruled disk pressure out by measuring the suite's ~5 MB footprint; this rules it out by showing the failure mode is wrong at any level of fullness.The fixture's git sequence alone is decisively not sufficient. 3,100 fixture builds — 2,100 on macOS at 14 workers, 1,000 on Linux at 4 CPUs — ≈ 589,000 git invocations, zero failures. Each build is one
test (g)equivalent, and the 1.9%/suite rate is concentrated in that test, so if the sequence alone carried the risk this should have produced ~59 failures. P(0) ≈ e⁻⁵⁹. Something about the CI environment or the surrounding suite is required.No fixture is built at module or describe scope, so no fixture can be deleted out from under a later test by
mkdtempClean'sonTestFinished. Every suspicious-looking call site is inside a helper function called from a test body.What it did NOT establish
Root cause. I did not find it, and I am not claiming it.
The 25 full-suite Linux runs were clean but underpowered: at 1.9%/run the chance of seeing zero failures is ≈62%, so they rule out nothing. Meaningful power needs ~150 runs (P(0) ≈ 5.6%). The 3,100-build figure above is the only statistically strong result here, and it is an elimination, not a cause.
Verification
pnpm --filter @octoshell/graph test—fixture-retry(2) andconventions(30) green against the changed file; 25 clean full-suite runs on Linux.Knowledge note update follows once #95 merges (its seventh-observation section lives on that branch).
🤖 Generated with Claude Code