Skip to main content

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