Skip to main content

EventKind

Enum EventKind 

Source
pub enum EventKind {
Show 55 variants MissionCreated { goal: String, base_branch: String, mission_branch: String, config: MissionConfig, }, PlanApproved { plan: Plan, base_sha: Option<String>, }, PlanRevisionProposed { revision: u32, plan: Plan, instructions: String, }, PlanRevised { revision: u32, plan: Plan, }, PlanRevisionRejected { revision: u32, reason: String, }, GrantRequested { milestone_id: String, kind: GrantKind, command: String, }, GrantApproved { kind: GrantKind, command: String, }, GrantDenied { kind: GrantKind, command: String, reason: String, }, MilestoneStarted { milestone_id: String, start_sha: String, }, FeatureStarted { feature_id: String, }, FeatureProgress { feature_id: String, base_sha: String, commits: Vec<String>, }, WorkerSpawned {
Show 13 fields run_id: String, role: Role, feature_id: Option<String>, milestone_id: Option<String>, candidate: Option<CandidateLink>, executor_route: Option<ExecutorRoute>, sdk_session_id: String, model: String, backend: Option<BackendKind>, quant: String, weight_hash: Option<String>, prompt_hash: String, transcript_path: String,
}, WorkerMessage { run_id: String, tag: String, content: String, }, WorkerEgressDenied { run_id: String, denials: Vec<EgressDenial>, omitted_count: u64, }, WorkerCompleted { run_id: String, result: RunResult, tokens: TokenUsage, cost_usd: Option<f64>, report: Option<WorkerReport>, }, FeatureCompleted { feature_id: String, commits: Vec<String>, }, FeatureFailed { feature_id: String, reason: String, commits: Vec<String>, }, FeatureSkipped { feature_id: String, reason: String, }, MilestoneValidating { milestone_id: String, }, ValidationFinding { milestone_id: String, run_id: String, finding: Finding, }, ValidatorTamper { milestone_id: String, run_id: String, role: Role, head_before: String, head_after: String, appeared: Vec<String>, resolved: Vec<String>, git_metadata_changed: bool, git_metadata_fields: Vec<String>, }, ValidationSnapshot { milestone_id: String, role: Role, path: String, target_tier: String, creation_ms: u64, detail: Option<String>, }, ValidationConfirm { milestone_id: String, local_run_id: String, confirm_run_id: String, confirmed: Vec<String>, disagreements: Vec<Finding>, judgment_opportunity: bool, }, ValidationPtyTranscript { milestone_id: String, assertion_id: String, verdict: GateVerdict, artefact_ref: String, detail: Option<String>, }, GateResult { gate: String, surface: GateSurface, kind: GateKind, index: u32, verdict: GateVerdict, artefact_ref: String, artefact_detail: Option<String>, score: Option<f64>, threshold: Option<f64>, rule_ids: Vec<String>, }, HookGateFired { run_id: String, gate: String, hook_event: String, tool: String, subject: String, verdict: String, detail: Option<String>, }, DivergenceNoted { unit: String, candidates: Vec<DivergenceCandidate>, diverged: bool, }, DivergenceResolved { unit: String, selected: Option<u32>, reason: String, decided_by: String, }, FixFeatureCreated { milestone_id: String, feature: Feature, }, TierEscalated { milestone_id: String, from: ExecutorTier, to: ExecutorTier, reason: String, }, WorkerEscalated { run_id: String, feature_id: String, from: ExecutorTier, to: ExecutorTier, reason: String, }, QuestionOpened { question_id: String, role: Role, text: String, options: Vec<String>, run_id: Option<String>, feature_id: Option<String>, milestone_id: Option<String>, }, QuestionAnswered { question_id: String, answer: String, via: String, option: Option<u32>, }, QuestionCleared { question_id: String, why: String, }, MilestoneBlocked { milestone_id: String, reason: String, block_context: Option<BlockContext>, }, MilestoneUnblocked { milestone_id: String, reason: String, block_context: Option<BlockContext>, validator_guidance: Option<String>, }, MilestoneCompleted { milestone_id: String, tag: Option<String>, }, MissionValidating {}, MissionPaused {}, MissionResumed {}, UserMessage { text: String, interrupt: bool, }, OrchestratorDecision { summary: String, detail: Option<String>, }, SecretRedacted { rule_id: String, fingerprint: String, location: String, }, ConfigChanged { patch: Value, }, MissionCompleted {}, MissionFailed { reason: String, }, MissionAbandoned { reason: String, }, WorkspaceProvisioned { provider: String, cwd: String, detail: Option<String>, takeover: Option<String>, previews: Option<Vec<ProvisionedPreview>>, }, WorkspaceReadinessReport { outcome: String, detail: Option<String>, }, WorkspaceTeardown { mode: String, state: Option<String>, }, WorkspaceProviderPinned { provider: String, template: String, version: String, }, StandardsResolved { source: String, pack_name: String, standards_root: String, digest: String, stage: String, task_class: Option<String>, touch_set: Vec<String>, context_paths: Vec<String>, rules: Vec<StandardsRuleRef>, approval_seq: u64, }, StandardsDrifted { approved_digest: String, current_digest: Option<String>, surface: String, changed_rules: Vec<String>, }, StandardsWaiverApproved { rule_id: String, rule_revision: u64, manifest_digest: String, approval_seq: u64, finding_fingerprint: String, paths: Vec<String>, diff_digest: String, reason: String, approver: String, surface: String, expires_at: DateTime<Utc>, }, StandardsAttestationApproved { rule_id: String, rule_revision: u64, manifest_digest: String, approval_seq: u64, paths: Vec<String>, diff_digest: String, reason: String, approver: String, surface: String, },
}
Expand description

