Skip to content

writ status fails on a store that has never been written; a fresh install cannot run it #756

Closed

Description

@David-Noble-at-work

Feature: #762 — The writ lifecycle surface: reconcile, scopes, and the vocabulary settlement

writ status against a store that has never been written fails, where it should report that nothing has run.

$ writ status --store "$(mktemp -d)"
Error: read run index /tmp/tmp.XYZ/index.ndjson: open /tmp/tmp.XYZ/index.ndjson: no such file or directory

Why this surfaced now

--store was registered and read nowhere until #753, so the empty-store path was unreachable: every
invocation folded the default store, which on a developed machine always has an index. Fixing the flag made
the state reachable for the first time.

It is not confined to --store. A machine that has installed the suite and not yet deployed anything has no
index either, so writ status fails on a fresh install for the same reason -- the first thing a new user is
likely to run.

Why an absent index is not an error

An index that cannot be read and an index that does not exist are different facts. The first is a store
whose contents disagree with itself, which Health.Findings already reports without failing. The second is
a store where nothing has run, which is the ordinary state of a new one and the honest answer to the
question writ status asks.

The report already has a shape for it -- runs: 0, entries: [] -- and reaches it whenever the index is
present and empty. Only the missing-file case diverges.

Fix

Treat a missing index as an empty one. A read error that is not fs.ErrNotExist stays an error, since a
store that exists and cannot be read is a real failure.

Care is needed in one place: entries currently serializes as null rather than [], because a nil slice
marshals to null. jq '.entries[]' errors on null and yields nothing on [], so the empty case should
produce the latter. packages has the opposite convention -- omitempty, so it disappears entirely --
which is worth settling at the same time: one struct should not carry two meanings of empty.

Verification

  • writ status --store <fresh> exits 0 and reports runs: 0 with no findings.
  • -o json gives "entries": [], not null, so jq '.entries[]' yields nothing rather than failing.
  • A store whose index exists but cannot be read still fails, and names the path.
  • A store whose index references documents that are gone still reports findings rather than failing, as it
    does today.

Ruled 2026-09-23 (schedule #916, lane 4, PR B)

Reconcile is valid only after a deployment (#762). Three exit codes, so a script can gate on the answer the way
git diff --exit-code does:

Answer Exit
never deployed: no record to compare against not-found -- ExitNoInput (66, EX_NOINPUT), the sysexits code for input that cannot be opened
deployed and clean: the system matches the record ExitOK (0)
deployed and drifted: any absent, changed, dangling or stale finding (#923) ExitError (1): the command ran; the answer is drift

This issue was filed against the opposite reading (reconcile works on a fresh install); it closes the ruled way.
The code that assigns the three is this lane's; the vocabulary of the findings is #923's.

Metadata

Metadata

Labels

Area:CLICommand-line interfaceEpic:WritDeploymentwrit deployment: layers, adoption, and driftThread:WritSelfInstalla fresh machine installs writ and can use itbugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions