Skip to main content

Module reject

Module reject 

Source
Expand description

Rejections that name the repair.

An agent that is told “stale head” learns that something failed. An agent told what was expected, what was found, and which of a small set of actions is admissible can act without a human. Two 2026 studies (arXiv:2607.14167, arXiv:2606.05037) measure a large gain in agent task success from errors that name the repair, and both isolate it to naming admissible alternatives — not to verbosity, and not to JSON rather than prose. The effect was null on at least one small model, so the magnitude is directional; the mechanism is what this implements.

§Why this is not on the sequencer seam

SubmitPolicy::check still returns Result<(), String>. Reason codes and next actions are properties of the API surface: they say what an HTTP client should do next. Pushing them into L2 admission would make the sequencer carry transport shape, and SubmitPolicy is implemented by things with no HTTP surface at all. So the policy renders a Rejection into its reason string, and the HTTP boundary decodes it — Rejection::decode falls back to a plain message for any reason that did not come from here, so nothing is lost when a rejection originates elsewhere.

Shape follows RFC 9457 (application/problem+json) loosely: type becomes the stable code, detail becomes error. It is not served as application/problem+json because every existing client and test reads error out of an ordinary JSON body, and changing the media type would break them for no gain an agent can use.

The symptom-first companion to the code table below:

§Troubleshooting

Symptoms and fixes. ERRORS.md, generated from the node’s rejection table, is the authority on any code field.

SymptomLikely causeFix
cargo build pulls huge tree / sqlite errorschoir-actor / rivetkitKeep .cargo/config.toml. Default members exclude actor; use -p choir-actor only when needed.
choir-actor ignored test fails / download brokenrivetkit 2.3.10 auto-downloadRIVETKIT_ENGINE_AUTO_DOWNLOAD=1 cargo test -p choir-actor -- --ignored
Node refuses bind addressNon-loopback without TLSAdd --tls-cert / --tls-key, or stay on 127.0.0.1 / SSH tunnel
/api/view → 401Auth enabled (expected)Pass -u user:token or --auth-file / --auth-user
Browser asks for a username/passwordAuth is mandatory on every endpointEnter a user and token from --auth-file. Only repositories granted to @anon are served anonymously (D78)
Push not in /api/viewRepository served without its pre-receive hookchoir repo create <owner/repo.git>, or restart the node
unknown_keyKey not in --keys-filechoir key … [channel] >> keys-file (hot-reloaded)
bad_signatureSignature does not cover the bytes sent; key is trustedRe-sign the exact (channel, payload). Unexpected: someone replayed a signature
stale_headCAS lost the raceRe-read /api/view, rebase on actual, resubmit
assignment_error / empty reviewersEmpty --reviewers-fileAdd at least two operator/… channels
review_requiredProtected ref, insufficient weightNode-drawn review, two operators approve, then push
Workspace slow / failsNo CoW FSUse APFS or btrfs
Lost submit responseNetwork blip after acceptResubmit identical signed bytes: already_applied: true (ERRORS.md)
Node will not start, log reported corruptA fully-written record breaks the chain mid-logchoir repair <log> --verify names the first bad record. Mid-log damage is a restore
A <log>.torn-<offset> file appearedKilled mid-write; the partial tail was quarantinedExpected. Nothing reads it
A submitter is told its quota is exhaustedThat actor has 512 ops awaiting a decisionNot the D37 quota. Retry when one completes
A restored node printed choir: retracted and refs are goneStarted before the git objects were in placeStart again from the backup into a clean root. Objects go in before first boot: docs/runbook-restore.md

Rejection code table: ERRORS.md.

Structs§

Rejection
A refusal, with enough for a client to decide what to do next.

Enums§

Code
Stable, machine-readable rejection reasons.

Functions§

errors_md
ERRORS.md: every code and what to do about it.
from_view_error
Maps a ViewError onto a rejection, unpacking the states it already carries rather than stringifying them into prose.