Skip to content

test(graph): make the fixture diagnostic see the object store, and git's own stderr - #98

Merged
arozumenko merged 1 commit into
mainfrom
fix/graph-fixture-object-diagnostics
Aug 13, 2026
Merged

test(graph): make the fixture diagnostic see the object store, and git's own stderr#98
arozumenko merged 1 commit into
mainfrom
fix/graph-fixture-object-diagnostics

Conversation

@arozumenko

Copy link
Copy Markdown
Collaborator

Seven occurrences of the packages/graph e2e 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

describeRepoState checked HEAD, refs/heads and index.lockall 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's Command 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 HEAD byte-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 --all survived — 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 healthyfsck clean, rev-parse HEAD and cat-file -t HEAD both 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's onTestFinished. 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 testfixture-retry (2) and conventions (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

…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
arozumenko merged commit bcc525d into main Aug 13, 2026
2 checks passed
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant