axon_frontend/ast.rs
1//! AXON AST node definitions — direct port of axon/compiler/ast_nodes.py.
2//!
3//! Tier 1 constructs have fully typed structs.
4//! Tier 2+ constructs use `GenericDeclaration` (structural fallback).
5
6#![allow(dead_code)]
7
8use crate::tokens::Trivia;
9
10// ── Location helper ──────────────────────────────────────────────────────────
11
12/// Source location shared by all AST nodes.
13#[derive(Debug, Clone, Default)]
14pub struct Loc {
15 pub line: u32,
16 pub column: u32,
17}
18
19// ── Trivia channel (v1.5.2 — Lossless lexing) ─────────────────────────────
20//
21// The Python AST attaches `leading_trivia` / `trailing_trivia` directly
22// to each ASTNode (97+ subclasses inherit empty defaults). The Rust
23// structs do not have inheritance, so adding two `Vec<Trivia>` fields
24// to every node would require touching each of the 97 structs and
25// every fixture test that constructs them — high mechanical churn for
26// a use case (LSP / formatter / doc gen) that can be served just as
27// well by indexing trivia by declaration position.
28//
29// `DeclarationTrivia` is a side-channel attached to `Program`. The
30// parser populates it in lockstep with `declarations` so consumer code
31// can do `program.declaration_trivia[i]` to get the leading/trailing
32// trivia of `program.declarations[i]`. This preserves the AST shape
33// (no breaking changes), keeps `IRProgram` JSON byte-identical with
34// the Python reference (trivia is never serialised), and ships the
35// adopter-reported feature end-to-end.
36//
37// If a future sub-phase wants per-node trivia inside the AST itself
38// (mirror of the Python ASTNode shape), this side-channel is the seed:
39// every `DeclarationTrivia` already carries the data; spreading it
40// into the structs is a mechanical refactor at that point.
41
42/// Comments attached to a single top-level declaration. Indexed
43/// in parallel with `Program.declarations`.
44#[derive(Debug, Clone, Default)]
45pub struct DeclarationTrivia {
46 /// Comment trivia that appeared before the declaration's first
47 /// token (since the previous declaration or file start).
48 pub leading: Vec<Trivia>,
49 /// Comment trivia on the same line as the declaration's last
50 /// effective token, before the next newline.
51 pub trailing: Vec<Trivia>,
52}
53
54// ── Top-level ────────────────────────────────────────────────────────────────
55
56#[derive(Debug)]
57pub struct Program {
58 pub declarations: Vec<Declaration>,
59 /// v1.5.2 — comment trivia attached per declaration (parallel
60 /// with `declarations`). Empty by default; populated by the parser
61 /// when source carries comments. Defaults preserve every existing
62 /// `Program { declarations, loc }` constructor — `..Default::default()`
63 /// on a `Program` literal fills in the new field.
64 pub declaration_trivia: Vec<DeclarationTrivia>,
65 pub loc: Loc,
66}
67
68/// A single top-level declaration in an AXON program.
69#[derive(Debug)]
70pub enum Declaration {
71 Import(ImportNode),
72 Persona(PersonaDefinition),
73 Context(ContextDefinition),
74 Anchor(AnchorConstraint),
75 Memory(MemoryDefinition),
76 Tool(ToolDefinition),
77 Type(TypeDefinition),
78 Flow(FlowDefinition),
79 /// v2.87.0 — `effect E { Op(p: T) -> R }`. A peer of `tool`, per
80 /// `the design plan` section 3.1.
81 Effect(EffectDefinition),
82 Intent(IntentNode),
83 Run(RunStatement),
84 Epistemic(EpistemicBlock),
85 Let(LetStatement),
86 /// Lambda Data (ΛD) — Epistemic State Vector definition.
87 LambdaData(LambdaDataDefinition),
88 // ── Tier 2 declarations (full AST) ──
89 Agent(AgentDefinition),
90 Shield(ShieldDefinition),
91 /// v4.5.0 — a signed determination, standing beside what was proved.
92 Attest(AttestDefinition),
93 /// v2.27.0 — a temporal execution-window guard.
94 Window(WindowDefinition),
95 /// v2.69.0 — a TOP-LEVEL `budget <Name> { … }`. Governs every flow that
96 /// calls the tools its quotas name — not just a daemon's.
97 Budget(BudgetBlock),
98 Pix(PixDefinition),
99 Ledger(LedgerDefinition),
100 Psyche(PsycheDefinition),
101 Corpus(CorpusDefinition),
102 Dataspace(DataspaceDefinition),
103 Ots(OtsDefinition),
104 Mandate(MandateDefinition),
105 Compute(ComputeDefinition),
106 Daemon(DaemonDefinition),
107 AxonStore(AxonStoreDefinition),
108 AxonEndpoint(AxonEndpointDefinition),
109 /// v2.5.0 — Closed-catalog extension mechanism. Declares
110 /// adopter-specific PROVENANCE members for a closed catalog
111 /// (`effects` bases or shield `scan` categories) so the
112 /// type-checker + PCC treat them as first-class. Auditable +
113 /// gateable; never extends the enforceable effect set (invariant
114 /// #2 — provenance-class only).
115 Extension(ExtensionDefinition),
116 /// v1.1.0 — I/O cognitivo primitives.
117 Resource(ResourceDefinition),
118 Fabric(FabricDefinition),
119 Manifest(ManifestDefinition),
120 Observe(ObserveDefinition),
121 /// v1.1.0 — Control cognitivo primitives.
122 Reconcile(ReconcileDefinition),
123 Lease(LeaseDefinition),
124 Ensemble(EnsembleDefinition),
125 /// v1.1.0 — Topology + π-calculus binary sessions.
126 Session(SessionDefinition),
127 Topology(TopologyDefinition),
128 /// v1.1.0 — Cognitive immune system (per docs/paper_immune_v2.md).
129 Immune(ImmuneDefinition),
130 Reflex(ReflexDefinition),
131 Heal(HealDefinition),
132 /// v1.3.1 — UI cognitiva declarativa.
133 Component(ComponentDefinition),
134 View(ViewDefinition),
135 /// v1.6.0 — Mobile typed channels (paper_mobile_channels.md).
136 Channel(ChannelDefinition),
137 /// v2.3.0 — typed WebSocket transport binding a `session` protocol
138 /// (paper_websocket_cognitive_primitive.md).
139 Socket(SocketDefinition),
140 /// v2.37.0 — the dual transport role of `socket`: a persistent,
141 /// config-resolved OUTBOUND connection to a third-party vendor, typed by
142 /// the same v2.3.0 session algebra on the axon-facing side and transcoded
143 /// to the vendor's wire frames by a declared total projection
144 /// (the design plan).
145 Upstream(UpstreamDefinition),
146 /// v2.37.0 — the voice-agent simplicity layer: macro-expands
147 /// (inspectable via `axon desugar`, the design decision) to `ots` + carrier
148 /// `session`/`socket` + `upstream` legs. The declaration stays in the
149 /// AST for provenance + v2.37.0 validation (T852); the IR carries only
150 /// the expansion — sugar the compliance reviewer can always see through.
151 Voice(VoiceDefinition),
152 /// v2.38.0 — a named, referenced browser-origin policy (mirrors
153 /// `shield`'s shape exactly), resolved per `axonendpoint.cors:`
154 /// reference (the design plan).
155 Cors(CorsDefinition),
156 /// v2.40.0 — a named, referenced result-memoization policy (mirrors
157 /// `cors`'s shape), resolved per `tool.cache:` / `retrieve.cache:`
158 /// (the design plan).
159 Cache(CacheDefinition),
160 /// v2.42.0 — the long-horizon autonomous research primitive: a governed
161 /// ORCHESTRATOR (not a monolith) that composes existing primitives
162 /// (`memory`/`corpus`, `par`, `quant`, `forge`, `daemon`, the v2.28.0 budget,
163 /// the v2.36.0 interruptible session, the v2.34.0 signed egress) into a
164 /// budget-bounded, interruptible, fail-closed, provenance-witnessed
165 /// research loop. Enterprise-exclusive at scale (charter split R1); the
166 /// keyword + type discipline + ports live in OSS
167 /// (the design plan).
168 Savant(SavantDefinition),
169 /// v2.42.0 — a dynamic tool-synthesis policy: the closed set of
170 /// conditions (risk ceiling, source language, mandatory WASM zero-trust
171 /// sandbox, Coder/Reviewer consensus) under which a `savant` may
172 /// synthesise + execute a tool at runtime. The paper's "OTS = Ontological
173 /// Tool Synthesis" grounded to a real keyword (`ots` already means
174 /// one-shot media transform — paper section 9.1). OSS declares + statically
175 /// disciplines the policy and ships a DENY-BY-DEFAULT reference; the real
176 /// Extism/WASM executor is enterprise (v2.42.0).
177 Synth(SynthDefinition),
178 /// v2.43.0 — an authorization scope: the signed envelope (`targets`
179 /// allowlist + `depth` ceiling + `approver`) a `warden` adversarial-analysis
180 /// block MUST run `within`. The load-bearing safety construct that makes
181 /// warden a governed auditor, not a weapon: no in-scope authorization ⇒ no
182 /// analysis (fail-closed). Referenced by `warden(t) within <Scope>`
183 /// (the design plan).
184 Scope(ScopeDefinition),
185 /// v2.46.0 — a named ephemeral-credential contract: TTL-bounded,
186 /// capability-attenuated bearer minting (`authority_only_attenuates` —
187 /// grants ⊆ the minter's own capabilities at mint, TTL ≤ the closed
188 /// ceiling). Declared once (the `cors`/`scope` shape), referenced by the
189 /// `mint <Credential> as <binding>` flow verb
190 /// (the design plan).
191 Credential(CredentialDefinition),
192 /// v2.4.0 — a Pauli-sum observable `M = Σ cₖ Pₖ` that a `quant`
193 /// block measures against (paper section 3.2; plan D5).
194 Observable(ObservableDefinition),
195 /// v2.23.0 — an Advantage Witness: a machine-checkable proof obligation
196 /// that a primitive's `claim` beats a cheaper `baseline` by a `metric` above
197 /// a `threshold` on real `data` (doctrine `axon://logic/no_unwitnessed_advantage`).
198 Witness(WitnessDefinition),
199 /// v2.53.0 — Native Document Synthesis: a declarative, compile-time-
200 /// validated DOCX/PPTX/XLSX structure that is the point where a value LEAVES
201 /// the epistemic lattice and becomes a human artifact. `target:` selects a
202 /// serializer, not a capability (the design decision — identical effect rows). The
203 /// assertion-laundering barrier refuses a value below `believe` in
204 /// an assertive slot without an `attribute:` or a shield
205 /// (the design plan).
206 Document(DocumentDefinition),
207 /// v2.60.0 — Governed CRM Delivery: a declarative, compile-time-validated
208 /// egress of assertions into a system of record (a CRM). The dual of
209 /// acquisition (`scrape`, v2.52.0): where `document` leaves the lattice into a
210 /// human artifact, `deliver` leaves it into a machine system others treat as
211 /// fact. The provenance-stripping barrier (the design decision, axon-T920) refuses a
212 /// `provenance: cleared` delivery of an unshielded flow value — a guess must
213 /// arrive labeled as a guess (the design plan).
214 Deliver(DeliverDefinition),
215 /// v2.66.0 — governed human notification.
216 Notify(NotifyDefinition),
217 /// Tier 3+ declarations parsed structurally (balanced braces, no detailed AST).
218 Generic(GenericDeclaration),
219}
220
221/// v2.76.0 — the named surface of a declaration: `(name, kind, loc)`,
222/// or `None` for the statement-like declarations that do not bind a
223/// referenceable top-level name (`import` / `run` / `let` / the epistemic
224/// block wrapper, whose body registers recursively).
225///
226/// # Parity contract
227///
228/// The `kind` strings here MUST match the kinds the type-checker's
229/// `register_declarations` assigns (that is what `TypeChecker::lookup`
230/// compares against when a `run` / reference names the symbol). The match
231/// below is deliberately **exhaustive — no wildcard arm** — so adding a
232/// `Declaration` variant without deciding its export surface is a compile
233/// error, not a silent gap in the module system.
234pub fn declaration_surface(decl: &Declaration) -> Option<(String, String, Loc)> {
235 match decl {
236 Declaration::Import(_)
237 | Declaration::Run(_)
238 | Declaration::Let(_)
239 | Declaration::Epistemic(_) => None,
240 Declaration::Persona(n) => Some((n.name.clone(), "persona".into(), n.loc.clone())),
241 Declaration::Context(n) => Some((n.name.clone(), "context".into(), n.loc.clone())),
242 Declaration::Anchor(n) => Some((n.name.clone(), "anchor".into(), n.loc.clone())),
243 Declaration::Memory(n) => Some((n.name.clone(), "memory".into(), n.loc.clone())),
244 Declaration::Tool(n) => Some((n.name.clone(), "tool".into(), n.loc.clone())),
245 Declaration::Type(n) => Some((n.name.clone(), "type".into(), n.loc.clone())),
246 Declaration::Flow(n) => Some((n.name.clone(), "flow".into(), n.loc.clone())),
247 // v2.87.0 — an `effect` IS exportable. A module that declares one and
248 // a flow in another module that handles it is the compositional case
249 // the whole paradigm rests on; hiding it from the module surface would
250 // make an effect usable only in the file that declares it.
251 Declaration::Effect(n) => Some((n.name.clone(), "effect".into(), n.loc.clone())),
252 Declaration::Intent(n) => Some((n.name.clone(), "intent".into(), n.loc.clone())),
253 Declaration::LambdaData(n) => Some((n.name.clone(), "lambda_data".into(), n.loc.clone())),
254 Declaration::Agent(n) => Some((n.name.clone(), "agent".into(), n.loc.clone())),
255 Declaration::Shield(n) => Some((n.name.clone(), "shield".into(), n.loc.clone())),
256 // v4.5.0 — an attestation is an exportable named symbol: a module that
257 // owns the determination can be imported by the flow that relies on it.
258 Declaration::Attest(n) => Some((n.name.clone(), "attest".into(), n.loc.clone())),
259 Declaration::Window(n) => Some((n.name.clone(), "window".into(), n.loc.clone())),
260 Declaration::Budget(n) => Some((n.name.clone(), "budget".into(), n.loc.clone())),
261 Declaration::Pix(n) => Some((n.name.clone(), "pix".into(), n.loc.clone())),
262 Declaration::Ledger(n) => Some((n.name.clone(), "ledger".into(), n.loc.clone())),
263 Declaration::Psyche(n) => Some((n.name.clone(), "psyche".into(), n.loc.clone())),
264 Declaration::Corpus(n) => Some((n.name.clone(), "corpus".into(), n.loc.clone())),
265 Declaration::Dataspace(n) => Some((n.name.clone(), "dataspace".into(), n.loc.clone())),
266 Declaration::Ots(n) => Some((n.name.clone(), "ots".into(), n.loc.clone())),
267 Declaration::Mandate(n) => Some((n.name.clone(), "mandate".into(), n.loc.clone())),
268 Declaration::Compute(n) => Some((n.name.clone(), "compute".into(), n.loc.clone())),
269 Declaration::Daemon(n) => Some((n.name.clone(), "daemon".into(), n.loc.clone())),
270 Declaration::AxonStore(n) => Some((n.name.clone(), "axonstore".into(), n.loc.clone())),
271 Declaration::AxonEndpoint(n) => {
272 Some((n.name.clone(), "axonendpoint".into(), n.loc.clone()))
273 }
274 Declaration::Extension(n) => Some((n.name.clone(), "extension".into(), n.loc.clone())),
275 Declaration::Resource(n) => Some((n.name.clone(), "resource".into(), n.loc.clone())),
276 Declaration::Fabric(n) => Some((n.name.clone(), "fabric".into(), n.loc.clone())),
277 Declaration::Manifest(n) => Some((n.name.clone(), "manifest".into(), n.loc.clone())),
278 Declaration::Observe(n) => Some((n.name.clone(), "observe".into(), n.loc.clone())),
279 Declaration::Reconcile(n) => Some((n.name.clone(), "reconcile".into(), n.loc.clone())),
280 Declaration::Lease(n) => Some((n.name.clone(), "lease".into(), n.loc.clone())),
281 Declaration::Ensemble(n) => Some((n.name.clone(), "ensemble".into(), n.loc.clone())),
282 Declaration::Session(n) => Some((n.name.clone(), "session".into(), n.loc.clone())),
283 Declaration::Topology(n) => Some((n.name.clone(), "topology".into(), n.loc.clone())),
284 Declaration::Immune(n) => Some((n.name.clone(), "immune".into(), n.loc.clone())),
285 Declaration::Reflex(n) => Some((n.name.clone(), "reflex".into(), n.loc.clone())),
286 Declaration::Heal(n) => Some((n.name.clone(), "heal".into(), n.loc.clone())),
287 Declaration::Component(n) => Some((n.name.clone(), "component".into(), n.loc.clone())),
288 Declaration::View(n) => Some((n.name.clone(), "view".into(), n.loc.clone())),
289 Declaration::Channel(n) => Some((n.name.clone(), "channel".into(), n.loc.clone())),
290 Declaration::Socket(n) => Some((n.name.clone(), "socket".into(), n.loc.clone())),
291 Declaration::Upstream(n) => Some((n.name.clone(), "upstream".into(), n.loc.clone())),
292 Declaration::Voice(n) => Some((n.name.clone(), "voice".into(), n.loc.clone())),
293 Declaration::Cors(n) => Some((n.name.clone(), "cors".into(), n.loc.clone())),
294 Declaration::Cache(n) => Some((n.name.clone(), "cache".into(), n.loc.clone())),
295 Declaration::Savant(n) => Some((n.name.clone(), "savant".into(), n.loc.clone())),
296 Declaration::Synth(n) => Some((n.name.clone(), "synth".into(), n.loc.clone())),
297 Declaration::Scope(n) => Some((n.name.clone(), "scope".into(), n.loc.clone())),
298 Declaration::Credential(n) => Some((n.name.clone(), "credential".into(), n.loc.clone())),
299 Declaration::Observable(n) => Some((n.name.clone(), "observable".into(), n.loc.clone())),
300 Declaration::Witness(n) => Some((n.name.clone(), "witness".into(), n.loc.clone())),
301 Declaration::Document(n) => Some((n.name.clone(), "document".into(), n.loc.clone())),
302 Declaration::Deliver(n) => Some((n.name.clone(), "deliver".into(), n.loc.clone())),
303 Declaration::Notify(n) => Some((n.name.clone(), "notify".into(), n.loc.clone())),
304 Declaration::Generic(n) => {
305 if n.name.is_empty() {
306 None
307 } else {
308 Some((n.name.clone(), n.keyword.clone(), n.loc.clone()))
309 }
310 }
311 }
312}
313
314// ── v2.53.0 — Native Document Synthesis ─────────────────────────────────────
315
316/// v2.53.0 — a declarative document. `target:` picks the serializer
317/// (docx|pptx|xlsx); `provenance:` picks how the provenance part is emitted
318/// (none|embedded|signed); `template:` names an enterprise template; `effects:`
319/// carries the propagated `sensitive:`/`legal:` basis. `blocks` is the body —
320/// a closed-catalog tree of [`DocBlock`]s whose vocabulary the checker validates
321/// against `target` (a `slide` in a `docx` is `axon-T9xx`, the design decision).
322#[derive(Debug, Default)]
323pub struct DocumentDefinition {
324 pub name: String,
325 /// v4.4.0 — `payload: <Type>`: the DECLARED TYPE this document renders. κ is read from it: a regulated
326 /// type reaching a document needs a `shield:` covering its classes.
327 ///
328 /// Empty when the declaration names no payload, which stays legal: the
329 /// rule bites on a payload that CARRIES a class, not on its absence.
330 pub payload: String,
331 /// v4.4.0 — the shield that covers the payload's κ (`axon-T1222`).
332 pub shield_ref: String,
333 /// `docx | pptx | xlsx` — closed catalog (axon-T910).
334 pub target: String,
335 /// Optional enterprise template reference (`.dotx/.potx/.xltx`, v2.53.0).
336 pub template: String,
337 /// `none | embedded | signed` — how the provenance part is emitted
338 ///. Empty ⇒ `none`. Closed catalog (axon-T911).
339 pub provenance: String,
340 /// The propagated effect row — `io`, `storage` (blob sink), and any
341 /// `sensitive:<cat>`/`legal:<basis>` the bound data carries.
342 pub effects: Option<EffectRow>,
343 /// The document body — the closed-catalog block tree.
344 pub blocks: Vec<DocBlock>,
345 pub loc: Loc,
346 pub leading_trivia: Vec<crate::tokens::Trivia>,
347 pub trailing_trivia: Vec<crate::tokens::Trivia>,
348}
349
350/// v2.53.0 — one block in a document body. A generic-but-closed node: `kind`
351/// is validated against the `target`'s vocabulary, `fields` against the kind's
352/// allowed set, and `children` are nested blocks (a `section` holds `para`s; a
353/// `slide` holds `bullets`; a `sheet` holds `row`s). Keeping the node generic
354/// (rather than one struct per block kind) keeps the grammar/IR small while the
355/// checker (`check_document`) enforces the same closed-catalog discipline.
356#[derive(Debug, Default)]
357pub struct DocBlock {
358 /// `section|heading|para|table|chart|image|toc|page_break|footnote|slide|
359 /// placeholder|bullets|notes|sheet|row|formula|range|format` — validated
360 /// per `target` at check time.
361 pub kind: String,
362 /// Scalar/list fields (`text:`, `columns:`, `range:`, `attribute:`, …).
363 pub fields: Vec<(String, DocScalar)>,
364 /// Nested child blocks.
365 pub children: Vec<DocBlock>,
366 pub loc: Loc,
367}
368
369impl DocBlock {
370 /// Look up a scalar field by name.
371 pub fn field(&self, name: &str) -> Option<&DocScalar> {
372 self.fields.iter().find(|(k, _)| k == name).map(|(_, v)| v)
373 }
374 /// Whether a field is present.
375 pub fn has_field(&self, name: &str) -> bool {
376 self.fields.iter().any(|(k, _)| k == name)
377 }
378}
379
380/// v2.53.0 — a document field value. A `Ref` is a binding to a flow value
381/// (the epistemic-egress barrier reads its level); a `Text` is a literal; a
382/// `List` is a bracketed set; `Int` is a scalar count.
383#[derive(Debug, Clone, PartialEq)]
384pub enum DocScalar {
385 /// A quoted string literal (`"Q3 Results"`, `"B2:B9"`).
386 Text(String),
387 /// A bare identifier — a reference to a flow value / declared name. THIS is
388 /// what the assertion-laundering barrier inspects at an assertive slot.
389 Ref(String),
390 /// A bracketed list of strings/identifiers (`["Region","Revenue"]`).
391 List(Vec<String>),
392 /// An integer scalar.
393 Int(i64),
394 /// A boolean scalar.
395 Bool(bool),
396}
397
398impl DocScalar {
399 /// The referenced name, if this value is a `Ref`.
400 pub fn as_ref_name(&self) -> Option<&str> {
401 match self {
402 DocScalar::Ref(s) => Some(s.as_str()),
403 _ => None,
404 }
405 }
406 /// The literal text, if this value is `Text`.
407 pub fn as_text(&self) -> Option<&str> {
408 match self {
409 DocScalar::Text(s) => Some(s.as_str()),
410 _ => None,
411 }
412 }
413}
414
415// ── v2.60.0 — Governed CRM Delivery ────────────────────────────────────────
416
417/// v2.60.0 — a declarative CRM delivery. `target:` picks the destination class
418/// (`crm`, closed catalog — axon-T921); `provenance:` picks how the epistemic
419/// origin of each delivered field is treated at the boundary (`attached` default
420/// | `cleared` — axon-T922); `secret:` names the per-tenant credential key
421/// (v2.48.0 custody, required — axon-T923); `effects:` carries the propagated row
422/// (must include `web` — axon-T924). `ops` is the body — a non-empty list of
423/// [`DeliverOp`]s whose `kind` the checker validates against a closed operation
424/// catalog (axon-T925). Field values reuse [`DocScalar`]: a `Ref` is a binding to
425/// a flow value (what the T920 barrier inspects), the rest are literals.
426#[derive(Debug, Default)]
427
428pub struct DeliverDefinition {
429 pub name: String,
430 /// v4.4.0 — `payload: <Type>`: the DECLARED TYPE this delivery carries to the system of record. The
431 /// widest commercial exit the language has, and the κ comes from here.
432 ///
433 /// Empty when the declaration names no payload, which stays legal: the
434 /// rule bites on a payload that CARRIES a class, not on its absence.
435 pub payload: String,
436 /// v4.4.0 — the shield that covers the payload's κ (`axon-T1223`).
437 pub shield_ref: String,
438 /// `crm` — closed catalog (axon-T921).
439 pub target: String,
440 /// `attached | cleared` — how field provenance crosses the boundary
441 ///. Empty ⇒ `attached` (the safe default: provenance travels).
442 /// Closed catalog (axon-T922).
443 pub provenance: String,
444 /// The per-tenant credential key resolved via v2.48.0 custody at dispatch — the
445 /// value never enters cognition. Required (axon-T923).
446 pub secret: String,
447 /// The propagated effect row — must include `web` (a CRM write crosses the
448 /// trust boundary over the network, axon-T924).
449 pub effects: Option<EffectRow>,
450 /// The delivery body — the closed-catalog operation list.
451 pub ops: Vec<DeliverOp>,
452 pub loc: Loc,
453 pub leading_trivia: Vec<crate::tokens::Trivia>,
454 pub trailing_trivia: Vec<crate::tokens::Trivia>,
455}
456
457/// v2.66.0 — Governed Human Notification: the third egress dual
458/// (`deliver` = systems of record, `document` = artifacts, `notify` =
459/// human attention). Three laws: T933 (the evidence barrier — a guess
460/// reaches a human labeled as a guess, or is refused), T934 (structure:
461/// closed channel catalog; the recipient is a v2.48.0 secret-class ref,
462/// NEVER a literal — PII never rides source or IR), T935 (attention:
463/// a `window:` is mandatory — unbounded interruption is refused).
464#[derive(Debug, Default)]
465pub struct NotifyDefinition {
466 pub name: String,
467 /// v4.4.0 — `payload: <Type>`: the DECLARED TYPE this notification carries. A recipient is already
468 /// PII (axon-T934); the payload is what the coverage rule reads.
469 ///
470 /// Empty when the declaration names no payload, which stays legal: the
471 /// rule bites on a payload that CARRIES a class, not on its absence.
472 pub payload: String,
473 /// v4.4.0 — the shield that covers the payload's κ (`axon-T1224`).
474 pub shield_ref: String,
475 /// `sms | whatsapp | telegram` — closed catalog (axon-T934).
476 pub channel: String,
477 /// The v2.48.0 secret-class ref the recipient resolves from AT DISPATCH
478 /// (`to: secret(ops.oncall_phone)`). The literal number/chat-id never
479 /// appears anywhere axon stores or reasons over.
480 pub to_secret: String,
481 /// True iff `to:` was written in the `secret(...)` form. A literal
482 /// recipient is an axon-T934 refusal (with a teaching message).
483 pub to_is_secret: bool,
484 /// The message template; `${ref}` slots bind flow values post-run.
485 pub template: String,
486 /// v2.27.0-style duration (`30m`, `4h`, `1d`) — at-most-once-per-window
487 /// per recipient (axon-T935; enforced durably by the ENT ledger).
488 pub window: String,
489 /// `attached | cleared` — how epistemic labels cross to the human
490 ///. Empty ⇒ `attached` (the safe default).
491 pub provenance: String,
492 /// Must include `web` (a notification crosses the trust boundary).
493 pub effects: Option<EffectRow>,
494 pub loc: Loc,
495 pub leading_trivia: Vec<crate::tokens::Trivia>,
496 pub trailing_trivia: Vec<crate::tokens::Trivia>,
497}
498
499/// v2.60.0 — one CRM operation in a delivery body. `kind ∈ {upsert_contact,
500/// create_deal, add_note}` (validated per-target, axon-T925). Each operation
501/// binds a set of `(field, value)` pairs; a `Ref` field carries a flow value
502/// into the CRM and is the T920 barrier's subject. Every operation requires a
503/// `key:` field — the idempotency key (the design decision, axon-T926) so an at-least-once
504/// retry never double-creates a record.
505#[derive(Debug, Default)]
506pub struct DeliverOp {
507 /// `upsert_contact | create_deal | add_note` — validated at check time.
508 pub kind: String,
509 /// Scalar/ref fields (`key:`, `email:`, `firstname:`, `amount:`, …).
510 pub fields: Vec<(String, DocScalar)>,
511 pub loc: Loc,
512}
513
514impl DeliverOp {
515 /// Look up a scalar field by name.
516 pub fn field(&self, name: &str) -> Option<&DocScalar> {
517 self.fields.iter().find(|(k, _)| k == name).map(|(_, v)| v)
518 }
519 /// Whether a field is present.
520 pub fn has_field(&self, name: &str) -> bool {
521 self.fields.iter().any(|(k, _)| k == name)
522 }
523 /// The flow-value references this operation binds (the barrier's subjects).
524 pub fn ref_fields(&self) -> impl Iterator<Item = (&str, &str)> {
525 self.fields.iter().filter_map(|(k, v)| match v {
526 DocScalar::Ref(name) => Some((k.as_str(), name.as_str())),
527 _ => None,
528 })
529 }
530}
531
532// ── v1.1.0 — Resource primitive ───────────────────────────────────────
533
534/// `resource Name { kind, endpoint, capacity, lifetime, certainty_floor, shield }`
535///
536/// An infrastructure resource declared as a linear, affine, or persistent
537/// token. Linear/affine resources cannot be aliased across manifests
538/// (Separation Logic `*` disjointness).
539#[derive(Debug, Default)]
540pub struct ResourceDefinition {
541 pub name: String,
542 /// v2.67.0 — a CLOSED catalog (`VALID_RESOURCE_KINDS`). Until v2.67.0 this
543 /// was a free string that **nothing validated**: `check_resource` never
544 /// read it, and no catalog const existed anywhere in the workspace.
545 pub kind: String,
546 /// v2.67.0 — the DSN, as a **per-tenant config key** (`axon-T944`).
547 ///
548 /// A production DB URI in source is exactly what `axon-T850` already
549 /// forbids one declaration over (*"URLs and credentials never appear in
550 /// source"*) and what v2.48.0 custody exists to refuse. `resource` was a
551 /// grandfathered violation of the language's own law.
552 pub endpoint: String,
553 /// v2.67.0 — **the pool size**, and the proof this cycle is a wire and not
554 /// a label. Before v2.67.0 every axonstore pool was hardcoded at 10.
555 pub capacity: Option<i64>,
556 /// v2.67.0 — **how many holders may name this resource** (Linear Logic):
557 /// `linear` = exactly one · `affine` = at most one (sharing is a breach) ·
558 /// `persistent` = the `!` exponential, freely shared. Default: `affine`.
559 pub lifetime: String,
560 pub certainty_floor: Option<f64>, // epistemic gate c ∈ [0.0, 1.0]
561 pub shield_ref: String, // optional shield reference
562 /// v2.67.0 — the `fabric` this resource lives in. **One field ⇒
563 /// Separation-Logic disjointness is unrepresentable, not verified.**
564 pub within: String,
565 pub loc: Loc,
566 /// v1.5.2 — leading comment trivia attached to this declaration
567 /// (comments preceding the declaration's first token, since the
568 /// previous declaration or file start). Empty by default.
569 pub leading_trivia: Vec<crate::tokens::Trivia>,
570 /// v1.5.2 — trailing comment trivia (same line as the
571 /// declaration's last effective token). Empty by default.
572 pub trailing_trivia: Vec<crate::tokens::Trivia>,
573}
574
575/// `fabric Name { provider, region, zones, ephemeral, shield }`
576///
577/// A tagged substrate — the topological container where resources are
578/// provisioned. Maps to VPC / cluster / namespace.
579#[derive(Debug, Default)]
580pub struct FabricDefinition {
581 pub name: String,
582 pub provider: String, // aws | gcp | azure | kubernetes | bare_metal | custom
583 pub region: String, // provider-specific region id
584 pub zones: Option<i64>, // number of availability zones
585 pub ephemeral: Option<bool>, // true = destroy on program end
586 pub shield_ref: String, // optional shield reference
587 pub loc: Loc,
588 /// v1.5.2 — leading comment trivia attached to this declaration
589 /// (comments preceding the declaration's first token, since the
590 /// previous declaration or file start). Empty by default.
591 pub leading_trivia: Vec<crate::tokens::Trivia>,
592 /// v1.5.2 — trailing comment trivia (same line as the
593 /// declaration's last effective token). Empty by default.
594 pub trailing_trivia: Vec<crate::tokens::Trivia>,
595}
596
597/// `manifest Name { resources, fabric, region, zones, compliance }`
598///
599/// A declarative specification of desired shape — not a "desired state" in
600/// the Terraform sense, a *belief* about structure. Linear/affine resources
601/// in `resources` must be disjoint (Separation Logic `*`).
602#[derive(Debug, Default)]
603pub struct ManifestDefinition {
604 pub name: String,
605 pub resources: Vec<String>, // references to ResourceDefinition names
606 pub fabric_ref: String, // reference to FabricDefinition name
607 pub region: String,
608 pub zones: Option<i64>,
609 pub compliance: Vec<String>, // κ — regulatory class (v1.2.0)
610 /// v4.5.0 — the census this deployment relies on to reduce a postal code
611 /// to three digits.
612 ///
613 /// Safe Harbor (B) permits three digits only where the resulting unit
614 /// holds twenty thousand people or more. That is a fact about the world on
615 /// a date, not about the program, so the deployment names the source and
616 /// the compiler checks only that it was named. Empty unless some control
617 /// actually reduces geography — see `axon-T1235`.
618 pub census: String,
619 pub loc: Loc,
620 /// v1.5.2 — leading comment trivia attached to this declaration
621 /// (comments preceding the declaration's first token, since the
622 /// previous declaration or file start). Empty by default.
623 pub leading_trivia: Vec<crate::tokens::Trivia>,
624 /// v1.5.2 — trailing comment trivia (same line as the
625 /// declaration's last effective token). Empty by default.
626 pub trailing_trivia: Vec<crate::tokens::Trivia>,
627}
628
629/// `observe Name from Manifest { sources, quorum, timeout, on_partition, certainty_floor }`
630///
631/// A quorum-gated observation of a manifest's real state. Each output
632/// carries ΛD envelope E = ⟨c, τ, ρ, δ⟩; `τ` records observation lag.
633/// `on_partition: fail` raises a CT-3 (Network Error) — partitions are ⊥ void.
634#[derive(Debug, Default)]
635pub struct ObserveDefinition {
636 pub name: String,
637 pub target: String, // name of ManifestDefinition being observed
638 pub sources: Vec<String>,
639 pub quorum: Option<i64>, // Byzantine quorum threshold
640 pub timeout: String, // duration literal "5s", "100ms"
641 pub on_partition: String, // fail (CT-3) | shield_quarantine
642 pub certainty_floor: Option<f64>,
643 pub loc: Loc,
644 /// v1.5.2 — leading comment trivia attached to this declaration
645 /// (comments preceding the declaration's first token, since the
646 /// previous declaration or file start). Empty by default.
647 pub leading_trivia: Vec<crate::tokens::Trivia>,
648 /// v1.5.2 — trailing comment trivia (same line as the
649 /// declaration's last effective token). Empty by default.
650 pub trailing_trivia: Vec<crate::tokens::Trivia>,
651}
652
653// ── v1.1.0 — Control cognitivo primitives ─────────────────────────────
654
655/// `reconcile Name { observe, threshold, tolerance, on_drift, shield, mandate, max_retries }`
656///
657/// A cognitive control loop that minimises variational free energy
658/// `F = D_KL(q(s) || p(s, o))` between a manifest belief and an observe
659/// evidence. Acting on the environment (`on_drift: provision`) is one of
660/// the two classical routes to reducing F (the other is belief revision).
661#[derive(Debug, Default)]
662pub struct ReconcileDefinition {
663 pub name: String,
664 pub observe_ref: String,
665 pub threshold: Option<f64>, // epistemic gate c ∈ [0.0, 1.0]
666 pub tolerance: Option<f64>, // drift tolerance [0.0, 1.0]
667 pub on_drift: String, // provision | alert | refine (default: provision)
668 pub shield_ref: String,
669 pub mandate_ref: String,
670 pub max_retries: i64, // default: 3
671 pub loc: Loc,
672 /// v1.5.2 — leading comment trivia attached to this declaration
673 /// (comments preceding the declaration's first token, since the
674 /// previous declaration or file start). Empty by default.
675 pub leading_trivia: Vec<crate::tokens::Trivia>,
676 /// v1.5.2 — trailing comment trivia (same line as the
677 /// declaration's last effective token). Empty by default.
678 pub trailing_trivia: Vec<crate::tokens::Trivia>,
679}
680
681/// `lease Name { resource, duration, acquire, on_expire }`
682///
683/// Affine/linear lease on a resource, with explicit Δt encoded in the `τ`
684/// of the ΛD envelope. Runtime materializes each lease as a revocable
685/// token; use post-expiry raises `LeaseExpiredError` (CT-2) per D2.
686#[derive(Debug, Default)]
687pub struct LeaseDefinition {
688 pub name: String,
689 pub resource_ref: String,
690 pub duration: String, // "30s", "5m", "2h"
691 pub acquire: String, // on_start | on_demand (default: on_start)
692 pub on_expire: String, // anchor_breach | release | extend (default: anchor_breach)
693 pub loc: Loc,
694 /// v1.5.2 — leading comment trivia attached to this declaration
695 /// (comments preceding the declaration's first token, since the
696 /// previous declaration or file start). Empty by default.
697 pub leading_trivia: Vec<crate::tokens::Trivia>,
698 /// v1.5.2 — trailing comment trivia (same line as the
699 /// declaration's last effective token). Empty by default.
700 pub trailing_trivia: Vec<crate::tokens::Trivia>,
701}
702
703/// `ensemble Name { observations, quorum, aggregation, certainty_mode }`
704///
705/// Byzantine quorum aggregator over ≥2 independent observations. Yields
706/// common knowledge `Cφ` (Fagin-Halpern) when at least `quorum` observers
707/// agree. Failed observations are excluded; below quorum raises CT-3.
708#[derive(Debug, Default)]
709pub struct EnsembleDefinition {
710 pub name: String,
711 pub observations: Vec<String>,
712 pub quorum: Option<i64>,
713 pub aggregation: String, // majority | weighted | byzantine (default: majority)
714 pub certainty_mode: String, // min | weighted | harmonic (default: min)
715 pub loc: Loc,
716 /// v1.5.2 — leading comment trivia attached to this declaration
717 /// (comments preceding the declaration's first token, since the
718 /// previous declaration or file start). Empty by default.
719 pub leading_trivia: Vec<crate::tokens::Trivia>,
720 /// v1.5.2 — trailing comment trivia (same line as the
721 /// declaration's last effective token). Empty by default.
722 pub trailing_trivia: Vec<crate::tokens::Trivia>,
723}
724
725// ── v1.1.0 — Topology + π-calculus binary sessions ──────────────────
726
727/// One step in a session protocol.
728///
729/// v1.1.0: `send T` | `receive T` | `loop` | `end`. v2.3.0 adds **choice**:
730/// `select { ℓ: [..], … }` (⊕ — this role chooses) and `branch { ℓ: [..], … }`
731/// (& — this role offers); for those `op`s the labelled continuations live in
732/// [`SessionStep::branches`] (a nested sub-protocol per label).
733#[derive(Debug, Clone, Default)]
734pub struct SessionStep {
735 pub op: String, // send | receive | loop | end | select | branch | interrupt
736 pub message_type: String, // send/receive: payload type · interrupt: the `on <Signal>` cause
737 /// v2.3.0 — populated only for `op == "select" | "branch"`: the labelled
738 /// branches, each a nested step sequence (its own sub-protocol).
739 ///
740 /// v2.36.0 — reused for `op == "interrupt"`: exactly two labelled arms,
741 /// `body` (the interruptible region) and `handler` (runs on the signal). The
742 /// handler may end in a `resume` step (back to `body`) or reach `end` (the
743 /// abandon exit) — see the paper section 3.5 two-exit construct.
744 pub branches: Vec<SessionBranch>,
745 /// v2.36.0 — `op == "interrupt"` only: the handler's signal binder from
746 /// `... as <sig> ...`. Empty for every other op. The handler references the
747 /// received `CallInterruptCause` value under this name.
748 pub binder: String,
749 /// v2.36.0 — `op == "interrupt"` only: `true` when the block declares a
750 /// `resumable { … }` handler (the v1 surface always does). Default `false`
751 /// keeps every non-interrupt step byte-identical in the IR (skip-if-false).
752 pub resumable: bool,
753 pub loc: Loc,
754}
755
756/// v2.3.0 — one labelled arm of a `select`/`branch` choice: `ℓ: [steps]`.
757#[derive(Debug, Clone, Default)]
758pub struct SessionBranch {
759 pub label: String,
760 pub steps: Vec<SessionStep>,
761 pub loc: Loc,
762}
763
764/// One role in a binary session — name + ordered list of steps.
765#[derive(Debug, Default)]
766pub struct SessionRole {
767 pub name: String,
768 pub steps: Vec<SessionStep>,
769 pub loc: Loc,
770}
771
772/// `session Name { role1: [step, …] role2: [step, …] }`
773///
774/// A binary session type — exactly two roles whose protocols MUST be
775/// pairwise Honda-Vasconcelos dual. Duality is verified by the type
776/// checker; non-dual programs are rejected at compile time.
777#[derive(Debug, Default)]
778pub struct SessionDefinition {
779 pub name: String,
780 pub roles: Vec<SessionRole>,
781 pub loc: Loc,
782 /// v1.5.2 — leading comment trivia attached to this declaration
783 /// (comments preceding the declaration's first token, since the
784 /// previous declaration or file start). Empty by default.
785 pub leading_trivia: Vec<crate::tokens::Trivia>,
786 /// v1.5.2 — trailing comment trivia (same line as the
787 /// declaration's last effective token). Empty by default.
788 pub trailing_trivia: Vec<crate::tokens::Trivia>,
789}
790
791/// `socket Name { protocol: SessionRef, backpressure: credit(n), reconnect:
792/// cognitive_state, legal_basis: ... }`
793///
794/// v2.3.0 — the typed WebSocket transport (paper_websocket_cognitive_primitive.md).
795/// `socket` is NOT the protocol — the protocol is a `session` it references by
796/// name (protocol and transport kept separate but composable). The type checker
797/// resolves `protocol` to a declared `session` (whose two roles are already
798/// duality-checked via the v2.3.0 algebra), so the dialogue carried over the WS
799/// connection is conformant + deadlock-free by construction.
800#[derive(Debug, Default)]
801pub struct SocketDefinition {
802 pub name: String,
803 /// The referenced `session` declaration's name — the protocol.
804 pub protocol: String,
805 /// The credit window of the typed-resource backpressure (`credit(n)`);
806 /// `None` if unspecified. A `0` credit is rejected by the type checker.
807 pub backpressure_credit: Option<i64>,
808 /// `reconnect: cognitive_state` → `true` (resume mid-dialogue via a sealed
809 /// v2.0.0 snapshot); absent or `reconnect: none` → `false`.
810 pub reconnect: bool,
811 /// Optional `legal_basis:` annotation (enterprise audit/shield gate).
812 pub legal_basis: Option<String>,
813 pub loc: Loc,
814 /// v1.5.2 — leading comment trivia.
815 pub leading_trivia: Vec<crate::tokens::Trivia>,
816 /// v1.5.2 — trailing comment trivia.
817 pub trailing_trivia: Vec<crate::tokens::Trivia>,
818}
819
820/// `upstream Name { transport:, protocol:, role:, resolve:, secret:, auth:,
821/// map: [...], reconnect: {...}, overflow:, backpressure: credit(n) }`
822///
823/// v2.37.0 — the client dual of `socket`: axon dials OUT to a third-party
824/// vendor (STT/TTS/realtime speech APIs). The axon-facing interface is a
825/// declared `session` (referenced by `protocol:`, same field meaning as
826/// `socket`) of which axon plays `role:`; the vendor side is realised by the
827/// `map:` projection rules — a compile-time-total transcoding contract
828/// (v2.37.0, axon-T849). `resolve:`/`secret:` name per-tenant config keys,
829/// never URL/credential literals (axon-T850) — the same "config, not code"
830/// property v2.8.0 gave `tool`, extended to persistent duplex streams.
831#[derive(Debug, Default)]
832pub struct UpstreamDefinition {
833 pub name: String,
834 /// Wire transport axon dials. Closed catalog; v1 sole member `websocket`.
835 pub transport: String,
836 /// The referenced `session` declaration's name — the axon-facing protocol.
837 pub protocol: String,
838 /// Which of the session's two roles axon plays; the peer role is the
839 /// vendor's, realised by the `map:` transcoding, never by axon code.
840 pub role: String,
841 /// Per-tenant config key holding the vendor URL (dot-separated,
842 /// `SecretKeyPolicy`-shaped — never a URL literal).
843 pub resolve: String,
844 /// v2.69.0 — the `resource` this upstream's channel runs on
845 /// (`upstream X { resource: Api }`). When present, the upstream DERIVES
846 /// its dial address from `resource.endpoint` (a per-tenant config key,
847 /// axon-T944) and its **max concurrent connection INSTANCES** from
848 /// `resource.capacity` — frames are already governed by
849 /// `backpressure_credit`, so capacity bounds CONNECTIONS, never frames
850 /// (making it frames would state one fact twice). Mutually exclusive
851 /// with `resolve:` (axon-T951): `resource:` beside a `resolve:` would
852 /// declare the channel's address twice — the v2.67.0 islands defect.
853 /// Authority attenuation: the resource encapsulates its own address
854 /// resolution; the upstream only names WHICH channel it rides.
855 pub resource_ref: String,
856 /// Per-tenant secret binding for the vendor credential (same charset).
857 pub secret: String,
858 /// Auth handshake kind: `header` | `query` | `signed_url`.
859 pub auth_kind: String,
860 /// Header/query-param name (`header("Authorization")` / `query("token")`).
861 pub auth_name: Option<String>,
862 /// Optional header value prefix (`header("Authorization", "Token ")`).
863 pub auth_prefix: Option<String>,
864 /// The wire↔session transcoding contract; totality checked at v2.37.0.
865 pub map: Vec<UpstreamMapRule>,
866 /// `reconnect: { backoff_ms:, max_attempts:, on_exhausted: }`.
867 pub reconnect: Option<UpstreamReconnect>,
868 /// Outbound-queue policy when the VENDOR is the slow side — a member of
869 /// the existing `BackpressurePolicy` catalog. `None` ⇒ `fail` (honest
870 /// default: no silently-lossy audio unless the adopter opts in).
871 pub overflow: Option<String>,
872 /// Axon-facing credit window, identical semantics to `socket`.
873 pub backpressure_credit: Option<i64>,
874 /// v2.37.0 — set when declared via `upstream X from Preset@vN {…}`;
875 /// carries the `Preset@vN` reference the desugar pass expanded.
876 pub preset: Option<String>,
877 pub loc: Loc,
878 /// v1.5.2 — leading comment trivia.
879 pub leading_trivia: Vec<crate::tokens::Trivia>,
880 /// v1.5.2 — trailing comment trivia.
881 pub trailing_trivia: Vec<crate::tokens::Trivia>,
882}
883
884/// One `map:` projection rule: `send M as json [tag "X"]` /
885/// `send M as binary` / `receive M as json [when "f" [= "v"]]` /
886/// `receive M as binary`. Inbound `json` payloads land as v2.26.0 `Json` (total
887/// navigation); the session message name is the routing + duality skeleton.
888#[derive(Debug, Default)]
889pub struct UpstreamMapRule {
890 /// `send` (axon → vendor) or `receive` (vendor → axon).
891 pub direction: String,
892 /// The session message type this rule transcodes.
893 pub message: String,
894 /// `json` or `binary` (raw passthrough).
895 pub framing: String,
896 /// send-json only. Absent ⇒ the payload is sent VERBATIM (the vendor's
897 /// exact wire shape, e.g. ElevenLabs `{"text": …}`); present ⇒ the tag
898 /// is injected as `"type": "<tag>"` into the payload object (the
899 /// Deepgram/OpenAI-Realtime envelope family).
900 pub tag: Option<String>,
901 /// receive-json only: discriminator field. Absent ⇒ the default
902 /// equality discriminator `"type" = "<MessageName>"`.
903 pub when_field: Option<String>,
904 /// receive-json only. `Some(v)` ⇒ equality match on `when_field`;
905 /// `None` with `when_field` present ⇒ field-PRESENCE match (vendors
906 /// like Gemini Live mark frame kinds by which key exists). Equality
907 /// rules dispatch before presence rules.
908 pub when_value: Option<String>,
909 pub loc: Loc,
910}
911
912/// `voice Name { stt:/tts: XOR realtime:, carrier:, interruptible:,
913/// legal_basis:, persona:, context: }`
914///
915/// v2.37.0 — the simplicity layer over v2.37.0's `upstream`: a blessed-
916/// preset phone agent in under 20 lines. `stt:`+`tts:` (cascaded) XOR
917/// `realtime:` (fused) — the design decision: one grammar, both architectures, never a
918/// special-cased second path. Each leg is a `Preset@vN` reference or a
919/// declared `upstream` name. Expansion is pure macro-lowering to existing
920/// primitives; `axon desugar` prints it.
921#[derive(Debug, Default)]
922pub struct VoiceDefinition {
923 pub name: String,
924 /// Cascaded STT leg (preset ref like `DeepgramSTT@v1` or upstream name).
925 pub stt: Option<String>,
926 /// Cascaded TTS leg.
927 pub tts: Option<String>,
928 /// Fused speech-to-speech leg (mutually exclusive with stt/tts — T852).
929 pub realtime: Option<String>,
930 /// Carrier codec: `mulaw8k` (default — PSTN; expansion emits the ots
931 /// μ-law↔PCM16 pair) or `pcm16` (browser/WebRTC-style, no transcode).
932 pub carrier: String,
933 /// `true` ⇒ the carrier session is a v2.36.0 interruptible region (barge-in
934 /// capable) and the socket parks residuals — which REQUIRES
935 /// `legal_basis:` (T852; the sugar must not generate a program
936 /// `ParkedResidualSoundness` refutes).
937 pub interruptible: bool,
938 /// Rides onto the generated socket (the v2.36.0 data-at-rest obligation).
939 pub legal_basis: Option<String>,
940 /// Optional references wired for the flow layer (validated to exist).
941 pub persona: Option<String>,
942 pub context: Option<String>,
943 pub loc: Loc,
944 /// v1.5.2 — leading comment trivia.
945 pub leading_trivia: Vec<crate::tokens::Trivia>,
946 /// v1.5.2 — trailing comment trivia.
947 pub trailing_trivia: Vec<crate::tokens::Trivia>,
948}
949
950/// `cors Name { allow_origins:, allow_methods:, allow_headers:,
951/// allow_credentials:, max_age:, expose_headers: }`
952///
953/// v2.38.0 — a named, referenced origin-policy declaration, mirroring
954/// `shield`'s shape exactly: declared once, referenced from any number of
955/// `axonendpoint`s via `cors: <Name>` (`AxonEndpointDefinition::cors_ref`).
956/// Makes the browser-facing origin policy a property of the ENDPOINT,
957/// resolved per the tenant's live deployed bundle — the shape a single
958/// process-wide CORS knob (the market-standard pattern) cannot express for
959/// a multi-tenant deploy where different bundles need different origins
960/// for a path with the same name.
961///
962/// **Unknown fields are a hard parse error** — a CORS policy is
963/// security-relevant, so `upstream`/`voice`'s stricter posture is followed
964/// here, not `shield`'s lenient `axon-W010` record-and-skip.
965#[derive(Debug, Default)]
966pub struct CorsDefinition {
967 pub name: String,
968 /// `["https://app.example.com", "https://*.kivi.io"]` — exact origins
969 /// or a single leading-wildcard host-label glob (the design decision/T854); no full
970 /// regex, matching the closed/decidable spirit of the rest of the
971 /// language. `["*"]` (any-origin) is legal UNLESS `allow_credentials`
972 /// is also `true` — that combination is `axon-T853` (the design decision, the CORS
973 /// spec's own rule, caught at compile time instead of a silent browser
974 /// rejection).
975 pub allow_origins: Vec<String>,
976 /// Reuses the closed `axonendpoint` method catalog (GET/POST/PUT/
977 /// PATCH/DELETE) — validated against the same list, not a free string
978 /// (T855).
979 pub allow_methods: Vec<String>,
980 /// Request headers the preflight may allow (e.g. `["Content-Type",
981 /// "Authorization"]`) — free-form header-name strings (hyphens are
982 /// common in real header names, hence string literals, not bare
983 /// identifiers).
984 pub allow_headers: Vec<String>,
985 /// `true` ⇒ `Access-Control-Allow-Credentials: true` is emitted.
986 /// Forbidden together with an any-origin `allow_origins` (T853).
987 pub allow_credentials: bool,
988 /// `Access-Control-Max-Age` — a duration literal (`"3600s"`, `"1h"`),
989 /// same lexer/token convention as `axonendpoint.timeout`. `None` ⇒ the
990 /// header is omitted (browser default caching applies).
991 pub max_age: Option<String>,
992 /// `Access-Control-Expose-Headers` — response headers the browser's
993 /// JS may read beyond the CORS-safelisted set. Free-form strings, same
994 /// rationale as `allow_headers`.
995 pub expose_headers: Vec<String>,
996 pub loc: Loc,
997 /// v1.5.2 — leading comment trivia.
998 pub leading_trivia: Vec<crate::tokens::Trivia>,
999 /// v1.5.2 — trailing comment trivia.
1000 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1001}
1002
1003/// v2.46.0 — `credential <Name> { ttl: grants: }`: a named
1004/// ephemeral-credential contract. `mint <Name> as <binding>` (v2.46.0) mints
1005/// a TTL-bounded bearer carrying exactly `grants` — and the runtime law
1006/// (`authority_only_attenuates`) admits the mint only when
1007/// `grants ⊆ capabilities(minter)`. An unknown field in a `credential { }`
1008/// block is a HARD PARSE ERROR (the v2.38.0 posture — this is security
1009/// surface; a typo'd field must not silently produce a permissive
1010/// contract).
1011#[derive(Debug, Default)]
1012pub struct CredentialDefinition {
1013 pub name: String,
1014 /// The bearer's lifetime — a duration literal (`"15m"`, `"900s"`),
1015 /// REQUIRED. Validated by `axon-T894`: parseable, > 0, and ≤ the closed
1016 /// 24h ceiling (an "ephemeral" credential that lives for days is a
1017 /// service account wearing a costume — v2.46.0 covers that shape).
1018 pub ttl: String,
1019 /// The capability slugs the minted bearer carries — REQUIRED,
1020 /// non-empty (`axon-T893`), each a dotted slug per
1021 /// `is_valid_capability_slug` (the `requires:` grammar). Attenuation
1022 /// (`⊆ minter`) is the runtime/mint-time half of the law.
1023 pub grants: Vec<String>,
1024 pub loc: Loc,
1025 /// v1.5.2 — leading comment trivia.
1026 pub leading_trivia: Vec<crate::tokens::Trivia>,
1027 /// v1.5.2 — trailing comment trivia.
1028 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1029}
1030
1031/// `cache Name { backend:, ttl:, key:, default:, apply_to_effects:,
1032/// invalidate_on: }` — v2.40.0, a named, referenced result-memoization
1033/// policy resolved per `tool.cache:` / `retrieve.cache:` (mirrors
1034/// `CorsDefinition`'s named-and-referenced shape).
1035///
1036/// The load-bearing idea: cacheability derives from the type system's
1037/// existing `effects: pure` proof — a `pure` tool is safe to cache by
1038/// construction. A `default: true` cache auto-covers every `pure` tool with
1039/// zero per-tool annotation; widening `apply_to_effects:` beyond `[pure]` is
1040/// allowed but the compiler names every non-pure tool it covers (W013) AND
1041/// forces a finite `ttl:` (T865 — you may cache a proven-deterministic result
1042/// forever, never a non-deterministic one).
1043///
1044/// **Unknown fields are a hard parse error** (the v2.38.0 the design decision discipline) — a
1045/// cache governs correctness (serving a stale/foreign result is a real bug), so
1046/// a typo'd field can never silently mean "no policy."
1047#[derive(Debug, Default)]
1048pub struct CacheDefinition {
1049 pub name: String,
1050 /// `redis` (multi-replica, enterprise tier) or `in_process` (the OSS
1051 /// default single-replica tier). Empty ⇒ `in_process`. Validated against a
1052 /// closed catalog at check time.
1053 pub backend: String,
1054 /// Time-to-live as a duration literal (`"10s"`, `"5m"`, `"1h"`), same lexer
1055 /// convention as `cors.max_age`/`tool.timeout`. `None` ⇒ "cache forever" —
1056 /// sound ONLY for a provably-`pure` cache; a non-pure cache with no `ttl:`
1057 /// is `axon-T865`.
1058 pub ttl: Option<String>,
1059 /// `key: [param, ...]` — the SUBSET of the covered tool's `parameters:`
1060 /// whose bound values form the cache key. Empty ⇒ ALL bound parameters
1061 /// (the automatic, zero-friction default). Used when one bound arg — e.g. a
1062 /// `request_id` — must NOT affect the key.
1063 pub key_params: Vec<String>,
1064 /// `default: true` ⇒ this cache auto-covers every eligible tool in the
1065 /// module without a per-tool `cache:` reference. At most one per module
1066 /// (`axon-T863`). Default `false`.
1067 pub default_policy: bool,
1068 /// `apply_to_effects: [pure, ...]` — the effect classes this cache is
1069 /// willing to memoise. Empty ⇒ `[pure]` (the only provably-safe default).
1070 /// Any member beyond `pure` is a WIDENING (W013 names each covered tool)
1071 /// and forces a finite `ttl:` (T865).
1072 pub apply_to_effects: Vec<String>,
1073 /// `invalidate_on: [Channel, ...]` — an `emit` on any listed channel
1074 /// flushes this cache's namespace. Each must resolve to a declared
1075 /// `channel` (`axon-T864`). Reuses the v1.6.0 pub/sub, not a second mechanism.
1076 pub invalidate_on: Vec<String>,
1077 pub loc: Loc,
1078 /// v1.5.2 — leading comment trivia.
1079 pub leading_trivia: Vec<crate::tokens::Trivia>,
1080 /// v1.5.2 — trailing comment trivia.
1081 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1082}
1083
1084/// v2.42.0 — `savant <Name> { domain:, cognition{…}, memory{…}, budget{…},
1085/// mandate <M> {…} … }` — the long-horizon autonomous research primitive.
1086///
1087/// A `savant` is a declarative ORCHESTRATOR, not a new engine: it composes the
1088/// primitives Axon already ships (memory/corpus retention, `par` swarms, the
1089/// `quant` Hilbert substrate, `forge` novelty synthesis, the `daemon` host, the
1090/// v2.28.0 linear budget, the v2.36.0 interruptible session, the v2.34.0 signed egress)
1091/// into a single governed research loop. The paper's vision (papers/
1092/// paper_primitiva_savant.md) grounded to real primitives in its section 9.
1093///
1094/// v2.42.0 parses the FULL block surface; the semantics land incrementally:
1095/// param-catalog + typed-output validation is v2.42.0 (checker), memory-ref
1096/// resolution + v2.28.0 budget binding + v2.36.0 interruptibility is v2.42.0, and the
1097/// `SavantSoundness` PCC proof is v2.42.0. **Unknown fields are a hard parse
1098/// error** (the v2.38.0 the design decision discipline, as `cache`/`cors`): a savant governs an
1099/// expensive, risk-bearing autonomous process, so a typo'd field can never
1100/// silently mean "no policy."
1101#[derive(Debug, Default)]
1102pub struct SavantDefinition {
1103 pub name: String,
1104 /// `domain: "…"` — the ontological scope of the generative boundary (the
1105 /// research topic the free-energy loop minimises surprise over). Required
1106 /// (v2.42.0 `axon-T873`); empty until parsed.
1107 pub domain: String,
1108 /// `cognition { … }` — the epistemic parameters of the active-inference
1109 /// engine (depth / entropic threshold / divergence). `None` ⇒ engine
1110 /// defaults (v2.42.0 supplies a catalog-checked default).
1111 pub cognition: Option<SavantCognition>,
1112 /// `memory { … }` — the retention layer. `backend` resolves to a declared
1113 /// `memory`/`corpus` primitive in v2.42.0 (`axon-T875`); `None` ⇒ ephemeral.
1114 pub memory: Option<SavantMemory>,
1115 /// `budget { … }` — the compute ceiling. Bound to a v2.28.0 linear budget
1116 /// (`RateLease`) in v2.42.0 so `max_iterations` is a TYPE-enforced ceiling,
1117 /// not a hope. `None` ⇒ v2.42.0 rejects (a weeks-long autonomous loop with no
1118 /// budget is uninsurable).
1119 pub budget: Option<SavantBudget>,
1120 /// `mandate <Name> { objective:, output: }` — one or more epistemic
1121 /// mandates the savant autonomously decomposes into tasks. At least one
1122 /// required (v2.42.0 `axon-T874`).
1123 pub mandates: Vec<SavantMandate>,
1124 pub loc: Loc,
1125 /// v1.5.2 — leading comment trivia.
1126 pub leading_trivia: Vec<crate::tokens::Trivia>,
1127 /// v1.5.2 — trailing comment trivia.
1128 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1129}
1130
1131/// v2.42.0 — the `cognition { … }` sub-block of a [`SavantDefinition`]: the
1132/// active-inference engine's epistemic parameters (paper section 3, section 7.1).
1133#[derive(Debug, Default)]
1134pub struct SavantCognition {
1135 /// `depth: standard | deep | hyper` — the HRR dimensionality tier of the
1136 /// holographic memory codec. Closed catalog (v2.42.0 `axon-T876`).
1137 pub depth: String,
1138 /// `entropic_threshold: <float>` — the Expected-Free-Energy convergence
1139 /// bound: the loop halts synthesis when no policy reduces EFE below this.
1140 /// Must be `> 0` (v2.42.0). `None` ⇒ engine default.
1141 pub entropic_threshold: Option<f64>,
1142 /// `divergence: low | med | high` — how aggressively the loop explores
1143 /// epistemic (β₂) voids vs. exploiting known structure. Closed catalog.
1144 pub divergence: String,
1145 pub loc: Loc,
1146}
1147
1148/// v2.42.0 — the `memory { … }` sub-block of a [`SavantDefinition`]: the
1149/// durable retention layer, composed from existing `memory`/`corpus` primitives.
1150#[derive(Debug, Default)]
1151pub struct SavantMemory {
1152 /// `backend: <Name>` — a reference to a declared `memory` or `corpus`
1153 /// primitive (resolved in v2.42.0 `axon-T875`). Empty ⇒ ephemeral memory.
1154 pub backend: String,
1155 /// `corpus_graph: <bool>` — whether to iteratively index the ingested
1156 /// corpus as a simplicial-complex graph for the topological (β_n) reading.
1157 pub corpus_graph: bool,
1158 /// `isolation_level: strict | …` — per-tenant tensor partitioning. The
1159 /// enterprise engine enforces it; OSS records it. Empty ⇒ default.
1160 pub isolation_level: String,
1161 pub loc: Loc,
1162}
1163
1164/// v2.42.0 — the `budget { … }` sub-block of a [`SavantDefinition`]: the
1165/// compute ceiling, bound to a v2.28.0 linear budget in v2.42.0.
1166#[derive(Debug, Default)]
1167pub struct SavantBudget {
1168 /// `max_iterations: <int>` — the hard ceiling on FEP-loop iterations before
1169 /// the savant pauses (the paper's `compute_budget`). `> 0` (v2.42.0).
1170 pub max_iterations: Option<i64>,
1171 /// `max_tool_synth: <int>` — the hard ceiling on `synth` (v2.42.0) dynamic
1172 /// tool-creation events per mandate. `None` ⇒ 0 (no synthesis).
1173 pub max_tool_synth: Option<i64>,
1174 pub loc: Loc,
1175}
1176
1177/// v2.42.0 — a `mandate <Name> { objective:, output: }` sub-block of a
1178/// [`SavantDefinition`]: one epistemic research goal the savant pursues.
1179#[derive(Debug, Default)]
1180pub struct SavantMandate {
1181 pub name: String,
1182 /// `objective: "…"` — the natural-language research goal. Required
1183 /// (non-empty, v2.42.0 `axon-T874`).
1184 pub objective: String,
1185 /// `output: <Type>` — the declared type the final report must inhabit
1186 /// (resolved to a declared `type` in v2.42.0). Required.
1187 pub output_type: String,
1188 pub loc: Loc,
1189}
1190
1191/// v2.42.0 — `synth <Name> { target:, risk:, language:, sandbox:, review:,
1192/// max_lines: }` — a dynamic tool-synthesis policy.
1193///
1194/// A `savant` that hits an epistemic gap it has no tool for can, under such a
1195/// policy, deduce + write a tool (a Coder sub-agent, a Reviewer sub-agent — a
1196/// `par` with an agreement condition), compile it to `wasm32-wasi`, and run it
1197/// in an Extism zero-trust sandbox, feeding stdout back as empirical evidence
1198/// (paper section 6). The policy declares the SAFETY ENVELOPE; the runtime enforces it.
1199///
1200/// **Deny-by-default (D87.d):** OSS parses + statically disciplines this policy
1201/// but ships a `SynthBackend` reference that REFUSES to execute — running
1202/// untrusted synthesised code needs the enterprise Extism/gVisor isolation
1203/// (v2.42.0). The checker therefore requires `sandbox: wasm` (T882): a synth
1204/// policy that would run code outside a sandbox can never compile.
1205///
1206/// **Unknown fields are a hard parse error**: a synth policy governs
1207/// arbitrary-code execution — the highest-stakes surface in the language.
1208#[derive(Debug, Default)]
1209pub struct SynthDefinition {
1210 pub name: String,
1211 /// `target: "…"` — what the synthesised tools are for (the capability scope).
1212 /// Required (v2.42.0 `axon-T879`).
1213 pub target: String,
1214 /// `risk: low | medium | high | critical` — the ceiling risk class the
1215 /// policy admits; governs review + isolation strictness. Required
1216 /// (v2.42.0 `axon-T880`).
1217 pub risk: String,
1218 /// `language: rust | c | python` — the allowed synthesis source language
1219 /// (all compiled to `wasm32-wasi`). Empty ⇒ any admitted language
1220 /// (v2.42.0 `axon-T881` validates when present).
1221 pub language: String,
1222 /// `sandbox: wasm` — the isolation tier. MUST be `wasm` (v2.42.0 `axon-T882`
1223 /// deny-by-default): synthesised code may only run in a zero-trust WASM
1224 /// sandbox. Empty ⇒ error (never a silent "no sandbox").
1225 pub sandbox: String,
1226 /// `review: required | none` — the Coder/Reviewer consensus requirement.
1227 /// Empty ⇒ `required` (the safe default). `none` is FORBIDDEN for
1228 /// `high`/`critical` risk (v2.42.0 `axon-T883`).
1229 pub review: String,
1230 /// `max_lines: <int>` — an optional hard cap on synthesised source length
1231 /// (a smaller attack + review surface). `None` ⇒ engine default.
1232 pub max_lines: Option<i64>,
1233 pub loc: Loc,
1234 /// v1.5.2 — leading comment trivia.
1235 pub leading_trivia: Vec<crate::tokens::Trivia>,
1236 /// v1.5.2 — trailing comment trivia.
1237 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1238}
1239
1240/// `reconnect: { backoff_ms: 500, max_attempts: 5, on_exhausted: fail }` —
1241/// exponential backoff (doubling from `backoff_ms`, jittered at runtime), at
1242/// most `max_attempts` redials; `on_exhausted` is a closed catalog mirroring
1243/// `budget`'s style (v1 sole member `fail` — fail-closed, the flow sees the
1244/// exhaustion; `degrade`/`park` are named deferred scope).
1245#[derive(Debug, Default)]
1246pub struct UpstreamReconnect {
1247 pub backoff_ms: i64,
1248 pub max_attempts: i64,
1249 pub on_exhausted: String,
1250}
1251
1252/// `source -> target : Session` — one directed edge of a topology.
1253///
1254/// Convention: the source plays the FIRST role of the session; the target
1255/// plays the SECOND role. Fixed so assignment is unambiguous.
1256#[derive(Debug, Default)]
1257pub struct TopologyEdge {
1258 pub source: String,
1259 pub target: String,
1260 pub session_ref: String,
1261 pub loc: Loc,
1262}
1263
1264/// `topology Name { nodes: […] edges: [A -> B : Session, …] }`
1265///
1266/// A typed directed graph over Axon entities. Edges carry session references
1267/// whose duality the type checker enforces; the graph is statically analysed
1268/// for Honda-liveness (deadlock-prone cycles).
1269#[derive(Debug, Default)]
1270pub struct TopologyDefinition {
1271 pub name: String,
1272 pub nodes: Vec<String>,
1273 pub edges: Vec<TopologyEdge>,
1274 pub loc: Loc,
1275 /// v1.5.2 — leading comment trivia attached to this declaration
1276 /// (comments preceding the declaration's first token, since the
1277 /// previous declaration or file start). Empty by default.
1278 pub leading_trivia: Vec<crate::tokens::Trivia>,
1279 /// v1.5.2 — trailing comment trivia (same line as the
1280 /// declaration's last effective token). Empty by default.
1281 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1282}
1283
1284// ── v1.1.0 — Cognitive immune system (per paper_immune_v2.md) ────────
1285
1286/// `immune Name { watch, sensitivity, baseline, window, scope, tau, decay }`
1287///
1288/// A continuous anomaly sensor over a declared observation vector.
1289/// Computes D_KL(q_baseline || p_observed) (paper section 3.2) and emits a
1290/// HealthReport at an epistemic level derived from the KL magnitude.
1291///
1292/// Pure sensor — `immune` takes NO action. Actions belong to `reflex`
1293/// and `heal`, which consume its HealthReport.
1294#[derive(Debug, Default)]
1295pub struct ImmuneDefinition {
1296 pub name: String,
1297 pub watch: Vec<String>, // observe / ensemble / any declared ref
1298 pub sensitivity: Option<f64>, // [0.0, 1.0]
1299 pub baseline: String, // "learned" (default) or name of a prior
1300 pub window: i64, // samples used to estimate baseline (default: 100)
1301 pub scope: String, // tenant | flow | global (MANDATORY, paper section 8.2)
1302 pub tau: String, // duration half-life
1303 pub decay: String, // exponential (default) | linear | none
1304 pub loc: Loc,
1305 /// v1.5.2 — leading comment trivia attached to this declaration
1306 /// (comments preceding the declaration's first token, since the
1307 /// previous declaration or file start). Empty by default.
1308 pub leading_trivia: Vec<crate::tokens::Trivia>,
1309 /// v1.5.2 — trailing comment trivia (same line as the
1310 /// declaration's last effective token). Empty by default.
1311 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1312}
1313
1314/// `reflex Name { trigger, on_level, action, scope, sla }`
1315///
1316/// Deterministic, O(1) motor response. Contract invariants (paper section 4.2):
1317/// never invokes an LLM; no long-running I/O; every activation emits a
1318/// signed_trace; idempotent on the same HealthReport.
1319#[derive(Debug, Default)]
1320pub struct ReflexDefinition {
1321 pub name: String,
1322 pub trigger: String, // immune name (MANDATORY)
1323 pub on_level: String, // know | believe | speculate | doubt (default: doubt)
1324 pub action: String, // drop | revoke | emit | redact | quarantine | terminate | alert
1325 pub scope: String, // MANDATORY, paper section 8.2
1326 pub sla: String, // duration budget (e.g. "1ms")
1327 pub loc: Loc,
1328 /// v1.5.2 — leading comment trivia attached to this declaration
1329 /// (comments preceding the declaration's first token, since the
1330 /// previous declaration or file start). Empty by default.
1331 pub leading_trivia: Vec<crate::tokens::Trivia>,
1332 /// v1.5.2 — trailing comment trivia (same line as the
1333 /// declaration's last effective token). Empty by default.
1334 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1335}
1336
1337/// `heal Name { source, on_level, mode, scope, review_sla, shield, max_patches }`
1338///
1339/// Linear-Logic one-shot patch synthesis. Patch type:
1340/// `!Synthesized ⊸ Applied ⊸ Collapsed` (paper section 6) — each transition
1341/// consumes its predecessor, guaranteeing single application + forced collapse.
1342///
1343/// Mode ∈ {audit_only | human_in_loop | adversarial} controls automation
1344/// (paper section 7); `adversarial` REQUIRES a shield gate (paper section 7.3).
1345#[derive(Debug, Default)]
1346pub struct HealDefinition {
1347 pub name: String,
1348 pub source: String, // immune name (MANDATORY)
1349 pub on_level: String, // know | believe | speculate | doubt
1350 pub mode: String, // audit_only | human_in_loop | adversarial
1351 pub scope: String, // MANDATORY
1352 pub review_sla: String, // duration
1353 pub shield_ref: String, // optional shield gate (required for adversarial)
1354 pub max_patches: i64, // bounded heal attempts (default: 3)
1355 pub loc: Loc,
1356 /// v1.5.2 — leading comment trivia attached to this declaration
1357 /// (comments preceding the declaration's first token, since the
1358 /// previous declaration or file start). Empty by default.
1359 pub leading_trivia: Vec<crate::tokens::Trivia>,
1360 /// v1.5.2 — trailing comment trivia (same line as the
1361 /// declaration's last effective token). Empty by default.
1362 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1363}
1364
1365// ── v1.3.1 — UI cognitiva (component / view) ─────────────────────────
1366
1367/// `component Name { renders, via_shield, on_interact, render_hint }`.
1368///
1369/// A reusable UI fragment. `renders` is the data type the component
1370/// visualizes; if that type has κ, `via_shield` is mandatory and its
1371/// compliance set MUST cover the type's κ (compile-time enforcement).
1372#[derive(Debug, Default)]
1373pub struct ComponentDefinition {
1374 pub name: String,
1375 pub renders: String,
1376 pub via_shield: String,
1377 pub on_interact: String,
1378 pub render_hint: String, // card | list | form | chart | custom
1379 pub loc: Loc,
1380 /// v1.5.2 — leading comment trivia attached to this declaration
1381 /// (comments preceding the declaration's first token, since the
1382 /// previous declaration or file start). Empty by default.
1383 pub leading_trivia: Vec<crate::tokens::Trivia>,
1384 /// v1.5.2 — trailing comment trivia (same line as the
1385 /// declaration's last effective token). Empty by default.
1386 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1387}
1388
1389/// `view Name { title, components: [...], route }`.
1390///
1391/// A top-level screen. `components` is an ordered list of declared
1392/// `component` names composed in the view's primary layout.
1393#[derive(Debug, Default)]
1394pub struct ViewDefinition {
1395 pub name: String,
1396 pub title: String,
1397 pub components: Vec<String>,
1398 pub route: String,
1399 pub loc: Loc,
1400 /// v1.5.2 — leading comment trivia attached to this declaration
1401 /// (comments preceding the declaration's first token, since the
1402 /// previous declaration or file start). Empty by default.
1403 pub leading_trivia: Vec<crate::tokens::Trivia>,
1404 /// v1.5.2 — trailing comment trivia (same line as the
1405 /// declaration's last effective token). Empty by default.
1406 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1407}
1408
1409// ── Tier 2+ structural fallback ──────────────────────────────────────────────
1410
1411/// A declaration we recognize by keyword but parse only structurally.
1412/// Validates brace balance and captures keyword + name.
1413#[derive(Debug)]
1414pub struct GenericDeclaration {
1415 pub keyword: String,
1416 pub name: String,
1417 pub loc: Loc,
1418 /// v1.5.2 — leading comment trivia attached to this declaration
1419 /// (comments preceding the declaration's first token, since the
1420 /// previous declaration or file start). Empty by default.
1421 pub leading_trivia: Vec<crate::tokens::Trivia>,
1422 /// v1.5.2 — trailing comment trivia (same line as the
1423 /// declaration's last effective token). Empty by default.
1424 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1425}
1426
1427// ── Agent ────────────────────────────────────────────────────────────────────
1428
1429#[derive(Debug)]
1430pub struct AgentDefinition {
1431 pub name: String,
1432 pub goal: String,
1433 pub tools: Vec<String>,
1434 pub memory_ref: String,
1435 pub strategy: String, // react | reflexion | plan_and_execute | custom
1436 pub on_stuck: String, // forge | hibernate | escalate | retry
1437 pub shield_ref: String,
1438 pub max_iterations: Option<i64>,
1439 pub max_tokens: Option<i64>,
1440 pub max_time: String,
1441 pub max_cost: Option<f64>,
1442 /// The declared result type of the agent — `return: T` inside the block,
1443 /// or the `-> T` position after the name. Empty when undeclared. Checked
1444 /// against the declared types (axon-T1219) and against the `output:` of
1445 /// the step that calls the agent.
1446 pub return_type: String,
1447 /// The `step … { … }` sequence written inside the agent block — the control
1448 /// policy of `strategy: custom`. Empty for every other strategy (a body
1449 /// under `react`/`reflexion`/`plan_and_execute` is axon-T1217). Until 4.1.0
1450 /// the parser discarded these blocks and `custom` was refused at dispatch.
1451 pub body: Vec<StepNode>,
1452 pub loc: Loc,
1453 /// v1.5.2 — leading comment trivia attached to this declaration
1454 /// (comments preceding the declaration's first token, since the
1455 /// previous declaration or file start). Empty by default.
1456 pub leading_trivia: Vec<crate::tokens::Trivia>,
1457 /// v1.5.2 — trailing comment trivia (same line as the
1458 /// declaration's last effective token). Empty by default.
1459 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1460}
1461
1462// ── v2.5.0 — Closed-catalog extension mechanism ────────────────────────────
1463
1464/// One member of an `extension` declaration. For `category: effects`
1465/// the `name` is a provenance base (e.g. `"epistemic:believe"`) with
1466/// optional `semantics` + `default_confidence` (a CEILING, never a
1467/// floor — v2.5.0 tainted-overriding). For `category: scan` the `name`
1468/// is a scan-category identifier and the metadata is typically absent.
1469#[derive(Debug, Clone)]
1470pub struct ExtensionMember {
1471 pub name: String,
1472 pub semantics: Option<String>,
1473 pub default_confidence: Option<f64>,
1474 pub loc: Loc,
1475}
1476
1477/// `extension Name { category: effects|scan, members: [ "x" : { … }, … ] }`
1478///
1479/// v2.5.0. A first-class, auditable + gateable declaration that
1480/// expands a closed catalog with adopter-specific PROVENANCE members.
1481/// Soundness invariants (validated in v2.5.0/v2.5.0): members are
1482/// provenance-class only (never the enforceable effect set), must not
1483/// shadow a canonical base/category, and ride in the IR + proof bundle
1484/// so an independent PCC verifier re-derives against the same artifact.
1485#[derive(Debug)]
1486pub struct ExtensionDefinition {
1487 pub name: String,
1488 /// `effects` | `scan` — validated against the closed category set
1489 /// in v2.5.0 (the type-checker), not the parser.
1490 pub category: String,
1491 pub members: Vec<ExtensionMember>,
1492 pub loc: Loc,
1493 /// v1.5.2 — leading comment trivia. Empty by default.
1494 pub leading_trivia: Vec<crate::tokens::Trivia>,
1495 /// v1.5.2 — trailing comment trivia. Empty by default.
1496 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1497}
1498
1499// ── Shield ───────────────────────────────────────────────────────────────────
1500
1501/// v2.27.0 — a temporal execution-window guard. Where `shield` guards the
1502/// CONTENT of an emission and `anchor` guards its TRUTH, `window` guards its
1503/// TIMING: whether a scheduled (cron) tick runs, by timezone-aware day/hour
1504/// windows. The runtime decision (`is_in_window`) lands in v2.27.0; the daemon
1505/// binding + the defer ledger in v2.27.0.
1506#[derive(Debug)]
1507pub struct WindowDefinition {
1508 pub name: String,
1509 /// IANA timezone (`"America/Bogota"`). Format-checked at compile time
1510 /// (v2.27.0); full IANA membership validated by the runtime (v2.27.0, chrono-tz).
1511 pub timezone: String,
1512 /// The allowed day/hour spans (at least one). A tick inside ANY span runs.
1513 pub allow: Vec<WindowSpan>,
1514 /// v2.27.0 — excluded dates (holidays): ISO `YYYY-MM-DD` date-string
1515 /// literals (`exclude: [ "2026-12-25", "2026-01-01" ]`). A tick whose local
1516 /// date (in `timezone`) is in this set is OUTSIDE the window regardless of the
1517 /// hour spans. The dates are LITERAL — part of the verified program, so the
1518 /// decision stays a pure, replayable function of `(now, the window, the tz-db
1519 /// version)` (the `time_is_an_explicit_input` doctrine). Empty ⇒ no holidays.
1520 pub exclude: Vec<String>,
1521 /// What to do when a tick falls OUTSIDE every allowed span:
1522 /// `skip` | `defer` | `warn` (closed catalog).
1523 pub on_outside: String,
1524 pub loc: Loc,
1525 pub leading_trivia: Vec<crate::tokens::Trivia>,
1526 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1527}
1528
1529/// v2.27.0 — one allowed day/hour span, `{ days: Mon..Fri, hours: 9..18 }`.
1530/// `days` are inclusive weekday-name bounds; `hours` are inclusive 0–23 bounds.
1531#[derive(Debug)]
1532pub struct WindowSpan {
1533 pub day_start: String,
1534 pub day_end: String,
1535 pub hour_start: i64,
1536 pub hour_end: i64,
1537 pub loc: Loc,
1538}
1539
1540/// `attest <Name> { for:, basis:, residual:, by:, on: }`
1541///
1542/// v4.5.0 — the half of a de-identification that a compiler cannot produce.
1543///
1544/// A declassification retires a regulatory class from a value, and by v4.5.0
1545/// the compiler decides most of what that requires: the class is real, the
1546/// control declares the capability, the destination type no longer carries the
1547/// class, every enumerable identifier is removed or reduced. What it cannot
1548/// decide is the remainder — the eighteenth Safe Harbor class and the
1549/// actual-knowledge clause, both of which quantify over facts the program does
1550/// not contain — and, entirely, the other legal route: expert determination.
1551///
1552/// Those do not become weaker compiler claims. They become a signature, with an
1553/// owner and a date, that travels in the evidence package NEXT TO the proof and
1554/// distinct from it. The point of the separation is that a reader can see where
1555/// the machine stopped talking and a person started.
1556///
1557/// It is a top-level declaration and not a `shield` block, per the founder’s
1558/// ratification: a shield is a control that executes and its scope ends with
1559/// the run, while an attestation is a fact that outlives the control that
1560/// motivated it — reused for a later legal basis, cited by a second
1561/// determination, and shipped on its own.
1562#[derive(Debug, Default)]
1563pub struct AttestDefinition {
1564 pub name: String,
1565 /// The type this determination is ABOUT — the output of the
1566 /// declassification, not its input. An attestation over the regulated
1567 /// value would be a statement about data nobody claimed was clean.
1568 pub for_type: String,
1569 /// `safe_harbor` | `expert_determination` — see `ATTESTATION_BASES`.
1570 pub basis: String,
1571 /// The judgements the signer takes on: precisely what the compiler left
1572 /// open. See `RESIDUAL_JUDGEMENTS`.
1573 pub residual: Vec<String>,
1574 /// Who signs. Prose on purpose — the compiler has no register of people
1575 /// and inventing a closed catalogue of them would be a fiction. What it
1576 /// CAN require is that the field not be empty, because an unattributed
1577 /// attestation is indistinguishable from a shortcut.
1578 pub by: String,
1579 /// When, ISO-8601. A determination is about a state of the world on a
1580 /// date; without one it cannot be superseded, and a determination that
1581 /// cannot go stale is not a determination.
1582 pub on: String,
1583 pub unknown_fields: Vec<(String, Loc)>,
1584 pub loc: Loc,
1585 pub leading_trivia: Vec<crate::tokens::Trivia>,
1586 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1587}
1588
1589#[derive(Debug)]
1590pub struct ShieldDefinition {
1591 pub name: String,
1592 pub scan: Vec<String>,
1593 pub strategy: String, // pattern | classifier | dual_llm | canary | perplexity | ensemble
1594 pub on_breach: String, // halt | sanitize_and_retry | escalate | quarantine | deflect
1595 pub severity: String, // low | medium | high | critical
1596 pub quarantine: String,
1597 pub max_retries: Option<i64>,
1598 pub confidence_threshold: Option<f64>,
1599 pub allow_tools: Vec<String>,
1600 pub deny_tools: Vec<String>,
1601 pub sandbox: Option<bool>,
1602 pub redact: Vec<String>,
1603 /// v4.5.0 — the regulatory classes this shield is authorised to RETIRE.
1604 ///
1605 /// Empty for almost every shield, and that is the point: scanning is not
1606 /// declassifying. A control that can end a regulatory obligation says so.
1607 pub declassifies: Vec<String>,
1608 /// v4.5.0 — the identifier KINDS this control removes entirely.
1609 ///
1610 /// Kinds, not field names, deliberately. A control that named
1611 /// `[mrn, ssn]` would be welded to one type's spelling and useless on the
1612 /// next; a control that names `[medical_record_number, ssn]` describes
1613 /// what it does to DATA and is reusable wherever that data appears. It is
1614 /// also the only form the catalogue can check: field names are prose.
1615 pub suppress: Vec<String>,
1616 /// v4.5.0 — the identifier kinds this control REDUCES rather than removes.
1617 ///
1618 /// The shield names the kind; the regime says how. Safe Harbor reduces a
1619 /// date to its year and a postal code to three digits, and those
1620 /// operations come from `HIPAA_SAFE_HARBOR` rather than being restated
1621 /// here — an author who could restate them could restate them wrong, and
1622 /// the regulation is the source.
1623 pub generalise: Vec<String>,
1624 pub log: String,
1625 pub deflect_message: String,
1626 pub taint: String,
1627 /// ESK — regulatory coverage (HIPAA, PCI_DSS, GDPR, …).
1628 pub compliance: Vec<String>,
1629 /// v2.34.0 — egress signing algorithm (closed catalog: `hmac_sha256`,
1630 /// `axon-T846`). Empty = the shield does not sign. A shield with `sign:`
1631 /// is an EGRESS shield: `publish <Channel> within <Shield>` marks the
1632 /// channel for signed external delivery (v2.34.0).
1633 pub sign: String,
1634 /// v2.34.0 (`axon-W010`) — block fields the parser did not recognize,
1635 /// with their source locations. Pre-77 the parser silently discarded
1636 /// these (`_ => skip_value()`), so a typo or an unsupported field passed
1637 /// `axon check` unremarked (Kivi brief #51 B.3). The parser still skips
1638 /// the VALUE (leniency preserved — existing programs keep compiling) but
1639 /// records the NAME so the type checker can warn honestly.
1640 pub unknown_fields: Vec<(String, Loc)>,
1641 pub loc: Loc,
1642 /// v1.5.2 — leading comment trivia attached to this declaration
1643 /// (comments preceding the declaration's first token, since the
1644 /// previous declaration or file start). Empty by default.
1645 pub leading_trivia: Vec<crate::tokens::Trivia>,
1646 /// v1.5.2 — trailing comment trivia (same line as the
1647 /// declaration's last effective token). Empty by default.
1648 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1649}
1650
1651// ── Pix ──────────────────────────────────────────────────────────────────────
1652
1653#[derive(Debug)]
1654pub struct PixDefinition {
1655 pub name: String,
1656 pub source: String,
1657 pub depth: Option<i64>,
1658 pub branching: Option<i64>,
1659 pub model: String,
1660 pub loc: Loc,
1661 /// v1.5.2 — leading comment trivia attached to this declaration
1662 /// (comments preceding the declaration's first token, since the
1663 /// previous declaration or file start). Empty by default.
1664 pub leading_trivia: Vec<crate::tokens::Trivia>,
1665 /// v1.5.2 — trailing comment trivia (same line as the
1666 /// declaration's last effective token). Empty by default.
1667 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1668}
1669
1670// ── Ledger ─────────────────────────────────────────────────────────────────
1671// v2.12.0 — the append-only, hash-linked audit chain. Took over the
1672// Provenance-Index role that `pix` historically (and only in the ℰMCP doc)
1673// occupied, so `pix` is freed for its true meaning: the PIX retrieval
1674// navigator (paper `paper_pix_formal_research.md`). A `ledger` binds a chain
1675// recorder to an audited surface (`axonstore://X`, `flow://X`, …); `depth`
1676// is chain retention, `branching` the Merkle factor, `model` the hash slug.
1677
1678#[derive(Debug)]
1679pub struct LedgerDefinition {
1680 pub name: String,
1681 pub source: String,
1682 pub depth: Option<i64>,
1683 pub branching: Option<i64>,
1684 pub model: String,
1685 pub loc: Loc,
1686 pub leading_trivia: Vec<crate::tokens::Trivia>,
1687 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1688}
1689
1690// ── Psyche ───────────────────────────────────────────────────────────────────
1691
1692#[derive(Debug)]
1693pub struct PsycheDefinition {
1694 pub name: String,
1695 pub dimensions: Vec<String>,
1696 pub manifold_noise: Option<f64>,
1697 pub manifold_momentum: Option<f64>,
1698 pub safety_constraints: Vec<String>,
1699 pub quantum_enabled: Option<bool>,
1700 pub inference_mode: String, // active | passive
1701 pub loc: Loc,
1702 /// v1.5.2 — leading comment trivia attached to this declaration
1703 /// (comments preceding the declaration's first token, since the
1704 /// previous declaration or file start). Empty by default.
1705 pub leading_trivia: Vec<crate::tokens::Trivia>,
1706 /// v1.5.2 — trailing comment trivia (same line as the
1707 /// declaration's last effective token). Empty by default.
1708 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1709}
1710
1711// ── Corpus ───────────────────────────────────────────────────────────────────
1712
1713/// v2.13.0 — a typed, weighted edge of an MDN corpus graph: `etype(from, to,
1714/// weight)`. `etype` is from the closed relation catalog (cite / elaborate /
1715/// corroborate / depend / implement / exemplify / contradict / supersede);
1716/// `from`/`to` name documents declared in the corpus; `weight ∈ (0, 1]`.
1717#[derive(Debug, Clone)]
1718pub struct CorpusRelation {
1719 pub etype: String,
1720 pub from: String,
1721 pub to: String,
1722 pub weight: f64,
1723 pub loc: Loc,
1724}
1725
1726#[derive(Debug)]
1727pub struct CorpusDefinition {
1728 pub name: String,
1729 pub documents: Vec<String>, // simplified: list of pix refs
1730 /// v2.13.0 — the typed weighted edges that make this corpus an MDN graph
1731 /// `C = (D, R, τ, ω, σ)`. Empty ⇒ the flat (edgeless) corpus.
1732 pub relations: Vec<CorpusRelation>,
1733 /// v2.13.0 — `adaptive: true` enables the memory endofunctor: navigations
1734 /// over this corpus learn (semantic edge reinforcement + procedural bias),
1735 /// and subsequent navigations use the memory-modified EPR. Requires the
1736 /// graph to carry edges (static `relations:` OR a store-sourced edge store).
1737 pub adaptive: bool,
1738 pub mcp_server: String,
1739 pub mcp_resource_uri: String,
1740 /// v2.14.0 — when `Some`, this is a DYNAMIC store-sourced MDN graph
1741 /// (`corpus N from axonstore { documents: DocStore(id, title) relations:
1742 /// EdgeStore(from, to, etype, weight) }`): the documents and typed edges live
1743 /// as ROWS in two declared `axonstore`s and the graph is built from the live
1744 /// rows at navigate-time (per-tenant, growing). Mutually exclusive with the
1745 /// static v2.13.0 form — the `documents`/`relations`/`mcp_*` fields stay empty.
1746 /// `None` ⇒ the static compile-time corpus (back-compat byte-identical).
1747 pub store_source: Option<CorpusStoreSource>,
1748 pub loc: Loc,
1749 /// v1.5.2 — leading comment trivia attached to this declaration
1750 /// (comments preceding the declaration's first token, since the
1751 /// previous declaration or file start). Empty by default.
1752 pub leading_trivia: Vec<crate::tokens::Trivia>,
1753 /// v1.5.2 — trailing comment trivia (same line as the
1754 /// declaration's last effective token). Empty by default.
1755 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1756}
1757
1758/// v2.14.0 — the dynamic, `axonstore`-sourced backing of an MDN corpus graph.
1759/// The graph's documents and typed edges are ROWS in two declared `axonstore`s,
1760/// so the graph grows at runtime (a new `persist` = a new node/edge) and is
1761/// per-tenant by inheritance from the store's v2.0.0 column-proof / RLS scope. The
1762/// runtime builds the `mdn::Corpus` from the live rows at navigate-time.
1763///
1764/// Surface:
1765/// ```text
1766/// corpus LtmGraph from axonstore {
1767/// documents: LtmSummaries( id, summary ) // (id-col, title-col)
1768/// relations: LtmEdges( from_id, to_id, etype, weight ) // (from, to, etype, weight)
1769/// adaptive: true
1770/// }
1771/// ```
1772/// Documents and edges live in SEPARATE stores (an `axonstore` is one table with
1773/// one column schema). The type-checker (`check_corpus`) validates that both
1774/// stores are declared and — when they carry a v1.31.0 column schema — that the
1775/// mapped columns exist with compatible types (id present; title text-like;
1776/// from/to match the id type; etype text-like; weight numeric). The weight-range
1777/// invariant `ω ∈ (0, 1]` (G4) becomes a RUNTIME check here, since weights are
1778/// per-row dynamic (clamp on read + store CHECK), not a compile-time literal.
1779#[derive(Debug, Clone)]
1780pub struct CorpusStoreSource {
1781 pub doc_store: String,
1782 pub doc_id_col: String,
1783 pub doc_title_col: String,
1784 pub edge_store: String,
1785 pub edge_from_col: String,
1786 pub edge_to_col: String,
1787 pub edge_type_col: String,
1788 pub edge_weight_col: String,
1789 pub loc: Loc,
1790}
1791
1792// ── Dataspace ────────────────────────────────────────────────────────────────
1793
1794/// v2.63.0 — the closed dataspace column-type catalog.
1795///
1796/// Six types, because a dataspace column type maps 1:1 to a physical
1797/// columnar buffer layout in the deterministic engine (v2.63.0, plan section 5.1):
1798///
1799/// | Type | Physical layout |
1800/// |-------------|----------------------------------------------------|
1801/// | `Text` | offsets `O ∈ ℤ₊^{N+1}` + raw UTF-8 byte buffer |
1802/// | `Int` | contiguous `i64` buffer (8 bytes/element) |
1803/// | `Float` | contiguous `f64` buffer (8 bytes/element) |
1804/// | `Bool` | bit-packed buffer |
1805/// | `Timestamp` | contiguous `i64` epoch-microseconds buffer |
1806/// | `Json` | offsets + raw serialized-JSON byte buffer |
1807///
1808/// Deliberately NOT `StoreColumnType` (v1.31.0): that catalog is
1809/// SQL-backend-oriented (Uuid, Numeric, Bytea, …); this one is the
1810/// engine's physical truth. `Float` is **f64** — diverging from the
1811/// research paper's Float32 on purpose: axon's determinism norm is
1812/// exact f64 (the v2.4.0 reference-simulator precedent), and halving
1813/// width is a performance claim we do not make pre-Sandbox.
1814/// Every column is nullable via the validity bitmap; nullability is
1815/// the ONLY flexibility.
1816#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1817pub enum DataspaceColumnType {
1818 Text,
1819 Int,
1820 Float,
1821 Bool,
1822 Timestamp,
1823 Json,
1824}
1825
1826impl DataspaceColumnType {
1827 /// The closed catalog in canonical declaration order.
1828 pub fn all() -> [DataspaceColumnType; 6] {
1829 [
1830 DataspaceColumnType::Text,
1831 DataspaceColumnType::Int,
1832 DataspaceColumnType::Float,
1833 DataspaceColumnType::Bool,
1834 DataspaceColumnType::Timestamp,
1835 DataspaceColumnType::Json,
1836 ]
1837 }
1838
1839 pub fn canonical_name(self) -> &'static str {
1840 match self {
1841 DataspaceColumnType::Text => "Text",
1842 DataspaceColumnType::Int => "Int",
1843 DataspaceColumnType::Float => "Float",
1844 DataspaceColumnType::Bool => "Bool",
1845 DataspaceColumnType::Timestamp => "Timestamp",
1846 DataspaceColumnType::Json => "Json",
1847 }
1848 }
1849
1850 pub fn all_canonical_names() -> Vec<&'static str> {
1851 Self::all().iter().map(|t| t.canonical_name()).collect()
1852 }
1853
1854 /// Resolve a declared type token — canonical names plus the common
1855 /// lowercase aliases (the v1.31.0 `from_token` convention).
1856 pub fn from_token(name: &str) -> Option<DataspaceColumnType> {
1857 match name {
1858 "Text" | "text" | "string" | "String" => Some(DataspaceColumnType::Text),
1859 "Int" | "int" | "integer" | "i64" => Some(DataspaceColumnType::Int),
1860 "Float" | "float" | "double" | "f64" => Some(DataspaceColumnType::Float),
1861 "Bool" | "bool" | "boolean" => Some(DataspaceColumnType::Bool),
1862 "Timestamp" | "timestamp" | "datetime" => Some(DataspaceColumnType::Timestamp),
1863 "Json" | "json" => Some(DataspaceColumnType::Json),
1864 _ => None,
1865 }
1866 }
1867}
1868
1869/// v2.63.0 — one declared dataspace column: `column <name>: <Type>`.
1870/// The type is kept RAW at parse time (the string the adopter wrote);
1871/// the v2.63.0 type-checker resolves it against the closed catalog and
1872/// emits `axon-T928` on a miss — so ALL schema errors in a declaration
1873/// accumulate in one compile, instead of dying at the first bad token.
1874#[derive(Debug)]
1875pub struct DataspaceColumn {
1876 pub name: String,
1877 pub declared_type: String,
1878 pub loc: Loc,
1879}
1880
1881#[derive(Debug)]
1882pub struct DataspaceDefinition {
1883 pub name: String,
1884 /// v2.63.0 — the typed columnar schema. A dataspace IS its
1885 /// schema: the v2.63.0 type-checker refuses an empty one (axon-T928).
1886 pub columns: Vec<DataspaceColumn>,
1887 pub loc: Loc,
1888 /// v1.5.2 — leading comment trivia attached to this declaration
1889 /// (comments preceding the declaration's first token, since the
1890 /// previous declaration or file start). Empty by default.
1891 pub leading_trivia: Vec<crate::tokens::Trivia>,
1892 /// v1.5.2 — trailing comment trivia (same line as the
1893 /// declaration's last effective token). Empty by default.
1894 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1895}
1896
1897// ── OTS ──────────────────────────────────────────────────────────────────────
1898
1899#[derive(Debug)]
1900pub struct OtsDefinition {
1901 pub name: String,
1902 pub teleology: String,
1903 pub homotopy_search: String, // shallow | deep | speculative
1904 pub loss_function: String,
1905 pub loc: Loc,
1906 /// v1.5.2 — leading comment trivia attached to this declaration
1907 /// (comments preceding the declaration's first token, since the
1908 /// previous declaration or file start). Empty by default.
1909 pub leading_trivia: Vec<crate::tokens::Trivia>,
1910 /// v1.5.2 — trailing comment trivia (same line as the
1911 /// declaration's last effective token). Empty by default.
1912 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1913}
1914
1915// ── Mandate ──────────────────────────────────────────────────────────────────
1916
1917#[derive(Debug)]
1918pub struct MandateDefinition {
1919 pub name: String,
1920 pub constraint: String,
1921 pub kp: Option<f64>,
1922 pub ki: Option<f64>,
1923 pub kd: Option<f64>,
1924 pub tolerance: Option<f64>,
1925 pub max_steps: Option<i64>,
1926 /// v2.83.0 — declared drift bound `D` (`sup|drift(t)|`, paper_mandate
1927 /// section 3). A HYPOTHESIS the runtime must discharge by measurement, not a fact.
1928 pub drift_bound: Option<f64>,
1929 /// v2.83.0 — declared Lipschitz constant `L` of the refinement map
1930 /// (prompt_opt section 6.3). Same standing as `drift_bound`.
1931 pub lipschitz: Option<f64>,
1932 pub on_violation: String, // coerce | halt | retry
1933 pub loc: Loc,
1934 /// v1.5.2 — leading comment trivia attached to this declaration
1935 /// (comments preceding the declaration's first token, since the
1936 /// previous declaration or file start). Empty by default.
1937 pub leading_trivia: Vec<crate::tokens::Trivia>,
1938 /// v1.5.2 — trailing comment trivia (same line as the
1939 /// declaration's last effective token). Empty by default.
1940 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1941}
1942
1943// ── Compute ──────────────────────────────────────────────────────────────────
1944
1945#[derive(Debug)]
1946pub struct ComputeDefinition {
1947 pub name: String,
1948 pub shield_ref: String,
1949 /// v2.67.0 — the typed parameters. Before v2.67.0, `parse_compute` SKIPPED
1950 /// everything between the name and the brace ("Skip optional parameters/
1951 /// return type"), so a compute had no inputs at all — which is one reason it
1952 /// could not compute anything.
1953 pub parameters: Vec<Parameter>,
1954 /// v2.67.0 — the declared result type.
1955 pub return_type: String,
1956 /// v2.67.0 — **the body**: a v2.26.0 `Expr`.
1957 ///
1958 /// This is what makes `compute` honest. The README sells it as "Deterministic
1959 /// muscle — native Fast-Path execution BYPASSING the LLM" and even asserts a
1960 /// complexity class ("compute steps: O(n)"). A v2.26.0 expression is exactly that
1961 /// and nothing more: a closed, total, side-effect-free term the runtime
1962 /// evaluates with `eval_expr` — the same native evaluator `let`, `grad` and
1963 /// `conditional` already use. Linear in the term. No model in the loop.
1964 ///
1965 /// `None` ⇒ a compute that cannot compute; applying it is refused
1966 /// (axon-T941), rather than binding the literal string `"compute:Name(args)"`
1967 /// as the pre-v2.67.0 runtime did — which a downstream step then consumed as if
1968 /// it were a number.
1969 pub body: Option<Expr>,
1970 pub loc: Loc,
1971 /// v1.5.2 — leading comment trivia attached to this declaration
1972 /// (comments preceding the declaration's first token, since the
1973 /// previous declaration or file start). Empty by default.
1974 pub leading_trivia: Vec<crate::tokens::Trivia>,
1975 /// v1.5.2 — trailing comment trivia (same line as the
1976 /// declaration's last effective token). Empty by default.
1977 pub trailing_trivia: Vec<crate::tokens::Trivia>,
1978}
1979
1980// ── Daemon ───────────────────────────────────────────────────────────────────
1981
1982#[derive(Debug)]
1983pub struct DaemonDefinition {
1984 pub name: String,
1985 pub goal: String,
1986 pub tools: Vec<String>,
1987 pub memory_ref: String,
1988 pub strategy: String, // react | reflexion | plan_and_execute | custom
1989 pub on_stuck: String, // hibernate | escalate | retry | forge
1990 pub shield_ref: String,
1991 /// v2.27.0 — the `window:` temporal binding (a `window` primitive name,
1992 /// v2.27.0). When set, the supervisor evaluates the bound window before
1993 /// claiming a scheduled tick: inside ⇒ fire; outside ⇒ `skip`/`warn`/`defer`
1994 /// per the window's `on_outside`. Empty for daemons with no temporal guard.
1995 pub window_ref: String,
1996 /// v2.28.0 — the `budget { … }` linear-effect rate limit. When set, each
1997 /// `on Tool(X)` quota gates that tool's dispatch on a renewable token bucket
1998 /// (the v2.28.0 `RateLease`): a call consumes a token, exhaustion applies
1999 /// `on_exhausted`. `None` for daemons with no effect budget.
2000 pub budget: Option<BudgetBlock>,
2001 pub max_tokens: Option<i64>,
2002 pub max_time: String,
2003 pub max_cost: Option<f64>,
2004 /// v1.6.0 D4 — listen blocks captured for type-checker
2005 /// validation (typed-channel ref + dual-mode deprecation warning).
2006 /// Pre-v1.6.0 the parser discarded these structurally; we now
2007 /// retain them so 13.b/13.f can validate emit/publish/discover
2008 /// inside listener bodies and surface D4 string-topic warnings.
2009 pub listeners: Vec<ListenStep>,
2010 /// v2.4.0 — the capability scope a daemon's runs are confined to
2011 /// (`requires: [cap, …]`, the same closed slug grammar as `axonendpoint
2012 /// requires:`). A scheduled (cron) daemon MUST declare this (it is a
2013 /// standing autonomous privilege); the enterprise supervisor mints a
2014 /// per-run principal scoped to EXACTLY these capabilities (least privilege,
2015 /// v2.4.0). Empty for event-only daemons / pre-v2.4.0 daemons.
2016 pub requires_capabilities: Vec<String>,
2017 pub loc: Loc,
2018 /// v1.5.2 — leading comment trivia attached to this declaration
2019 /// (comments preceding the declaration's first token, since the
2020 /// previous declaration or file start). Empty by default.
2021 pub leading_trivia: Vec<crate::tokens::Trivia>,
2022 /// v1.5.2 — trailing comment trivia (same line as the
2023 /// declaration's last effective token). Empty by default.
2024 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2025}
2026
2027/// v2.28.0 — a `budget { … }` block: a set of per-effect rate quotas plus the
2028/// exhaustion policy. Where `window` guards an effect's TIMING, `budget` guards
2029/// its RATE — a tool call consumes one token from a renewable bucket, and
2030/// over-emission is impossible by construction (the Logic pillar's linearity
2031/// made real for external effects).
2032#[derive(Debug)]
2033pub struct BudgetBlock {
2034 /// v2.69.0 — the budget's NAME when it is declared **top-level**.
2035 ///
2036 /// Empty ⇒ the daemon-attached form (`daemon D { budget { … } }`), which is
2037 /// anonymous and scoped to that daemon's ticks.
2038 ///
2039 /// # Why top-level had to exist
2040 ///
2041 /// Until v2.69.0, `budget` was a **field of `daemon` and nothing else**. So an
2042 /// adopter deploying an HTTP endpoint that calls a vendor tool had **no way in
2043 /// the language to bound how often it does that.** Not "the bound did not
2044 /// work" — **the bound could not be written.** And the HTTP endpoint is what
2045 /// people actually deploy.
2046 pub name: String,
2047 /// The per-effect quotas (`rate:`/`max:` lines). At least one.
2048 pub quotas: Vec<BudgetQuota>,
2049 /// What to do when a quota is exhausted: `block` (fail-closed, the default) |
2050 /// `defer` (reschedule via the v2.27.0 defer ledger) | `shed` (skip the call).
2051 pub on_exhausted: String,
2052 pub loc: Loc,
2053 /// v2.69.0 — comment trivia, so a top-level `budget` does not silently lose
2054 /// its doc comments through the formatter (v1.5.2). Empty for the
2055 /// daemon-attached form.
2056 pub leading_trivia: Vec<crate::tokens::Trivia>,
2057 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2058}
2059
2060/// v2.28.0 — one quota line of a [`BudgetBlock`]:
2061/// `<kind>: <limit> per <period> on Tool(<effect>)`.
2062#[derive(Debug)]
2063pub struct BudgetQuota {
2064 /// `rate` (a renewable bucket that refills `limit` tokens per `period`) or
2065 /// `max` (a windowed hard cap of `limit` per `period`, no intra-window refill).
2066 pub kind: String,
2067 /// The token allowance per period (> 0).
2068 pub limit: i64,
2069 /// The renewal/window period: `second` | `minute` | `hour` | `day`.
2070 pub period: String,
2071 /// The effect this quota governs — a declared `Tool` name (`on Tool(X)`).
2072 pub effect: String,
2073 pub loc: Loc,
2074}
2075
2076// ── AxonStore ────────────────────────────────────────────────────────────────
2077
2078#[derive(Debug)]
2079pub struct AxonStoreDefinition {
2080 pub name: String,
2081 pub backend: String, // in_memory | postgresql | secrets
2082 /// The DSN — **the field that actually runs today**. `connection:` →
2083 /// `resolve_dsn` → a real sqlx pool, with no global-pool fallback.
2084 ///
2085 /// v2.67.0: still accepted (the live deployment depends on it), but it
2086 /// **warns**, and a store declared this way is INELIGIBLE for
2087 /// `lease` / `observe` / `reconcile`. *You cannot govern what you did not
2088 /// declare.*
2089 pub connection: String,
2090 /// v2.67.0 — the `resource` this store runs on. When present, the store
2091 /// DERIVES its DSN, its **pool size** and its sharing discipline from the
2092 /// resource. The derivation is the point; a bare reference would be the
2093 /// nominal link this cycle exists to avoid.
2094 pub resource_ref: String,
2095 pub confidence_floor: Option<f64>,
2096 pub isolation: String, // read_committed | repeatable_read | serializable
2097 pub on_breach: String, // rollback | raise | log
2098 /// v1.30.0 (D11) — Pillar IV: the capability slug required to
2099 /// access this store. Empty = no capability gate. Validated at
2100 /// parse time against the closed slug grammar (shared with the
2101 /// v1.23.0 `requires:` grammar).
2102 pub capability: String,
2103 /// v2.48.0 — the secret-class prefix of a `backend: secrets`
2104 /// metadata store (doctrine `rotation_without_revelation`). A
2105 /// dotted lowercase identifier, e.g. `crm` — the store enumerates
2106 /// the tenant's secrets whose keys live under `<class>.` (so
2107 /// `class: crm` covers `crm.hubspot`, `crm.zoho.acct_x`, …).
2108 /// REQUIRED when `backend: secrets` and FORBIDDEN otherwise
2109 /// (`axon-T900`): a class-less secrets store would enumerate the
2110 /// tenant's ENTIRE secret namespace (`llm.*` included) — that
2111 /// over-broad view is unrepresentable, not discouraged.
2112 pub class: String,
2113 /// v1.31.0 (D1) — the OPTIONAL column-schema declaration. Three
2114 /// closed forms (inline / manifest-ref / env-var); `None` means the
2115 /// 37.x runtime+deploy path applies verbatim (D5 absolute). The
2116 /// v1.31.0 / v1.31.0 `StoreColumnProof` pass consumes this; the v1.31.0
2117 /// CLI exports it. For a `backend: secrets` store this is always
2118 /// `None` in the AST (declaring one is `axon-T900`) — the fixed
2119 /// metadata schema is synthesized at IR time
2120 /// (`store_schema::secrets_metadata_schema`).
2121 pub column_schema: Option<crate::store_schema::StoreColumnSchema>,
2122 pub loc: Loc,
2123 /// v1.5.2 — leading comment trivia attached to this declaration
2124 /// (comments preceding the declaration's first token, since the
2125 /// previous declaration or file start). Empty by default.
2126 pub leading_trivia: Vec<crate::tokens::Trivia>,
2127 /// v1.5.2 — trailing comment trivia (same line as the
2128 /// declaration's last effective token). Empty by default.
2129 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2130}
2131
2132// ── AxonEndpoint ─────────────────────────────────────────────────────────────
2133
2134#[derive(Debug)]
2135pub struct AxonEndpointDefinition {
2136 pub name: String,
2137 pub method: String, // GET | POST | PUT | DELETE
2138 pub path: String,
2139 pub body_type: String,
2140 pub execute_flow: String,
2141 pub output_type: String,
2142 pub shield_ref: String,
2143 /// v2.38.0 — the `cors: <Name>` reference, or `""` if absent
2144 /// (the design decision: absent ⇒ no CORS headers, ever — secure by default). Same
2145 /// empty-string sentinel convention as `shield_ref`, not `Option`.
2146 pub cors_ref: String,
2147 pub retries: Option<i64>,
2148 pub timeout: String,
2149 /// ESK — regulatory coverage on the boundary.
2150 pub compliance: Vec<String>,
2151 /// v1.21.0 — HTTP wire transport for the response. Closed enum
2152 /// per D2 ratified 2026-05-10: {"json" | "sse" | "ndjson"}.
2153 /// Default "json" (D1 — backwards-compat preserved). When set
2154 /// to "sse", the type-checker (30.c) verifies that
2155 /// `execute_flow` produces a Stream<T> (D3).
2156 pub transport: String,
2157 /// v1.21.0 — Keepalive comment interval for SSE transport (D6).
2158 /// Optional; default applied at runtime when transport == "sse"
2159 /// (default 15s). Closed enum at parse time:
2160 /// {"5s" | "15s" | "30s" | "60s"}. Empty string means
2161 /// "use runtime default".
2162 pub keepalive: String,
2163 /// v1.22.0 — Type-Driven Wire Inference (D1, D7).
2164 /// `transport_explicit` is `true` if the source declared
2165 /// `transport:` explicitly (any of json/sse/ndjson). `false` if
2166 /// the field was omitted, in which case `transport` reflects the
2167 /// D1 default `"json"` but `implicit_transport` (computed by the
2168 /// `axon_frontend::type_checker::compute_implicit_transports`
2169 /// pass) carries the inferred value.
2170 pub transport_explicit: bool,
2171 /// v1.22.0 — Inferred wire transport per D1:
2172 /// implicit_transport(E) =
2173 /// declared_transport(E) if transport_explicit
2174 /// "sse" if produces_stream(execute_flow) ∧ ¬explicit
2175 /// "json" otherwise
2176 /// Empty string `""` before the type-checker runs. The Python
2177 /// reference implementation in `axon/compiler/type_checker.py`
2178 /// sets the field byte-identically (D7 cross-stack contract).
2179 pub implicit_transport: String,
2180 /// v1.23.0 (D8) — Auth scope: capability slugs the request
2181 /// bearer must hold for the endpoint to dispatch. Empty vec
2182 /// means "no auth gate" (D9 backwards-compat). Slug grammar
2183 /// (closed): `^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$`. Examples:
2184 /// `admin`, `legal.read`, `hipaa.phi.read`. The runtime checks
2185 /// declared_requires ⊆ token_capabilities (AND semantics — every
2186 /// declared capability must be present in the bearer's claims).
2187 pub requires_capabilities: Vec<String>,
2188 /// v2.44.0 — `public: true` is the EXPLICIT authorization-coverage
2189 /// opt-out (doctrine `every_boundary_is_guarded`). An `axonendpoint`
2190 /// compiles iff it is covered by ≥1 discipline (`requires:` / `shield:` /
2191 /// `compliance:`) OR declares `public: true`. Omitting BOTH is a hard
2192 /// error (`axon-T890`, v2.44.0) — this is what closes Modo 1 (a guard
2193 /// bypassable by silent omission). `public: true` does NOT bypass HTTP
2194 /// authentication (the enterprise `require_auth` middleware is a
2195 /// SEPARATE concern); it declares — deliberately + auditably — that the
2196 /// endpoint carries no capability/shield/compliance coverage. Default
2197 /// `false` (parser + programmatic construction); the v2.44.0 rule reads it.
2198 pub public: bool,
2199 /// v1.23.0 — Replay-token binding (D9 plan-vivo).
2200 /// `replay_explicit` is `true` when the source declared `replay:`
2201 /// explicitly. `false` when the field was omitted, in which case
2202 /// `replay` reflects the method-default (POST/PUT → true, GET/
2203 /// DELETE → false) computed at deploy time. When the effective
2204 /// value resolves to `true`, every successful 2xx response is
2205 /// recorded in the runtime's axonendpoint replay log keyed by
2206 /// trace_id; auditors retrieve it via GET /v1/replay/<trace_id>.
2207 pub replay_explicit: bool,
2208 pub replay: bool,
2209 /// v1.28.0 — Selected SSE wire-format dialect.
2210 ///
2211 /// Populated when the source uses the parametrized grammar
2212 /// `transport: sse(<dialect>)`. Closed catalog
2213 /// (`AXONENDPOINT_TRANSPORT_DIALECTS`): `{axon, openai, anthropic}`.
2214 /// Empty string `""` when:
2215 /// - the source declared a non-SSE transport (`json`/`ndjson`), OR
2216 /// - the source declared bare `transport: sse` without parens, OR
2217 /// - the source omitted `transport:` entirely (D1 implicit path).
2218 ///
2219 /// When empty + the effective wire is SSE (per the runtime
2220 /// classifier `classify_dynamic_route_wire`), the runtime
2221 /// resolves the dialect via the Q1 algebraic-effect-driven
2222 /// default: openai for tool-streaming flows (algebraic predicate
2223 /// true), axon for type-annotation-only flows (algebraic predicate
2224 /// false). D3 explicit `transport: sse(<dialect>)` overrides the
2225 /// default.
2226 pub transport_dialect: String,
2227 /// v1.27.1 — Algebraic-effect override predicate.
2228 ///
2229 /// `true` when `execute_flow` references a tool that declares
2230 /// `effects: <stream:<policy>>` (v1.21.0 algebraic-effect surface).
2231 /// Mirrors `type_checker::flow_uses_streaming_tool(execute_flow, program)`.
2232 ///
2233 /// Used by the runtime classifier
2234 /// (`axon_server::classify_dynamic_route_wire`) to OVERRIDE the
2235 /// v1.22.0 D6 backwards-compat gate: a tool with a declared stream
2236 /// effect is a LANGUAGE-LEVEL commitment to streaming, not a
2237 /// client preference. When this field is `true` AND
2238 /// `transport: json` is NOT explicitly declared (D3 opt-out remains
2239 /// sacred), the route wire is unconditionally `Sse` — no
2240 /// `Accept: text/event-stream` header required, no
2241 /// `AXON_STRICT_TYPE_DRIVEN_TRANSPORT=1` runtime flag required.
2242 ///
2243 /// Computed in lockstep with `implicit_transport` by the
2244 /// `compute_implicit_transports` pass. Default `false` before the
2245 /// pass runs (matches AST construction defaults; D9 backwards-
2246 /// compat preserved for older AST consumers).
2247 pub has_algebraic_stream_effect: bool,
2248 /// v1.31.0 (D2) — the declared execution backend for the flow
2249 /// behind this endpoint. Empty string `""` means "not declared"
2250 /// (the endpoint resolves its backend down the v1.31.0 D1
2251 /// precedence ladder — server default → environment-available
2252 /// `auto`). When non-empty the parser has validated it against the
2253 /// closed catalog [`crate::parser::AXONENDPOINT_BACKEND_VALUES`]
2254 /// and the type-checker rejects an unknown name as a compile
2255 /// error. A declared `backend:` is rung 2 of the resolution
2256 /// contract.
2257 pub backend: String,
2258 /// v1.32.0 (D1) — Path parameter names extracted from the
2259 /// `path:` string at parse time. For `path: "/api/tenants/{tenant_id}/secrets/{secret_name}"`
2260 /// this is `["tenant_id", "secret_name"]`. Empty Vec when the
2261 /// path has no `{name}` placeholders (D5 backwards-compat — an
2262 /// endpoint without path params produces byte-identical IR to
2263 /// v1.38.4).
2264 ///
2265 /// Names are deduplicated + recorded in declaration order. A
2266 /// duplicate `{tenant_id}` in the same path is a parse error
2267 /// (HTTP route patterns reject duplicates structurally — `axum`
2268 /// would panic at registration). Type binding is always `Text`
2269 /// in v1.38.5 (HTTP path-segment convention); a future v1.32.0
2270 /// may add per-placeholder type-override grammar `{tenant_id: Uuid}`.
2271 ///
2272 /// The v1.32.0 D2 totality check (extended by 37.y D3) treats
2273 /// every name here as covering an equivalent flow parameter
2274 /// declared `Text`. Collision with a body field of the same name
2275 /// is a compile error (`axon-T901`, D4).
2276 pub path_params: Vec<String>,
2277 /// v1.32.0 (D2) — Query parameters declared via the inline
2278 /// `query: { name: Type, name: Type? }` block on the endpoint.
2279 /// Empty Vec when the source omits the block (D5 backwards-compat).
2280 ///
2281 /// Closed type catalog (parser-enforced):
2282 /// `{Text, Int, Float, Bool, Uuid}`. The runtime receives every
2283 /// query value as a textual `String` and binds it to the same-named
2284 /// flow parameter; the closed catalog enables future per-type
2285 /// parsing/validation without breaking the manifest format.
2286 ///
2287 /// The optional flag (`?` suffix in the source) reuses
2288 /// `TypeExpr.optional`. An optional query param need not be
2289 /// covered by a flow parameter (D3 totality is over required
2290 /// params); a required query param missing from the flow signature
2291 /// is a `axon-T?nn` future arm. For v1.38.5 the totality check
2292 /// treats every query param as a binding-source candidate for any
2293 /// same-named flow param.
2294 ///
2295 /// Reusing `TypeField` (shared with body type declarations) keeps
2296 /// the D2 totality check uniform — the same `field.type_expr.name
2297 /// == param.type_expr.name` comparator works for body fields AND
2298 /// query params.
2299 pub query_params: Vec<TypeField>,
2300 pub loc: Loc,
2301 /// v1.5.2 — leading comment trivia attached to this declaration
2302 /// (comments preceding the declaration's first token, since the
2303 /// previous declaration or file start). Empty by default.
2304 pub leading_trivia: Vec<crate::tokens::Trivia>,
2305 /// v1.5.2 — trailing comment trivia (same line as the
2306 /// declaration's last effective token). Empty by default.
2307 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2308}
2309
2310// ── Import ───────────────────────────────────────────────────────────────────
2311
2312#[derive(Debug)]
2313pub struct ImportNode {
2314 pub module_path: Vec<String>,
2315 pub names: Vec<String>,
2316 /// v2.76.0 — the `@allow_downgrade` ECC valve: acknowledges an
2317 /// epistemic downgrade across this import edge (silences `axon-W017`,
2318 /// downgrades `axon-T954` to a *visible* `axon-W017`). `false` for
2319 /// every import written before v2.76.0.
2320 pub allow_downgrade: bool,
2321 pub loc: Loc,
2322 /// v1.5.2 — leading comment trivia attached to this declaration
2323 /// (comments preceding the declaration's first token, since the
2324 /// previous declaration or file start). Empty by default.
2325 pub leading_trivia: Vec<crate::tokens::Trivia>,
2326 /// v1.5.2 — trailing comment trivia (same line as the
2327 /// declaration's last effective token). Empty by default.
2328 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2329}
2330
2331// ── Persona ──────────────────────────────────────────────────────────────────
2332
2333#[derive(Debug)]
2334pub struct PersonaDefinition {
2335 pub name: String,
2336 pub domain: Vec<String>,
2337 pub tone: String,
2338 pub confidence_threshold: Option<f64>,
2339 pub cite_sources: Option<bool>,
2340 pub refuse_if: Vec<String>,
2341 pub language: String,
2342 pub description: String,
2343 pub loc: Loc,
2344 /// v1.5.2 — leading comment trivia attached to this declaration
2345 /// (comments preceding the declaration's first token, since the
2346 /// previous declaration or file start). Empty by default.
2347 pub leading_trivia: Vec<crate::tokens::Trivia>,
2348 /// v1.5.2 — trailing comment trivia (same line as the
2349 /// declaration's last effective token). Empty by default.
2350 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2351}
2352
2353// ── Context ──────────────────────────────────────────────────────────────────
2354
2355#[derive(Debug)]
2356pub struct ContextDefinition {
2357 pub name: String,
2358 pub memory_scope: String,
2359 pub language: String,
2360 pub depth: String,
2361 pub max_tokens: Option<i64>,
2362 pub temperature: Option<f64>,
2363 pub cite_sources: Option<bool>,
2364 /// v2.46.0 — the conversational frame's declared cognitive timezone
2365 /// (IANA name). Every step running within this context carries the run's
2366 /// captured instant rendered in this zone, unless the step declares its
2367 /// own `now:` override. Format-checked (`axon-T892`); `None` → no
2368 /// temporal injection (back-compat).
2369 pub now_tz: Option<String>,
2370 pub loc: Loc,
2371 /// v1.5.2 — leading comment trivia attached to this declaration
2372 /// (comments preceding the declaration's first token, since the
2373 /// previous declaration or file start). Empty by default.
2374 pub leading_trivia: Vec<crate::tokens::Trivia>,
2375 /// v1.5.2 — trailing comment trivia (same line as the
2376 /// declaration's last effective token). Empty by default.
2377 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2378}
2379
2380// ── Anchor ───────────────────────────────────────────────────────────────────
2381
2382#[derive(Debug)]
2383pub struct AnchorConstraint {
2384 pub name: String,
2385 pub require: String,
2386 pub reject: Vec<String>,
2387 pub enforce: String,
2388 pub description: String,
2389 pub confidence_floor: Option<f64>,
2390 pub unknown_response: String,
2391 pub on_violation: String,
2392 pub on_violation_target: String,
2393 pub loc: Loc,
2394 /// v1.5.2 — leading comment trivia attached to this declaration
2395 /// (comments preceding the declaration's first token, since the
2396 /// previous declaration or file start). Empty by default.
2397 pub leading_trivia: Vec<crate::tokens::Trivia>,
2398 /// v1.5.2 — trailing comment trivia (same line as the
2399 /// declaration's last effective token). Empty by default.
2400 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2401}
2402
2403// ── Memory ───────────────────────────────────────────────────────────────────
2404
2405#[derive(Debug)]
2406pub struct MemoryDefinition {
2407 pub name: String,
2408 pub store: String,
2409 pub backend: String,
2410 pub retrieval: String,
2411 pub decay: String,
2412 pub loc: Loc,
2413 /// v1.5.2 — leading comment trivia attached to this declaration
2414 /// (comments preceding the declaration's first token, since the
2415 /// previous declaration or file start). Empty by default.
2416 pub leading_trivia: Vec<crate::tokens::Trivia>,
2417 /// v1.5.2 — trailing comment trivia (same line as the
2418 /// declaration's last effective token). Empty by default.
2419 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2420}
2421
2422// ── Tool ─────────────────────────────────────────────────────────────────────
2423
2424#[derive(Debug)]
2425pub struct ToolDefinition {
2426 pub name: String,
2427 pub provider: String,
2428 pub max_results: Option<i64>,
2429 pub filter_expr: String,
2430 pub timeout: String,
2431 pub runtime: String,
2432 /// v2.69.0 — the `resource` this tool's channel runs on (`tool T { resource: Api }`).
2433 ///
2434 /// When present, the tool DERIVES its endpoint from `resource.endpoint`, its
2435 /// concurrency bound from `resource.capacity`, and (via `lease`/`observe`) its
2436 /// lifecycle and health from the resource. `runtime:` then names the PATH
2437 /// within that channel, not the channel itself.
2438 ///
2439 /// This is what governs `tool.runtime` — the third island. An absolute
2440 /// `runtime: "https://…"` (a production URL in source, with no lifetime, no
2441 /// capacity, no shield) is now refused; the address lives on the resource.
2442 ///
2443 /// Empty ⇒ the legacy form (slug `runtime:` joined onto a per-tenant base URL,
2444 /// which already conforms). Ungoverned, and therefore ineligible for the
2445 /// channel `shield` / `lease` / `observe`.
2446 pub resource_ref: String,
2447 pub sandbox: Option<bool>,
2448 pub effects: Option<EffectRow>,
2449 /// v2.8.0 — the tool's typed INPUT SCHEMA (W2: the caller↔tool
2450 /// contract). Each entry is a named, typed parameter that the canonical
2451 /// `use Tool(k = v, …)` invocation binds against and the type-checker
2452 /// validates the caller's args against (CT-2 caller blame, pre-HTTP).
2453 /// Empty for a schema-less tool — the legacy single-`on <arg>` form still
2454 /// applies (v2.8.0 D5 back-compat). Reuses `Parameter` (same `TypeExpr`
2455 /// grammar as flow params).
2456 pub parameters: Vec<Parameter>,
2457 /// v4.3.0 — the shield that covers the κ of this tool's `parameters:`.
2458 /// A tool is how an AXON program talks to anything outside it, which
2459 /// makes it the widest exit the language has; `axon-T1221` requires this
2460 /// when a parameter's type carries a regulatory class.
2461 pub shield_ref: String,
2462 /// v2.8.0 — the tool's declared OUTPUT type, so a tool-step's result
2463 /// is referenceable as `${Step.output}` with a real type (v2.8.0 D8). Flat
2464 /// string (mirrors step `output:`); `None` when undeclared.
2465 pub output_type: Option<String>,
2466 /// v2.77.0 — the authorization scopes this tool's operation
2467 /// requires (`requires: ["w_organization_social"]`): flat capability atoms,
2468 /// the same vocabulary as `credential.grants` (v2.46.0) and endpoint
2469 /// `requires_capabilities` (v2.4.0). `axon-T956` enforces subset coverage —
2470 /// every `use` of a tool with a non-empty `requires` must occur where the
2471 /// program's granted set covers it. Empty = no scope demand (every
2472 /// pre-v2.77.0 tool, unchanged). Flat SETS by design: OAuth scopes are
2473 /// per-platform atoms with no hierarchy — a scope tree would model
2474 /// structure the domain does not have.
2475 pub requires: Vec<String>,
2476 /// v2.48.0 — the per-tenant secret KEY injected into every dispatch
2477 /// of this tool (doctrine `rotation_without_revelation`): at `use`
2478 /// time the runtime resolves the key against the tenant's secret
2479 /// custody and injects the value into the tool-server request under
2480 /// the reserved `axon_secret` field — the flow never touches it. The
2481 /// v2.37.0 posture extended to tools: this is a config KEY, never a
2482 /// credential literal (`axon-T902`, the T850 charset mirror). Empty =
2483 /// no injection (every pre-v2.48.0 tool). Meaningless on a
2484 /// `target:`-bound technician tool (execve dispatch, no HTTP request
2485 /// to inject into) — declaring both is `axon-T902`.
2486 pub secret: String,
2487 /// v2.49.0 — the `secret_partition:` field (doctrine
2488 /// `selection_without_revelation`): the name of one of THIS tool's own
2489 /// `parameters:` whose runtime value is appended as a single key
2490 /// SEGMENT to `secret:` at dispatch, so one tool serves N sub-tenants
2491 /// multiplexed under one axon-tenant. With `secret: crm.hubspot` and
2492 /// `secret_partition: tenant_id`, a `use CrmCrearContacto(tenant_id =
2493 /// "acme", …)` resolves the custody key `crm.hubspot.acme`. The
2494 /// `secret:` class prefix is pinned at compile time (a literal); only
2495 /// this bounded segment is dynamic — the resolved key can NEVER leave
2496 /// the tool's declared class (the segment is charset-checked to a
2497 /// single dot-free run at dispatch, fail-closed). Empty = the v2.48.0
2498 /// static-key behaviour, unchanged. `axon-T903` governs its laws:
2499 /// requires a non-empty `secret:`, must name a `String` parameter of
2500 /// this tool, forbidden on a technician tool. The value SELECTED is
2501 /// still never revealed to cognition — `secret_partition` chooses
2502 /// WHICH borrowed authority to spend, never reads it.
2503 pub secret_partition: String,
2504 /// v2.39.0 — Remote Hands. The `socket` this technician tool dispatches
2505 /// over: a program acting on a real machine dials `axon` as a `socket`
2506 /// client, and a `target:`-bound tool call sends its rendered argv down
2507 /// that connection. `None` ⇒ today's unchanged in-process / model-surface
2508 /// behaviour (zero regression; the whole v2.39.0 surface is inert unless
2509 /// `target:` is set). Resolved to a declared `socket` and duality-checked
2510 /// by `axon-T861`.
2511 pub target: Option<String>,
2512 /// v2.39.0 — the operation's risk class, a v1-closed catalog of exactly
2513 /// `safe | destructive` (`technician::VALID_RISK_LEVELS`). `destructive`
2514 /// forces the bound session to carry a reachable `branch{approved/denied}`
2515 /// confirmation (`axon-T860`). `None` on a non-technician tool.
2516 pub risk: Option<String>,
2517 /// v2.39.0 — the **argv template**: an ordered list of argv elements,
2518 /// each either a literal token (`"ping"`, `"-c"`) or a *whole-element*
2519 /// `${param}` placeholder (`"${host}"`). A placeholder binds to a declared
2520 /// `parameters:` entry and is substituted as ONE opaque argv argument at
2521 /// dispatch — never concatenated, never re-parsed by a shell. This
2522 /// is the injection-safety keystone: the market's free `template:` STRING
2523 /// is deliberately NOT offered. Empty for a non-technician tool; required
2524 /// (`axon-T858`) when `target:` is set on a `provider: bash` tool.
2525 pub argv: Vec<String>,
2526 /// v2.40.0 — the result-memoization policy for this tool. Names a
2527 /// declared `cache` (`axon-T864`), or the reserved sentinel `none` to opt
2528 /// OUT of an active `cache { default: true }` policy (the escape hatch for
2529 /// a rare mislabeled-`pure` tool). Empty ⇒ governed by the module default
2530 /// if one exists and this tool is eligible (`pure`, or covered by the
2531 /// default's `apply_to_effects`). Distinct from `memory`.
2532 pub cache: String,
2533 /// v2.52.0 — Native Web Acquisition. The closed-catalog scrape
2534 /// configuration for a tool whose `provider:` is one of the three
2535 /// web-acquisition engines (`scrape_http` | `scrape_dom` |
2536 /// `scrape_crawl`). `None` ⇒ this is not a scrape tool — the entire
2537 /// v2.52.0 surface is inert (zero regression). Present ⇒ the tool acquires
2538 /// content from the OPEN, ADVERSARIAL web: its output is born
2539 /// epistemically Untrusted (⊥, the design decision) and its `effects:` row MUST
2540 /// carry the first-class `web` base (`axon-T904`, effect honesty).
2541 /// The sub-block is a closed catalog — an unknown field is a hard
2542 /// parse error (the v2.38.0/v2.39.0 discipline, the design decision).
2543 pub scrape: Option<ScrapeSpec>,
2544 pub loc: Loc,
2545 /// v1.5.2 — leading comment trivia attached to this declaration
2546 /// (comments preceding the declaration's first token, since the
2547 /// previous declaration or file start). Empty by default.
2548 pub leading_trivia: Vec<crate::tokens::Trivia>,
2549 /// v1.5.2 — trailing comment trivia (same line as the
2550 /// declaration's last effective token). Empty by default.
2551 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2552}
2553
2554/// v2.52.0 — the closed-catalog scrape configuration block
2555/// (`scrape: { … }`) on a web-acquisition `tool`. Every field is
2556/// optional/defaulted so a minimal `scrape: {}` is legal; the fields
2557/// that apply depend on the tool's `provider:` (the type-checker cross-
2558/// validates provider ↔ field applicability, `axon-T905`). The whole
2559/// struct is deliberately flat + serializable-friendly (`Option`/`Vec`/
2560/// scalar), mirroring the v2.39.0 technician-field discipline, so the IR
2561/// stays byte-stable and the runtime classifies identically.
2562#[derive(Debug, Default)]
2563pub struct ScrapeSpec {
2564 /// The acquisition engine: `impersonate` (HTTP-fingerprint stealth,
2565 /// the GA tier) | `browser` (headless-render sidecar, the gray tier).
2566 /// `None` ⇒ `impersonate`. Closed catalog (`axon-T905`).
2567 /// Applies to `scrape_http` / `scrape_crawl`.
2568 pub engine: Option<String>,
2569 /// The browser-fingerprint impersonation PROFILE name
2570 /// (`chrome`, `firefox`, `safari` — closed catalog). Only meaningful
2571 /// with `engine: impersonate`. The concrete JA3/JA4 + HTTP/2 profile
2572 /// is resolved by the enterprise engine (v2.52.0); OSS records the
2573 /// declared intent. `None` ⇒ the engine's default profile.
2574 pub impersonate: Option<String>,
2575 /// The post-navigation settle wait for `engine: browser` (a Duration,
2576 /// e.g. `2s`) — how long to let JS render before snapshotting. Bounded
2577 ///. Ignored by the impersonate engine (no JS runtime).
2578 pub render_wait: Option<String>,
2579 /// The per-tenant proxy-pool config KEY (a dotted key, resolved via
2580 /// the same SecretResolver `secret:`/`tool.base_url` use — the design decision),
2581 /// never a proxy URL literal. Empty ⇒ direct connection.
2582 pub proxy: String,
2583 /// Whether `robots.txt` is honored (default TRUE, the design decision). Setting
2584 /// `respect_robots: false` is the audited, `scrape.aggressive`-gated
2585 /// override (enforced enterprise-side, v2.52.0); in OSS it is recorded.
2586 pub respect_robots: Option<bool>,
2587 /// `scrape_dom` extraction spec: an ordered list of `name=selector`
2588 /// FieldSpecs (`["title=h1", "price=.amount"]`). A closed, bracketed
2589 /// string list (reuses the v2.38.0/v2.39.0 list helper). Each entry must be a
2590 /// single `name=selector` pair (`axon-T906`).
2591 pub extract: Vec<String>,
2592 /// `scrape_dom` adaptive relocation: when a declared selector misses,
2593 /// the engine attempts a HEURISTIC relocation above `similarity_floor`
2594 /// (the design decision — a heuristic, NOT a proof). `None`/`false` ⇒ strict
2595 /// selectors only. Enabling it makes the tool carry `<storage>` (the
2596 /// per-tenant selector-memory, v2.52.0).
2597 pub adaptive: Option<bool>,
2598 /// The similarity threshold ∈ [0,1] governing adaptive relocation
2599 /// (`axon-T907`). Only meaningful with `adaptive: true`.
2600 pub similarity_floor: Option<f64>,
2601 /// `scrape_crawl` link-follow selector/pattern: which links to enqueue
2602 /// from each fetched page. Empty ⇒ no expansion (single-page crawl).
2603 pub follow: String,
2604 /// `scrape_crawl` maximum link depth from the seed (bounded, the design decision).
2605 pub max_depth: Option<i64>,
2606 /// `scrape_crawl` maximum total pages fetched (bounded, the design decision). A
2607 /// hostile/infinite site can never exhaust the crawler (`axon-T908`).
2608 pub max_pages: Option<i64>,
2609 /// `scrape_crawl` fetch concurrency (bounded, ≥ 1).
2610 pub concurrency: Option<i64>,
2611 /// `scrape_crawl` politeness/rate reference: a declared `budget`
2612 /// (`budget{rate:/max:}`, v2.28.0) governing per-host request pacing
2613 /// (D98 reuse of the budget kernel). Empty ⇒ engine default pacing.
2614 pub politeness: String,
2615 /// `scrape_crawl` checkpoint store reference: a declared `axonstore`
2616 /// the crawler persists frontier/visited state into for resumable,
2617 /// at-least-once crawling. Empty ⇒ in-memory (non-resumable).
2618 pub checkpoint: String,
2619 pub loc: Loc,
2620}
2621
2622#[derive(Debug)]
2623pub struct EffectRow {
2624 pub effects: Vec<String>,
2625 pub epistemic_level: String,
2626 pub loc: Loc,
2627}
2628
2629// ── Type ─────────────────────────────────────────────────────────────────────
2630
2631#[derive(Debug)]
2632pub struct TypeDefinition {
2633 pub name: String,
2634 pub fields: Vec<TypeField>,
2635 pub range_constraint: Option<RangeConstraint>,
2636 pub where_clause: Option<WhereClause>,
2637 /// ESK — κ regulatory class attached to a type.
2638 pub compliance: Vec<String>,
2639 /// v4.5.0 — WHAT this type is, from the closed identifier catalogue.
2640 ///
2641 /// κ says which regime a value falls under; this says whether it is a
2642 /// social-security number or a clinical note. De-identification needs the
2643 /// second question answered — a rule that can only see the regime can
2644 /// check that a class was declared and nothing about what was removed.
2645 ///
2646 /// Empty for the ordinary case: most types are not identifiers.
2647 pub identifier: String,
2648 pub loc: Loc,
2649 /// v1.5.2 — leading comment trivia attached to this declaration
2650 /// (comments preceding the declaration's first token, since the
2651 /// previous declaration or file start). Empty by default.
2652 pub leading_trivia: Vec<crate::tokens::Trivia>,
2653 /// v1.5.2 — trailing comment trivia (same line as the
2654 /// declaration's last effective token). Empty by default.
2655 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2656}
2657
2658#[derive(Debug, Clone)]
2659pub struct TypeExpr {
2660 pub name: String,
2661 pub generic_param: String,
2662 pub optional: bool,
2663 pub loc: Loc,
2664}
2665
2666#[derive(Debug)]
2667pub struct TypeField {
2668 pub name: String,
2669 pub type_expr: TypeExpr,
2670 pub loc: Loc,
2671}
2672
2673#[derive(Debug)]
2674pub struct RangeConstraint {
2675 pub min_value: f64,
2676 pub max_value: f64,
2677 pub loc: Loc,
2678}
2679
2680#[derive(Debug)]
2681pub struct WhereClause {
2682 pub expression: String,
2683 pub loc: Loc,
2684}
2685
2686// ── Flow ─────────────────────────────────────────────────────────────────────
2687
2688#[derive(Debug)]
2689pub struct FlowDefinition {
2690 pub name: String,
2691 pub parameters: Vec<Parameter>,
2692 pub return_type: Option<TypeExpr>,
2693 pub body: Vec<FlowStep>,
2694 pub loc: Loc,
2695 /// v1.5.2 — leading comment trivia attached to this declaration
2696 /// (comments preceding the declaration's first token, since the
2697 /// previous declaration or file start). Empty by default.
2698 pub leading_trivia: Vec<crate::tokens::Trivia>,
2699 /// v1.5.2 — trailing comment trivia (same line as the
2700 /// declaration's last effective token). Empty by default.
2701 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2702}
2703
2704#[derive(Debug)]
2705pub struct Parameter {
2706 pub name: String,
2707 pub type_expr: TypeExpr,
2708 pub loc: Loc,
2709}
2710
2711/// Statements that can appear inside a flow body.
2712#[derive(Debug)]
2713pub enum FlowStep {
2714 Step(StepNode),
2715 If(ConditionalNode),
2716 ForIn(ForInStatement),
2717 Let(LetStatement),
2718 Return(ReturnStatement),
2719 /// v1.14.0 — `break` keyword. Payload-free; carries only its
2720 /// source location for error reporting.
2721 Break(BreakStatement),
2722 /// v1.14.0 — `continue` keyword. Payload-free; same shape as
2723 /// `Break`.
2724 Continue(ContinueStatement),
2725 /// Lambda Data application in a flow step.
2726 LambdaDataApply(LambdaDataApplyNode),
2727 // ── Tier 2 flow steps ──
2728 Probe(ProbeStep),
2729 Reason(ReasonStep),
2730 Validate(ValidateStep),
2731 Refine(RefineStep),
2732 Weave(WeaveStep),
2733 UseTool(UseToolStep),
2734 Remember(RememberStep),
2735 Recall(RecallStep),
2736 Par(ParBlock),
2737 Hibernate(HibernateStep),
2738 Deliberate(DeliberateBlock),
2739 Consensus(ConsensusBlock),
2740 Forge(ForgeBlock),
2741 Focus(FocusStep),
2742 /// v2.65.0 — the proof-carrying derivative step.
2743 Grad(GradStep),
2744 Associate(AssociateStep),
2745 Aggregate(AggregateStep),
2746 ExploreStep(ExploreStepNode),
2747 Ingest(IngestStep),
2748 ShieldApply(ShieldApplyStep),
2749 Declassify(DeclassifyStep),
2750 Stream(StreamBlock),
2751 /// v2.87.0 — `handle E { … } in { … }`, the delimited handler scope.
2752 Handle(HandleBlock),
2753 /// v2.87.0 — `perform Op(args)`. Legal at flow level and inside a step
2754 /// body (where it lands on [`StepNode::performs`], NOT on `pix_ops`: a
2755 /// `pix_op` is an ELEVATION that runs BEFORE generation, and a `perform`
2756 /// whose argument is the step's own output must run AFTER it).
2757 Perform(PerformStep),
2758 /// v2.87.0 — `resume(v)`. Clause bodies only.
2759 Resume(ResumeStep),
2760 /// v2.87.0 — `abort(v)`. Clause bodies only.
2761 Abort(AbortStep),
2762 /// v2.87.0 — `forward Op(args)` (D12). Clause bodies only.
2763 Forward(ForwardStep),
2764 Navigate(NavigateStep),
2765 Drill(DrillStep),
2766 Trail(TrailStep),
2767 Corroborate(CorroborateStep),
2768 OtsApply(OtsApplyStep),
2769 MandateApply(MandateApplyStep),
2770 ComputeApply(ComputeApplyStep),
2771 /// v2.83.0 — `<Agent>(arg, …)`, the step-body invocation of a
2772 /// declared agent. Dispatches v2.83.0's bounded control loop.
2773 AgentCall(AgentCallStep),
2774 Listen(ListenStep),
2775 DaemonStep(DaemonStepNode),
2776 /// v1.6.0 — π-calculus output prefix `c⟨v⟩.P` (Chan-Output / Chan-Mobility).
2777 Emit(EmitStatement),
2778 /// v2.46.0 — `mint <Credential> as <binding>`: ephemeral-credential
2779 /// minting (attenuated, TTL-bounded; `authority_only_attenuates`).
2780 Mint(MintStep),
2781 /// v2.48.0 — `rotate <SecretsStore> [where "…"] with <Tool> as
2782 /// <binding>`: mediated secret renewal (`rotation_without_revelation`).
2783 Rotate(RotateStep),
2784 /// v1.6.0 — capability extrusion (Publish-Ext, paper section 4.3).
2785 Publish(PublishStatement),
2786 /// v1.6.0 — dual of publish (dynamic typed handle import).
2787 Discover(DiscoverStatement),
2788 Persist(PersistStep),
2789 Retrieve(RetrieveStep),
2790 Mutate(MutateStep),
2791 Purge(PurgeStep),
2792 Transact(TransactBlock),
2793 /// v2.43.0 — `warden(<target>) within <Scope> { … }` adversarial
2794 /// security-analysis block. A flow-body block (like `quant`): a target
2795 /// reference + a mandatory `within <Scope>` authorization clause + a nested
2796 /// body (`find_exploits()` → `list[Vulnerability]`, `fortify`). NOT a
2797 /// top-level declaration.
2798 Warden(WardenBlock),
2799 /// v2.4.0 — `quant { … }` cognitive block (Hilbert-space projection).
2800 /// Carries an optional attribute header + a real nested body of flow steps
2801 /// (so v2.4.0's Continuous Type Invariant can scan it). Lives inside a flow
2802 /// body like `par`; NOT a top-level declaration.
2803 Quant(QuantBlock),
2804 /// v2.4.0 — `yield <expr>` measurement point inside a `quant` block.
2805 /// Collapses the evolved amplitudes back to classical silicon; the effect
2806 /// operation whose resolution is a one-shot delimited continuation. Only
2807 /// well-formed inside a `quant` block (the checker rejects it elsewhere).
2808 Yield(YieldStatement),
2809 /// v2.4.0 — `run <Flow>(args)` as a flow-step: invoke a declared flow
2810 /// from inside a body (notably a `daemon`'s `listen` handler — the Q3 ask).
2811 /// Reuses the top-level [`RunStatement`] shape (flow name + args + optional
2812 /// persona/context/anchors). Distinct from `Declaration::Run` only by
2813 /// position (a step inside a body vs. a program-root run).
2814 Run(RunStatement),
2815 /// Flow-level statements we recognize but parse structurally.
2816 GenericStep(GenericFlowStep),
2817}
2818
2819/// A flow step we recognize by keyword but parse only structurally.
2820#[derive(Debug)]
2821pub struct GenericFlowStep {
2822 pub keyword: String,
2823 pub loc: Loc,
2824}
2825
2826// ── Step ─────────────────────────────────────────────────────────────────────
2827
2828/// v2.83.0 — a governance application written INSIDE the step it
2829/// governs: `mandate SECCompliance on data`, `shield PatientShield on symptoms
2830/// -> clean_data`, `ots Extract on raw`.
2831///
2832/// README XV has always written the application in this position — a mandate
2833/// next to the `output:` it constrains, scoped to THIS step's generation — and
2834/// the parser accepted the same form only at flow level, which is why README
2835/// blocks 40–42 never compiled. The AST node is deliberately the same shape as
2836/// the flow-level `*ApplyStep` family: one concept, two positions.
2837#[derive(Debug)]
2838pub struct StepGuardNode {
2839 /// Which primitive: `"mandate"` | `"shield"` | `"ots"`.
2840 pub kind: String,
2841 /// The declared governor this guard names (e.g. `SECCompliance`).
2842 pub name: String,
2843 /// What it is applied to — a binding or a call expression, verbatim
2844 /// (`data`, `ContractDrafter(terms)`). Empty when no `on` clause.
2845 pub target: String,
2846 /// The binding the guarded result flows into (`-> clean_data`). Empty when
2847 /// absent.
2848 pub binding: String,
2849 pub loc: Loc,
2850}
2851
2852#[derive(Debug)]
2853pub struct StepNode {
2854 pub name: String,
2855 pub persona_ref: String,
2856 pub given: String,
2857 pub ask: String,
2858 pub output_type: String,
2859 pub confidence_floor: Option<f64>,
2860 pub navigate_ref: String,
2861 pub apply_ref: String,
2862 /// v2.22.0 — the step's declared MODEL CAPABILITY requirement: the
2863 /// context window (in tokens) the cognitive act needs. The v2.22.0 resolver
2864 /// maps it to the smallest concrete model that satisfies it (per the
2865 /// resolved backend's v2.22.0 catalog); `None` → the backend default
2866 /// (back-compat). Declare the NEED, not the vendor SKU.
2867 pub requires_context: Option<u32>,
2868 /// v2.46.0 — the step's declared cognitive timezone: an IANA name
2869 /// (`"America/Bogota"`, `"UTC"`). When present, the runtime injects the
2870 /// run's captured instant — rendered in THIS zone — into the step's
2871 /// cognitive context (`time_is_an_explicit_input`, the v2.27.0 doctrine
2872 /// applied to cognition). Format-checked at compile time (`axon-T892`);
2873 /// full IANA membership is the runtime's job (chrono-tz, v2.46.0).
2874 /// Overrides a bound `context`'s `now:` for this step. `None` → no
2875 /// temporal injection (back-compat).
2876 pub now_tz: Option<String>,
2877 /// v2.83.0 — the governance applications declared in this
2878 /// step's body, in source order. Empty for every pre-v2.83.0 program.
2879 pub guards: Vec<StepGuardNode>,
2880 /// v2.83.0 — the STATEMENTS written in this step's body, in source
2881 /// order: the PIX verbs (`navigate` / `drill` / `trail` / `validate`)
2882 /// and the step-scoped invocations (`probe … for […]`, `use_tool … with
2883 /// …`, a bare `<Agent>(args)` call, `par { … }`).
2884 ///
2885 /// README's pix/corpus family writes them exactly here, with a braceless
2886 /// field list, and each produces a binding (`as: relevant_sections`) the
2887 /// step's own `ask:` then interpolates. So they are ELEVATIONS, the same
2888 /// shape v2.83.0 gave `lambda`/`ots`: dispatch runs them BEFORE the step's
2889 /// generation. Reusing the flow-level node types (no new AST shapes) is
2890 /// the the design decision doctrine — one concept, two positions.
2891 pub pix_ops: Vec<FlowStep>,
2892 /// v2.83.0 — a `stream<T> { … }` written in THIS step's body.
2893 ///
2894 /// Deliberately NOT a [`Self::pix_ops`] entry, and the distinction is the
2895 /// whole design. Every `pix_ops` statement is an ELEVATION: dispatch runs it
2896 /// BEFORE the step generates, so its binding is available to the step's
2897 /// `ask:`. A stream handler is the opposite — `on_chunk` runs DURING the
2898 /// step's own output, once per chunk, and there is nothing to elevate.
2899 ///
2900 /// Filing it under `pix_ops` would also have produced a specific, silent
2901 /// bug: README block 15's `step Stream` declares no `ask:` at all, so
2902 /// `run_step` would have run the handlers as an elevation and then fallen
2903 /// through to the LLM path with an EMPTY prompt — a real upstream call, made
2904 /// on nothing, once per run. The field is what tells the dispatcher this
2905 /// step's output IS the stream.
2906 pub stream: Option<Box<StreamBlock>>,
2907 /// v2.87.0 — the `perform Op(args)` statements written in THIS step's
2908 /// body, in source order.
2909 ///
2910 /// A THIRD position, and for the same reason v2.83.0 needed a second one.
2911 /// `the design plan` section 3.1 publishes:
2912 ///
2913 /// ```text
2914 /// step generate {
2915 /// given: prompt
2916 /// let response = ask "Generate response"
2917 /// perform Emit(response.token)
2918 /// perform Done()
2919 /// }
2920 /// ```
2921 ///
2922 /// The performed argument IS the step's own output. Filing these under
2923 /// [`Self::pix_ops`] would run them BEFORE generation, so `response.token`
2924 /// would resolve against a binding that does not exist yet — the handler
2925 /// would receive an unresolved symbol and the wire would carry a name where
2926 /// the adopter expected a token. Dispatch runs `performs` AFTER the step
2927 /// generates, with the step's output in scope.
2928 pub performs: Vec<PerformStep>,
2929 pub loc: Loc,
2930}
2931
2932// ── Intent ───────────────────────────────────────────────────────────────────
2933
2934#[derive(Debug)]
2935pub struct IntentNode {
2936 pub name: String,
2937 pub given: String,
2938 pub ask: String,
2939 pub output_type: Option<TypeExpr>,
2940 pub confidence_floor: Option<f64>,
2941 pub loc: Loc,
2942 /// v1.5.2 — leading comment trivia attached to this declaration
2943 /// (comments preceding the declaration's first token, since the
2944 /// previous declaration or file start). Empty by default.
2945 pub leading_trivia: Vec<crate::tokens::Trivia>,
2946 /// v1.5.2 — trailing comment trivia (same line as the
2947 /// declaration's last effective token). Empty by default.
2948 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2949}
2950
2951// ── Run ──────────────────────────────────────────────────────────────────────
2952
2953#[derive(Debug)]
2954pub struct RunStatement {
2955 pub flow_name: String,
2956 pub arguments: Vec<String>,
2957 pub persona: String,
2958 pub context: String,
2959 pub anchors: Vec<String>,
2960 pub on_failure: String,
2961 pub on_failure_params: Vec<(String, String)>,
2962 pub output_to: String,
2963 pub effort: String,
2964 pub loc: Loc,
2965 /// v1.5.2 — leading comment trivia attached to this declaration
2966 /// (comments preceding the declaration's first token, since the
2967 /// previous declaration or file start). Empty by default.
2968 pub leading_trivia: Vec<crate::tokens::Trivia>,
2969 /// v1.5.2 — trailing comment trivia (same line as the
2970 /// declaration's last effective token). Empty by default.
2971 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2972}
2973
2974// ── Epistemic ────────────────────────────────────────────────────────────────
2975
2976#[derive(Debug)]
2977pub struct EpistemicBlock {
2978 pub mode: String,
2979 pub body: Vec<Declaration>,
2980 pub loc: Loc,
2981 /// v1.5.2 — leading comment trivia attached to this declaration
2982 /// (comments preceding the declaration's first token, since the
2983 /// previous declaration or file start). Empty by default.
2984 pub leading_trivia: Vec<crate::tokens::Trivia>,
2985 /// v1.5.2 — trailing comment trivia (same line as the
2986 /// declaration's last effective token). Empty by default.
2987 pub trailing_trivia: Vec<crate::tokens::Trivia>,
2988}
2989
2990// ── v2.26.0 — the pure expression engine (`Expr`) ─────────────────────────
2991
2992/// A pure, total expression in AXON's closed-catalog expression sublanguage
2993/// (v2.26.0). Evaluates to a value with no side effects, no I/O, no recursion
2994/// and no unbounded loops — so it is decidable and const-foldable. Mounted as
2995/// the condition of an `if` (and, in later steps, `let` values + `where:`
2996/// predicates). Field/index access and the builtin catalog land in v2.26.0.
2997#[derive(Debug, Clone)]
2998pub enum Expr {
2999 /// A typed literal (`42`, `3.14`, `true`, `"hello"`).
3000 Lit(ExprLit),
3001 /// A reference to a binding or dotted path (`x`, `User.tier`).
3002 Ref(String),
3003 /// A unary operation (`-x`, `not x`).
3004 Unary(UnOp, Box<Expr>),
3005 /// A binary operation (`a + b`, `a >= b`, `a and b`).
3006 Binary(BinOp, Box<Expr>, Box<Expr>),
3007 /// v2.26.0 — a closed-catalog builtin call. `args[0]` is the receiver
3008 /// (the value before the `.`); any further entries are the call arguments.
3009 /// E.g. `recent.length` → `Call(Length, [Ref("recent")])`,
3010 /// `name.starts_with("Dr")` → `Call(StartsWith, [Ref("name"), Lit(Str)])`.
3011 Call(Builtin, Vec<Expr>),
3012 /// v2.26.0 — field access on a non-reference base (`items[0].name`,
3013 /// `(expr).field`). A plain dotted path stays a `Ref` (`a.b.c`) for
3014 /// back-compat; this node is the structured form the JSONB SQL lowering
3015 /// (deferred v2.26.0) consumes. The `String` is the field name.
3016 Field(Box<Expr>, String),
3017 /// v2.26.0 — index access `base[index]` (array element / string char).
3018 Index(Box<Expr>, Box<Expr>),
3019 /// v2.83.0 — `let <name> = <value>` scoped over `<body>`: the classic
3020 /// let-in term, `let x = e₁ in e₂`.
3021 ///
3022 /// **Why the expression engine and not a list of bindings on the compute.**
3023 /// Every published `compute` writes a CHAIN —
3024 /// `logic { let a = … let b = … return e }` — and the obvious shortcut is
3025 /// to hang a `Vec<(String, Expr)>` off `ComputeDefinition` and substitute at
3026 /// evaluation time. That is wrong twice over: substitution DUPLICATES the
3027 /// bound term at every use site (so `let t = expensive()` evaluates once per
3028 /// mention, changing cost and, for anything non-total, meaning), and it
3029 /// confines `let` to computes when it is a property of expressions.
3030 ///
3031 /// As a `Let` term the chain nests — `Let(a, e₁, Let(b, e₂, e₃))` — which is
3032 /// exactly one evaluation per binding, shadowing that falls out of the
3033 /// nesting instead of being reimplemented, and a `let` usable anywhere an
3034 /// expression is.
3035 Let {
3036 name: String,
3037 value: Box<Expr>,
3038 body: Box<Expr>,
3039 },
3040}
3041
3042/// The closed catalog of pure builtins (v2.26.0). All are total + pure.
3043/// Collection/string predicates only; the predicate-taking folds (`any`/`all`/
3044/// `none`) need lambdas and are deferred, as are `sum`/`min`/`max` and `in`/`??`.
3045#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3046pub enum Builtin {
3047 /// `.length` — collection element count, or character count of a string.
3048 Length,
3049 /// `.count` — alias of `length`.
3050 Count,
3051 /// `.is_empty` — `length == 0`.
3052 IsEmpty,
3053 /// `.is_null` — the value is absent / empty / `null`.
3054 IsNull,
3055 /// `.contains(x)` — array membership, or string substring.
3056 Contains,
3057 /// `.starts_with(s)` — string prefix test.
3058 StartsWith,
3059 /// `.ends_with(s)` — string suffix test.
3060 EndsWith,
3061 /// v2.26.0 — `.as_int` — honest coercion of a `Json` value to an
3062 /// integer. Fail-closed: a value that is not a JSON integer resolves
3063 /// to `null`, never a panic (doctrine `open_data_is_total`).
3064 AsInt,
3065 /// v2.26.0 — `.as_float` — honest coercion to a float (an integer
3066 /// widens; anything else → `null`).
3067 AsFloat,
3068 /// v2.26.0 — `.as_string` — honest coercion to a string (only a
3069 /// JSON string succeeds; a number / bool / null → `null`).
3070 AsString,
3071 /// v2.26.0 — `.as_bool` — honest coercion to a boolean (only a
3072 /// JSON bool succeeds; anything else → `null`).
3073 AsBool,
3074}
3075
3076impl Builtin {
3077 /// The number of arguments AFTER the receiver (`args[0]`).
3078 pub fn extra_arity(self) -> usize {
3079 match self {
3080 Builtin::Length
3081 | Builtin::Count
3082 | Builtin::IsEmpty
3083 | Builtin::IsNull
3084 | Builtin::AsInt
3085 | Builtin::AsFloat
3086 | Builtin::AsString
3087 | Builtin::AsBool => 0,
3088 Builtin::Contains | Builtin::StartsWith | Builtin::EndsWith => 1,
3089 }
3090 }
3091
3092 /// The surface name (after the `.`).
3093 pub fn surface(self) -> &'static str {
3094 match self {
3095 Builtin::Length => "length",
3096 Builtin::Count => "count",
3097 Builtin::IsEmpty => "is_empty",
3098 Builtin::IsNull => "is_null",
3099 Builtin::Contains => "contains",
3100 Builtin::StartsWith => "starts_with",
3101 Builtin::EndsWith => "ends_with",
3102 Builtin::AsInt => "as_int",
3103 Builtin::AsFloat => "as_float",
3104 Builtin::AsString => "as_string",
3105 Builtin::AsBool => "as_bool",
3106 }
3107 }
3108
3109 /// Resolve a name (after a `.`) to a builtin, or `None` if it is an ordinary
3110 /// field / path segment.
3111 pub fn from_name(name: &str) -> Option<Builtin> {
3112 Some(match name {
3113 "length" => Builtin::Length,
3114 "count" => Builtin::Count,
3115 "is_empty" => Builtin::IsEmpty,
3116 "is_null" => Builtin::IsNull,
3117 "contains" => Builtin::Contains,
3118 "starts_with" => Builtin::StartsWith,
3119 "ends_with" => Builtin::EndsWith,
3120 "as_int" => Builtin::AsInt,
3121 "as_float" => Builtin::AsFloat,
3122 "as_string" => Builtin::AsString,
3123 "as_bool" => Builtin::AsBool,
3124 _ => return None,
3125 })
3126 }
3127}
3128
3129/// A literal value inside an [`Expr`]. The lexical form is preserved enough to
3130/// round-trip; the runtime evaluator (v2.26.0) coerces across these per the
3131/// existing string-runtime discipline.
3132#[derive(Debug, Clone)]
3133pub enum ExprLit {
3134 Int(i64),
3135 Float(f64),
3136 Bool(bool),
3137 Str(String),
3138}
3139
3140/// Unary operators (closed catalog).
3141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3142pub enum UnOp {
3143 /// Arithmetic negation `-`.
3144 Neg,
3145 /// Boolean negation `not`.
3146 Not,
3147}
3148
3149/// Binary operators (closed catalog). Precedence is encoded in the Pratt parser.
3150#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3151pub enum BinOp {
3152 Add,
3153 Sub,
3154 Mul,
3155 Div,
3156 Mod,
3157 Eq,
3158 Ne,
3159 Lt,
3160 Le,
3161 Gt,
3162 Ge,
3163 And,
3164 Or,
3165}
3166
3167// ── Control flow ─────────────────────────────────────────────────────────────
3168
3169#[derive(Debug)]
3170pub struct ConditionalNode {
3171 pub condition: String,
3172 pub comparison_op: String,
3173 pub comparison_value: String,
3174 pub then_body: Vec<FlowStep>,
3175 pub else_body: Vec<FlowStep>,
3176 pub conditions: Vec<(String, String, String)>,
3177 pub conjunctor: String,
3178 /// v2.26.0 — the parsed expression form of the condition. `None` when
3179 /// the condition fits the legacy `(condition, op, value)` + `or` shape
3180 /// (then the legacy fields drive evaluation, byte-identical to pre-v2.26.0);
3181 /// `Some` only for the richer forms the legacy triple cannot express
3182 /// (`and`, `not`, arithmetic, parentheses, nesting), which the runtime
3183 /// evaluates via the pure expression evaluator. Zero IR drift for existing
3184 /// programs.
3185 pub cond: Option<Expr>,
3186 pub loc: Loc,
3187}
3188
3189#[derive(Debug)]
3190pub struct ForInStatement {
3191 pub variable: String,
3192 pub iterable: String,
3193 pub body: Vec<FlowStep>,
3194 pub loc: Loc,
3195}
3196
3197#[derive(Debug)]
3198pub struct LetStatement {
3199 pub identifier: String,
3200 pub value_expr: String,
3201 /// v1.12.0 — preserves the parser's tokenization intent so the
3202 /// runtime dispatcher can distinguish a quoted literal from a
3203 /// dotted-identifier reference. One of "literal", "reference",
3204 /// "expression". Defaults to "literal" so any pre-cycle-17 caller
3205 /// that constructs a LetStatement directly behaves as a literal.
3206 pub value_kind: String,
3207 /// v2.4.0 — optional type annotation `let x: <TypeExpr> = …`.
3208 /// `None` for the bare `let x = …` form (all pre-51.c.3 lets). Inside a
3209 /// `quant` block the Continuous Type Invariant inspects this to enforce the
3210 /// continuous-carrier discipline (`DensityMatrix[D]` D=2ⁿ; reject discrete
3211 /// conversational types). Carries the typed encoder-boundary contract.
3212 pub type_annotation: Option<TypeExpr>,
3213 /// v2.26.0 — the parsed expression form of the value, present only when
3214 /// `value_kind == "expression"` (`let total = price * qty + tax`). The
3215 /// runtime evaluates it via the pure expression evaluator instead of the
3216 /// pre-v2.26.0 behaviour (which treated an expression as an opaque literal
3217 /// string). `None` for literal / reference / list values (byte-identical to
3218 /// pre-v2.26.0).
3219 pub value_ast: Option<Expr>,
3220 pub loc: Loc,
3221 /// v1.5.2 — leading comment trivia attached to this declaration
3222 /// (comments preceding the declaration's first token, since the
3223 /// previous declaration or file start). Empty by default.
3224 pub leading_trivia: Vec<crate::tokens::Trivia>,
3225 /// v1.5.2 — trailing comment trivia (same line as the
3226 /// declaration's last effective token). Empty by default.
3227 pub trailing_trivia: Vec<crate::tokens::Trivia>,
3228}
3229
3230#[derive(Debug)]
3231pub struct ReturnStatement {
3232 pub value_expr: String,
3233 pub loc: Loc,
3234}
3235
3236/// v2.4.0 — `yield <expr>` measurement point inside a `quant` block.
3237#[derive(Debug)]
3238pub struct YieldStatement {
3239 /// The measured expression (the structural hypothesis / density-matrix
3240 /// surrogate collapsed out of the Hilbert-space scope).
3241 pub value_expr: String,
3242 /// Tokenization intent (`literal` / `reference` / `expression`), mirroring
3243 /// `LetStatement.value_kind` so the runtime resolves the yielded value.
3244 pub value_kind: String,
3245 pub loc: Loc,
3246}
3247
3248/// v1.14.0 — `break` keyword inside a for-in body. Carries no
3249/// payload; the runner translates it into a sentinel that
3250/// terminates the loop. Parser scope check (`loop_depth`)
3251/// guarantees this only appears inside a for-in body.
3252#[derive(Debug)]
3253pub struct BreakStatement {
3254 pub loc: Loc,
3255}
3256
3257/// v1.14.0 — `continue` keyword inside a for-in body. Same
3258/// shape as ``BreakStatement``; the runner uses a different
3259/// sentinel type to distinguish loop-exit from iteration-skip.
3260#[derive(Debug)]
3261pub struct ContinueStatement {
3262 pub loc: Loc,
3263}
3264
3265// ── Lambda Data (ΛD) — Epistemic State Vectors ─────────────────────────────
3266
3267/// Top-level ΛD definition: ψ = ⟨T, V, E⟩ where E = ⟨c, τ, ρ, δ⟩.
3268#[derive(Debug)]
3269pub struct LambdaDataDefinition {
3270 pub name: String,
3271 pub ontology: String, // T ∈ O — ontological type
3272 pub certainty: f64, // c ∈ [0,1] — epistemic certainty scalar
3273 pub temporal_frame_start: String, // τ_start
3274 pub temporal_frame_end: String, // τ_end
3275 pub provenance: String, // ρ ∈ EntityRef — causal origin
3276 pub derivation: String, // δ ∈ Δ — see derivation catalogue (raw, derived, inferred, aggregated, transformed)
3277 pub loc: Loc,
3278 /// v1.5.2 — leading comment trivia attached to this declaration
3279 /// (comments preceding the declaration's first token, since the
3280 /// previous declaration or file start). Empty by default.
3281 pub leading_trivia: Vec<crate::tokens::Trivia>,
3282 /// v1.5.2 — trailing comment trivia (same line as the
3283 /// declaration's last effective token). Empty by default.
3284 pub trailing_trivia: Vec<crate::tokens::Trivia>,
3285}
3286
3287/// In-flow ΛD application: binds epistemic state vector to a data target.
3288#[derive(Debug)]
3289pub struct LambdaDataApplyNode {
3290 pub lambda_data_name: String, // reference to LambdaDataDefinition
3291 pub target: String, // expression to bind
3292 pub output_type: String, // result type after epistemic binding
3293 pub loc: Loc,
3294}
3295
3296// ── Tier 2 flow step nodes ──────────────────────────────────────────────────
3297
3298#[derive(Debug)]
3299pub struct ProbeStep {
3300 pub target: String,
3301 /// v2.83.0 — the extraction list README writes:
3302 /// `probe doc for [parties, obligations, dates]`. Pre-v2.83.0 the step
3303 /// body reached `probe` and ran `skip_flow_step_structural`, which
3304 /// DISCARDED it (the v2.67.0 silent-drop shape); the flow-level form kept
3305 /// only the target and never had a slot for the fields at all.
3306 pub fields: Vec<String>,
3307 pub loc: Loc,
3308}
3309/// v2.83.0 — `reason { given: … ask: "…" depth: N }`, the README's
3310/// most-published cognitive block (16 occurrences) and, until this cycle, the
3311/// most expensive silent drop in the language.
3312///
3313/// **What was wrong.** The block form had NO home in this struct: `strategy`
3314/// and `target` were its only fields. Written at flow level, `reason { … }`
3315/// did not parse at all (the parser wanted `reason <target>`); written inside a
3316/// `step { }` body — the only place the README ever writes it — it hit
3317/// `skip_flow_step_structural`, which threw the whole block away. Measured on
3318/// 2.85.0: a step whose ENTIRE cognition was a `reason { given ask depth }`
3319/// block passed `axon check` with exit 0 and lowered to `"ask": ""`,
3320/// `"given": ""`. `advertised.rs` attested `reason` as
3321/// `Real { proof: "pure_shape::run_reason" }` — and the attestation was true
3322/// of an engine no published program could reach. v2.67.0's own words: motor
3323/// real, cable muerto.
3324///
3325/// The field set is CLOSED (v2.83.0's rule: when a block skips what it does
3326/// not recognise, ask which direction the silence fails in — a typo'd `ask:`
3327/// yields a promptless deliberation, which is weaker, not louder).
3328#[derive(Debug)]
3329pub struct ReasonStep {
3330 /// `chain_of_thought: enabled` and `strategy: <name>` both land here.
3331 pub strategy: String,
3332 /// The pre-v2.83.0 positional form `reason <target>`. Empty for the
3333 /// block form, which names its evidence in `given` instead.
3334 pub target: String,
3335 /// `given:` — the evidence this deliberation reasons OVER. One reference,
3336 /// a comma list (`given: Initialize.output, sessions`) or a bracketed list
3337 /// (`given: [baseline.topology, current.topology]`); all three forms occur
3338 /// in the published README. Resolved against the flow bindings at dispatch.
3339 pub given: String,
3340 /// `ask:` — the question. This is the deliberation's actual prompt; before
3341 /// v2.83.0 it reached the model in exactly zero published programs.
3342 pub ask: String,
3343 /// `depth:` — the declared deliberation depth. Consumed by the dispatch
3344 /// FRAMING (like `strategy`, the other declared-posture field), not by a
3345 /// runtime iteration bound. Stated plainly so the field is not read as a
3346 /// loop count it has never been.
3347 pub depth: Option<u32>,
3348 pub loc: Loc,
3349}
3350#[derive(Debug)]
3351pub struct ValidateStep {
3352 pub target: String,
3353 pub rule: String,
3354 /// v2.88.0 — `if confidence < 0.8 -> refine(max_attempts: 2)`, ATTACHED
3355 /// to the validation it governs.
3356 ///
3357 /// The guard is a field of the `validate` rather than a sibling statement,
3358 /// and the difference is what makes `confidence` unambiguous BY
3359 /// CONSTRUCTION. As a sibling, "which confidence does this guard read?"
3360 /// needs a resolution rule (nearest preceding validate), a compile error
3361 /// for the zero case, and dispatch-side re-pairing — three places to
3362 /// drift. As a field there is exactly one validation it can mean, the
3363 /// pairing survives into the IR untouched, and a guard with no validation
3364 /// is UNREPRESENTABLE rather than refused.
3365 pub guard: Option<ConfidenceGuard>,
3366 pub loc: Loc,
3367}
3368
3369/// v2.88.0 — the self-correction guard three README blocks publish:
3370///
3371/// ```text
3372/// validate Assess.output against: ContractSchema
3373/// if confidence < 0.8 -> refine(max_attempts: 2)
3374/// ```
3375///
3376/// NOT control flow. It has no `else`, no braced body, no nesting; the metric,
3377/// the comparison and the action are each a CLOSED catalog of one. What it
3378/// declares is a floor and a bounded recovery: *if the validation's CSR is
3379/// below `threshold`, refine the validated value — at most `max_attempts`
3380/// times — re-scoring each attempt.* Landing it as a guard keeps "no
3381/// imperative branching inside a step body" true by construction while the
3382/// published surface compiles verbatim.
3383#[derive(Debug)]
3384pub struct ConfidenceGuard {
3385 /// The floor. The type-checker requires `0 < threshold ≤ 1`: the CSR lives
3386 /// in `[0, 1]`, so a floor of 0 can never fire (dead governance that reads
3387 /// as live) and a floor above 1 always fires (a retry loop disguised as a
3388 /// conditional). Both are refused, not warned.
3389 pub threshold: f64,
3390 /// Bound on recovery attempts. Required by the grammar itself — the
3391 /// published form always carries it — and the type-checker refuses 0 (a
3392 /// guard that promises recovery and performs none). Termination is by
3393 /// construction: attempts strictly increase toward this bound.
3394 pub max_attempts: u32,
3395 pub loc: Loc,
3396}
3397#[derive(Debug)]
3398pub struct RefineStep {
3399 pub target: String,
3400 pub strategy: String,
3401 pub loc: Loc,
3402}
3403/// v2.83.0 — `weave [a, b] format: T include: [x, y]`, the synthesis
3404/// statement the README closes fourteen of its examples with.
3405///
3406/// **What was wrong.** The parser accepted only the BRACED field form
3407/// (`weave { sources: [...] format: T }`), which the README never writes. The
3408/// published bracket form fell into `skip_flow_step_structural` — and that
3409/// skipper stops at the first `output` KEYWORD it meets, so
3410/// `weave [A.output, B.output]` left the parser mid-list and the step then
3411/// failed with `Expected Colon` pointing at the comma. A silent drop that also
3412/// mislocated its own error.
3413#[derive(Debug)]
3414pub struct WeaveStep {
3415 pub sources: Vec<String>,
3416 pub target: String,
3417 pub format_type: String,
3418 pub priority: Vec<String>,
3419 pub style: String,
3420 /// v2.83.0 — `include: [summary, risks, recommendations]`: the parts
3421 /// the synthesis must contain. Published in twelve of the fourteen README
3422 /// weaves and, until this cycle, had no slot at any position. Consumed by
3423 /// the dispatch framing, like `priority` and `style`.
3424 pub include: Vec<String>,
3425 pub loc: Loc,
3426}
3427/// v2.8.0 — the closed catalog of `use <Tool>` argument forms. The
3428/// invocation surfaces are mutually exclusive, so a sum type models them
3429/// exactly (no ambiguous dual-empty state). NOTE: `apply: Tool given: <struct>`
3430/// (the splat form) is NOT here — it rides `StepNode.apply_ref` and is
3431/// validated against the tool schema in v2.8.0, not parsed as a `use`.
3432#[derive(Debug, Clone, PartialEq)]
3433pub enum UseArgs {
3434 /// `use Tool on "${arg}"` / `use Tool on query` — the v2.7.0 single
3435 /// positional argument. D5 back-compat: behaves byte-identically to the
3436 /// pre-58 `argument: String` (empty string when no `on` clause).
3437 LegacyPositional(String),
3438 /// `use Tool(query = "${q}", max_results = 5)` — D2 canonical multi-field
3439 /// keyword args. Each entry is `(name, value, value_kind)`: `value` is the
3440 /// expression STRING (the frontend has no structured `Expr`; mirrors
3441 /// `argument` / `parse_argument_list`); `value_kind` is `"literal"` or
3442 /// `"reference"` — the v2.10.0 classification from `parse_let_atom`, so the
3443 /// runtime resolves a bare identifier / `Step.output` as a binding lookup
3444 /// (like `let`) instead of passing the name literally. The type-checker
3445 /// (v2.8.0 + v2.10.0) validates each entry against the tool's declared input
3446 /// schema (W2 / CT-2 caller blame) and references against their source.
3447 Named(Vec<(String, String, String)>),
3448}
3449
3450impl UseArgs {
3451 /// v2.8.0 transitional — the legacy single-arg string for the IR `argument`
3452 /// field (still `String` until v2.8.0 carries structured named args).
3453 /// `Named` projects an empty argument here; the type-checker validates
3454 /// named args from the AST, and v2.8.0 wire their structured dispatch.
3455 pub fn legacy_argument(&self) -> String {
3456 match self {
3457 UseArgs::LegacyPositional(s) => s.clone(),
3458 UseArgs::Named(_) => String::new(),
3459 }
3460 }
3461}
3462
3463#[derive(Debug)]
3464pub struct UseToolStep {
3465 pub tool_name: String,
3466 pub args: UseArgs,
3467 pub loc: Loc,
3468}
3469#[derive(Debug)]
3470pub struct RememberStep {
3471 pub expression: String,
3472 pub memory_target: String,
3473 pub loc: Loc,
3474}
3475#[derive(Debug)]
3476pub struct RecallStep {
3477 pub query: String,
3478 pub memory_source: String,
3479 pub loc: Loc,
3480}
3481#[derive(Debug)]
3482pub struct ParBlock {
3483 /// v2.15.0 — the concurrent branches. Each top-level statement inside
3484 /// `par { … }` is one branch (a single-statement body); they execute
3485 /// concurrently at runtime. Empty for a `par {}` with no statements
3486 /// (degenerate no-op). Before v2.15.0 this was payload-free (the branches were
3487 /// skipped at parse time), so `par` ran as a stub.
3488 pub branches: Vec<Vec<FlowStep>>,
3489 pub loc: Loc,
3490}
3491#[derive(Debug)]
3492pub struct HibernateStep {
3493 pub event_name: String,
3494 pub timeout: String,
3495 pub loc: Loc,
3496}
3497#[derive(Debug)]
3498pub struct DeliberateBlock {
3499 pub loc: Loc,
3500}
3501#[derive(Debug)]
3502pub struct ConsensusBlock {
3503 pub loc: Loc,
3504}
3505/// v2.41.0 — `forge <Name>(seed: <string>) -> <Type> { mode:, novelty:,
3506/// depth:, branches:, constraints: }` — Directed Creative Synthesis. A
3507/// flow-body block that runs the Poincaré-Hadamard four-phase creative process
3508/// (Preparation → Incubation → Illumination → Verification) under a **measured,
3509/// fail-closed novelty guarantee**: the returned typed value must
3510/// clear a Normalized-Compression-Distance novelty floor against the obvious
3511/// baseline AND its `constraints:` anchor, or the forge fails structurally.
3512///
3513/// Before v2.41.0 this was a no-op stub (`{ loc }` only, body discarded). v2.41.0 makes
3514/// the README's long-standing claim true.
3515#[derive(Debug, Default)]
3516pub struct ForgeBlock {
3517 /// The synthesis name (`forge Artwork(...)` → `"Artwork"`).
3518 pub name: String,
3519 /// The creative seed — the conceptual starting point (`seed: "..."`).
3520 pub seed: String,
3521 /// The declared output type (`-> Visual` → `"Visual"`).
3522 pub output_type: String,
3523 /// Boden creativity mode (closed catalog: `combinatorial | exploratory |
3524 /// transformational`, `axon-T868`). Empty ⇒ defaults to `exploratory`.
3525 pub mode: String,
3526 /// Novelty target `[0.0, 1.0]` (`axon-T869`) — sets the fail-closed novelty
3527 /// floor and blends the incubation temperature. Default 0.5.
3528 pub novelty: f64,
3529 /// Incubation iterations (`depth ≥ 1`, `axon-T870`). Default 1.
3530 pub depth: i64,
3531 /// Illumination parallel branches (best-of-N, `branches ≥ 1`, `axon-T870`).
3532 /// Default 1.
3533 pub branches: i64,
3534 /// Optional `constraints:` reference to a declared `anchor` (`axon-T871`) —
3535 /// the verification predicate + coherence floor. Empty ⇒ novelty-floor-only
3536 /// verification.
3537 pub constraints_ref: String,
3538 pub loc: Loc,
3539}
3540#[derive(Debug)]
3541pub struct FocusStep {
3542 /// v2.63.0 — the declared dataspace this σ∘π reads (the field
3543 /// keeps its historical name; T930 requires it to resolve to a
3544 /// `dataspace` symbol).
3545 pub expression: String,
3546 /// v2.63.0 — the data-plane `where:` clause (the v1.30.0 closed
3547 /// filter grammar, shared with retrieve/navigate — the design decision). Empty
3548 /// ⇒ no filter. Validated fail-closed at dispatch, like retrieve.
3549 pub where_expr: String,
3550 /// v2.63.0 — π: the projected columns (empty ⇒ all).
3551 pub select: Vec<String>,
3552 /// v2.63.0 — the binding name for the result (`as:`). Empty ⇒
3553 /// the dataspace name.
3554 pub output: String,
3555 pub loc: Loc,
3556}
3557/// v2.65.0 — `grad <letName> wrt <x> [as <name>]`: differentiate the
3558/// EXPRESSION a prior rich `let` bound (its AST rides the IR), at compile
3559/// time, symbolically. The derivative is checked (T931/T932), simplified,
3560/// and stored in the IR — a proof-carrying artifact, re-derived at deploy.
3561#[derive(Debug)]
3562pub struct GradStep {
3563 /// The prior rich `let` whose expression is differentiated.
3564 pub target: String,
3565 /// The variables to differentiate against (`wrt x` / `wrt [x, y]`).
3566 pub wrt: Vec<String>,
3567 /// Result binding (`as:`). Empty ⇒ `d_<target>`.
3568 pub output: String,
3569 pub loc: Loc,
3570}
3571
3572#[derive(Debug)]
3573pub struct AssociateStep {
3574 pub left: String,
3575 pub right: String,
3576 pub using_field: String,
3577 /// v2.63.0 — result binding name (`as:`). Empty ⇒ `<L>_<R>`.
3578 pub output: String,
3579 pub loc: Loc,
3580}
3581#[derive(Debug)]
3582pub struct AggregateStep {
3583 pub target: String,
3584 pub group_by: Vec<String>,
3585 pub alias: String,
3586 /// v2.63.0 — the closed aggregate catalog entries
3587 /// (`count` | `count(col)` | `sum(col)` | `avg(col)` | `min(col)` |
3588 /// `max(col)`), kept RAW here; T930 validates shape + columns.
3589 pub compute: Vec<String>,
3590 /// v2.63.0 — data-plane `where:`. Empty ⇒ no filter.
3591 pub where_expr: String,
3592 pub loc: Loc,
3593}
3594#[derive(Debug)]
3595pub struct ExploreStepNode {
3596 pub target: String,
3597 pub limit: Option<i64>,
3598 /// v2.63.0 — result binding name (`as:`). Empty ⇒ the target.
3599 pub output: String,
3600 pub loc: Loc,
3601}
3602#[derive(Debug)]
3603pub struct IngestStep {
3604 pub source: String,
3605 pub target: String,
3606 /// v2.63.0 — the declared wire format of the source bytes
3607 /// (closed catalog: `csv` | `json`). Kept RAW at parse; the v2.63.0
3608 /// type-checker requires it and validates it (`axon-T929`) — an
3609 /// ingest that does not declare what it is parsing is refused.
3610 pub format: String,
3611 /// v2.63.0 — bounds enforced on the RAW byte stream BEFORE any
3612 /// parsing (the v2.54.0 discipline). `None` ⇒ the engine's conservative
3613 /// defaults apply (bounded by default, never unbounded).
3614 pub max_bytes: Option<u64>,
3615 pub max_rows: Option<u64>,
3616 pub loc: Loc,
3617}
3618/// v4.5.0 — `declassify <Class> from <source> -> <Type> via <Shield>`.
3619///
3620/// Retiring a class is an ACT, not an inference. The compiler does not decide
3621/// that a value stopped being PHI; someone declares it, and the compiler
3622/// refuses the declaration when it is structurally impossible — when the
3623/// destination type still carries the class being retired.
3624///
3625/// The class is NAMED at the site rather than left to the shield, so a reader
3626/// of the flow sees what was retired without going to look it up.
3627#[derive(Debug, Default)]
3628pub struct DeclassifyStep {
3629 /// The regulatory class being retired. One per statement: retiring two
3630 /// classes is two acts, and collapsing them would hide which control
3631 /// justified which.
3632 pub class: String,
3633 /// The value entering the operation.
3634 pub source: String,
3635 /// The DECLARED TYPE the value leaves as. It must be a different type,
3636 /// because the type is the only thing a boundary reads.
3637 pub output_type: String,
3638 /// The shield that authorises this. It must declare the class in its own
3639 /// `declassifies:` — retiring a class is a capability, not a side effect
3640 /// of scanning.
3641 pub shield: String,
3642 pub loc: Loc,
3643}
3644#[derive(Debug)]
3645pub struct ShieldApplyStep {
3646 pub shield_name: String,
3647 pub target: String,
3648 pub output_type: String,
3649 pub loc: Loc,
3650}
3651/// v1.29.0 / v2.67.0 / **v2.83.0** — `stream<T> { on_chunk … on_complete … }`.
3652///
3653/// The body used to NOT EXIST. `parse_block_step` — shared with `deliberate`,
3654/// `consensus` and (pre-retraction) `transact` — called `skip_braced_block()`
3655/// and threw the block's contents away at PARSE time. The handler was not a
3656/// no-op because someone forgot to implement it; it was a no-op because the
3657/// body never reached the AST for anything to execute. Four advertised
3658/// primitives died in that one function.
3659///
3660/// **v2.83.0 — and v2.67.0 closed that with the WRONG SHAPE.** It gave the block a
3661/// `body: Vec<FlowStep>`, which no published block and no paper writes. The
3662/// specified surface — `the design plan` section 3.7, whose D8
3663/// promises *"backward compat for `stream<τ>` 100%, cero cambios en `.axon`
3664/// source files de adopters"* — is `stream<T> { on_chunk: B₁ on_complete: B₂ }`,
3665/// and README block 15 publishes exactly that. Measured before this landed:
3666///
3667/// * at FLOW level the published body was a hard parse error
3668/// (`Unexpected token in flow body: 'on_chunk'`);
3669/// * in a STEP body the whole block was silently discarded by
3670/// `skip_flow_step_structural`, so block 15's `step Stream` reached the
3671/// dispatcher with `pix_ops=0`, `ask=""`, `output=""` — an EMPTY step, whose
3672/// `Stream.output` the next step then reasoned over.
3673///
3674/// So v2.67.0's attestation was the v2.83.0 `reason` defect one more time: a real
3675/// engine behind a grammar no adopter could write. `body` is KEPT (it parses, it
3676/// lowers, it runs, and removing it would break any program written against
3677/// v2.67.0), but it is no longer the primitive's published face.
3678#[derive(Debug)]
3679pub struct StreamBlock {
3680 /// The `<T>` in `stream<T>` — the CHUNK type. Empty when the block is
3681 /// written without one.
3682 ///
3683 /// It used to be discarded silently: `parse_stream_block`'s "tolerate the
3684 /// pre-111 form" loop advanced to the first `{`, eating `<QuoteData>` on the
3685 /// way. A type parameter consumed by nothing is the v2.67.0 defect, so it is
3686 /// captured here and type-checked at the handler boundary.
3687 pub chunk_type: String,
3688 /// `on_chunk: { … }` — run ONCE PER CHUNK, with the chunk bound under
3689 /// `chunk`. `None` when the handler is absent.
3690 ///
3691 /// It is a [`StepNode`], not a `Vec<FlowStep>`, because the published arm
3692 /// body is a STEP body and not a flow body: block 15 writes
3693 /// `on_chunk: { probe chunk for […] output: QuoteSnapshot }`, and `output:`
3694 /// is a step field that has no flow-level position at all. Sharing the shape
3695 /// means the arm reuses `run_step` — the design decision's "one concept, two positions",
3696 /// so there is no second dispatch implementation to drift.
3697 pub on_chunk: Option<StepNode>,
3698 /// `on_complete: { … }` — run ONCE, after the source closes, with the
3699 /// accumulated stream bound under `complete`. `None` when absent.
3700 pub on_complete: Option<StepNode>,
3701 /// v2.83.0 — `on_error: { … }` — run when the SOURCE fails, with the
3702 /// failure bound under `error`.
3703 ///
3704 /// It handles a failure of the **producer**, never a failure of the author's
3705 /// own handlers. If `on_chunk` panics its way to a dispatch error, that is a
3706 /// bug in the program, and routing it here would let a broken handler
3707 /// silently catch itself and report the stream as healthy. Cancellation is
3708 /// not a failure either — a cancelled stream propagates as cancelled.
3709 ///
3710 /// When present and the source fails, the step COMPLETES with this arm's
3711 /// output: the author declared what to do, so the recovery is explicit
3712 /// rather than a swallowed error. When absent, the failure propagates.
3713 pub on_error: Option<StepNode>,
3714 /// v2.67.0's body form: `stream { <steps> }`. Executed in order; each
3715 /// one's fragments are emitted on the flow's event channel as produced.
3716 /// Retained for compatibility — see the type-level note above.
3717 pub body: Vec<FlowStep>,
3718 pub loc: Loc,
3719}
3720// ── v2.87.0 — algebraic effects (Plotkin/Pretnar) ─────────────────────────
3721//
3722// The four constructs `the design plan` section 3.6/section 3.7 fixes: a top-level `effect`
3723// declaration, `perform` in a step or flow body, `handle … in …` in a flow
3724// body, and `resume()` / `abort()` / `forward` inside a handler clause.
3725//
3726// ⚠️ These are NOT the `Instruction` types in `axon-rs/src/effects/ir.rs`.
3727// That module is a self-contained FSM over a JSON instruction alphabet whose
3728// catch-all variant (`Instruction::Passthrough`, `#[serde(other)]`) is INERT —
3729// lowering a handler body onto it would make every non-effect node in the body
3730// a no-op, which is precisely the v2.67.0 defect this cycle exists not to repeat.
3731// the design decision: the effect machine is the DISPATCHER, and the instruction alphabet is
3732// `IRFlowNode`, so a handler clause can `emit`, `use` a tool or `persist` like
3733// any other body. See `the design plan`.
3734
3735/// `effect SSE { Emit(token: Token) -> Unit Done() -> Never }` — a top-level
3736/// declaration, a peer of `tool` / `persona` / `anchor` per `the design plan` section 3.1.
3737///
3738/// The declaration is what makes the operation catalog CLOSED. the design decision resolves
3739/// a bare `perform Emit(x)` against exactly this set: one declarer ⇒ resolved,
3740/// two ⇒ a compile error naming both, zero ⇒ a compile error. Without the
3741/// declaration there is no catalog and `effect_name` would have to be guessed.
3742#[derive(Debug)]
3743pub struct EffectDefinition {
3744 pub name: String,
3745 pub operations: Vec<EffectOperation>,
3746 pub loc: Loc,
3747 /// v1.5.2 — leading comment trivia attached to this declaration.
3748 pub leading_trivia: Vec<crate::tokens::Trivia>,
3749 /// v1.5.2 — trailing comment trivia.
3750 pub trailing_trivia: Vec<crate::tokens::Trivia>,
3751}
3752
3753/// One operation inside an `effect` declaration: `Emit(token: Token) -> Unit`.
3754#[derive(Debug)]
3755pub struct EffectOperation {
3756 pub name: String,
3757 pub parameters: Vec<Parameter>,
3758 /// The declared return type. `Never` is the bottom sentinel `the design plan` section 3.1
3759 /// writes on `Done() -> Never` — an operation whose handler is not expected
3760 /// to `resume`. Empty when the source omits `-> T`.
3761 pub return_type: String,
3762 pub loc: Loc,
3763}
3764
3765/// `handle SSE { Emit(token) -> { … } } in { … }` — the delimited handler
3766/// scope (D3: an effect is interceptable only inside `body`).
3767#[derive(Debug)]
3768pub struct HandleBlock {
3769 /// `handle E1, E2 { … }` — the effects this frame intercepts. More than one
3770 /// is legal; `IRHandlerFrame.effect_names` in the cycle-23 IR is a `Vec` for
3771 /// the same reason.
3772 pub effect_names: Vec<String>,
3773 pub clauses: Vec<HandlerClause>,
3774 /// The `in { … }` block. Ordinary flow steps — this is what the design decision buys.
3775 pub body: Vec<FlowStep>,
3776 pub loc: Loc,
3777}
3778
3779/// One clause of a [`HandleBlock`]: `Emit(token) -> { … }`.
3780#[derive(Debug)]
3781pub struct HandlerClause {
3782 pub operation_name: String,
3783 /// The clause's binders. `perform Emit(x)`'s argument is bound under the
3784 /// clause's parameter name for the duration of the clause body — the same
3785 /// discipline `EffectRuntime::dispatch_clause_for` uses (save, bind,
3786 /// restore), so a clause cannot leak a binding into its continuation.
3787 pub parameter_names: Vec<String>,
3788 pub body: Vec<FlowStep>,
3789 pub loc: Loc,
3790}
3791
3792/// `perform Emit(x)` (bare) or `perform SSE.Emit(x)` (qualified).
3793///
3794/// the design decision accepts both. `effect_name` is `None` for the bare form as written;
3795/// the IR generator resolves it against the declared catalog and the
3796/// type-checker refuses an ambiguous or unknown operation with the offending
3797/// location. The bare form is what `the design plan` section 3.1 publishes, and under v2.83.0's
3798/// doctrine the published surface is the promise.
3799#[derive(Debug)]
3800pub struct PerformStep {
3801 pub effect_name: Option<String>,
3802 pub operation_name: String,
3803 /// Argument expressions, verbatim source text. The cycle-23 IR carries
3804 /// `arguments: Vec<String>` for the same reason: resolution against the
3805 /// live bindings is a RUNTIME act, and pre-resolving here would freeze a
3806 /// value the enclosing step has not produced yet.
3807 pub arguments: Vec<String>,
3808 pub loc: Loc,
3809}
3810
3811/// `resume()` / `resume(value)` — invoke the captured one-shot continuation.
3812/// Legal only inside a handler clause body (D2, and the parser enforces it).
3813#[derive(Debug)]
3814pub struct ResumeStep {
3815 /// The resumed value, verbatim. Empty ⇒ `resume()` ⇒ Unit.
3816 pub value_expr: String,
3817 pub loc: Loc,
3818}
3819
3820/// `abort()` / `abort(value)` — terminate the enclosing `handle` without
3821/// resuming. The continuation is dropped, never invoked.
3822#[derive(Debug)]
3823pub struct AbortStep {
3824 pub value_expr: String,
3825 pub loc: Loc,
3826}
3827
3828/// `forward Emit(t)` / `forward SSE.Emit(t)` (D12) — propagate the operation to
3829/// the next OUTER frame, bypassing this one. What makes a handler a decorator
3830/// rather than a terminator.
3831#[derive(Debug)]
3832pub struct ForwardStep {
3833 pub effect_name: Option<String>,
3834 pub operation_name: String,
3835 pub arguments: Vec<String>,
3836 pub loc: Loc,
3837}
3838
3839#[derive(Debug)]
3840pub struct NavigateStep {
3841 /// v2.83.0 — per-navigation `depth:` override (README's pix family
3842 /// writes it inline). `None` ⇒ the navigator's bounded-rationality
3843 /// default. Threaded into `NavConfig.d_max` at dispatch, so this field
3844 /// DECIDES something — adding one consumed by nothing would be the v2.67.0
3845 /// defect this cycle exists to end.
3846 pub depth: Option<i64>,
3847 pub pix_name: String,
3848 pub corpus_name: String,
3849 pub query_expr: String,
3850 pub trail_enabled: bool,
3851 pub output_name: String,
3852 /// v2.13.0 — for MDN corpus-graph navigation: the seed document `from:`
3853 /// to start the ε-informative traversal. Empty for PIX tree navigation.
3854 pub seed: String,
3855 /// v2.13.0 — for MDN: the `budget:` (max documents). `None` = default.
3856 pub budget: Option<i64>,
3857 /// v2.17.0 (Q2) — optional column-scope filter (`where:`) for a
3858 /// `corpus from axonstore`. A raw filter expr (same shape as `retrieve …
3859 /// where`) pushed to the SELECT sourcing the corpus rows, so an adopter
3860 /// multiplexing sub-tenants in one axon-tenant via a column can scope the
3861 /// MDN graph to a single sub-tenant. Empty = no column filter (RLS-only).
3862 pub where_expr: String,
3863 pub loc: Loc,
3864}
3865#[derive(Debug)]
3866pub struct DrillStep {
3867 pub pix_name: String,
3868 pub subtree_path: String,
3869 pub query_expr: String,
3870 pub output_name: String,
3871 pub loc: Loc,
3872}
3873#[derive(Debug)]
3874pub struct TrailStep {
3875 pub navigate_ref: String,
3876 pub loc: Loc,
3877}
3878#[derive(Debug)]
3879pub struct CorroborateStep {
3880 pub navigate_ref: String,
3881 pub output_name: String,
3882 pub loc: Loc,
3883}
3884#[derive(Debug)]
3885pub struct OtsApplyStep {
3886 pub ots_name: String,
3887 pub target: String,
3888 pub output_type: String,
3889 pub loc: Loc,
3890}
3891#[derive(Debug)]
3892pub struct MandateApplyStep {
3893 pub mandate_name: String,
3894 pub target: String,
3895 pub output_type: String,
3896 pub loc: Loc,
3897}
3898/// v2.83.0 — `<Agent>(arg, …)` written as a step-body statement: the
3899/// form the README uses in every one of its agent examples, and the last piece
3900/// that makes v2.83.0's executor reachable from source.
3901///
3902/// It is a distinct node rather than a reuse of [`ComputeApplyStep`] because
3903/// the two are opposites: a `compute` is a PURE function with no model in the
3904/// loop and no budget, and an agent is a bounded deliberation that spends. A
3905/// shared node would invite a shared handler, and the first person to add a
3906/// field would have to decide which of the two it meant.
3907#[derive(Debug)]
3908pub struct AgentCallStep {
3909 /// The declared `agent` being invoked. A NAME — never dotted.
3910 pub agent_name: String,
3911 /// Positional arguments, each a v2.83.0 SUBJECT (a dotted reference or a
3912 /// literal). README writes `TrendAnalyzer(Gather.output)`.
3913 pub arguments: Vec<String>,
3914 pub loc: Loc,
3915}
3916#[derive(Debug)]
3917pub struct ComputeApplyStep {
3918 pub compute_name: String,
3919 pub arguments: Vec<String>,
3920 pub output_name: String,
3921 pub loc: Loc,
3922}
3923/// v1.6.0 D4 — dual-mode listen.
3924///
3925/// `channel_is_ref = true` ⇒ `channel` is the name of a declared
3926/// `ChannelDefinition` (canonical v1.6.0 form). `false` ⇒ legacy
3927/// string topic (deprecated; type checker emits a warning).
3928#[derive(Debug)]
3929pub struct ListenStep {
3930 pub channel: String,
3931 pub channel_is_ref: bool,
3932 pub event_alias: String,
3933 /// v2.4.0 — the handler body: real flow-steps executed on each event /
3934 /// scheduled tick. Pre-v2.4.0 the `{ … }` block was `skip_braced_block`'d
3935 /// (the listener was inert); now it is parsed so a `daemon` can run logic
3936 /// (e.g. `run <Flow>(…)`) per trigger. Empty for a bodyless `listen`.
3937 pub body: Vec<FlowStep>,
3938 pub loc: Loc,
3939}
3940#[derive(Debug)]
3941pub struct DaemonStepNode {
3942 pub daemon_ref: String,
3943 pub loc: Loc,
3944}
3945#[derive(Debug)]
3946pub struct PersistStep {
3947 pub store_name: String,
3948 /// v1.30.0 — the `{ col: value }` field block. Empty when the
3949 /// step is written without a block (`persist <store>`), in which
3950 /// case the runtime falls back to writing the flow's user
3951 /// bindings as a row (backward-compatible with v1.30.0).
3952 pub fields: Vec<(String, String)>,
3953 pub loc: Loc,
3954}
3955#[derive(Debug)]
3956pub struct RetrieveStep {
3957 pub store_name: String,
3958 pub where_expr: String,
3959 pub alias: String,
3960 /// v2.21.0 — optional `order_by:` clause: a closed
3961 /// comma-separated list of `column [asc|desc]` (same identifier
3962 /// discipline as `where:` columns — no injection). Empty = no
3963 /// ordering. Raw string, parsed + validated by the runtime
3964 /// (`filter::render_bounds`) and at `axon check` (v1.31.0 `axon-T807`).
3965 pub order_by: String,
3966 /// v2.21.0 — optional `limit:` clause: a `u32` literal OR a
3967 /// `${binding}` resolved to a `u32` at runtime. Empty = no limit.
3968 /// Raw string (`"100"` or `"${max}"`), validated at `axon check`
3969 /// (v1.31.0 `axon-T808`).
3970 pub limit_expr: String,
3971 /// v2.33.0 — optional `aggregate:` clause: a member of the CLOSED
3972 /// catalog `count` | `sum(<col>)` | `avg(<col>)` | `min(<col>)` |
3973 /// `max(<col>)`. Empty = a plain `SELECT *` retrieve. Raw string,
3974 /// parsed + validated by the runtime (`filter::parse_aggregate_clause`)
3975 /// and at `axon check` (v2.33.0 `axon-T843`/`T844`/`T845`).
3976 pub aggregate: String,
3977 /// v2.33.0 — optional `group_by:` clause: a comma-separated list
3978 /// of column identifiers (same discipline as `order_by:` columns).
3979 /// Requires an `aggregate:`. Empty = no grouping.
3980 pub group_by: String,
3981 /// v2.40.0 — optional `cache:` reference. A `retrieve` reads a store
3982 /// (a `storage` effect — never `pure`), so caching it is always a WIDENING
3983 /// that accepts staleness: the named `cache` MUST carry a finite `ttl:`
3984 /// (`axon-T865`) and typically an `invalidate_on:`. Names a declared
3985 /// `cache` (`axon-T864`); empty = uncached. Never governed by a
3986 /// `default: true` policy (defaults only auto-cover provably-`pure` tools).
3987 pub cache: String,
3988 pub loc: Loc,
3989}
3990#[derive(Debug)]
3991pub struct MutateStep {
3992 pub store_name: String,
3993 pub where_expr: String,
3994 /// v1.30.0 — the `{ col: value }` SET assignments. Empty when
3995 /// the step declares no columns, in which case the runtime falls
3996 /// back to writing the flow's user bindings as the `SET` clause
3997 /// (backward-compatible with v1.31.0).
3998 pub fields: Vec<(String, String)>,
3999 pub loc: Loc,
4000}
4001#[derive(Debug)]
4002pub struct PurgeStep {
4003 pub store_name: String,
4004 pub where_expr: String,
4005 pub loc: Loc,
4006}
4007#[derive(Debug)]
4008pub struct TransactBlock {
4009 pub loc: Loc,
4010}
4011
4012/// v2.43.0 — `scope <Name> { targets:, depth:, approver: }` — the
4013/// authorization scope a `warden` block runs `within`. The load-bearing safety
4014/// construct (paper section 5.2): it declares which resources may be analysed
4015/// (`targets` allowlist), how invasively (`depth` ceiling), and who authorised
4016/// it (`approver` capability). A `warden` with no resolvable in-scope
4017/// authorization does not compile (fail-closed). Named + referenced, like
4018/// `cache`/`cors`. **Unknown fields are a hard parse error**: a scope
4019/// governs an offensive-capable analysis, so a typo can never silently widen it.
4020#[derive(Debug, Default)]
4021pub struct ScopeDefinition {
4022 pub name: String,
4023 /// `targets: [ "<resource>", … ]` — the allowlist of resources the operator
4024 /// owns/controls and authorises for analysis. Required + non-empty (v2.43.0
4025 /// `axon-T88x`); a target outside this list is a typed rejection.
4026 pub targets: Vec<String>,
4027 /// `depth: static_artifact | memory_dump | live_network` — the MOST invasive
4028 /// analysis depth this scope permits (the ceiling). Closed catalog, ordered
4029 /// least→most invasive; empty ⇒ the safest default `static_artifact` (v2.43.0).
4030 pub depth: String,
4031 /// `approver: [requires] "<capability>"` — the capability whose holder
4032 /// authorised this scope (segregation of duties, the `mandate` v1.13.1 model).
4033 /// Required (v2.43.0).
4034 pub approver: String,
4035 pub loc: Loc,
4036 /// v1.5.2 — leading comment trivia.
4037 pub leading_trivia: Vec<crate::tokens::Trivia>,
4038 /// v1.5.2 — trailing comment trivia.
4039 pub trailing_trivia: Vec<crate::tokens::Trivia>,
4040}
4041
4042/// v2.43.0 — the `warden(<target>) within <Scope> { … }` adversarial
4043/// security-analysis block. A flow-body block (like `quant`): it audits a
4044/// `target` under a paraconsistent adversarial framing, emitting attested
4045/// `Vulnerability` findings — but ONLY `within` a signed authorization `scope`.
4046/// v2.43.0 ships the SURFACE only; scope resolution + the depth/witness discipline
4047/// is v2.43.0, and the real analysis engine is v2.43.0 (enterprise).
4048#[derive(Debug, Default)]
4049pub struct WardenBlock {
4050 /// `warden(<target>)` — a reference to the resource under analysis (a
4051 /// let-bound value / declared target). v2.43.0 checks it is within the scope's
4052 /// `targets` allowlist.
4053 pub target: String,
4054 /// `within <Scope>` — the MANDATORY authorization scope reference. Empty is a
4055 /// hard error (v2.43.0 `axon-T88x`, fail-closed): no scope ⇒ no analysis.
4056 pub scope_ref: String,
4057 /// The nested flow-body statements (`find_exploits()`, `fortify`, `emit`),
4058 /// parsed like `par`/`quant` branches so v2.43.0 can walk them.
4059 pub body: Vec<FlowStep>,
4060 pub loc: Loc,
4061}
4062
4063/// v2.4.0 — the `quant` cognitive primitive block surface
4064/// (`papers/paper_primitiva_quant.md`; enterprise v2.4.0).
4065///
4066/// `quant` projects an MEK semantic tensor into a complex Hilbert space,
4067/// evolves it under a variational / kernel-feature map, and collapses back to
4068/// classical silicon. The attribute header is OPTIONAL — the bare `quant { … }`
4069/// form (the paper's example) leaves every attribute defaulted. The richer form
4070/// `quant(encoding: amplitude, observable: M, qubits: 10, depth: 4,
4071/// bandwidth: 0.5, backend: quant_sim) { … }` pins the encoding scheme (D2),
4072/// the Pauli-sum observable (D5), the register width / circuit depth, the
4073/// projected-kernel bandwidth γ (D7), and the algebraic-effect backend (D1/D9).
4074///
4075/// v2.4.0 ships the SURFACE only. The Continuous Type Invariant over `body`
4076/// (v2.4.0), the typed continuous grammar incl. typed `let` + `Observable`
4077/// (v2.4.0), and the `quant_sim`/`qpu_native` effect injection + `yield`
4078/// measurement point (v2.4.0) land in subsequent steps.
4079#[derive(Debug, Default)]
4080pub struct QuantBlock {
4081 /// `encoding:` — `amplitude` (default) or `angle` (shallow). `None` = the
4082 /// compiler default (amplitude). Carried as the surface spelling; v2.4.0
4083 /// validates against the closed scheme set.
4084 pub encoding: Option<String>,
4085 /// `observable:` — the name of a declared `Observable` (Pauli-sum, D5).
4086 /// `None` if unspecified (v2.4.0 resolves + Hermiticity-checks it).
4087 pub observable: Option<String>,
4088 /// `qubits:` — the register width n (D = 2ⁿ). `None` = inferred from the
4089 /// encoded tensor dimensionality. The OSS reference backend caps n ≤ 10
4090 /// (D1); that bound is enforced at v2.4.0, not here.
4091 pub qubits: Option<i64>,
4092 /// `depth:` — the variational circuit depth L. `None` = backend default.
4093 pub depth: Option<i64>,
4094 /// `bandwidth:` — the projected-quantum-kernel bandwidth γ (D7). `None` =
4095 /// backend default.
4096 pub bandwidth: Option<f64>,
4097 /// v2.23.0 — `reupload:` L, the number of DATA RE-UPLOADING layers. `None`
4098 /// or `1` = no re-uploading (the data enters once → a quadratic form, provably
4099 /// classical for amplitude+Pauli, v2.23.0). `L ≥ 2` interleaves the data
4100 /// encoding with entangling layers L times — the ONLY provable escape from the
4101 /// quadratic bound (Havlíček-style; canonical with `encoding: angle`). The
4102 /// resulting kernel must still pass an Advantage Witness to be deployed
4103 /// claiming advantage (v2.23.0).
4104 pub reupload: Option<i64>,
4105 /// The algebraic-effect backend tag: `quant_sim` (default) or `qpu_native`
4106 /// (D1/D9). Stored as the bare backend name; v2.4.0 injects the full
4107 /// `ots:backend:<tag>` effect into the enclosing flow's effect row.
4108 pub effect: String,
4109 /// The nested flow-body statements (parsed like `par` branches, so v2.4.0
4110 /// can apply the Continuous Type Invariant to real AST). Empty for an
4111 /// empty `quant {}`.
4112 pub body: Vec<FlowStep>,
4113 pub loc: Loc,
4114}
4115
4116/// v2.4.0 — one term `cₖ · Pₖ` of a Pauli-sum observable.
4117///
4118/// `coefficient` is a real scalar (parsed as `f64`); `pauli` is a Pauli string
4119/// over the closed alphabet `{I, X, Y, Z}` (one char per qubit), e.g. `"ZZ"` or
4120/// `"XI"`. A real linear combination of Pauli strings is **Hermitian by
4121/// construction** (each Pauli string is Hermitian; real-weighted sums preserve
4122/// Hermiticity), which is why the observable needs no separate Hermiticity check.
4123#[derive(Debug, Default, Clone)]
4124pub struct PauliTerm {
4125 pub coefficient: f64,
4126 pub pauli: String,
4127 pub loc: Loc,
4128}
4129
4130/// v2.4.0 — the `observable <Name> { qubits, term: cₖ·Pₖ … }` declaration
4131/// (paper section 3.2; plan D5). A typed Pauli-sum `M = Σ cₖ Pₖ` that a `quant` block
4132/// measures the evolved state against. The type-checker validates the closed
4133/// `{I,X,Y,Z}` alphabet + equal term lengths + non-empty sum; Hermiticity is
4134/// guaranteed by construction (real coefficients).
4135#[derive(Debug, Default)]
4136pub struct ObservableDefinition {
4137 pub name: String,
4138 /// `qubits: n` — the register width every Pauli string must span. `None`
4139 /// = inferred from the (equal) term lengths.
4140 pub qubits: Option<i64>,
4141 pub terms: Vec<PauliTerm>,
4142 pub loc: Loc,
4143 /// v1.5.2 — leading comment trivia.
4144 pub leading_trivia: Vec<crate::tokens::Trivia>,
4145 /// v1.5.2 — trailing comment trivia.
4146 pub trailing_trivia: Vec<crate::tokens::Trivia>,
4147}
4148
4149/// v2.23.0 — `witness <Name> { claim: <ref> against: <baseline>
4150/// metric: <metric> threshold: <ε> data: <source> }`. The Advantage-Witness
4151/// proof obligation. The compiler proves it WELL-FORMED (v2.23.0, `axon-E0790`);
4152/// the advantage VALUE is computed on real `data` at deploy/runtime and carried
4153/// as a verdict (v2.23.0+). Fields are order-free `key: value` pairs.
4154#[derive(Debug)]
4155pub struct WitnessDefinition {
4156 pub name: String,
4157 /// The primitive instance whose advantage is claimed (e.g. an `observable` /
4158 /// `corpus` name, or a quant kernel reference).
4159 pub claim: String,
4160 /// The cheaper alternative the claim must beat (a closed-catalog baseline
4161 /// like `cosine` / `flat_retrieval` / `single_shot`, or a reference).
4162 pub baseline: String,
4163 /// How advantage is measured — a closed-catalog metric (`geometric_difference`,
4164 /// `kernel_target_alignment`, `ranking_lift`, `outcome_lift`).
4165 pub metric: String,
4166 /// The minimum advantage that justifies the cost (ε ≥ 0).
4167 pub threshold: f64,
4168 /// The real-data source the witness is evaluated on (a ref to an axonstore /
4169 /// corpus / labelled set). Required — advantage cannot be claimed in the abstract.
4170 pub data: String,
4171 pub loc: Loc,
4172 pub leading_trivia: Vec<crate::tokens::Trivia>,
4173 pub trailing_trivia: Vec<crate::tokens::Trivia>,
4174}
4175
4176// ── v1.6.0 — Mobile Typed Channels ──────────────────────────────────
4177
4178/// `channel Name { message: T, qos: X, lifetime: ℓ, persistence: π, shield: σ }`.
4179///
4180/// First-class affine resource carrying a typed message. Direct port
4181/// of `axon.compiler.ast_nodes.ChannelDefinition`. `message` retains
4182/// the surface spelling (e.g. `"Order"` or `"Channel<Order>"`) so the
4183/// type checker can resolve nested mobility (paper section 3.3).
4184#[derive(Debug)]
4185pub struct ChannelDefinition {
4186 pub name: String,
4187 pub message: String, // type name OR "Channel<T>" for second-order
4188 pub qos: String, // at_most_once | at_least_once | exactly_once | broadcast | queue
4189 pub lifetime: String, // linear | affine | persistent (D1 default: affine)
4190 pub persistence: String, // ephemeral | persistent_axonstore
4191 pub shield_ref: String, // optional σ-shield gate for publish (D8)
4192 pub loc: Loc,
4193 /// v1.5.2 — leading comment trivia attached to this declaration
4194 /// (comments preceding the declaration's first token, since the
4195 /// previous declaration or file start). Empty by default.
4196 pub leading_trivia: Vec<crate::tokens::Trivia>,
4197 /// v1.5.2 — trailing comment trivia (same line as the
4198 /// declaration's last effective token). Empty by default.
4199 pub trailing_trivia: Vec<crate::tokens::Trivia>,
4200}
4201
4202/// `emit ChannelName(value_ref)` — π-calculus output prefix `c⟨v⟩.P`.
4203///
4204/// Direct port of `axon.compiler.ast_nodes.EmitStatement`. Handles
4205/// both Chan-Output (scalar payload) and Chan-Mobility (channel-as-
4206/// value); the type checker dispatches based on whether `value_ref`
4207/// resolves to a `ChannelDefinition`.
4208#[derive(Debug)]
4209pub struct EmitStatement {
4210 pub channel_ref: String,
4211 pub value_ref: String,
4212 pub loc: Loc,
4213}
4214
4215/// v2.46.0 — `mint <Credential> as <binding>`: the flow-step verb that
4216/// mints a declared ephemeral `credential` at runtime. The binding
4217/// receives the raw bearer string (shown once — the type checker forbids
4218/// it from flowing into a `persist` payload, `axon-T896`: credentials do
4219/// not enter stores). Undeclared credential reference = `axon-T895`.
4220#[derive(Debug)]
4221pub struct MintStep {
4222 pub credential_ref: String,
4223 pub binding: String,
4224 pub loc: Loc,
4225}
4226
4227/// v2.48.0 — `rotate <SecretsStore> [where "<filter>"] with <Tool> as
4228/// <binding>`: the mediated secret-renewal flow verb (doctrine
4229/// `rotation_without_revelation`). Set-oriented like `mutate`: every
4230/// custody entry of the store's class matching the filter (whole class
4231/// when the filter is omitted — the post-breach bulk-rotation shape) is
4232/// renewed through ONE mediated exchange per key: the runtime reveals
4233/// the current value only into the tool call, the tool returns the new
4234/// value, the runtime commits it (CAS on version — concurrent rotators
4235/// cannot double-spend a refresh credential). The binding receives the
4236/// METADATA-ONLY summary `{attempted, rotated, failed}` — no term
4237/// evaluates to a secret value. `rotate` on a non-secrets store =
4238/// `axon-T898`; an undeclared tool = `axon-T899`.
4239#[derive(Debug)]
4240pub struct RotateStep {
4241 pub store_ref: String,
4242 /// The v2.21.0-grammar metadata filter (`expires_at < now() + interval
4243 /// '10 minutes'`, `key LIKE 'crm.%'`, …). Empty = the whole class.
4244 pub where_expr: String,
4245 pub tool_ref: String,
4246 pub binding: String,
4247 pub loc: Loc,
4248}
4249
4250/// `publish ChannelName within ShieldName` — capability extrusion.
4251///
4252/// Paper section 4.3 (Publish-Ext) materialized as a flow step. The `within
4253/// <Shield>` clause is mandatory (D8) — the parser rejects bare
4254/// `publish C`, the type checker rejects publishes whose shield does
4255/// not cover κ(message_type) (v1.2.0 + paper section 3.4).
4256#[derive(Debug)]
4257pub struct PublishStatement {
4258 pub channel_ref: String,
4259 pub shield_ref: String,
4260 pub loc: Loc,
4261}
4262
4263/// `discover ChannelName as alias` — dual of publish.
4264///
4265/// Imports a previously-published handle into a fresh affine local
4266/// binding. The `as <alias>` is mandatory; the type checker rejects
4267/// discovery of channels that were never declared with `shield_ref`.
4268#[derive(Debug)]
4269pub struct DiscoverStatement {
4270 pub capability_ref: String,
4271 pub alias: String,
4272 pub loc: Loc,
4273}