Serialized as "type": "<dotted.name>", "payload": { ... }.

Variants§

§

MissionCreated

Fields

§goal: String
§base_branch: String
§mission_branch: String
§

PlanApproved

Fields

§plan: Plan
§base_sha: Option<String>

Base-branch commit SHA pinned at approval time (validation contract diffs against this, not the moving base branch).

§

PlanRevisionProposed

Fields

§revision: u32
§plan: Plan
§instructions: String
§

PlanRevised

Fields

§revision: u32
§plan: Plan
§

PlanRevisionRejected

Fields

§revision: u32
§reason: String
§

GrantRequested

A run was stopped by a capability boundary and parks the milestone’s validation for an operator approve/deny decision — the capability-denial analogue of plan.revision.proposed. kind selects the boundary: a command (validator command outside its allow-set → command_grants), a touch-path (worker write outside the touch_settouch_set), a worker-deny (worker command blocked by a deny rule → deny_exceptions), or an egress (sandboxed run refused a destination by the egress proxy → egress_grants). Validators/sweeps are keyed to a milestone (they diff its start..HEAD), so this is too. Deny is the default; an unanswered request times out to grant.denied. command holds the target (a command, a path glob, a deny rule, or host:port).

Fields

§milestone_id: String
§command: String
§

GrantApproved

Operator approved the parked grant. The reducer extends the list kind selects (command_grants, touch_set, deny_exceptions, or egress_grants), extend-only, so the retried run clears the boundary.

Fields

§command: String
§

GrantDenied

Operator denied the parked grant, or it timed out (deny-default). A denied command or egress grant blocks the milestone (refusal); a denied touch-path grant lets the out-of-contract write flow to the normal fix/waive path.

Fields

§command: String
§reason: String
§

MilestoneStarted

Fields

§milestone_id: String
§start_sha: String

SHA at milestone start; validators diff start..HEAD (§4.4).

§

FeatureStarted

Fields

§feature_id: String
§

FeatureProgress

Engine-observed sequential feature baseline and cumulative commit receipts. Recorded before execution and after checkpoints, so retries and resume cannot turn retained work into an apparently commitless feature.

Fields

§feature_id: String
§base_sha: String
§commits: Vec<String>
§

WorkerSpawned

Fields

§run_id: String
§role: Role
§feature_id: Option<String>
§milestone_id: Option<String>
§candidate: Option<CandidateLink>

Sibling-candidate linkage when this run is one stream of a heterogeneous dispatch pool (KRZ-303): which unit it belongs to, the stream’s index, N, and the backend it ran. Additive; absent on ordinary runs and in every pre-pool log — None never hits the wire. Carried on worker.spawned (not worker.completed) so the run is a labelled candidate from the moment it exists.

§executor_route: Option<ExecutorRoute>

The effective executor route and the rule that decided it (ticket routing-rules-config): routing is provenance, not a hidden implementation detail, so it rides the same event that already records the model. Additive; present only on Worker-role spawns of missions whose seed carried a task class — absent everywhere else and in every pre-provenance log, where it folds to None and None never hits the wire.

§sdk_session_id: String
§model: String
§backend: Option<BackendKind>

Actual dispatch backend after resolution/fallback; absent in old logs.

§quant: String

Quantization of the model weights used for this run (provenance).

§weight_hash: Option<String>

Hash of the model weights used for this run, when known (provenance).

§prompt_hash: String
§transcript_path: String
§

WorkerMessage

Throttled stream deltas; also carries denied guardrail hits (§4.7).

Fields

§run_id: String
§tag: String

“text” | “tool-use” | “tool-result” | “denied” | “system”

§content: String

Scrubbed + truncated human-readable content.

§

WorkerEgressDenied

Durable, run-attributed audit record for destinations refused by the filtering egress proxy. Record-only: grant handling still uses the in-memory crate::egress_proxy::EgressDenial returned by the session, while this event survives runtime-artifact cleanup and can be projected as bounded validator evidence.

Fields

§run_id: String
§omitted_count: u64

Repeated or over-cap denial records excluded from denials. Additive default keeps an early/pre-field event readable.

§

WorkerCompleted

Fields

§run_id: String
§result: RunResult
§tokens: TokenUsage
§cost_usd: Option<f64>
§

FeatureCompleted

Fields

§feature_id: String
§commits: Vec<String>
§

FeatureFailed

Fields

§feature_id: String
§reason: String
§commits: Vec<String>

Commits the failed feature landed on the mission branch before the judgement (empty for a run that never committed — the m-eee81f auth-death class — and for parallel/dirty-tree paths where nothing reached the branch). Recorded so the supersession guard can tell “failed with real work” (started; re-proposal rejects) from “failed commitless” (re-proposable). Additive; old logs default to empty.

§

FeatureSkipped

Fields

§feature_id: String
§reason: String
§

MilestoneValidating

Fields

§milestone_id: String
§

ValidationFinding

Fields

§milestone_id: String
§run_id: String
§finding: Finding
§

ValidatorTamper

A validator session altered its checkout (validator immutability proof, ticket validator-immutability-proof): the HEAD/index/worktree identity assertion around every validator session found drift, so the round failed honestly — the milestone blocks, with no retry and no waivable finding. The payload records WHAT changed: HEAD before/after and the git status --porcelain entries gained/lost across the session. Additive event; absent in pre-field logs.

Fields

§milestone_id: String
§run_id: String
§role: Role
§head_before: String

HEAD when the session started.

§head_after: String

HEAD when the session ended (== headBefore unless the session moved it, e.g. a validator-run git commit).

§appeared: Vec<String>

Porcelain entries present after but not before (the session’s writes: M <path>, A <path>, ?? <path>, …).

§resolved: Vec<String>

Porcelain entries present before but not after (the session reverted or hid a pre-existing dirty state — equally a mutation).

§git_metadata_changed: bool

Whether .git metadata (config/hooks/refs) changed across the session — the checkout can look identical while the plumbing was weaponized (core.fsmonitor/core.hooksPath execute on the ENGINE’s own git invocations; a moved ref retargets later merges).

§git_metadata_fields: Vec<String>

WHICH metadata surfaces changed (additive): config / hooks / refs / index-flags / info-exclude — a tripwire fire is diagnosable from the event alone.

§

ValidationSnapshot

A validator session ran in a throwaway snapshot of the session checkout (copy-on-write immutable validator snapshot, the follow-up to ticket validator-immutability-proof; module crate::validator_snapshot): HEAD plus the worker’s uncommitted diff and untracked files, a warmed target/ copy, discarded after the session regardless of outcome. The payload records the snapshot path, which target-copy tier warmed it, and the creation cost. Additive event; absent in pre-field logs.

Fields

§milestone_id: String
§role: Role
§path: String

Absolute path of the (already discarded) snapshot worktree, under the mission’s gitignored runs/ scratch.

§target_tier: String

How the snapshot’s target/ was warmed: “clonefile”, “reflink”, “copy”, “fresh” (empty target — the cost is named in detail), or “absent” (no target/ in the session checkout).

§creation_ms: u64

Wall-clock cost of building the snapshot (worktree add + diff apply + untracked copy + target warm), in milliseconds.

§detail: Option<String>

Extra context — notably the named cost when targetTier is “fresh”.

§

ValidationConfirm

Local-validator confirm-on-pass (ticket local-inference-validator-guarded, KRZ-206b; review addendum §4 of docs/scoping/local-inference-executor-tier.md): a LOCAL functional validator’s PASS never greens a gate alone — a frontier functional session re-judged the same milestone and engine-captured contract-command evidence, and this event records the comparison. confirmed names the contract-command assertions both tiers pass; disagreements carries every frontier finding on a subject the local report passed (a local PASS vs frontier FAIL — the miss), each of which ALSO lands as a validation.finding and fails closed into the round as the frontier verdict. A local FAIL never triggers this event: failures are visible (they cost a fix cycle), misses are the danger — the asymmetry is deliberate.

The confirmations ARE the local-vs-frontier miss-rate ground truth the ticket’s start precondition demands: misses = disagreement subjects, opportunities = confirmed + disagreement command assertions + judgmentOpportunity (0/1), all computable from the log alone (join localRunId / confirmRunId against worker.spawned for the models). Additive event; absent in pre-field logs, which simply have no local-validator confirmations to measure.

Fields

§milestone_id: String
§local_run_id: String

Run id of the LOCAL functional session whose PASS was confirmed.

§confirm_run_id: String

Run id of the FRONTIER confirmation session.

§confirmed: Vec<String>

Contract-command assertion ids both the local report and the frontier confirmation pass.

§disagreements: Vec<Finding>

Frontier findings on subjects the local report passed — the misses. Failed closed: each stands as the round’s verdict.

§judgment_opportunity: bool

True when the confirmed PASS was JUDGMENT-only: a contract with no command assertions hands the local session pure judgment, and its all-clean report is confirmed exactly like a command- assertion PASS — but there are no assertion ids to list, so confirmed/disagreements alone would record ZERO opportunities for a confirmation that covered one, silently undercounting the miss-rate denominator (14th-pass review). Additive; absent (= false) in logs predating the field, which simply never recorded a judgment-only confirmation.

§

ValidationPtyTranscript

Pty-driven functional validation: one engine-run pty-script contract assertion (ticket pty-functional-validation, module crate::pty_harness) produced a bounded session transcript under the mission’s gitignored runs/pty-transcripts/; this audit record names the milestone, the assertion, the stated verdict, and the transcript’s file:-schemed mission-relative reference (the crate::gate_results ArtefactRef idiom — mission-relative, never an absolute host path, resolving to “unresolved” rather than erroring once the bytes are pruned). Record-only: the verdict reaches the round through the functional validator’s evidence block, not through this event, so the reducer treats it as an audit record exactly like validation.snapshot. Additive event; absent in pre-field logs, which simply have no pty-driven validations.

Fields

§milestone_id: String
§assertion_id: String

The contract assertion the session drove.

§verdict: GateVerdict

The verdict the harness stated — pass (every expect matched) or fail (the failing session’s transcript is the evidence).

§artefact_ref: String

The file:-schemed mission-relative transcript path.

§detail: Option<String>

The per-step summary (contract-authored patterns and timings — no raw target output).

§

GateResult

One gate evaluation, recorded as a first-class event (ticket .kranz/tickets/gate-results-first-class-events, KRZ-312 — the governance evidence layer’s last substrate gap before provenance-replay). Every crate::gate::GatePipeline evaluation emits one of these per gate, in pipeline order, carrying the gate id, its ladder position, the stated verdict, and the artefact handle — so the mission’s full gate ladder replays from the log alone, with no dependency on external state that may have moved. Record-only: the reducer treats it as an audit record (like secret.redacted), never a state transition, so old logs without any gate.result fold unchanged.

WHY surface is a first-class field: the same gate id is evaluated more than once per mission (approval and final gate), so gate id + ladder position cannot name ONE evaluation — and reconstructing the surface from neighbouring events would couple replay to emission order, exactly the external-state fragility this event abolishes.

WHY there is no separate section field: crate::gate::GateKind selects the pipeline section one-to-one (gate.rs), so kind doubles as the section discriminator; index is the zero-based evaluation position WITHIN that section.

Artefact discipline (ticket text): artefactRef is mission-relative or content-addressed, NEVER an absolute host path — a file:-schemed mission-relative path when the evidence is a file (crate::gate_results), or the gate-local handle verbatim (a command line, a description) when the evidence is inherently textual. A reference whose bytes are gone resolves to “unresolved”, never to an error that blocks replay.

Fields

§gate: String

Gate identity: the registered Gate::name() — e.g. a defect-class name (vacuous-filter), a pack gate name, merge-gate-suite.

§surface: GateSurface

Which evaluation surface ran the pipeline (see crate::gate::GateSurface).

§kind: GateKind

The gate’s kind — doubling as the ladder section (see the variant docs).

§index: u32

Zero-based evaluation position within the section: registration order is evaluation order (gate.rs), so index order within (surface, kind) IS the pipeline order.

§verdict: GateVerdict

The verdict the gate stated — never derived from score.

§artefact_ref: String

The artefact handle, verbatim from the outcome’s crate::gate::ArtefactRef::reference.

§artefact_detail: Option<String>

Evidence captured verbatim by the gate (a failing command’s output tail, per-assertion findings), from crate::gate::ArtefactRef::detail. Absent when the reference alone is the evidence; None never hits the wire.

§score: Option<f64>

Gate-supplied confidence score (KRZ-315), purely evidentiary — absent for boolean-only gates, never consulted to compute verdict.

§threshold: Option<f64>

The threshold the gate judged score against; present exactly when score is (the two travel as a pair from crate::gate::GateScore).

§rule_ids: Vec<String>

The stable Flight Rules standards rule ids this evaluation joined (KRZ-343, design D-H): the linkage the coverage matrix joins on, from crate::gate::GateOutcome::rule_ids. Additive and evidentiary only — a gate with no standards linkage carries an empty list, which never hits the wire, so a boolean-only gate’s payload stays byte-identical.

§

HookGateFired

