Saphan StudioDocs
Reference/Command reference

saphan verify-stream

Deterministic, zero-LLM verification of a stream's worktree (build/vet/test/gofmt)

saphan verify-stream

Deterministic, zero-LLM verification of a stream's worktree (build/vet/test/gofmt)

saphan verify-stream <stream> [flags]

Run, in a stream's LOCAL worktree and in this fixed order — go build ./..., go vet ./..., go test -v -count=1 ./... (module-wide: parity with Makefile and CI), then gofmt. Every stage runs even after an earlier red, so the first failure cannot mask a later independent one.

The test step counts the tests that actually ran (from the test binary's own "=== RUN" lines) and carries that count as tests_executed in the record: an "ok" from a run that executed zero tests is RED, never a silent green, and a module with no test files at all gets its own named status (no-test-files) — an honest absence, not a defect, but still not a measured green.

gofmt alone scores differently: it scans the whole repo, but only files THIS STREAM changed since its recorded base can turn the verdict red — everything else it finds is "inherited drift", reported but never scored. When the stream's base cannot be resolved, the gofmt step reports "base-unknown" rather than guessing green or red.

The verdict is a durable RECORD, not only a print: it lands under <workspace>/.saphan/verify/<stream>/record.json carrying the worktree's HEAD sha AND tree state (clean/dirty) at the moment it ran — a dirty worktree can never certify green (verdict "green-dirty" instead), because "green on <sha>" is a claim about a commit, not about uncommitted edits sitting on top of it. Via --status, a later reader can see that HEAD or the tree state has since moved past it (STALE); --status exits non-zero whenever the answer is anything but a fresh, actually-green record.

A step that never reached a verdict on the code is never reported as a red. Each step has its own wall-clock budget (10 minutes by default, raised by setting verify.full.timeout to a longer Go duration), and a step that runs out of it records "timeout"; a step whose process was killed by a signal records "killed"; a step the engine could not run at all records "unrunnable". All three carry what an operator can do about them, and the closing line says the step did not finish rather than naming a build, vet, test or gofmt failure that was never measured.

A missing go/gofmt/git binary on PATH is a NAMED refusal (exit 2), checked before anything else in this verb runs, never a silent "ok". A worktree with no go.mod gets its own named refusal (not-a-go-worktree) rather than a build failure that was never this stream's to fix.

Local worktrees only — remote transport is explicitly out of scope; this verb never resolves or touches a path on any other machine.

Options

OptionTypeDefaultDescription
--statusboolfalseread the last recorded verdict without re-running checks; reports staleness against the live HEAD sha and tree state

On this page