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
PlanApproved
Fields
PlanRevisionProposed
PlanRevised
PlanRevisionRejected
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_set → touch_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).
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.
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.
MilestoneStarted
Fields
FeatureStarted
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.
WorkerSpawned
Fields
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.
backend: Option<BackendKind>Actual dispatch backend after resolution/fallback; absent in old logs.
WorkerMessage
Throttled stream deltas; also carries denied guardrail hits (§4.7).
Fields
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
denials: Vec<EgressDenial>WorkerCompleted
FeatureCompleted
FeatureFailed
Fields
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
MilestoneValidating
ValidationFinding
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
head_after: StringHEAD 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).
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
path: StringAbsolute path of the (already discarded) snapshot worktree,
under the mission’s gitignored runs/ scratch.
target_tier: StringHow 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).
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
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: boolTrue 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
verdict: GateVerdictThe verdict the harness stated — pass (every expect matched) or fail (the failing session’s transcript is the evidence).
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: StringGate identity: the registered Gate::name() — e.g. a defect-class
name (vacuous-filter), a pack gate name, merge-gate-suite.
surface: GateSurfaceWhich evaluation surface ran the pipeline (see
crate::gate::GateSurface).
index: u32Zero-based evaluation position within the section: registration order is evaluation order (gate.rs), so index order within (surface, kind) IS the pipeline order.
verdict: GateVerdictThe verdict the gate stated — never derived from score.
artefact_ref: StringThe 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
gate: StringGate identity (e.g. out-of-contract-write) — the same
defect-class name the engine-side sweep reports, so one gate
reads at two layers.
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.requested → grant.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: StringThe 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.
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
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.
FixFeatureCreated
Orchestrator converted findings into a fix-feature (origin: fix).
TierEscalated
Orchestrator escalated the executor tier after repeated failed local validations, rather than blocking the milestone.
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
feature_id: StringThe feature whose worker asked (denormalized onto the event so the log reads without a join; the run record is the join of record).
from: ExecutorTierSource route: the executor capability class the escalating worker session ran on.
to: ExecutorTierTarget route: the advisor capability class requested — always
frontier in this pass (see the variant docs).
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
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.
QuestionAnswered
The operator answered an open question (ticket
structured-human-question-events), mirroring
grant.requested → grant.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
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”, …).
MilestoneBlocked
Fields
block_context: Option<BlockContext>Absent only in legacy logs; present unknown values fail closed.
MilestoneUnblocked
Fields
block_context: Option<BlockContext>Absent only in legacy logs; present unknown values fail closed.
MilestoneCompleted
MissionValidating
Final contract gate started (plan §4.5).
MissionPaused
MissionResumed
UserMessage
OrchestratorDecision
SecretRedacted
ConfigChanged
MissionCompleted
MissionFailed
MissionAbandoned
Operator retired the mission (kranz abandon) — terminal, not a failure.
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
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.
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
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.
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: Stringrepo-tracked or external-pinned (StandardsPinSource).
stage: StringThe resolution surface: approval for the pinning resolution
(stage-specific projections are KRZ-345’s emitters).
rules: Vec<StandardsRuleRef>The selected rules, stable-sorted by id.
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
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
manifest_digest: Stringsha256 of the approved manifest the waiver binds to
(StandardsPin::digest).
approval_seq: u64The seq of the plan.approved event whose pin the waiver binds
— a re-approval supersedes every earlier waiver.
finding_fingerprint: Stringsha256 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: Stringsha256 over the affected-path diff bytes at approval time — a later change to any affected path digests differently and invalidates the waiver.
approver: StringThe 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).
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.