One deterministic gate projected onto a Claude Code lifecycle hook fired IN-PROCESS inside a worker session (ticket .kranz/tickets/claude-code-hook-gate-projection.md, KRZ-302; module crate::hook_gates). The first projection is the out-of-contract write rule: a PreToolUse hook on the file-writing tools judges the target path against the mission’s touch_set and blocks an out-of-contract write before it happens. The payload carries the gate identity, the hook event, the tool, the judged path, and the guard’s verdict (blocked — refused in-process; error — the guard itself failed open, so only the engine-side sweep can judge it).

Additive, RECORD-ONLY (the gate.result template): the engine-side gate ladder remains authoritative — hooks are defense-in-depth, never a replacement — so this event drives no state transition; it is the in-process layer’s evidence landing in the log (folded from the per-session record file after the session stream closes, BEFORE worker.completed). runId is stamped from the run’s metadata at fold time, never from the session-writable record file.

Fields

§run_id: String
§gate: String

Gate identity (e.g. out-of-contract-write) — the same defect-class name the engine-side sweep reports, so one gate reads at two layers.

§hook_event: String

The lifecycle event that fired (PreToolUse).

§tool: String

The tool whose call was judged (Write, Edit, …).

§subject: String

The judged target (repo-relative when it resolved inside the checkout, else the raw path).

§verdict: String

blocked | error (see the variant docs).

§detail: Option<String>

The guard’s reason / error note, scrubbed and truncated at fold time. Absent when the record carried none; None never hits the wire.

§

DivergenceNoted

The candidate-comparison record of a heterogeneous dispatch pool (ticket divergence-first-class-event, KRZ-304; the follow-up the KRZ-303 pool parks for): when a unit’s sibling streams have all recorded and the engine parks the milestone for judgement, the candidate branch TREES are compared and exactly one of these is appended, naming the unit, every compared candidate (run id, branch, backend, tree hash — see crate::types::DivergenceCandidate), and the verdict.

Agreement between models is a signal to log, never a criterion to trust. Identical candidate trees produce THE SAME record kind with diverged: false — the agreement record: logged, never trusted. A unit is done when gates are green and no escalation is open, not when streams stop disagreeing; no gate, judgement, or park posture anywhere in the engine is keyed on this verdict (the agreement-record test pins that).

TWO kinds, not one with a resolution field: the log is append-only, so a resolution that arrives later (or never) could only ever be a second event — mirroring grant.requestedgrant.approved / grant.denied. Record-only in the reducer (the gate.result additive template, with reference validation as a corruption guard): the accompanying milestone.blocked drives the park, so old logs without any divergence.noted fold unchanged.

WHY the tree hash travels on the event: it pins the exact bytes the verdict was computed from, so replay (provenance, the training corpus) never needs git — the branches stay for the judging human, the hash is the audit anchor. Only streams that produced a run record are compared (a stream that never started has no candidate diff; counting its untouched branch would fabricate agreement out of a failure), and with fewer than two recorded candidates NO event is appended at all — a one-stream “agreement” would be vacuous.

Fields

§unit: String

The dispatch unit — the feature id fanned out to the pool (crate::types::CandidateLink::unit of every compared run).

§candidates: Vec<DivergenceCandidate>

Every compared candidate stream, in candidate-index order.

§diverged: bool

TRUE when at least two candidate branch trees differ (the streams diverged); FALSE = the agreement record (identical trees) — logged, never trusted (see the variant docs).

§

DivergenceResolved

The resolution of a unit’s divergence record (ticket divergence-first-class-event, KRZ-304): WHICH candidate was chosen (or that none was), WHY, and decided by WHOM — today always the operator through the milestone unblock path the pool parks on; the string leaves room for a gate decider without a schema change. RECORD ONLY: the engine never merges a candidate (the KRZ-303 freeze), so this changes nothing about the mission’s course — it is the judgement landing in the log, feeding the escalation ledger and the provenance chain. At most one per unit: the first operator judgement stands (the reducer folds the unit set the engine dedupes against across restarts).

Fields

§unit: String

The dispatch unit whose divergence is resolved (the feature id).

§selected: Option<u32>

The chosen candidate’s zero-based stream index (the -c<i> branch suffix / crate::types::CandidateLink::index); None when no candidate was selected — a judged-and-abandoned unit is itself a recorded resolution, distinct from “not yet judged”. None never hits the wire.

§reason: String

WHY, verbatim from the decider (the operator’s note, or the unblock action when no note was given).

§decided_by: String

WHO or WHAT decided: "operator" for the unblock path; a gate identity when a gate ever resolves (none does today).

§

FixFeatureCreated

Orchestrator converted findings into a fix-feature (origin: fix).

Fields

§milestone_id: String
§feature: Feature
§

TierEscalated

Orchestrator escalated the executor tier after repeated failed local validations, rather than blocking the milestone.

Fields

§milestone_id: String
§reason: String
§

WorkerEscalated

