pub enum CoderEventKind {
Show 27 variants
StateChanged {
from: String,
to: String,
},
ContractProposed {
contract: OutcomeContract,
},
EngineSelected {
engine: String,
reason: String,
},
EngineFallback {
from: String,
to: String,
reason: String,
},
ModelFallback {
from: String,
to: String,
reason: String,
},
IterationStarted {
n: u32,
max: u32,
},
InferenceWaiting {
elapsed_secs: u64,
},
OperatorGuidance {
text: String,
status: String,
},
InferenceRetry {
model: String,
attempt: u32,
reason: String,
backoff_ms: u64,
},
AuthRequired {
message: String,
wait_secs: u64,
},
BudgetExhausted {
reason: String,
elapsed_secs: u64,
iterations: u32,
},
InvocationRetried {
hypothesis: u32,
reason: String,
retries_remaining: u32,
},
PlanText {
text: String,
},
ToolCall {
tool: String,
params_preview: String,
},
ToolResult {
tool: String,
ok: bool,
preview: String,
},
CheckStarted {
name: String,
},
CheckCompleted {
result: CheckResult,
},
ContractBaseline {
results: Vec<CheckResult>,
gates_nothing: bool,
},
ExternalEvent {
raw: Value,
},
FindingProposed {
finding: NoChangeFinding,
},
FindingResolved {
accepted: bool,
comment: Option<String>,
},
DiffReady {
stat: String,
patch: String,
patch_truncated: bool,
patch_full_bytes: usize,
changed_paths: usize,
contract_overlap: Vec<CheckOverlap>,
overlap_disclosure: Option<String>,
},
UserInputRequested {
prompt: String,
},
UserInputExpired {
prompt: String,
waited_secs: u64,
},
ContractRevisionRejected {
request: String,
reason: String,
},
MergeCompleted {
branch: String,
},
Error {
message: String,
},
}Expand description
What happened. Serialized with "type": "snake_case_name" for WS clients.
Variants§
StateChanged
ContractProposed
Fields
contract: OutcomeContractEngineSelected
EngineFallback
ModelFallback
The preferred inference lane was skipped and a different model served
the call. Distinct from EngineFallback, which is about the coder
ENGINE (native vs an external CLI), not the model behind it.
Emitted at most once per PHASE — contract derivation, each contract revision, and the run loop announce independently, and a session that degrades in more than one of them emits more than one. The guard is against narrating every routing decision inside a phase, not against a second phase reporting a degrade the operator has not seen resolved.
Fields
IterationStarted
InferenceWaiting
A native model call is still pending; not evidence of tool execution.
OperatorGuidance
Status: queued, applied (included in the next turn), or not_applied.
InferenceRetry
Sanitized provider retry metadata from the inference engine.
AuthRequired
The run is blocked on sign-in and is waiting for the human, rather
than failing. Not terminal: if a credential appears within wait_secs
the session resumes from where it stopped, worktree intact.
Distinct from Error on purpose. A client should surface this as an
action the user can take (“sign in to continue”), because it is the one
failure mode a person standing at the machine can clear in seconds — and
previously it read as no inference backend is available, which points
at models and accounts instead of at the sign-in it actually needs.
Fields
BudgetExhausted
The session hit its wall-clock ceiling and the next iteration was not
admitted. Terminal, and the session ends Failed — it never reaches the
merge gate, which requires green checks. The worktree IS retained for
postmortem (the budget path forces keep_workspace_on_failure), so the
partial work survives on disk at workspace_path.
Fields
InvocationRetried
A worker invocation died mid-run (timeout / I/O) with the contract still red, and the same hypothesis is being re-invoked.
Distinct from IterationStarted on purpose: a retry costs no hypothesis,
so folding it in would make that event’s n/max misreport the budget.
A chronically flaky CLI is otherwise indistinguishable from a fast clean
one in the A/B’s wall-clock.
Fields
PlanText
ToolCall
ToolResult
CheckStarted
CheckCompleted
Fields
result: CheckResultContractBaseline
The contract evaluated against the unmodified worktree at session
start (car#707). Distinct from CheckStarted/CheckCompleted, which
mean “the contract is being evaluated on the work” — replaying those for
a baseline would show checks going green before a line was written.
gates_nothing is true when every check already passed, i.e. the
contract verifies nothing for this task.
ExternalEvent
FindingProposed
The loop nominated a “no code should change” conclusion. A nomination, not a verdict: the runtime decides what happens next.
Fields
finding: NoChangeFindingFindingResolved
A nominated finding was accepted or rejected.
DiffReady
Fields
patch: StringThe patch body, tail-capped to the configured budget. Named for what
it is; patch_truncated (the bool) says whether it is partial.
patch_truncated: boolTrue when patch is a tail. A UI must be able to say “you are
approving against a partial diff” without string-matching the
…[truncated]… marker (car#706).
changed_paths: usizeHow many distinct paths the diff touches. Named paths, not
files, because a rename contributes BOTH of its endpoints — one
file moved is two paths touched, and for a reviewer asking “what did
this session reach into” that is the honest number. stat carries it
too, but only as prose a client must parse; scope explosion is what a
reviewer most needs stated plainly before deciding whether to read
the patch at all.
contract_overlap: Vec<CheckOverlap>Contract checks whose commands execute a path this diff modified. Disclosure, never denial: editing tests is frequently the task, and the human at the gate is who should judge which case this is.
overlap_disclosure: Option<String>The rendered disclosure sentence, or None when nothing overlaps.
On the wire so every surface prints the SAME words. Hand-rolling it
per renderer had already lost “that is often legitimate” from both
the CLI and the host app while the log kept it — dropping the
non-accusatory half of a sentence whose entire design posture is
disclosure rather than accusation, and leaving the only tested copy
the one no human reads. contract_overlap stays alongside it for
machine consumers that want the structure.
UserInputRequested
UserInputExpired
The mid-session question’s answer window closed server-side without an answer. The loop carried on without one; the prompt is DEAD.
Its own event because a client has no other way to learn: the gate
simply stops being pending, which is a state a board can only discover
by asking again. Without this, a board kept rendering the question as
live — and counting it under “needs you” — until the operator happened
to refresh. It is also what drives the coder.session_changed fanout
that drops needs_you back to null.
Fields
ContractRevisionRejected
A coder.revise_contract request could NOT be honored: the redraft did
not validate, or the request was not expressible as checks. The session
stays at the gate with the PREVIOUS contract intact.
Its own event rather than a generic Error because the operator needs
to know the contract they are still looking at is the old one — a
revision that silently passes as applied is the failure mode this
exists to make impossible.
Fields
MergeCompleted
Error
Trait Implementations§
Source§impl Clone for CoderEventKind
impl Clone for CoderEventKind
Source§impl Debug for CoderEventKind
impl Debug for CoderEventKind
Source§impl<'de> Deserialize<'de> for CoderEventKind
impl<'de> Deserialize<'de> for CoderEventKind
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for CoderEventKind
impl RefUnwindSafe for CoderEventKind
impl Send for CoderEventKind
impl Sync for CoderEventKind
impl Unpin for CoderEventKind
impl UnsafeUnpin for CoderEventKind
impl UnwindSafe for CoderEventKind
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more