When mex graph status finds an active sidecar next to the store it skips
immutable inspection — correctly — but still prints placeholder values in the
same shape it prints measurements. Three of the five lines are then false.
To reproduce
On a 111-file TypeScript repository with a healthy, freshly indexed store:
$ mex graph status
Graph status: stale
Repository: main @ df89810df4f5
Last successful index: 2026-09-13T04:33:14.973Z
Sources: 1 changed (0 added, 0 modified, 1 deleted)
Parse health: 111 ok, 0 partial, 0 failed
Strand a non-empty WAL beside the store — an interrupted write leaves exactly
this — and run the same command against the same untouched database:
$ mex graph status
Graph status: degraded
Repository: main @ df89810df4f5
Last successful index: never
Sources: 0 changed (0 added, 0 modified, 0 deleted)
Parse health: 0 ok, 0 partial, 0 failed
WARNING GRAPH_INDEX_SIDECAR_ACTIVE: Graph maintenance or recovery is active (graph.db-wal); immutable inspection was skipped.
Next: mex graph repair
Nothing about the store changed between those two runs. mex graph repair
restores 111 ok and the real index timestamp immediately.
Parse health: 0 ok reads as "nothing parsed". It means "not inspected".
Last successful index: never is false — the store was indexed on 09-13.
Sources: 0 changed reads as "up to date". Nothing was compared.
--json is partly affected. lastSuccessfulIndexAt, indexedAt,
schemaVersion and the version fields all come back null, which is honest.
But parseHealth and changes come back as fully-populated zero objects:
"parseHealth": { "total": 0, "ok": 0, "partial": 0, "failed": 0,
"failedPaths": [], "failedPathsTruncated": false },
"changes": { "total": 0, "added": [], "modified": [], "deleted": [], ... }
A consumer cannot distinguish that from a store that genuinely parsed nothing.
Cause
printStatus (src/graph/cli-graph.ts:181) prints all five lines
unconditionally, with ?? "never" supplying the index-time placeholder.
src/graph/status.ts has 16 early-return paths that fill parse health
with emptyParseHealth(). The WAL is only the case reproduced here — an
unreadable sidecar, a containment failure or a failed invariant audit all
print the same zeros.
Expected behavior
Distinguish "not inspected" from "measured zero". In text, something like
Parse health: not inspected (graph.db-wal present), and suppress or mark the
index-time and sources lines on the same paths — that half is contained to
printStatus.
For JSON, prefer an additive inspected: false (or equivalent) over making
parseHealth and changes nullable. parseHealth alone has ~163 non-test
references, including invariant checks in src/graph/read-session.ts that
compare its counts against the file list, so widening the type is a much larger
change than the reporting bug warrants. An additive flag breaks no consumer.
Additional context
This was diagnosed publicly in #140 — "that placeholder reads like 'zero files
parsed' when it actually means 'not inspected'; we'll fix the wording" — but
nothing on main changes it and no issue tracks it. Filing so it is not lost.
The severity is that a clone's 0 ok was read there as a failed graph when the
store was intact.
When
mex graph statusfinds an active sidecar next to the store it skipsimmutable inspection — correctly — but still prints placeholder values in the
same shape it prints measurements. Three of the five lines are then false.
To reproduce
On a 111-file TypeScript repository with a healthy, freshly indexed store:
Strand a non-empty WAL beside the store — an interrupted write leaves exactly
this — and run the same command against the same untouched database:
Nothing about the store changed between those two runs.
mex graph repairrestores
111 okand the real index timestamp immediately.Parse health: 0 okreads as "nothing parsed". It means "not inspected".Last successful index: neveris false — the store was indexed on 09-13.Sources: 0 changedreads as "up to date". Nothing was compared.--jsonis partly affected.lastSuccessfulIndexAt,indexedAt,schemaVersionand the version fields all come backnull, which is honest.But
parseHealthandchangescome back as fully-populated zero objects:A consumer cannot distinguish that from a store that genuinely parsed nothing.
Cause
printStatus(src/graph/cli-graph.ts:181) prints all five linesunconditionally, with
?? "never"supplying the index-time placeholder.src/graph/status.tshas 16 early-return paths that fill parse healthwith
emptyParseHealth(). The WAL is only the case reproduced here — anunreadable sidecar, a containment failure or a failed invariant audit all
print the same zeros.
Expected behavior
Distinguish "not inspected" from "measured zero". In text, something like
Parse health: not inspected (graph.db-wal present), and suppress or mark theindex-time and sources lines on the same paths — that half is contained to
printStatus.For JSON, prefer an additive
inspected: false(or equivalent) over makingparseHealthandchangesnullable.parseHealthalone has ~163 non-testreferences, including invariant checks in
src/graph/read-session.tsthatcompare its counts against the file list, so widening the type is a much larger
change than the reporting bug warrants. An additive flag breaks no consumer.
Additional context
This was diagnosed publicly in #140 — "that placeholder reads like 'zero files
parsed' when it actually means 'not inspected'; we'll fix the wording" — but
nothing on
mainchanges it and no issue tracks it. Filing so it is not lost.The severity is that a clone's
0 okwas read there as a failed graph when thestore was intact.