Worker-initiated escalation to the frontier advisor (ticket backend-routing-abstraction, KRZ-331): a worker whose report carried an escalation reason judged its task beyond its route’s confidence and asked for frontier-tier advice. Distinct from tier.escalated — that is the ORCHESTRATOR’s fix-cycle-cap valve, which flips the executor tier and resets the milestone; THIS is the WORKER’s request, layered on top of the deterministic routing floor and never replacing it.

RECORD-ONLY (the gate.result additive template): the fold validates the run reference as a corruption guard and changes NO state — the validator route, the executor tier, the respawn budget, and every milestone status are all untouched, so a worker escalation can never bypass the floor’s validator requirements. The judgement turn that already reads the worker’s report IS the frontier advisor act consuming the request (the orchestrator role’s model/endpoint, frontier-floor enforced by config::validate); this event is the provenance that the request was made, feeding the escalation record the ticket requires of every escalation. Old logs without any worker.escalated fold unchanged.

Routes are capability classes (ExecutorTier), never model ids — the same discipline as the routing table itself.

Fields

§run_id: String
§feature_id: String

The feature whose worker asked (denormalized onto the event so the log reads without a join; the run record is the join of record).

§from: ExecutorTier

Source route: the executor capability class the escalating worker session ran on.

§to: ExecutorTier

Target route: the advisor capability class requested — always frontier in this pass (see the variant docs).

§reason: String

WHY the worker asked, verbatim from its report (already credential-scrubbed with the report text it was parsed from).

§

QuestionOpened

A worker asked the human a structured question (ticket structured-human-question-events): the report’s questions payload (the “ask the human” tool shape — text plus capped structured choices) opened as ONE entry of the pending-decision projection (crate::types::MissionState::pending_questions) that the dashboard and Slack render beside grants — the D-X channel-unification ruling: permission prompts stay on the grant flow, ticket underspecification stays on NeedsContext, and ONLY orchestrator/worker structured asks land here, so this is not a third competing human-input inbox.

Unlike grant.requested, opening a question parks NOTHING: the worker’s own run result drives the mission’s course exactly as before (a prose-only report opens no question at all — the prose fallback), and an answer reaches the running mission through the existing user-message consult fold (see question.answered). The id is engine-minted (q-<n> from the folded crate::types::MissionState::question_count — restart-safe, never reused), never model-supplied. Text and options are credential- scrubbed and size-capped at write (orchestrator.rs caps); role names who asked (worker today — an orchestrator ask path can land without a schema change). The run/feature/milestone refs are denormalized context so surfaces render without a join.

Fields

§question_id: String

Engine-minted id (q-<n>, per-mission monotonic).

§role: Role

Who asked — worker in this pass.

§text: String

The question text (scrubbed, capped at write).

§options: Vec<String>

Structured choices the asker offered (each scrubbed + capped, the list capped at write). EMPTY means a free-text answer is expected. Absent in pre-field logs and omitted from the wire when empty.

§run_id: Option<String>

The run whose report carried the ask. None never hits the wire.

§feature_id: Option<String>

Feature the asking run worked on (context ref). None never hits the wire.

§milestone_id: Option<String>

Milestone the asking run worked under (context ref; the clear-on- complete sweep keys on it). None never hits the wire.

§

QuestionAnswered

The operator answered an open question (ticket structured-human-question-events), mirroring grant.requestedgrant.approved: the reducer cross-checks the id against the parked projection (a stale or forged answer for a question that is not open fails the fold), removes it from crate::types::MissionState::pending_questions, and folds the answer onto pending_user_messages — the EXISTING consult path, so the answer reaches the running mission (and replays after restart) with no new delivery mechanism. answer is the chosen option’s text verbatim or the operator’s free text (scrubbed + capped at write — an operator can paste a token into an answer box, and the log is corpus-exported); option records the 0-based index when an offered option was picked, None for free text. via names the control path that delivered it (the answer-question control kind today; a free-form string so a future msg-carried answer needs no schema change).

Fields

§question_id: String
§answer: String
§option: Option<u32>

0-based index into the question’s options when an offered option was picked; absent for free-text answers. None never hits the wire.

§

QuestionCleared

An open question stopped being actionable WITHOUT an answer (ticket structured-human-question-events) — its milestone completed, or the mission ended with the ask still open. Third kind rather than a resolution field on question.opened for the same reason grants are two kinds: the log is append-only, so a later resolution can only ever be a second event. why is the engine’s reason verbatim (“milestone completed”, “mission completed”, …).

Fields

§question_id: String
§

MilestoneBlocked

Fields

§milestone_id: String
§reason: String
§block_context: Option<BlockContext>

Absent only in legacy logs; present unknown values fail closed.

§

MilestoneUnblocked

Fields

§milestone_id: String
§reason: String

e.g. “raised fix-cycle cap”, “user skipped findings”

§block_context: Option<BlockContext>

