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