Repository navigation
feat: structured, durable evidence for every check a pipeline gate runs - #422
Merged
Merged
Conversation
The first slice of loops (docs/loop-engineering-design.md §7, milestone A). A check's verdict is what a command did, captured by the daemon: result (pass / fail / inconclusive / error / cancelled), exit status or signal, bounded excerpts, the full output as artifact files, the verifier's digest, and the environment — persisted in the daemon DB. - evidence/runner.ts runs each check as its own process group, so a timeout, cancel, or the check's own exit kills everything it spawned; a test run that selects no tests is inconclusive, never a pass. - Pipeline command gates and execution probes record evidence, carry the failing output into the gate reason, and list their evidence on the phase. - evidence.get reads one record (pipeline:read, tenant- and owner-scoped; an id the caller cannot see is not_found); codeoid evidence <id> prints it; the halted phase in the web cockpit shows the latest check's output. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…te files, retention, cancellation - Checks run with the agent subprocess environment (no CODEOID_/ZEROID_/ TELEGRAM_), since their output now flows back to the worker. - Stored excerpts and gate diagnostics are redacted; artifacts are 0600 in 0700 directories; unrecorded checks use a private mkdtemp directory. - Zero-test detection scans every output line (go/cargo counts across the whole run), not the excerpt; excerpt cuts keep whole UTF-8 characters. - EvidenceService tracks live checks: pipeline.abort and daemon drain stop them. A retention sweep (30 days / 2 GiB, orphan dirs) runs off the boot path and daily; the per-stream artifact cap is 8 MiB. - evidence.get authorizes before any lookup; pipeline wire carries a phase's evidence in every status; stderr gets priority in gate diagnostics; the web view refetches when a newer check lands; the delayed SIGKILL is cleared once the group exits; a missing workdir is named as such. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…, log-safe redaction, resilient artifacts - A gate check stopped by an abort or shutdown no longer fails the gate: the engine drops the step unsaved, so the gate re-runs on resume instead of halting, burning a retry, or failing the pipeline. - An owner's abort also cancels checks it starts afterwards; shutdown refuses new checks. - Redaction uses log-specific rules over the whole excerpt (PEM blocks, JWTs, URL userinfo, auth headers, known token formats, secret-named keys) and keeps test names, paths, hashes and exit codes readable; excerpt edges are cut at line boundaries. - An artifact write error (disk full, EMFILE) no longer crashes the daemon; the artifact is marked truncated. - Artifact directories are stored relative to the evidence root and the sweep never removes a running check's directory. - Checks keep common toolchain variables (LC_*, XDG_*, CI, GOPATH, …) plus CODEOID_CHECK_ENV_ALLOW, never the daemon's credentials. - The web evidence cache is per connection and bounded; a git-diff probe that cannot run says so. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
rsharath
approved these changes
Oct 25, 2026
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.
What this adds
The first piece of loops (docs/loop-engineering-design.md §7, milestone A): every check a pipeline gate executes now leaves durable evidence: what ran, on which tree, its result, and its full output. Until now a gate's command output was thrown away and its verdict was just an exit code.
pass,fail,inconclusive,errororcancelled. A test probe that exits 0 after running no tests isinconclusive, not a pass. A missing command iserror. A check that runs past its time limit is stopped, along with everything it started, and recorded as a timed-outfail.codeoid evidence <id>prints a record.codeoid pipeline showlists each phase's evidence. A halted phase in the web cockpit has "Show check output".Behaviour change: an auto-derived
test/verifyprobe on a repo where the test command runs zero tests now fails as inconclusive. Packcommandgates are still judged on exit status alone.Review
Two independent audit rounds, each covering security and correctness.
Full suite: 3822 pass / 0 fail. Web typecheck and tests pass.
For agents: implementation
src/daemon/evidence/:types.ts:EvidenceRecord,CheckSpec.runner.ts:runCheck. The check runs withdetached(its own group) andcheckEnv()=buildSubprocessEnvplus a toolchain allowlist andCODEOID_CHECK_ENV_ALLOW. Output goes through a line-scannedZeroTestScan, head/tail excerpts are UTF-8 safe and cut at line boundaries, and artifact files are 0600 with an error listener.parsers.ts,redact.ts: log-specific rules.store.ts: theevidencetable, withartifact_dirrelative to the root.service.ts:EvidenceServicewith per-owner abort flags,abortAll,sweep(age, size, orphans; skips live dirs), andephemeralCheckvia mkdtemp.wire.ts:evidenceToWire. Paths are not exposed.gate-probes.tsand thepack.tscommand gate run throughctx.runCheck, returnevidenceIdsplusdiagnosticTail, and returncancelledwhen the check was stopped.engine.ts:GateCancelleddrops the step inrun(). Evidence ids go on the active phase, capped at 50.interface.ts:GateCtx.runCheck,GateVerdict.evidenceIds/cancelled,PipelinePhase.evidence.session-manager.ts:EvidenceService. The sweep runs 60 s after boot and then daily, and its timers are cleared indrain.abortAllruns indrain;abortOwnerruns onpipeline.abort.#evidenceGetcheckspipeline:readand the pipeline before looking anything up, and returnsnot_foundfor anything the caller can't see.evidencefor every status.packages/protocol/src/evidence.ts(evidence.get/evidence.record), plus its schema.codeoid evidence,src/terminal/evidence-format.ts, and a pipeline-format line.EvidenceView/EvidenceLinkandstate/evidence.ts(cached per connection, bounded).🤖 Generated with Claude Code