Absent only in legacy logs; present unknown values fail closed.

§validator_guidance: Option<String>

Operator guidance carried verbatim into the next validator task (and its retry). Folded into milestone state so it survives a process restart; replaced by each new unblock, cleared on milestone completion. Absent in pre-field logs.

§

MilestoneCompleted

Fields

§milestone_id: String
§

MissionValidating

Final contract gate started (plan §4.5).

§

MissionPaused

§

MissionResumed

§

UserMessage

Fields

§text: String
§interrupt: bool
§

OrchestratorDecision

Fields

§summary: String
§detail: Option<String>
§

SecretRedacted

Fields

§rule_id: String
§fingerprint: String
§location: String
§

ConfigChanged

Fields

§patch: Value
§

MissionCompleted

§

MissionFailed

Fields

§reason: String
§

MissionAbandoned

Operator retired the mission (kranz abandon) — terminal, not a failure.

Fields

§reason: String
§

WorkspaceProvisioned

A crate::workspace_provider::WorkspaceProvider provisioned the mission workspace (design D-B/D-E): records the provider kind and the execution cwd so the audit trail names the environment workers ran in. Emitted once per run() invocation, before readiness.

Fields

§provider: String
§detail: Option<String>

Additive (ticket local-container-workspace): provider-specific detail — the container provider records its compose project name. Absent on old logs and for providers without extra detail.

§takeover: Option<String>

Additive (ticket workspace-remote-coder-provider): the substrate-reported takeover URL (SSH/web) for remote providers. Absent on old logs and for local kinds (their takeover truth is the workspace cwd — no SSH/remote fiction).

§previews: Option<Vec<ProvisionedPreview>>

Additive (ticket workspace-remote-coder-provider): previews as provisioned — the substrate-reported URLs name-matched to the contract’s previews[]. Absent on old logs and for local kinds (their placeholders derive from the contract itself).

§

WorkspaceReadinessReport

The provider’s readiness outcome (D-E: readiness status is a mission artifact). Emitted only when a workspace contract drove a real bootstrap/readiness execution — never with outcome = "ready" for a contract-less run, which would imply a runnable environment that does not exist (D-H). detail carries the scrubbed block reason on failure.

Fields

§outcome: String
§detail: Option<String>
§

WorkspaceTeardown

Workspace teardown recorded (D-E). The engine drives the configured workspace.teardownMode when a run reaches a terminal state (ticket workspace-idle-hibernate) and keep otherwise; local-worktree is always keep — the integration worktree’s filesystem lifecycle stays with the existing mission-branch/merge machinery.

Fields

§mode: String
§state: Option<String>

Additive (ticket workspace-idle-hibernate): the teardown OUTCOME — "kept" (mode keep), "stopped" (hibernate), "destroyed" (destroy), "failed" (the provider call failed; the run’s outcome stands — see the accompanying orchestrator.decision). Absent on old logs (v1 keep-only teardowns recorded no outcome); folds into crate::types::MissionState::workspace_lifecycle with the event’s own ts as the workspace-hours anchor.

§

WorkspaceProviderPinned

The effective workspace provider identity pinned at plan approval (design D-B, ticket workspace-provider-pin-at-approval) — the consent artifact recording WHAT was approved: provider kind, template (isolation mode for local kinds; the configured substrate template/image id for remote), and version (the workspace contract’s schemaVersion, "none" without a contract, or the remote adapter version). Emitted in approve_plan immediately before plan.approved, so the log reads: contract validated → provider pinned → plan approved. See crate::types::WorkspacePin for the per-kind field meanings.

Fields

§provider: String
§template: String
§version: String
§

StandardsResolved

The Flight Rules resolution record (KRZ-342, design D-D/D-E/D-H): emitted at plan approval, immediately after plan.approved, when a standards-configured pack governed the approval. Records the source identity + digest, the selection inputs (stage, task class, touch set), the selected rule revisions, and the plan.approved seq the pin attaches to — the queryable provenance for the consent artifact the plan’s standardsManifest carries in full.

D-H’s record list, verified for KRZ-343: the source identity/digest, selection inputs, stage, rule revisions, and approval sequence all ride in this payload; the effective-time evaluation instant is the event envelope’s own ts — resolution runs in the same approve_plan call as the emission, so the append stamp IS the instant the effective statuses were judged (payloads never duplicate the envelope clock anywhere in this schema). The RFC effective_at absorption window itself stays unevaluated in this slice: KRZ-341 parses and carries the field, and the stage-projection slice that evaluates it (KRZ-345) records its own surfaces.

Fields

§source: String

repo-tracked or external-pinned (StandardsPinSource).

§pack_name: String
§standards_root: String
§digest: String

sha256 over the pack’s normalized canonical manifest text.

§stage: String

The resolution surface: approval for the pinning resolution (stage-specific projections are KRZ-345’s emitters).

§task_class: Option<String>
§touch_set: Vec<String>
§context_paths: Vec<String>
§rules: Vec<StandardsRuleRef>

The selected rules, stable-sorted by id.

§approval_seq: u64

The seq of the plan.approved event this resolution pins.

§

StandardsDrifted

The Flight Rules policy-drift refusal (KRZ-342, design D-E/D-H): emitted when merge re-resolves the LIVE base policy against the exact scratch integration diff and the applicable ENFORCED set differs from the approved pin’s — the merge is refused and the mission requires explicit revalidation/reapproval. currentDigest is None when the live base no longer yields a readable standards manifest at all (a removed or malformed pack — the ultimate drift, failed closed). Audit-only in the reducer: the refusal already happened; the event is the evidence.

Fields

§approved_digest: String

The digest pinned at approval.

§current_digest: Option<String>

The digest resolved from the live base, when one resolved.

§surface: String

The surface that detected the drift (merge in this slice).

§changed_rules: Vec<String>

Id-level descriptions of the changed applicable enforced rules (added / removed / changed), stable-sorted.

§

StandardsWaiverApproved

The Flight Rules human waiver decision (ticket .kranz/tickets/flight-rules-waiver-decisions.md, KRZ-344; design D-I — “waivers are narrow human decisions”): the ONE authorized exception path for a standards failure. Only an authenticated human surface records it (kranz standards waive in this slice) — a model may request a waiver or propose a fix but can NEVER approve one, so no engine or backend code path emits this event. The binding is deliberately narrow enough that the waiver cannot survive a meaningful rule/finding/scope/diff change: it names the pinned rule id + revision + manifest digest + approval sequence, the fingerprint of the EXACT finding it subtracts, the affected paths, and the sha256 over the affected-path diff (the whole diff for an unscoped rule), plus the reason, the approver, and the expiry. A change to the affected-path diff, the rule revision, the finding fingerprint, or the pin — or the expiry passing — invalidates the waiver and restores the block; unrelated paths receive no authority. It subtracts EXACTLY ONE matching standards failure: it never disables a checker, an RFC, a domain, or a class, and engine floor gates have no waiver slot at all. Audit-only in the reducer: the coverage fold joins it straight from the log.

Fields

§rule_id: String

The pinned rule id the waiver excepts (frontmatter id:).

§rule_revision: u64

The pinned rule revision — a waiver naming any other revision joins nothing.

§manifest_digest: String

sha256 of the approved manifest the waiver binds to (StandardsPin::digest).

§approval_seq: u64

The seq of the plan.approved event whose pin the waiver binds — a re-approval supersedes every earlier waiver.

§finding_fingerprint: String

sha256 fingerprint of the ONE finding this waiver subtracts (crate::standards_waiver::finding_fingerprint).

§paths: Vec<String>

The affected paths the bound diff covers: the rule’s when-paths intersected with the mission diff, or the whole changed set for an unscoped rule. Recorded so the audit names exactly what the digest covers; empty when a scoped rule matched no changed path (the waiver then binds the empty scoped diff).

§diff_digest: String

sha256 over the affected-path diff bytes at approval time — a later change to any affected path digests differently and invalidates the waiver.

§reason: String

The human’s reason, verbatim (scrubbed at write like every payload string).

§approver: String

The approver principal: the authenticated identity where the local authority model can name one, else honestly local-operator (D-I — never invent a real-world identity).

§surface: String

The authenticated invocation surface (cli in this slice). The coverage fold honors only recognized human surfaces — a hand-cut event claiming a model surface carries no authority.

§expires_at: DateTime<Utc>

The expiry instant. The fold judges it against the log’s own frontier (the latest event instant — never a wall clock, so replays stay byte-identical); an enforcement decision re-judges it against its own clock.

§

StandardsAttestationApproved

Positive human verdict for a rule whose typed checker is manual-attestation (KRZ-346 D-F). Like a waiver, authority is narrow: exact mission pin, rule revision, affected paths, and current diff. Unlike a waiver it does not except a failing checker; it IS the checker and therefore carries no finding fingerprint or expiry.

Fields

§rule_id: String
§rule_revision: u64
§manifest_digest: String
§approval_seq: u64
§paths: Vec<String>
§diff_digest: String
§reason: String
§approver: String
§surface: String

Implementations§

Source§

impl EventKind

Source

pub fn type_name(&self) -> &'static str

The dotted wire name of this event (matches the serde rename).

Source

pub fn is_stream_delta(&self) -> bool

Lifecycle events are fsynced per append; stream deltas (worker.message) may be batched (§4.3).

Trait Implementations§

Source§

impl Clone for EventKind

Source§

fn clone(&self) -> EventKind

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EventKind

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for EventKind

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for EventKind

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more