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    Pix(PixDefinition),
89    Ledger(LedgerDefinition),
90    Psyche(PsycheDefinition),
91    Corpus(CorpusDefinition),
92    Dataspace(DataspaceDefinition),
93    Ots(OtsDefinition),
94    Mandate(MandateDefinition),
95    Compute(ComputeDefinition),
96    Daemon(DaemonDefinition),
97    AxonStore(AxonStoreDefinition),
98    AxonEndpoint(AxonEndpointDefinition),
99    /// §Fase 53 — Closed-catalog extension mechanism. Declares
100    /// adopter-specific PROVENANCE members for a closed catalog
101    /// (`effects` bases or shield `scan` categories) so the
102    /// type-checker + PCC treat them as first-class. Auditable +
103    /// gateable; never extends the enforceable effect set (invariant
104    /// #2 — provenance-class only).
105    Extension(ExtensionDefinition),
106    /// §λ-L-E Fase 1 — I/O cognitivo primitives.
107    Resource(ResourceDefinition),
108    Fabric(FabricDefinition),
109    Manifest(ManifestDefinition),
110    Observe(ObserveDefinition),
111    /// §λ-L-E Fase 3 — Control cognitivo primitives.
112    Reconcile(ReconcileDefinition),
113    Lease(LeaseDefinition),
114    Ensemble(EnsembleDefinition),
115    /// §λ-L-E Fase 4 — Topology + π-calculus binary sessions.
116    Session(SessionDefinition),
117    Topology(TopologyDefinition),
118    /// §λ-L-E Fase 5 — Cognitive immune system (per docs/paper_immune_v2.md).
119    Immune(ImmuneDefinition),
120    Reflex(ReflexDefinition),
121    Heal(HealDefinition),
122    /// §λ-L-E Fase 9 — UI cognitiva declarativa.
123    Component(ComponentDefinition),
124    View(ViewDefinition),
125    /// §λ-L-E Fase 13 — Mobile typed channels (paper_mobile_channels.md).
126    Channel(ChannelDefinition),
127    /// §Fase 41.b — typed WebSocket transport binding a `session` protocol
128    /// (paper_websocket_cognitive_primitive.md).
129    Socket(SocketDefinition),
130    /// §Fase 51.c.2 — a Pauli-sum observable `M = Σ cₖ Pₖ` that a `quant`
131    /// block measures against (paper §3.2; plan D5).
132    Observable(ObservableDefinition),
133    /// §Fase 69.a — an Advantage Witness: a machine-checkable proof obligation
134    /// that a primitive's `claim` beats a cheaper `baseline` by a `metric` above
135    /// a `threshold` on real `data` (doctrine `axon://logic/no_unwitnessed_advantage`).
136    Witness(WitnessDefinition),
137    /// Tier 3+ declarations parsed structurally (balanced braces, no detailed AST).
138    Generic(GenericDeclaration),
139}
140
141// ── §λ-L-E Fase 1 — Resource primitive ───────────────────────────────────────
142
143/// `resource Name { kind, endpoint, capacity, lifetime, certainty_floor, shield }`
144///
145/// An infrastructure resource declared as a linear, affine, or persistent
146/// token. Linear/affine resources cannot be aliased across manifests
147/// (Separation Logic `*` disjointness).
148#[derive(Debug, Default)]
149pub struct ResourceDefinition {
150    pub name: String,
151    pub kind: String, // postgres | redis | s3 | vpc | gpu | compute | file | custom
152    pub endpoint: String, // connection URI
153    pub capacity: Option<i64>, // pool size / instance count hint
154    pub lifetime: String, // linear | affine | persistent (default: affine)
155    pub certainty_floor: Option<f64>, // epistemic gate c ∈ [0.0, 1.0]
156    pub shield_ref: String, // optional shield reference
157    pub loc: Loc,
158    /// Fase 14.b — leading comment trivia attached to this declaration
159    /// (comments preceding the declaration's first token, since the
160    /// previous declaration or file start). Empty by default.
161    pub leading_trivia: Vec<crate::tokens::Trivia>,
162    /// Fase 14.b — trailing comment trivia (same line as the
163    /// declaration's last effective token). Empty by default.
164    pub trailing_trivia: Vec<crate::tokens::Trivia>,
165}
166
167/// `fabric Name { provider, region, zones, ephemeral, shield }`
168///
169/// A tagged substrate — the topological container where resources are
170/// provisioned. Maps to VPC / cluster / namespace.
171#[derive(Debug, Default)]
172pub struct FabricDefinition {
173    pub name: String,
174    pub provider: String, // aws | gcp | azure | kubernetes | bare_metal | custom
175    pub region: String,   // provider-specific region id
176    pub zones: Option<i64>, // number of availability zones
177    pub ephemeral: Option<bool>, // true = destroy on program end
178    pub shield_ref: String, // optional shield reference
179    pub loc: Loc,
180    /// Fase 14.b — leading comment trivia attached to this declaration
181    /// (comments preceding the declaration's first token, since the
182    /// previous declaration or file start). Empty by default.
183    pub leading_trivia: Vec<crate::tokens::Trivia>,
184    /// Fase 14.b — trailing comment trivia (same line as the
185    /// declaration's last effective token). Empty by default.
186    pub trailing_trivia: Vec<crate::tokens::Trivia>,
187}
188
189/// `manifest Name { resources, fabric, region, zones, compliance }`
190///
191/// A declarative specification of desired shape — not a "desired state" in
192/// the Terraform sense, a *belief* about structure. Linear/affine resources
193/// in `resources` must be disjoint (Separation Logic `*`).
194#[derive(Debug, Default)]
195pub struct ManifestDefinition {
196    pub name: String,
197    pub resources: Vec<String>, // references to ResourceDefinition names
198    pub fabric_ref: String,     // reference to FabricDefinition name
199    pub region: String,
200    pub zones: Option<i64>,
201    pub compliance: Vec<String>, // κ — regulatory class (Fase 6.1)
202    pub loc: Loc,
203    /// Fase 14.b — leading comment trivia attached to this declaration
204    /// (comments preceding the declaration's first token, since the
205    /// previous declaration or file start). Empty by default.
206    pub leading_trivia: Vec<crate::tokens::Trivia>,
207    /// Fase 14.b — trailing comment trivia (same line as the
208    /// declaration's last effective token). Empty by default.
209    pub trailing_trivia: Vec<crate::tokens::Trivia>,
210}
211
212/// `observe Name from Manifest { sources, quorum, timeout, on_partition, certainty_floor }`
213///
214/// A quorum-gated observation of a manifest's real state. Each output
215/// carries ΛD envelope E = ⟨c, τ, ρ, δ⟩; `τ` records observation lag.
216/// `on_partition: fail` raises a CT-3 (Network Error) — partitions are ⊥ void.
217#[derive(Debug, Default)]
218pub struct ObserveDefinition {
219    pub name: String,
220    pub target: String, // name of ManifestDefinition being observed
221    pub sources: Vec<String>,
222    pub quorum: Option<i64>,  // Byzantine quorum threshold
223    pub timeout: String,      // duration literal "5s", "100ms"
224    pub on_partition: String, // fail (CT-3) | shield_quarantine
225    pub certainty_floor: Option<f64>,
226    pub loc: Loc,
227    /// Fase 14.b — leading comment trivia attached to this declaration
228    /// (comments preceding the declaration's first token, since the
229    /// previous declaration or file start). Empty by default.
230    pub leading_trivia: Vec<crate::tokens::Trivia>,
231    /// Fase 14.b — trailing comment trivia (same line as the
232    /// declaration's last effective token). Empty by default.
233    pub trailing_trivia: Vec<crate::tokens::Trivia>,
234}
235
236// ── §λ-L-E Fase 3 — Control cognitivo primitives ─────────────────────────────
237
238/// `reconcile Name { observe, threshold, tolerance, on_drift, shield, mandate, max_retries }`
239///
240/// A cognitive control loop that minimises variational free energy
241/// `F = D_KL(q(s) || p(s, o))` between a manifest belief and an observe
242/// evidence. Acting on the environment (`on_drift: provision`) is one of
243/// the two classical routes to reducing F (the other is belief revision).
244#[derive(Debug, Default)]
245pub struct ReconcileDefinition {
246    pub name: String,
247    pub observe_ref: String,
248    pub threshold: Option<f64>, // epistemic gate c ∈ [0.0, 1.0]
249    pub tolerance: Option<f64>, // drift tolerance [0.0, 1.0]
250    pub on_drift: String,       // provision | alert | refine (default: provision)
251    pub shield_ref: String,
252    pub mandate_ref: String,
253    pub max_retries: i64, // default: 3
254    pub loc: Loc,
255    /// Fase 14.b — leading comment trivia attached to this declaration
256    /// (comments preceding the declaration's first token, since the
257    /// previous declaration or file start). Empty by default.
258    pub leading_trivia: Vec<crate::tokens::Trivia>,
259    /// Fase 14.b — trailing comment trivia (same line as the
260    /// declaration's last effective token). Empty by default.
261    pub trailing_trivia: Vec<crate::tokens::Trivia>,
262}
263
264/// `lease Name { resource, duration, acquire, on_expire }`
265///
266/// Affine/linear lease on a resource, with explicit Δt encoded in the `τ`
267/// of the ΛD envelope. Runtime materializes each lease as a revocable
268/// token; use post-expiry raises `LeaseExpiredError` (CT-2) per D2.
269#[derive(Debug, Default)]
270pub struct LeaseDefinition {
271    pub name: String,
272    pub resource_ref: String,
273    pub duration: String,  // "30s", "5m", "2h"
274    pub acquire: String,   // on_start | on_demand (default: on_start)
275    pub on_expire: String, // anchor_breach | release | extend (default: anchor_breach)
276    pub loc: Loc,
277    /// Fase 14.b — leading comment trivia attached to this declaration
278    /// (comments preceding the declaration's first token, since the
279    /// previous declaration or file start). Empty by default.
280    pub leading_trivia: Vec<crate::tokens::Trivia>,
281    /// Fase 14.b — trailing comment trivia (same line as the
282    /// declaration's last effective token). Empty by default.
283    pub trailing_trivia: Vec<crate::tokens::Trivia>,
284}
285
286/// `ensemble Name { observations, quorum, aggregation, certainty_mode }`
287///
288/// Byzantine quorum aggregator over ≥2 independent observations. Yields
289/// common knowledge `Cφ` (Fagin-Halpern) when at least `quorum` observers
290/// agree. Failed observations are excluded; below quorum raises CT-3.
291#[derive(Debug, Default)]
292pub struct EnsembleDefinition {
293    pub name: String,
294    pub observations: Vec<String>,
295    pub quorum: Option<i64>,
296    pub aggregation: String, // majority | weighted | byzantine (default: majority)
297    pub certainty_mode: String, // min | weighted | harmonic (default: min)
298    pub loc: Loc,
299    /// Fase 14.b — leading comment trivia attached to this declaration
300    /// (comments preceding the declaration's first token, since the
301    /// previous declaration or file start). Empty by default.
302    pub leading_trivia: Vec<crate::tokens::Trivia>,
303    /// Fase 14.b — trailing comment trivia (same line as the
304    /// declaration's last effective token). Empty by default.
305    pub trailing_trivia: Vec<crate::tokens::Trivia>,
306}
307
308// ── §λ-L-E Fase 4 — Topology + π-calculus binary sessions ──────────────────
309
310/// One step in a session protocol.
311///
312/// §Fase 4: `send T` | `receive T` | `loop` | `end`. §Fase 41.b adds **choice**:
313/// `select { ℓ: [..], … }` (⊕ — this role chooses) and `branch { ℓ: [..], … }`
314/// (& — this role offers); for those `op`s the labelled continuations live in
315/// [`SessionStep::branches`] (a nested sub-protocol per label).
316#[derive(Debug, Clone, Default)]
317pub struct SessionStep {
318    pub op: String,           // send | receive | loop | end | select | branch
319    pub message_type: String, // only meaningful for send / receive
320    /// §Fase 41.b — populated only for `op == "select" | "branch"`: the labelled
321    /// branches, each a nested step sequence (its own sub-protocol).
322    pub branches: Vec<SessionBranch>,
323    pub loc: Loc,
324}
325
326/// §Fase 41.b — one labelled arm of a `select`/`branch` choice: `ℓ: [steps]`.
327#[derive(Debug, Clone, Default)]
328pub struct SessionBranch {
329    pub label: String,
330    pub steps: Vec<SessionStep>,
331    pub loc: Loc,
332}
333
334/// One role in a binary session — name + ordered list of steps.
335#[derive(Debug, Default)]
336pub struct SessionRole {
337    pub name: String,
338    pub steps: Vec<SessionStep>,
339    pub loc: Loc,
340}
341
342/// `session Name { role1: [step, …]  role2: [step, …] }`
343///
344/// A binary session type — exactly two roles whose protocols MUST be
345/// pairwise Honda-Vasconcelos dual. Duality is verified by the type
346/// checker; non-dual programs are rejected at compile time.
347#[derive(Debug, Default)]
348pub struct SessionDefinition {
349    pub name: String,
350    pub roles: Vec<SessionRole>,
351    pub loc: Loc,
352    /// Fase 14.b — leading comment trivia attached to this declaration
353    /// (comments preceding the declaration's first token, since the
354    /// previous declaration or file start). Empty by default.
355    pub leading_trivia: Vec<crate::tokens::Trivia>,
356    /// Fase 14.b — trailing comment trivia (same line as the
357    /// declaration's last effective token). Empty by default.
358    pub trailing_trivia: Vec<crate::tokens::Trivia>,
359}
360
361/// `socket Name { protocol: SessionRef, backpressure: credit(n), reconnect:
362/// cognitive_state, legal_basis: ... }`
363///
364/// §Fase 41.b — the typed WebSocket transport (paper_websocket_cognitive_primitive.md).
365/// `socket` is NOT the protocol — the protocol is a `session` it references by
366/// name (protocol and transport kept separate but composable). The type checker
367/// resolves `protocol` to a declared `session` (whose two roles are already
368/// duality-checked via the §41.a algebra), so the dialogue carried over the WS
369/// connection is conformant + deadlock-free by construction.
370#[derive(Debug, Default)]
371pub struct SocketDefinition {
372    pub name: String,
373    /// The referenced `session` declaration's name — the protocol.
374    pub protocol: String,
375    /// The credit window of the typed-resource backpressure (`credit(n)`);
376    /// `None` if unspecified. A `0` credit is rejected by the type checker.
377    pub backpressure_credit: Option<i64>,
378    /// `reconnect: cognitive_state` → `true` (resume mid-dialogue via a sealed
379    /// §40.t snapshot); absent or `reconnect: none` → `false`.
380    pub reconnect: bool,
381    /// Optional `legal_basis:` annotation (enterprise audit/shield gate).
382    pub legal_basis: Option<String>,
383    pub loc: Loc,
384    /// Fase 14.b — leading comment trivia.
385    pub leading_trivia: Vec<crate::tokens::Trivia>,
386    /// Fase 14.b — trailing comment trivia.
387    pub trailing_trivia: Vec<crate::tokens::Trivia>,
388}
389
390/// `source -> target : Session` — one directed edge of a topology.
391///
392/// Convention: the source plays the FIRST role of the session; the target
393/// plays the SECOND role. Fixed so assignment is unambiguous.
394#[derive(Debug, Default)]
395pub struct TopologyEdge {
396    pub source: String,
397    pub target: String,
398    pub session_ref: String,
399    pub loc: Loc,
400}
401
402/// `topology Name { nodes: […]  edges: [A -> B : Session, …] }`
403///
404/// A typed directed graph over Axon entities. Edges carry session references
405/// whose duality the type checker enforces; the graph is statically analysed
406/// for Honda-liveness (deadlock-prone cycles).
407#[derive(Debug, Default)]
408pub struct TopologyDefinition {
409    pub name: String,
410    pub nodes: Vec<String>,
411    pub edges: Vec<TopologyEdge>,
412    pub loc: Loc,
413    /// Fase 14.b — leading comment trivia attached to this declaration
414    /// (comments preceding the declaration's first token, since the
415    /// previous declaration or file start). Empty by default.
416    pub leading_trivia: Vec<crate::tokens::Trivia>,
417    /// Fase 14.b — trailing comment trivia (same line as the
418    /// declaration's last effective token). Empty by default.
419    pub trailing_trivia: Vec<crate::tokens::Trivia>,
420}
421
422// ── §λ-L-E Fase 5 — Cognitive immune system (per paper_immune_v2.md) ────────
423
424/// `immune Name { watch, sensitivity, baseline, window, scope, tau, decay }`
425///
426/// A continuous anomaly sensor over a declared observation vector.
427/// Computes D_KL(q_baseline || p_observed) (paper §3.2) and emits a
428/// HealthReport at an epistemic level derived from the KL magnitude.
429///
430/// Pure sensor — `immune` takes NO action. Actions belong to `reflex`
431/// and `heal`, which consume its HealthReport.
432#[derive(Debug, Default)]
433pub struct ImmuneDefinition {
434    pub name: String,
435    pub watch: Vec<String>,       // observe / ensemble / any declared ref
436    pub sensitivity: Option<f64>, // [0.0, 1.0]
437    pub baseline: String,         // "learned" (default) or name of a prior
438    pub window: i64,              // samples used to estimate baseline (default: 100)
439    pub scope: String,            // tenant | flow | global (MANDATORY, paper §8.2)
440    pub tau: String,              // duration half-life
441    pub decay: String,            // exponential (default) | linear | none
442    pub loc: Loc,
443    /// Fase 14.b — leading comment trivia attached to this declaration
444    /// (comments preceding the declaration's first token, since the
445    /// previous declaration or file start). Empty by default.
446    pub leading_trivia: Vec<crate::tokens::Trivia>,
447    /// Fase 14.b — trailing comment trivia (same line as the
448    /// declaration's last effective token). Empty by default.
449    pub trailing_trivia: Vec<crate::tokens::Trivia>,
450}
451
452/// `reflex Name { trigger, on_level, action, scope, sla }`
453///
454/// Deterministic, O(1) motor response. Contract invariants (paper §4.2):
455/// never invokes an LLM; no long-running I/O; every activation emits a
456/// signed_trace; idempotent on the same HealthReport.
457#[derive(Debug, Default)]
458pub struct ReflexDefinition {
459    pub name: String,
460    pub trigger: String,  // immune name (MANDATORY)
461    pub on_level: String, // know | believe | speculate | doubt (default: doubt)
462    pub action: String,   // drop | revoke | emit | redact | quarantine | terminate | alert
463    pub scope: String,    // MANDATORY, paper §8.2
464    pub sla: String,      // duration budget (e.g. "1ms")
465    pub loc: Loc,
466    /// Fase 14.b — leading comment trivia attached to this declaration
467    /// (comments preceding the declaration's first token, since the
468    /// previous declaration or file start). Empty by default.
469    pub leading_trivia: Vec<crate::tokens::Trivia>,
470    /// Fase 14.b — trailing comment trivia (same line as the
471    /// declaration's last effective token). Empty by default.
472    pub trailing_trivia: Vec<crate::tokens::Trivia>,
473}
474
475/// `heal Name { source, on_level, mode, scope, review_sla, shield, max_patches }`
476///
477/// Linear-Logic one-shot patch synthesis. Patch type:
478/// `!Synthesized ⊸ Applied ⊸ Collapsed` (paper §6) — each transition
479/// consumes its predecessor, guaranteeing single application + forced collapse.
480///
481/// Mode ∈ {audit_only | human_in_loop | adversarial} controls automation
482/// (paper §7); `adversarial` REQUIRES a shield gate (paper §7.3).
483#[derive(Debug, Default)]
484pub struct HealDefinition {
485    pub name: String,
486    pub source: String,     // immune name (MANDATORY)
487    pub on_level: String,   // know | believe | speculate | doubt
488    pub mode: String,       // audit_only | human_in_loop | adversarial
489    pub scope: String,      // MANDATORY
490    pub review_sla: String, // duration
491    pub shield_ref: String, // optional shield gate (required for adversarial)
492    pub max_patches: i64,   // bounded heal attempts (default: 3)
493    pub loc: Loc,
494    /// Fase 14.b — leading comment trivia attached to this declaration
495    /// (comments preceding the declaration's first token, since the
496    /// previous declaration or file start). Empty by default.
497    pub leading_trivia: Vec<crate::tokens::Trivia>,
498    /// Fase 14.b — trailing comment trivia (same line as the
499    /// declaration's last effective token). Empty by default.
500    pub trailing_trivia: Vec<crate::tokens::Trivia>,
501}
502
503// ── §λ-L-E Fase 9 — UI cognitiva (component / view) ─────────────────────────
504
505/// `component Name { renders, via_shield, on_interact, render_hint }`.
506///
507/// A reusable UI fragment. `renders` is the data type the component
508/// visualizes; if that type has κ, `via_shield` is mandatory and its
509/// compliance set MUST cover the type's κ (compile-time enforcement).
510#[derive(Debug, Default)]
511pub struct ComponentDefinition {
512    pub name: String,
513    pub renders: String,
514    pub via_shield: String,
515    pub on_interact: String,
516    pub render_hint: String, // card | list | form | chart | custom
517    pub loc: Loc,
518    /// Fase 14.b — leading comment trivia attached to this declaration
519    /// (comments preceding the declaration's first token, since the
520    /// previous declaration or file start). Empty by default.
521    pub leading_trivia: Vec<crate::tokens::Trivia>,
522    /// Fase 14.b — trailing comment trivia (same line as the
523    /// declaration's last effective token). Empty by default.
524    pub trailing_trivia: Vec<crate::tokens::Trivia>,
525}
526
527/// `view Name { title, components: [...], route }`.
528///
529/// A top-level screen. `components` is an ordered list of declared
530/// `component` names composed in the view's primary layout.
531#[derive(Debug, Default)]
532pub struct ViewDefinition {
533    pub name: String,
534    pub title: String,
535    pub components: Vec<String>,
536    pub route: String,
537    pub loc: Loc,
538    /// Fase 14.b — leading comment trivia attached to this declaration
539    /// (comments preceding the declaration's first token, since the
540    /// previous declaration or file start). Empty by default.
541    pub leading_trivia: Vec<crate::tokens::Trivia>,
542    /// Fase 14.b — trailing comment trivia (same line as the
543    /// declaration's last effective token). Empty by default.
544    pub trailing_trivia: Vec<crate::tokens::Trivia>,
545}
546
547// ── Tier 2+ structural fallback ──────────────────────────────────────────────
548
549/// A declaration we recognize by keyword but parse only structurally.
550/// Validates brace balance and captures keyword + name.
551#[derive(Debug)]
552pub struct GenericDeclaration {
553    pub keyword: String,
554    pub name: String,
555    pub loc: Loc,
556    /// Fase 14.b — leading comment trivia attached to this declaration
557    /// (comments preceding the declaration's first token, since the
558    /// previous declaration or file start). Empty by default.
559    pub leading_trivia: Vec<crate::tokens::Trivia>,
560    /// Fase 14.b — trailing comment trivia (same line as the
561    /// declaration's last effective token). Empty by default.
562    pub trailing_trivia: Vec<crate::tokens::Trivia>,
563}
564
565// ── Agent ────────────────────────────────────────────────────────────────────
566
567#[derive(Debug)]
568pub struct AgentDefinition {
569    pub name: String,
570    pub goal: String,
571    pub tools: Vec<String>,
572    pub memory_ref: String,
573    pub strategy: String, // react | reflexion | plan_and_execute | custom
574    pub on_stuck: String, // forge | hibernate | escalate | retry
575    pub shield_ref: String,
576    pub max_iterations: Option<i64>,
577    pub max_tokens: Option<i64>,
578    pub max_time: String,
579    pub max_cost: Option<f64>,
580    pub loc: Loc,
581    /// Fase 14.b — leading comment trivia attached to this declaration
582    /// (comments preceding the declaration's first token, since the
583    /// previous declaration or file start). Empty by default.
584    pub leading_trivia: Vec<crate::tokens::Trivia>,
585    /// Fase 14.b — trailing comment trivia (same line as the
586    /// declaration's last effective token). Empty by default.
587    pub trailing_trivia: Vec<crate::tokens::Trivia>,
588}
589
590// ── §Fase 53 — Closed-catalog extension mechanism ────────────────────────────
591
592/// One member of an `extension` declaration. For `category: effects`
593/// the `name` is a provenance base (e.g. `"epistemic:believe"`) with
594/// optional `semantics` + `default_confidence` (a CEILING, never a
595/// floor — §53.d tainted-overriding). For `category: scan` the `name`
596/// is a scan-category identifier and the metadata is typically absent.
597#[derive(Debug, Clone)]
598pub struct ExtensionMember {
599    pub name: String,
600    pub semantics: Option<String>,
601    pub default_confidence: Option<f64>,
602    pub loc: Loc,
603}
604
605/// `extension Name { category: effects|scan, members: [ "x" : { … }, … ] }`
606///
607/// §Fase 53. A first-class, auditable + gateable declaration that
608/// expands a closed catalog with adopter-specific PROVENANCE members.
609/// Soundness invariants (validated in §53.c/§53.d): members are
610/// provenance-class only (never the enforceable effect set), must not
611/// shadow a canonical base/category, and ride in the IR + proof bundle
612/// so an independent PCC verifier re-derives against the same artifact.
613#[derive(Debug)]
614pub struct ExtensionDefinition {
615    pub name: String,
616    /// `effects` | `scan` — validated against the closed category set
617    /// in §53.c (the type-checker), not the parser.
618    pub category: String,
619    pub members: Vec<ExtensionMember>,
620    pub loc: Loc,
621    /// Fase 14.b — leading comment trivia. Empty by default.
622    pub leading_trivia: Vec<crate::tokens::Trivia>,
623    /// Fase 14.b — trailing comment trivia. Empty by default.
624    pub trailing_trivia: Vec<crate::tokens::Trivia>,
625}
626
627// ── Shield ───────────────────────────────────────────────────────────────────
628
629#[derive(Debug)]
630pub struct ShieldDefinition {
631    pub name: String,
632    pub scan: Vec<String>,
633    pub strategy: String, // pattern | classifier | dual_llm | canary | perplexity | ensemble
634    pub on_breach: String, // halt | sanitize_and_retry | escalate | quarantine | deflect
635    pub severity: String, // low | medium | high | critical
636    pub quarantine: String,
637    pub max_retries: Option<i64>,
638    pub confidence_threshold: Option<f64>,
639    pub allow_tools: Vec<String>,
640    pub deny_tools: Vec<String>,
641    pub sandbox: Option<bool>,
642    pub redact: Vec<String>,
643    pub log: String,
644    pub deflect_message: String,
645    pub taint: String,
646    /// §ESK Fase 6.1 — regulatory coverage (HIPAA, PCI_DSS, GDPR, …).
647    pub compliance: Vec<String>,
648    pub loc: Loc,
649    /// Fase 14.b — leading comment trivia attached to this declaration
650    /// (comments preceding the declaration's first token, since the
651    /// previous declaration or file start). Empty by default.
652    pub leading_trivia: Vec<crate::tokens::Trivia>,
653    /// Fase 14.b — trailing comment trivia (same line as the
654    /// declaration's last effective token). Empty by default.
655    pub trailing_trivia: Vec<crate::tokens::Trivia>,
656}
657
658// ── Pix ──────────────────────────────────────────────────────────────────────
659
660#[derive(Debug)]
661pub struct PixDefinition {
662    pub name: String,
663    pub source: String,
664    pub depth: Option<i64>,
665    pub branching: Option<i64>,
666    pub model: String,
667    pub loc: Loc,
668    /// Fase 14.b — leading comment trivia attached to this declaration
669    /// (comments preceding the declaration's first token, since the
670    /// previous declaration or file start). Empty by default.
671    pub leading_trivia: Vec<crate::tokens::Trivia>,
672    /// Fase 14.b — trailing comment trivia (same line as the
673    /// declaration's last effective token). Empty by default.
674    pub trailing_trivia: Vec<crate::tokens::Trivia>,
675}
676
677// ── Ledger ─────────────────────────────────────────────────────────────────
678// §Fase 62.0 — the append-only, hash-linked audit chain. Took over the
679// Provenance-Index role that `pix` historically (and only in the ℰMCP doc)
680// occupied, so `pix` is freed for its true meaning: the PIX retrieval
681// navigator (paper `paper_pix_formal_research.md`). A `ledger` binds a chain
682// recorder to an audited surface (`axonstore://X`, `flow://X`, …); `depth`
683// is chain retention, `branching` the Merkle factor, `model` the hash slug.
684
685#[derive(Debug)]
686pub struct LedgerDefinition {
687    pub name: String,
688    pub source: String,
689    pub depth: Option<i64>,
690    pub branching: Option<i64>,
691    pub model: String,
692    pub loc: Loc,
693    pub leading_trivia: Vec<crate::tokens::Trivia>,
694    pub trailing_trivia: Vec<crate::tokens::Trivia>,
695}
696
697// ── Psyche ───────────────────────────────────────────────────────────────────
698
699#[derive(Debug)]
700pub struct PsycheDefinition {
701    pub name: String,
702    pub dimensions: Vec<String>,
703    pub manifold_noise: Option<f64>,
704    pub manifold_momentum: Option<f64>,
705    pub safety_constraints: Vec<String>,
706    pub quantum_enabled: Option<bool>,
707    pub inference_mode: String, // active | passive
708    pub loc: Loc,
709    /// Fase 14.b — leading comment trivia attached to this declaration
710    /// (comments preceding the declaration's first token, since the
711    /// previous declaration or file start). Empty by default.
712    pub leading_trivia: Vec<crate::tokens::Trivia>,
713    /// Fase 14.b — trailing comment trivia (same line as the
714    /// declaration's last effective token). Empty by default.
715    pub trailing_trivia: Vec<crate::tokens::Trivia>,
716}
717
718// ── Corpus ───────────────────────────────────────────────────────────────────
719
720/// §Fase 63.A — a typed, weighted edge of an MDN corpus graph: `etype(from, to,
721/// weight)`. `etype` is from the closed relation catalog (cite / elaborate /
722/// corroborate / depend / implement / exemplify / contradict / supersede);
723/// `from`/`to` name documents declared in the corpus; `weight ∈ (0, 1]`.
724#[derive(Debug, Clone)]
725pub struct CorpusRelation {
726    pub etype: String,
727    pub from: String,
728    pub to: String,
729    pub weight: f64,
730    pub loc: Loc,
731}
732
733#[derive(Debug)]
734pub struct CorpusDefinition {
735    pub name: String,
736    pub documents: Vec<String>, // simplified: list of pix refs
737    /// §Fase 63.A — the typed weighted edges that make this corpus an MDN graph
738    /// `C = (D, R, τ, ω, σ)`. Empty ⇒ the flat (edgeless) corpus.
739    pub relations: Vec<CorpusRelation>,
740    /// §Fase 63.C — `adaptive: true` enables the memory endofunctor: navigations
741    /// over this corpus learn (semantic edge reinforcement + procedural bias),
742    /// and subsequent navigations use the memory-modified EPR. Requires the
743    /// graph to carry edges (static `relations:` OR a store-sourced edge store).
744    pub adaptive: bool,
745    pub mcp_server: String,
746    pub mcp_resource_uri: String,
747    /// §Fase 64.A — when `Some`, this is a DYNAMIC store-sourced MDN graph
748    /// (`corpus N from axonstore { documents: DocStore(id, title)  relations:
749    /// EdgeStore(from, to, etype, weight) }`): the documents and typed edges live
750    /// as ROWS in two declared `axonstore`s and the graph is built from the live
751    /// rows at navigate-time (per-tenant, growing). Mutually exclusive with the
752    /// static §63 form — the `documents`/`relations`/`mcp_*` fields stay empty.
753    /// `None` ⇒ the static compile-time corpus (back-compat byte-identical).
754    pub store_source: Option<CorpusStoreSource>,
755    pub loc: Loc,
756    /// Fase 14.b — leading comment trivia attached to this declaration
757    /// (comments preceding the declaration's first token, since the
758    /// previous declaration or file start). Empty by default.
759    pub leading_trivia: Vec<crate::tokens::Trivia>,
760    /// Fase 14.b — trailing comment trivia (same line as the
761    /// declaration's last effective token). Empty by default.
762    pub trailing_trivia: Vec<crate::tokens::Trivia>,
763}
764
765/// §Fase 64.A — the dynamic, `axonstore`-sourced backing of an MDN corpus graph.
766/// The graph's documents and typed edges are ROWS in two declared `axonstore`s,
767/// so the graph grows at runtime (a new `persist` = a new node/edge) and is
768/// per-tenant by inheritance from the store's §40 column-proof / RLS scope. The
769/// runtime builds the `mdn::Corpus` from the live rows at navigate-time.
770///
771/// Surface:
772/// ```text
773/// corpus LtmGraph from axonstore {
774///     documents: LtmSummaries( id, summary )                 // (id-col, title-col)
775///     relations: LtmEdges( from_id, to_id, etype, weight )   // (from, to, etype, weight)
776///     adaptive: true
777/// }
778/// ```
779/// Documents and edges live in SEPARATE stores (an `axonstore` is one table with
780/// one column schema). The type-checker (`check_corpus`) validates that both
781/// stores are declared and — when they carry a §38 column schema — that the
782/// mapped columns exist with compatible types (id present; title text-like;
783/// from/to match the id type; etype text-like; weight numeric). The weight-range
784/// invariant `ω ∈ (0, 1]` (G4) becomes a RUNTIME check here, since weights are
785/// per-row dynamic (clamp on read + store CHECK), not a compile-time literal.
786#[derive(Debug, Clone)]
787pub struct CorpusStoreSource {
788    pub doc_store: String,
789    pub doc_id_col: String,
790    pub doc_title_col: String,
791    pub edge_store: String,
792    pub edge_from_col: String,
793    pub edge_to_col: String,
794    pub edge_type_col: String,
795    pub edge_weight_col: String,
796    pub loc: Loc,
797}
798
799// ── Dataspace ────────────────────────────────────────────────────────────────
800
801#[derive(Debug)]
802pub struct DataspaceDefinition {
803    pub name: String,
804    pub loc: Loc,
805    /// Fase 14.b — leading comment trivia attached to this declaration
806    /// (comments preceding the declaration's first token, since the
807    /// previous declaration or file start). Empty by default.
808    pub leading_trivia: Vec<crate::tokens::Trivia>,
809    /// Fase 14.b — trailing comment trivia (same line as the
810    /// declaration's last effective token). Empty by default.
811    pub trailing_trivia: Vec<crate::tokens::Trivia>,
812}
813
814// ── OTS ──────────────────────────────────────────────────────────────────────
815
816#[derive(Debug)]
817pub struct OtsDefinition {
818    pub name: String,
819    pub teleology: String,
820    pub homotopy_search: String, // shallow | deep | speculative
821    pub loss_function: String,
822    pub loc: Loc,
823    /// Fase 14.b — leading comment trivia attached to this declaration
824    /// (comments preceding the declaration's first token, since the
825    /// previous declaration or file start). Empty by default.
826    pub leading_trivia: Vec<crate::tokens::Trivia>,
827    /// Fase 14.b — trailing comment trivia (same line as the
828    /// declaration's last effective token). Empty by default.
829    pub trailing_trivia: Vec<crate::tokens::Trivia>,
830}
831
832// ── Mandate ──────────────────────────────────────────────────────────────────
833
834#[derive(Debug)]
835pub struct MandateDefinition {
836    pub name: String,
837    pub constraint: String,
838    pub kp: Option<f64>,
839    pub ki: Option<f64>,
840    pub kd: Option<f64>,
841    pub tolerance: Option<f64>,
842    pub max_steps: Option<i64>,
843    pub on_violation: String, // coerce | halt | retry
844    pub loc: Loc,
845    /// Fase 14.b — leading comment trivia attached to this declaration
846    /// (comments preceding the declaration's first token, since the
847    /// previous declaration or file start). Empty by default.
848    pub leading_trivia: Vec<crate::tokens::Trivia>,
849    /// Fase 14.b — trailing comment trivia (same line as the
850    /// declaration's last effective token). Empty by default.
851    pub trailing_trivia: Vec<crate::tokens::Trivia>,
852}
853
854// ── Compute ──────────────────────────────────────────────────────────────────
855
856#[derive(Debug)]
857pub struct ComputeDefinition {
858    pub name: String,
859    pub shield_ref: String,
860    pub loc: Loc,
861    /// Fase 14.b — leading comment trivia attached to this declaration
862    /// (comments preceding the declaration's first token, since the
863    /// previous declaration or file start). Empty by default.
864    pub leading_trivia: Vec<crate::tokens::Trivia>,
865    /// Fase 14.b — trailing comment trivia (same line as the
866    /// declaration's last effective token). Empty by default.
867    pub trailing_trivia: Vec<crate::tokens::Trivia>,
868}
869
870// ── Daemon ───────────────────────────────────────────────────────────────────
871
872#[derive(Debug)]
873pub struct DaemonDefinition {
874    pub name: String,
875    pub goal: String,
876    pub tools: Vec<String>,
877    pub memory_ref: String,
878    pub strategy: String, // react | reflexion | plan_and_execute | custom
879    pub on_stuck: String, // hibernate | escalate | retry | forge
880    pub shield_ref: String,
881    pub max_tokens: Option<i64>,
882    pub max_time: String,
883    pub max_cost: Option<f64>,
884    /// §λ-L-E Fase 13 D4 — listen blocks captured for type-checker
885    /// validation (typed-channel ref + dual-mode deprecation warning).
886    /// Pre-Fase 13 the parser discarded these structurally; we now
887    /// retain them so 13.b/13.f can validate emit/publish/discover
888    /// inside listener bodies and surface D4 string-topic warnings.
889    pub listeners: Vec<ListenStep>,
890    /// §Fase 52.d — the capability scope a daemon's runs are confined to
891    /// (`requires: [cap, …]`, the same closed slug grammar as `axonendpoint
892    /// requires:`). A scheduled (cron) daemon MUST declare this (it is a
893    /// standing autonomous privilege); the enterprise supervisor mints a
894    /// per-run principal scoped to EXACTLY these capabilities (least privilege,
895    /// §52.d). Empty for event-only daemons / pre-§52 daemons.
896    pub requires_capabilities: Vec<String>,
897    pub loc: Loc,
898    /// Fase 14.b — leading comment trivia attached to this declaration
899    /// (comments preceding the declaration's first token, since the
900    /// previous declaration or file start). Empty by default.
901    pub leading_trivia: Vec<crate::tokens::Trivia>,
902    /// Fase 14.b — trailing comment trivia (same line as the
903    /// declaration's last effective token). Empty by default.
904    pub trailing_trivia: Vec<crate::tokens::Trivia>,
905}
906
907// ── AxonStore ────────────────────────────────────────────────────────────────
908
909#[derive(Debug)]
910pub struct AxonStoreDefinition {
911    pub name: String,
912    pub backend: String, // sqlite | postgresql | mysql
913    pub connection: String,
914    pub confidence_floor: Option<f64>,
915    pub isolation: String, // read_committed | repeatable_read | serializable
916    pub on_breach: String, // rollback | raise | log
917    /// §Fase 35.j (D11) — Pillar IV: the capability slug required to
918    /// access this store. Empty = no capability gate. Validated at
919    /// parse time against the closed slug grammar (shared with the
920    /// Fase 32.g `requires:` grammar).
921    pub capability: String,
922    /// §Fase 38.b (D1) — the OPTIONAL column-schema declaration. Three
923    /// closed forms (inline / manifest-ref / env-var); `None` means the
924    /// 37.x runtime+deploy path applies verbatim (D5 absolute). The
925    /// §38.d / §38.e `StoreColumnProof` pass consumes this; the §38.h
926    /// CLI exports it.
927    pub column_schema: Option<crate::store_schema::StoreColumnSchema>,
928    pub loc: Loc,
929    /// Fase 14.b — leading comment trivia attached to this declaration
930    /// (comments preceding the declaration's first token, since the
931    /// previous declaration or file start). Empty by default.
932    pub leading_trivia: Vec<crate::tokens::Trivia>,
933    /// Fase 14.b — trailing comment trivia (same line as the
934    /// declaration's last effective token). Empty by default.
935    pub trailing_trivia: Vec<crate::tokens::Trivia>,
936}
937
938// ── AxonEndpoint ─────────────────────────────────────────────────────────────
939
940#[derive(Debug)]
941pub struct AxonEndpointDefinition {
942    pub name: String,
943    pub method: String, // GET | POST | PUT | DELETE
944    pub path: String,
945    pub body_type: String,
946    pub execute_flow: String,
947    pub output_type: String,
948    pub shield_ref: String,
949    pub retries: Option<i64>,
950    pub timeout: String,
951    /// §ESK Fase 6.1 — regulatory coverage on the boundary.
952    pub compliance: Vec<String>,
953    /// §Fase 30 — HTTP wire transport for the response. Closed enum
954    /// per D2 ratified 2026-05-10: {"json" | "sse" | "ndjson"}.
955    /// Default "json" (D1 — backwards-compat preserved). When set
956    /// to "sse", the type-checker (30.c) verifies that
957    /// `execute_flow` produces a Stream<T> (D3).
958    pub transport: String,
959    /// §Fase 30 — Keepalive comment interval for SSE transport (D6).
960    /// Optional; default applied at runtime when transport == "sse"
961    /// (default 15s). Closed enum at parse time:
962    /// {"5s" | "15s" | "30s" | "60s"}. Empty string means
963    /// "use runtime default".
964    pub keepalive: String,
965    /// §Fase 31.b — Type-Driven Wire Inference (D1, D7).
966    /// `transport_explicit` is `true` if the source declared
967    /// `transport:` explicitly (any of json/sse/ndjson). `false` if
968    /// the field was omitted, in which case `transport` reflects the
969    /// D1 default `"json"` but `implicit_transport` (computed by the
970    /// `axon_frontend::type_checker::compute_implicit_transports`
971    /// pass) carries the inferred value.
972    pub transport_explicit: bool,
973    /// §Fase 31.b — Inferred wire transport per D1:
974    ///   implicit_transport(E) =
975    ///     declared_transport(E)   if transport_explicit
976    ///     "sse"                    if produces_stream(execute_flow) ∧ ¬explicit
977    ///     "json"                   otherwise
978    /// Empty string `""` before the type-checker runs. The Python
979    /// reference implementation in `axon/compiler/type_checker.py`
980    /// sets the field byte-identically (D7 cross-stack contract).
981    pub implicit_transport: String,
982    /// §Fase 32.g (D8) — Auth scope: capability slugs the request
983    /// bearer must hold for the endpoint to dispatch. Empty vec
984    /// means "no auth gate" (D9 backwards-compat). Slug grammar
985    /// (closed): `^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$`. Examples:
986    /// `admin`, `legal.read`, `hipaa.phi.read`. The runtime checks
987    /// declared_requires ⊆ token_capabilities (AND semantics — every
988    /// declared capability must be present in the bearer's claims).
989    pub requires_capabilities: Vec<String>,
990    /// §Fase 32.h — Replay-token binding (D9 plan-vivo).
991    /// `replay_explicit` is `true` when the source declared `replay:`
992    /// explicitly. `false` when the field was omitted, in which case
993    /// `replay` reflects the method-default (POST/PUT → true, GET/
994    /// DELETE → false) computed at deploy time. When the effective
995    /// value resolves to `true`, every successful 2xx response is
996    /// recorded in the runtime's axonendpoint replay log keyed by
997    /// trace_id; auditors retrieve it via GET /v1/replay/<trace_id>.
998    pub replay_explicit: bool,
999    pub replay: bool,
1000    /// §Fase 33.z.k.b (v1.28.0) — Selected SSE wire-format dialect.
1001    ///
1002    /// Populated when the source uses the parametrized grammar
1003    /// `transport: sse(<dialect>)`. Closed catalog
1004    /// (`AXONENDPOINT_TRANSPORT_DIALECTS`): `{axon, openai, anthropic}`.
1005    /// Empty string `""` when:
1006    ///   - the source declared a non-SSE transport (`json`/`ndjson`), OR
1007    ///   - the source declared bare `transport: sse` without parens, OR
1008    ///   - the source omitted `transport:` entirely (D1 implicit path).
1009    ///
1010    /// When empty + the effective wire is SSE (per the runtime
1011    /// classifier `classify_dynamic_route_wire`), the runtime
1012    /// resolves the dialect via the Q1 algebraic-effect-driven
1013    /// default: openai for tool-streaming flows (algebraic predicate
1014    /// true), axon for type-annotation-only flows (algebraic predicate
1015    /// false). D3 explicit `transport: sse(<dialect>)` overrides the
1016    /// default.
1017    pub transport_dialect: String,
1018    /// §Fase 33.z.k.1 (v1.27.1) — Algebraic-effect override predicate.
1019    ///
1020    /// `true` when `execute_flow` references a tool that declares
1021    /// `effects: <stream:<policy>>` (Fase 30 algebraic-effect surface).
1022    /// Mirrors `type_checker::flow_uses_streaming_tool(execute_flow, program)`.
1023    ///
1024    /// Used by the runtime classifier
1025    /// (`axon_server::classify_dynamic_route_wire`) to OVERRIDE the
1026    /// v1.22.0 D6 backwards-compat gate: a tool with a declared stream
1027    /// effect is a LANGUAGE-LEVEL commitment to streaming, not a
1028    /// client preference. When this field is `true` AND
1029    /// `transport: json` is NOT explicitly declared (D3 opt-out remains
1030    /// sacred), the route wire is unconditionally `Sse` — no
1031    /// `Accept: text/event-stream` header required, no
1032    /// `AXON_STRICT_TYPE_DRIVEN_TRANSPORT=1` runtime flag required.
1033    ///
1034    /// Computed in lockstep with `implicit_transport` by the
1035    /// `compute_implicit_transports` pass. Default `false` before the
1036    /// pass runs (matches AST construction defaults; D9 backwards-
1037    /// compat preserved for older AST consumers).
1038    pub has_algebraic_stream_effect: bool,
1039    /// §Fase 36.d (D2) — the declared execution backend for the flow
1040    /// behind this endpoint. Empty string `""` means "not declared"
1041    /// (the endpoint resolves its backend down the Fase 36 D1
1042    /// precedence ladder — server default → environment-available
1043    /// `auto`). When non-empty the parser has validated it against the
1044    /// closed catalog [`crate::parser::AXONENDPOINT_BACKEND_VALUES`]
1045    /// and the type-checker rejects an unknown name as a compile
1046    /// error. A declared `backend:` is rung 2 of the resolution
1047    /// contract.
1048    pub backend: String,
1049    /// §Fase 37.y (D1) — Path parameter names extracted from the
1050    /// `path:` string at parse time. For `path: "/api/tenants/{tenant_id}/secrets/{secret_name}"`
1051    /// this is `["tenant_id", "secret_name"]`. Empty Vec when the
1052    /// path has no `{name}` placeholders (D5 backwards-compat — an
1053    /// endpoint without path params produces byte-identical IR to
1054    /// v1.38.4).
1055    ///
1056    /// Names are deduplicated + recorded in declaration order. A
1057    /// duplicate `{tenant_id}` in the same path is a parse error
1058    /// (HTTP route patterns reject duplicates structurally — `axum`
1059    /// would panic at registration). Type binding is always `Text`
1060    /// in v1.38.5 (HTTP path-segment convention); a future Fase 37.z
1061    /// may add per-placeholder type-override grammar `{tenant_id: Uuid}`.
1062    ///
1063    /// The Fase 37 D2 totality check (extended by 37.y D3) treats
1064    /// every name here as covering an equivalent flow parameter
1065    /// declared `Text`. Collision with a body field of the same name
1066    /// is a compile error (`axon-T901`, D4).
1067    pub path_params: Vec<String>,
1068    /// §Fase 37.y (D2) — Query parameters declared via the inline
1069    /// `query: { name: Type, name: Type? }` block on the endpoint.
1070    /// Empty Vec when the source omits the block (D5 backwards-compat).
1071    ///
1072    /// Closed type catalog (parser-enforced):
1073    /// `{Text, Int, Float, Bool, Uuid}`. The runtime receives every
1074    /// query value as a textual `String` and binds it to the same-named
1075    /// flow parameter; the closed catalog enables future per-type
1076    /// parsing/validation without breaking the manifest format.
1077    ///
1078    /// The optional flag (`?` suffix in the source) reuses
1079    /// `TypeExpr.optional`. An optional query param need not be
1080    /// covered by a flow parameter (D3 totality is over required
1081    /// params); a required query param missing from the flow signature
1082    /// is a `axon-T?nn` future arm. For v1.38.5 the totality check
1083    /// treats every query param as a binding-source candidate for any
1084    /// same-named flow param.
1085    ///
1086    /// Reusing `TypeField` (shared with body type declarations) keeps
1087    /// the D2 totality check uniform — the same `field.type_expr.name
1088    /// == param.type_expr.name` comparator works for body fields AND
1089    /// query params.
1090    pub query_params: Vec<TypeField>,
1091    pub loc: Loc,
1092    /// Fase 14.b — leading comment trivia attached to this declaration
1093    /// (comments preceding the declaration's first token, since the
1094    /// previous declaration or file start). Empty by default.
1095    pub leading_trivia: Vec<crate::tokens::Trivia>,
1096    /// Fase 14.b — trailing comment trivia (same line as the
1097    /// declaration's last effective token). Empty by default.
1098    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1099}
1100
1101// ── Import ───────────────────────────────────────────────────────────────────
1102
1103#[derive(Debug)]
1104pub struct ImportNode {
1105    pub module_path: Vec<String>,
1106    pub names: Vec<String>,
1107    pub loc: Loc,
1108    /// Fase 14.b — leading comment trivia attached to this declaration
1109    /// (comments preceding the declaration's first token, since the
1110    /// previous declaration or file start). Empty by default.
1111    pub leading_trivia: Vec<crate::tokens::Trivia>,
1112    /// Fase 14.b — trailing comment trivia (same line as the
1113    /// declaration's last effective token). Empty by default.
1114    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1115}
1116
1117// ── Persona ──────────────────────────────────────────────────────────────────
1118
1119#[derive(Debug)]
1120pub struct PersonaDefinition {
1121    pub name: String,
1122    pub domain: Vec<String>,
1123    pub tone: String,
1124    pub confidence_threshold: Option<f64>,
1125    pub cite_sources: Option<bool>,
1126    pub refuse_if: Vec<String>,
1127    pub language: String,
1128    pub description: String,
1129    pub loc: Loc,
1130    /// Fase 14.b — leading comment trivia attached to this declaration
1131    /// (comments preceding the declaration's first token, since the
1132    /// previous declaration or file start). Empty by default.
1133    pub leading_trivia: Vec<crate::tokens::Trivia>,
1134    /// Fase 14.b — trailing comment trivia (same line as the
1135    /// declaration's last effective token). Empty by default.
1136    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1137}
1138
1139// ── Context ──────────────────────────────────────────────────────────────────
1140
1141#[derive(Debug)]
1142pub struct ContextDefinition {
1143    pub name: String,
1144    pub memory_scope: String,
1145    pub language: String,
1146    pub depth: String,
1147    pub max_tokens: Option<i64>,
1148    pub temperature: Option<f64>,
1149    pub cite_sources: Option<bool>,
1150    pub loc: Loc,
1151    /// Fase 14.b — leading comment trivia attached to this declaration
1152    /// (comments preceding the declaration's first token, since the
1153    /// previous declaration or file start). Empty by default.
1154    pub leading_trivia: Vec<crate::tokens::Trivia>,
1155    /// Fase 14.b — trailing comment trivia (same line as the
1156    /// declaration's last effective token). Empty by default.
1157    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1158}
1159
1160// ── Anchor ───────────────────────────────────────────────────────────────────
1161
1162#[derive(Debug)]
1163pub struct AnchorConstraint {
1164    pub name: String,
1165    pub require: String,
1166    pub reject: Vec<String>,
1167    pub enforce: String,
1168    pub description: String,
1169    pub confidence_floor: Option<f64>,
1170    pub unknown_response: String,
1171    pub on_violation: String,
1172    pub on_violation_target: String,
1173    pub loc: Loc,
1174    /// Fase 14.b — leading comment trivia attached to this declaration
1175    /// (comments preceding the declaration's first token, since the
1176    /// previous declaration or file start). Empty by default.
1177    pub leading_trivia: Vec<crate::tokens::Trivia>,
1178    /// Fase 14.b — trailing comment trivia (same line as the
1179    /// declaration's last effective token). Empty by default.
1180    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1181}
1182
1183// ── Memory ───────────────────────────────────────────────────────────────────
1184
1185#[derive(Debug)]
1186pub struct MemoryDefinition {
1187    pub name: String,
1188    pub store: String,
1189    pub backend: String,
1190    pub retrieval: String,
1191    pub decay: String,
1192    pub loc: Loc,
1193    /// Fase 14.b — leading comment trivia attached to this declaration
1194    /// (comments preceding the declaration's first token, since the
1195    /// previous declaration or file start). Empty by default.
1196    pub leading_trivia: Vec<crate::tokens::Trivia>,
1197    /// Fase 14.b — trailing comment trivia (same line as the
1198    /// declaration's last effective token). Empty by default.
1199    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1200}
1201
1202// ── Tool ─────────────────────────────────────────────────────────────────────
1203
1204#[derive(Debug)]
1205pub struct ToolDefinition {
1206    pub name: String,
1207    pub provider: String,
1208    pub max_results: Option<i64>,
1209    pub filter_expr: String,
1210    pub timeout: String,
1211    pub runtime: String,
1212    pub sandbox: Option<bool>,
1213    pub effects: Option<EffectRow>,
1214    /// §Fase 58.a — the tool's typed INPUT SCHEMA (W2: the caller↔tool
1215    /// contract). Each entry is a named, typed parameter that the canonical
1216    /// `use Tool(k = v, …)` invocation binds against and the type-checker
1217    /// validates the caller's args against (CT-2 caller blame, pre-HTTP).
1218    /// Empty for a schema-less tool — the legacy single-`on <arg>` form still
1219    /// applies (§58 D5 back-compat). Reuses `Parameter` (same `TypeExpr`
1220    /// grammar as flow params).
1221    pub parameters: Vec<Parameter>,
1222    /// §Fase 58.a — the tool's declared OUTPUT type, so a tool-step's result
1223    /// is referenceable as `${Step.output}` with a real type (§58 D8). Flat
1224    /// string (mirrors step `output:`); `None` when undeclared.
1225    pub output_type: Option<String>,
1226    pub loc: Loc,
1227    /// Fase 14.b — leading comment trivia attached to this declaration
1228    /// (comments preceding the declaration's first token, since the
1229    /// previous declaration or file start). Empty by default.
1230    pub leading_trivia: Vec<crate::tokens::Trivia>,
1231    /// Fase 14.b — trailing comment trivia (same line as the
1232    /// declaration's last effective token). Empty by default.
1233    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1234}
1235
1236#[derive(Debug)]
1237pub struct EffectRow {
1238    pub effects: Vec<String>,
1239    pub epistemic_level: String,
1240    pub loc: Loc,
1241}
1242
1243// ── Type ─────────────────────────────────────────────────────────────────────
1244
1245#[derive(Debug)]
1246pub struct TypeDefinition {
1247    pub name: String,
1248    pub fields: Vec<TypeField>,
1249    pub range_constraint: Option<RangeConstraint>,
1250    pub where_clause: Option<WhereClause>,
1251    /// §ESK Fase 6.1 — κ regulatory class attached to a type.
1252    pub compliance: Vec<String>,
1253    pub loc: Loc,
1254    /// Fase 14.b — leading comment trivia attached to this declaration
1255    /// (comments preceding the declaration's first token, since the
1256    /// previous declaration or file start). Empty by default.
1257    pub leading_trivia: Vec<crate::tokens::Trivia>,
1258    /// Fase 14.b — trailing comment trivia (same line as the
1259    /// declaration's last effective token). Empty by default.
1260    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1261}
1262
1263#[derive(Debug, Clone)]
1264pub struct TypeExpr {
1265    pub name: String,
1266    pub generic_param: String,
1267    pub optional: bool,
1268    pub loc: Loc,
1269}
1270
1271#[derive(Debug)]
1272pub struct TypeField {
1273    pub name: String,
1274    pub type_expr: TypeExpr,
1275    pub loc: Loc,
1276}
1277
1278#[derive(Debug)]
1279pub struct RangeConstraint {
1280    pub min_value: f64,
1281    pub max_value: f64,
1282    pub loc: Loc,
1283}
1284
1285#[derive(Debug)]
1286pub struct WhereClause {
1287    pub expression: String,
1288    pub loc: Loc,
1289}
1290
1291// ── Flow ─────────────────────────────────────────────────────────────────────
1292
1293#[derive(Debug)]
1294pub struct FlowDefinition {
1295    pub name: String,
1296    pub parameters: Vec<Parameter>,
1297    pub return_type: Option<TypeExpr>,
1298    pub body: Vec<FlowStep>,
1299    pub loc: Loc,
1300    /// Fase 14.b — leading comment trivia attached to this declaration
1301    /// (comments preceding the declaration's first token, since the
1302    /// previous declaration or file start). Empty by default.
1303    pub leading_trivia: Vec<crate::tokens::Trivia>,
1304    /// Fase 14.b — trailing comment trivia (same line as the
1305    /// declaration's last effective token). Empty by default.
1306    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1307}
1308
1309#[derive(Debug)]
1310pub struct Parameter {
1311    pub name: String,
1312    pub type_expr: TypeExpr,
1313    pub loc: Loc,
1314}
1315
1316/// Statements that can appear inside a flow body.
1317#[derive(Debug)]
1318pub enum FlowStep {
1319    Step(StepNode),
1320    If(ConditionalNode),
1321    ForIn(ForInStatement),
1322    Let(LetStatement),
1323    Return(ReturnStatement),
1324    /// Fase 19.e — `break` keyword. Payload-free; carries only its
1325    /// source location for error reporting.
1326    Break(BreakStatement),
1327    /// Fase 19.e — `continue` keyword. Payload-free; same shape as
1328    /// `Break`.
1329    Continue(ContinueStatement),
1330    /// Lambda Data application in a flow step.
1331    LambdaDataApply(LambdaDataApplyNode),
1332    // ── Tier 2 flow steps ──
1333    Probe(ProbeStep),
1334    Reason(ReasonStep),
1335    Validate(ValidateStep),
1336    Refine(RefineStep),
1337    Weave(WeaveStep),
1338    UseTool(UseToolStep),
1339    Remember(RememberStep),
1340    Recall(RecallStep),
1341    Par(ParBlock),
1342    Hibernate(HibernateStep),
1343    Deliberate(DeliberateBlock),
1344    Consensus(ConsensusBlock),
1345    Forge(ForgeBlock),
1346    Focus(FocusStep),
1347    Associate(AssociateStep),
1348    Aggregate(AggregateStep),
1349    ExploreStep(ExploreStepNode),
1350    Ingest(IngestStep),
1351    ShieldApply(ShieldApplyStep),
1352    Stream(StreamBlock),
1353    Navigate(NavigateStep),
1354    Drill(DrillStep),
1355    Trail(TrailStep),
1356    Corroborate(CorroborateStep),
1357    OtsApply(OtsApplyStep),
1358    MandateApply(MandateApplyStep),
1359    ComputeApply(ComputeApplyStep),
1360    Listen(ListenStep),
1361    DaemonStep(DaemonStepNode),
1362    /// §λ-L-E Fase 13 — π-calculus output prefix `c⟨v⟩.P` (Chan-Output / Chan-Mobility).
1363    Emit(EmitStatement),
1364    /// §λ-L-E Fase 13 — capability extrusion (Publish-Ext, paper §4.3).
1365    Publish(PublishStatement),
1366    /// §λ-L-E Fase 13 — dual of publish (dynamic typed handle import).
1367    Discover(DiscoverStatement),
1368    Persist(PersistStep),
1369    Retrieve(RetrieveStep),
1370    Mutate(MutateStep),
1371    Purge(PurgeStep),
1372    Transact(TransactBlock),
1373    /// §Fase 51.a — `quant { … }` cognitive block (Hilbert-space projection).
1374    /// Carries an optional attribute header + a real nested body of flow steps
1375    /// (so §51.b's Continuous Type Invariant can scan it). Lives inside a flow
1376    /// body like `par`; NOT a top-level declaration.
1377    Quant(QuantBlock),
1378    /// §Fase 51.d.2 — `yield <expr>` measurement point inside a `quant` block.
1379    /// Collapses the evolved amplitudes back to classical silicon; the effect
1380    /// operation whose resolution is a one-shot delimited continuation. Only
1381    /// well-formed inside a `quant` block (the checker rejects it elsewhere).
1382    Yield(YieldStatement),
1383    /// §Fase 52.c — `run <Flow>(args)` as a flow-step: invoke a declared flow
1384    /// from inside a body (notably a `daemon`'s `listen` handler — the Q3 ask).
1385    /// Reuses the top-level [`RunStatement`] shape (flow name + args + optional
1386    /// persona/context/anchors). Distinct from `Declaration::Run` only by
1387    /// position (a step inside a body vs. a program-root run).
1388    Run(RunStatement),
1389    /// Flow-level statements we recognize but parse structurally.
1390    GenericStep(GenericFlowStep),
1391}
1392
1393/// A flow step we recognize by keyword but parse only structurally.
1394#[derive(Debug)]
1395pub struct GenericFlowStep {
1396    pub keyword: String,
1397    pub loc: Loc,
1398}
1399
1400// ── Step ─────────────────────────────────────────────────────────────────────
1401
1402#[derive(Debug)]
1403pub struct StepNode {
1404    pub name: String,
1405    pub persona_ref: String,
1406    pub given: String,
1407    pub ask: String,
1408    pub output_type: String,
1409    pub confidence_floor: Option<f64>,
1410    pub navigate_ref: String,
1411    pub apply_ref: String,
1412    /// §Fase 68.b — the step's declared MODEL CAPABILITY requirement: the
1413    /// context window (in tokens) the cognitive act needs. The §68.c resolver
1414    /// maps it to the smallest concrete model that satisfies it (per the
1415    /// resolved backend's §68.a catalog); `None` → the backend default
1416    /// (back-compat). Declare the NEED, not the vendor SKU (D68.1).
1417    pub requires_context: Option<u32>,
1418    pub loc: Loc,
1419}
1420
1421// ── Intent ───────────────────────────────────────────────────────────────────
1422
1423#[derive(Debug)]
1424pub struct IntentNode {
1425    pub name: String,
1426    pub given: String,
1427    pub ask: String,
1428    pub output_type: Option<TypeExpr>,
1429    pub confidence_floor: Option<f64>,
1430    pub loc: Loc,
1431    /// Fase 14.b — leading comment trivia attached to this declaration
1432    /// (comments preceding the declaration's first token, since the
1433    /// previous declaration or file start). Empty by default.
1434    pub leading_trivia: Vec<crate::tokens::Trivia>,
1435    /// Fase 14.b — trailing comment trivia (same line as the
1436    /// declaration's last effective token). Empty by default.
1437    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1438}
1439
1440// ── Run ──────────────────────────────────────────────────────────────────────
1441
1442#[derive(Debug)]
1443pub struct RunStatement {
1444    pub flow_name: String,
1445    pub arguments: Vec<String>,
1446    pub persona: String,
1447    pub context: String,
1448    pub anchors: Vec<String>,
1449    pub on_failure: String,
1450    pub on_failure_params: Vec<(String, String)>,
1451    pub output_to: String,
1452    pub effort: String,
1453    pub loc: Loc,
1454    /// Fase 14.b — leading comment trivia attached to this declaration
1455    /// (comments preceding the declaration's first token, since the
1456    /// previous declaration or file start). Empty by default.
1457    pub leading_trivia: Vec<crate::tokens::Trivia>,
1458    /// Fase 14.b — trailing comment trivia (same line as the
1459    /// declaration's last effective token). Empty by default.
1460    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1461}
1462
1463// ── Epistemic ────────────────────────────────────────────────────────────────
1464
1465#[derive(Debug)]
1466pub struct EpistemicBlock {
1467    pub mode: String,
1468    pub body: Vec<Declaration>,
1469    pub loc: Loc,
1470    /// Fase 14.b — leading comment trivia attached to this declaration
1471    /// (comments preceding the declaration's first token, since the
1472    /// previous declaration or file start). Empty by default.
1473    pub leading_trivia: Vec<crate::tokens::Trivia>,
1474    /// Fase 14.b — trailing comment trivia (same line as the
1475    /// declaration's last effective token). Empty by default.
1476    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1477}
1478
1479// ── §Fase 70.a — the pure expression engine (`Expr`) ─────────────────────────
1480
1481/// A pure, total expression in AXON's closed-catalog expression sublanguage
1482/// (§Fase 70). Evaluates to a value with no side effects, no I/O, no recursion
1483/// and no unbounded loops — so it is decidable and const-foldable. Mounted as
1484/// the condition of an `if` (and, in later sub-fases, `let` values + `where:`
1485/// predicates). Field/index access and the builtin catalog land in §70.c/d.
1486#[derive(Debug, Clone)]
1487pub enum Expr {
1488    /// A typed literal (`42`, `3.14`, `true`, `"hello"`).
1489    Lit(ExprLit),
1490    /// A reference to a binding or dotted path (`x`, `User.tier`).
1491    Ref(String),
1492    /// A unary operation (`-x`, `not x`).
1493    Unary(UnOp, Box<Expr>),
1494    /// A binary operation (`a + b`, `a >= b`, `a and b`).
1495    Binary(BinOp, Box<Expr>, Box<Expr>),
1496    /// §Fase 70.c — a closed-catalog builtin call. `args[0]` is the receiver
1497    /// (the value before the `.`); any further entries are the call arguments.
1498    /// E.g. `recent.length` → `Call(Length, [Ref("recent")])`,
1499    /// `name.starts_with("Dr")` → `Call(StartsWith, [Ref("name"), Lit(Str)])`.
1500    Call(Builtin, Vec<Expr>),
1501    /// §Fase 70.d — field access on a non-reference base (`items[0].name`,
1502    /// `(expr).field`). A plain dotted path stays a `Ref` (`a.b.c`) for
1503    /// back-compat; this node is the structured form the JSONB SQL lowering
1504    /// (deferred §73) consumes. The `String` is the field name.
1505    Field(Box<Expr>, String),
1506    /// §Fase 70.d — index access `base[index]` (array element / string char).
1507    Index(Box<Expr>, Box<Expr>),
1508}
1509
1510/// The closed catalog of pure builtins (§Fase 70.c). All are total + pure.
1511/// Collection/string predicates only; the predicate-taking folds (`any`/`all`/
1512/// `none`) need lambdas and are deferred, as are `sum`/`min`/`max` and `in`/`??`.
1513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1514pub enum Builtin {
1515    /// `.length` — collection element count, or character count of a string.
1516    Length,
1517    /// `.count` — alias of `length`.
1518    Count,
1519    /// `.is_empty` — `length == 0`.
1520    IsEmpty,
1521    /// `.is_null` — the value is absent / empty / `null`.
1522    IsNull,
1523    /// `.contains(x)` — array membership, or string substring.
1524    Contains,
1525    /// `.starts_with(s)` — string prefix test.
1526    StartsWith,
1527    /// `.ends_with(s)` — string suffix test.
1528    EndsWith,
1529}
1530
1531impl Builtin {
1532    /// The number of arguments AFTER the receiver (`args[0]`).
1533    pub fn extra_arity(self) -> usize {
1534        match self {
1535            Builtin::Length | Builtin::Count | Builtin::IsEmpty | Builtin::IsNull => 0,
1536            Builtin::Contains | Builtin::StartsWith | Builtin::EndsWith => 1,
1537        }
1538    }
1539
1540    /// The surface name (after the `.`).
1541    pub fn surface(self) -> &'static str {
1542        match self {
1543            Builtin::Length => "length",
1544            Builtin::Count => "count",
1545            Builtin::IsEmpty => "is_empty",
1546            Builtin::IsNull => "is_null",
1547            Builtin::Contains => "contains",
1548            Builtin::StartsWith => "starts_with",
1549            Builtin::EndsWith => "ends_with",
1550        }
1551    }
1552
1553    /// Resolve a name (after a `.`) to a builtin, or `None` if it is an ordinary
1554    /// field / path segment.
1555    pub fn from_name(name: &str) -> Option<Builtin> {
1556        Some(match name {
1557            "length" => Builtin::Length,
1558            "count" => Builtin::Count,
1559            "is_empty" => Builtin::IsEmpty,
1560            "is_null" => Builtin::IsNull,
1561            "contains" => Builtin::Contains,
1562            "starts_with" => Builtin::StartsWith,
1563            "ends_with" => Builtin::EndsWith,
1564            _ => return None,
1565        })
1566    }
1567}
1568
1569/// A literal value inside an [`Expr`]. The lexical form is preserved enough to
1570/// round-trip; the runtime evaluator (§70.f) coerces across these per the
1571/// existing string-runtime discipline.
1572#[derive(Debug, Clone)]
1573pub enum ExprLit {
1574    Int(i64),
1575    Float(f64),
1576    Bool(bool),
1577    Str(String),
1578}
1579
1580/// Unary operators (closed catalog).
1581#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1582pub enum UnOp {
1583    /// Arithmetic negation `-`.
1584    Neg,
1585    /// Boolean negation `not`.
1586    Not,
1587}
1588
1589/// Binary operators (closed catalog). Precedence is encoded in the Pratt parser.
1590#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1591pub enum BinOp {
1592    Add,
1593    Sub,
1594    Mul,
1595    Div,
1596    Mod,
1597    Eq,
1598    Ne,
1599    Lt,
1600    Le,
1601    Gt,
1602    Ge,
1603    And,
1604    Or,
1605}
1606
1607// ── Control flow ─────────────────────────────────────────────────────────────
1608
1609#[derive(Debug)]
1610pub struct ConditionalNode {
1611    pub condition: String,
1612    pub comparison_op: String,
1613    pub comparison_value: String,
1614    pub then_body: Vec<FlowStep>,
1615    pub else_body: Vec<FlowStep>,
1616    pub conditions: Vec<(String, String, String)>,
1617    pub conjunctor: String,
1618    /// §Fase 70.a — the parsed expression form of the condition. `None` when
1619    /// the condition fits the legacy `(condition, op, value)` + `or` shape
1620    /// (then the legacy fields drive evaluation, byte-identical to pre-§70);
1621    /// `Some` only for the richer forms the legacy triple cannot express
1622    /// (`and`, `not`, arithmetic, parentheses, nesting), which the runtime
1623    /// evaluates via the pure expression evaluator. Zero IR drift for existing
1624    /// programs.
1625    pub cond: Option<Expr>,
1626    pub loc: Loc,
1627}
1628
1629#[derive(Debug)]
1630pub struct ForInStatement {
1631    pub variable: String,
1632    pub iterable: String,
1633    pub body: Vec<FlowStep>,
1634    pub loc: Loc,
1635}
1636
1637#[derive(Debug)]
1638pub struct LetStatement {
1639    pub identifier: String,
1640    pub value_expr: String,
1641    /// Fase 17.a — preserves the parser's tokenization intent so the
1642    /// runtime dispatcher can distinguish a quoted literal from a
1643    /// dotted-identifier reference. One of "literal", "reference",
1644    /// "expression". Defaults to "literal" so any pre-Fase-17 caller
1645    /// that constructs a LetStatement directly behaves as a literal.
1646    pub value_kind: String,
1647    /// §Fase 51.c.3 — optional type annotation `let x: <TypeExpr> = …`.
1648    /// `None` for the bare `let x = …` form (all pre-51.c.3 lets). Inside a
1649    /// `quant` block the Continuous Type Invariant inspects this to enforce the
1650    /// continuous-carrier discipline (`DensityMatrix[D]` D=2ⁿ; reject discrete
1651    /// conversational types). Carries the typed encoder-boundary contract.
1652    pub type_annotation: Option<TypeExpr>,
1653    /// §Fase 70.f — the parsed expression form of the value, present only when
1654    /// `value_kind == "expression"` (`let total = price * qty + tax`). The
1655    /// runtime evaluates it via the pure expression evaluator instead of the
1656    /// pre-§70 behaviour (which treated an expression as an opaque literal
1657    /// string). `None` for literal / reference / list values (byte-identical to
1658    /// pre-§70.f).
1659    pub value_ast: Option<Expr>,
1660    pub loc: Loc,
1661    /// Fase 14.b — leading comment trivia attached to this declaration
1662    /// (comments preceding the declaration's first token, since the
1663    /// previous declaration or file start). Empty by default.
1664    pub leading_trivia: Vec<crate::tokens::Trivia>,
1665    /// Fase 14.b — trailing comment trivia (same line as the
1666    /// declaration's last effective token). Empty by default.
1667    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1668}
1669
1670#[derive(Debug)]
1671pub struct ReturnStatement {
1672    pub value_expr: String,
1673    pub loc: Loc,
1674}
1675
1676/// §Fase 51.d.2 — `yield <expr>` measurement point inside a `quant` block.
1677#[derive(Debug)]
1678pub struct YieldStatement {
1679    /// The measured expression (the structural hypothesis / density-matrix
1680    /// surrogate collapsed out of the Hilbert-space scope).
1681    pub value_expr: String,
1682    /// Tokenization intent (`literal` / `reference` / `expression`), mirroring
1683    /// `LetStatement.value_kind` so the runtime resolves the yielded value.
1684    pub value_kind: String,
1685    pub loc: Loc,
1686}
1687
1688/// Fase 19.e — `break` keyword inside a for-in body. Carries no
1689/// payload; the runner translates it into a sentinel that
1690/// terminates the loop. Parser scope check (`loop_depth`)
1691/// guarantees this only appears inside a for-in body.
1692#[derive(Debug)]
1693pub struct BreakStatement {
1694    pub loc: Loc,
1695}
1696
1697/// Fase 19.e — `continue` keyword inside a for-in body. Same
1698/// shape as ``BreakStatement``; the runner uses a different
1699/// sentinel type to distinguish loop-exit from iteration-skip.
1700#[derive(Debug)]
1701pub struct ContinueStatement {
1702    pub loc: Loc,
1703}
1704
1705// ── Lambda Data (ΛD) — Epistemic State Vectors ─────────────────────────────
1706
1707/// Top-level ΛD definition: ψ = ⟨T, V, E⟩ where E = ⟨c, τ, ρ, δ⟩.
1708#[derive(Debug)]
1709pub struct LambdaDataDefinition {
1710    pub name: String,
1711    pub ontology: String,             // T ∈ O — ontological type
1712    pub certainty: f64,               // c ∈ [0,1] — epistemic certainty scalar
1713    pub temporal_frame_start: String, // τ_start
1714    pub temporal_frame_end: String,   // τ_end
1715    pub provenance: String,           // ρ ∈ EntityRef — causal origin
1716    pub derivation: String, // δ ∈ Δ — see derivation catalogue (raw, derived, inferred, aggregated, transformed)
1717    pub loc: Loc,
1718    /// Fase 14.b — leading comment trivia attached to this declaration
1719    /// (comments preceding the declaration's first token, since the
1720    /// previous declaration or file start). Empty by default.
1721    pub leading_trivia: Vec<crate::tokens::Trivia>,
1722    /// Fase 14.b — trailing comment trivia (same line as the
1723    /// declaration's last effective token). Empty by default.
1724    pub trailing_trivia: Vec<crate::tokens::Trivia>,
1725}
1726
1727/// In-flow ΛD application: binds epistemic state vector to a data target.
1728#[derive(Debug)]
1729pub struct LambdaDataApplyNode {
1730    pub lambda_data_name: String, // reference to LambdaDataDefinition
1731    pub target: String,           // expression to bind
1732    pub output_type: String,      // result type after epistemic binding
1733    pub loc: Loc,
1734}
1735
1736// ── Tier 2 flow step nodes ──────────────────────────────────────────────────
1737
1738#[derive(Debug)]
1739pub struct ProbeStep {
1740    pub target: String,
1741    pub loc: Loc,
1742}
1743#[derive(Debug)]
1744pub struct ReasonStep {
1745    pub strategy: String,
1746    pub target: String,
1747    pub loc: Loc,
1748}
1749#[derive(Debug)]
1750pub struct ValidateStep {
1751    pub target: String,
1752    pub rule: String,
1753    pub loc: Loc,
1754}
1755#[derive(Debug)]
1756pub struct RefineStep {
1757    pub target: String,
1758    pub strategy: String,
1759    pub loc: Loc,
1760}
1761#[derive(Debug)]
1762pub struct WeaveStep {
1763    pub sources: Vec<String>,
1764    pub target: String,
1765    pub format_type: String,
1766    pub priority: Vec<String>,
1767    pub style: String,
1768    pub loc: Loc,
1769}
1770/// §Fase 58.b — the closed catalog of `use <Tool>` argument forms. The
1771/// invocation surfaces are mutually exclusive, so a sum type models them
1772/// exactly (no ambiguous dual-empty state). NOTE: `apply: Tool given: <struct>`
1773/// (the splat form) is NOT here — it rides `StepNode.apply_ref` and is
1774/// validated against the tool schema in §58.d, not parsed as a `use`.
1775#[derive(Debug, Clone, PartialEq)]
1776pub enum UseArgs {
1777    /// `use Tool on "${arg}"` / `use Tool on query` — the §54.b single
1778    /// positional argument. D5 back-compat: behaves byte-identically to the
1779    /// pre-58 `argument: String` (empty string when no `on` clause).
1780    LegacyPositional(String),
1781    /// `use Tool(query = "${q}", max_results = 5)` — D2 canonical multi-field
1782    /// keyword args. Each entry is `(name, value, value_kind)`: `value` is the
1783    /// expression STRING (the frontend has no structured `Expr`; mirrors
1784    /// `argument` / `parse_argument_list`); `value_kind` is `"literal"` or
1785    /// `"reference"` — the §Fase 60 classification from `parse_let_atom`, so the
1786    /// runtime resolves a bare identifier / `Step.output` as a binding lookup
1787    /// (like `let`) instead of passing the name literally. The type-checker
1788    /// (§58.d + §60.c) validates each entry against the tool's declared input
1789    /// schema (W2 / CT-2 caller blame) and references against their source.
1790    Named(Vec<(String, String, String)>),
1791}
1792
1793impl UseArgs {
1794    /// §58.b transitional — the legacy single-arg string for the IR `argument`
1795    /// field (still `String` until §58.c carries structured named args).
1796    /// `Named` projects an empty argument here; the type-checker validates
1797    /// named args from the AST, and §58.c/e wire their structured dispatch.
1798    pub fn legacy_argument(&self) -> String {
1799        match self {
1800            UseArgs::LegacyPositional(s) => s.clone(),
1801            UseArgs::Named(_) => String::new(),
1802        }
1803    }
1804}
1805
1806#[derive(Debug)]
1807pub struct UseToolStep {
1808    pub tool_name: String,
1809    pub args: UseArgs,
1810    pub loc: Loc,
1811}
1812#[derive(Debug)]
1813pub struct RememberStep {
1814    pub expression: String,
1815    pub memory_target: String,
1816    pub loc: Loc,
1817}
1818#[derive(Debug)]
1819pub struct RecallStep {
1820    pub query: String,
1821    pub memory_source: String,
1822    pub loc: Loc,
1823}
1824#[derive(Debug)]
1825pub struct ParBlock {
1826    /// §Fase 65 — the concurrent branches. Each top-level statement inside
1827    /// `par { … }` is one branch (a single-statement body); they execute
1828    /// concurrently at runtime. Empty for a `par {}` with no statements
1829    /// (degenerate no-op). Before §65 this was payload-free (the branches were
1830    /// skipped at parse time), so `par` ran as a stub.
1831    pub branches: Vec<Vec<FlowStep>>,
1832    pub loc: Loc,
1833}
1834#[derive(Debug)]
1835pub struct HibernateStep {
1836    pub event_name: String,
1837    pub timeout: String,
1838    pub loc: Loc,
1839}
1840#[derive(Debug)]
1841pub struct DeliberateBlock {
1842    pub loc: Loc,
1843}
1844#[derive(Debug)]
1845pub struct ConsensusBlock {
1846    pub loc: Loc,
1847}
1848#[derive(Debug)]
1849pub struct ForgeBlock {
1850    pub loc: Loc,
1851}
1852#[derive(Debug)]
1853pub struct FocusStep {
1854    pub expression: String,
1855    pub loc: Loc,
1856}
1857#[derive(Debug)]
1858pub struct AssociateStep {
1859    pub left: String,
1860    pub right: String,
1861    pub using_field: String,
1862    pub loc: Loc,
1863}
1864#[derive(Debug)]
1865pub struct AggregateStep {
1866    pub target: String,
1867    pub group_by: Vec<String>,
1868    pub alias: String,
1869    pub loc: Loc,
1870}
1871#[derive(Debug)]
1872pub struct ExploreStepNode {
1873    pub target: String,
1874    pub limit: Option<i64>,
1875    pub loc: Loc,
1876}
1877#[derive(Debug)]
1878pub struct IngestStep {
1879    pub source: String,
1880    pub target: String,
1881    pub loc: Loc,
1882}
1883#[derive(Debug)]
1884pub struct ShieldApplyStep {
1885    pub shield_name: String,
1886    pub target: String,
1887    pub output_type: String,
1888    pub loc: Loc,
1889}
1890#[derive(Debug)]
1891pub struct StreamBlock {
1892    pub loc: Loc,
1893}
1894#[derive(Debug)]
1895pub struct NavigateStep {
1896    pub pix_name: String,
1897    pub corpus_name: String,
1898    pub query_expr: String,
1899    pub trail_enabled: bool,
1900    pub output_name: String,
1901    /// §Fase 63.B — for MDN corpus-graph navigation: the seed document `from:`
1902    /// to start the ε-informative traversal. Empty for PIX tree navigation.
1903    pub seed: String,
1904    /// §Fase 63.B — for MDN: the `budget:` (max documents). `None` = default.
1905    pub budget: Option<i64>,
1906    /// §Fase 66 (Q2) — optional column-scope filter (`where:`) for a
1907    /// `corpus from axonstore`. A raw filter expr (same shape as `retrieve …
1908    /// where`) pushed to the SELECT sourcing the corpus rows, so an adopter
1909    /// multiplexing sub-tenants in one axon-tenant via a column can scope the
1910    /// MDN graph to a single sub-tenant. Empty = no column filter (RLS-only).
1911    pub where_expr: String,
1912    pub loc: Loc,
1913}
1914#[derive(Debug)]
1915pub struct DrillStep {
1916    pub pix_name: String,
1917    pub subtree_path: String,
1918    pub query_expr: String,
1919    pub output_name: String,
1920    pub loc: Loc,
1921}
1922#[derive(Debug)]
1923pub struct TrailStep {
1924    pub navigate_ref: String,
1925    pub loc: Loc,
1926}
1927#[derive(Debug)]
1928pub struct CorroborateStep {
1929    pub navigate_ref: String,
1930    pub output_name: String,
1931    pub loc: Loc,
1932}
1933#[derive(Debug)]
1934pub struct OtsApplyStep {
1935    pub ots_name: String,
1936    pub target: String,
1937    pub output_type: String,
1938    pub loc: Loc,
1939}
1940#[derive(Debug)]
1941pub struct MandateApplyStep {
1942    pub mandate_name: String,
1943    pub target: String,
1944    pub output_type: String,
1945    pub loc: Loc,
1946}
1947#[derive(Debug)]
1948pub struct ComputeApplyStep {
1949    pub compute_name: String,
1950    pub arguments: Vec<String>,
1951    pub output_name: String,
1952    pub loc: Loc,
1953}
1954/// §λ-L-E Fase 13 D4 — dual-mode listen.
1955///
1956/// `channel_is_ref = true` ⇒ `channel` is the name of a declared
1957/// `ChannelDefinition` (canonical Fase 13 form).  `false` ⇒ legacy
1958/// string topic (deprecated; type checker emits a warning).
1959#[derive(Debug)]
1960pub struct ListenStep {
1961    pub channel: String,
1962    pub channel_is_ref: bool,
1963    pub event_alias: String,
1964    /// §Fase 52.a — the handler body: real flow-steps executed on each event /
1965    /// scheduled tick. Pre-§52.a the `{ … }` block was `skip_braced_block`'d
1966    /// (the listener was inert); now it is parsed so a `daemon` can run logic
1967    /// (e.g. `run <Flow>(…)`) per trigger. Empty for a bodyless `listen`.
1968    pub body: Vec<FlowStep>,
1969    pub loc: Loc,
1970}
1971#[derive(Debug)]
1972pub struct DaemonStepNode {
1973    pub daemon_ref: String,
1974    pub loc: Loc,
1975}
1976#[derive(Debug)]
1977pub struct PersistStep {
1978    pub store_name: String,
1979    /// §Fase 35.o — the `{ col: value }` field block. Empty when the
1980    /// step is written without a block (`persist <store>`), in which
1981    /// case the runtime falls back to writing the flow's user
1982    /// bindings as a row (backward-compatible with v1.30.0).
1983    pub fields: Vec<(String, String)>,
1984    pub loc: Loc,
1985}
1986#[derive(Debug)]
1987pub struct RetrieveStep {
1988    pub store_name: String,
1989    pub where_expr: String,
1990    pub alias: String,
1991    /// §Fase 67.b — optional `order_by:` clause: a closed
1992    /// comma-separated list of `column [asc|desc]` (same identifier
1993    /// discipline as `where:` columns — no injection). Empty = no
1994    /// ordering. Raw string, parsed + validated by the runtime
1995    /// (`filter::render_bounds`) and at `axon check` (§38.d `axon-T807`).
1996    pub order_by: String,
1997    /// §Fase 67.b — optional `limit:` clause: a `u32` literal OR a
1998    /// `${binding}` resolved to a `u32` at runtime. Empty = no limit.
1999    /// Raw string (`"100"` or `"${max}"`), validated at `axon check`
2000    /// (§38.d `axon-T808`).
2001    pub limit_expr: String,
2002    pub loc: Loc,
2003}
2004#[derive(Debug)]
2005pub struct MutateStep {
2006    pub store_name: String,
2007    pub where_expr: String,
2008    /// §Fase 35.p — the `{ col: value }` SET assignments. Empty when
2009    /// the step declares no columns, in which case the runtime falls
2010    /// back to writing the flow's user bindings as the `SET` clause
2011    /// (backward-compatible with v1.31.0).
2012    pub fields: Vec<(String, String)>,
2013    pub loc: Loc,
2014}
2015#[derive(Debug)]
2016pub struct PurgeStep {
2017    pub store_name: String,
2018    pub where_expr: String,
2019    pub loc: Loc,
2020}
2021#[derive(Debug)]
2022pub struct TransactBlock {
2023    pub loc: Loc,
2024}
2025
2026/// §Fase 51.a — the `quant` cognitive primitive block surface
2027/// (`docs/papers/paper_primitiva_quant.md`; enterprise §Fase 51).
2028///
2029/// `quant` projects an MEK semantic tensor into a complex Hilbert space,
2030/// evolves it under a variational / kernel-feature map, and collapses back to
2031/// classical silicon. The attribute header is OPTIONAL — the bare `quant { … }`
2032/// form (the paper's example) leaves every attribute defaulted. The richer form
2033/// `quant(encoding: amplitude, observable: M, qubits: 10, depth: 4,
2034/// bandwidth: 0.5, backend: quant_sim) { … }` pins the encoding scheme (D2),
2035/// the Pauli-sum observable (D5), the register width / circuit depth, the
2036/// projected-kernel bandwidth γ (D7), and the algebraic-effect backend (D1/D9).
2037///
2038/// §51.a ships the SURFACE only. The Continuous Type Invariant over `body`
2039/// (§51.b), the typed continuous grammar incl. typed `let` + `Observable`
2040/// (§51.c), and the `quant_sim`/`qpu_native` effect injection + `yield`
2041/// measurement point (§51.d) land in subsequent sub-fases.
2042#[derive(Debug, Default)]
2043pub struct QuantBlock {
2044    /// `encoding:` — `amplitude` (default) or `angle` (shallow). `None` = the
2045    /// compiler default (amplitude). Carried as the surface spelling; §51.c
2046    /// validates against the closed scheme set.
2047    pub encoding: Option<String>,
2048    /// `observable:` — the name of a declared `Observable` (Pauli-sum, D5).
2049    /// `None` if unspecified (§51.c resolves + Hermiticity-checks it).
2050    pub observable: Option<String>,
2051    /// `qubits:` — the register width n (D = 2ⁿ). `None` = inferred from the
2052    /// encoded tensor dimensionality. The OSS reference backend caps n ≤ 10
2053    /// (D1); that bound is enforced at §51.e, not here.
2054    pub qubits: Option<i64>,
2055    /// `depth:` — the variational circuit depth L. `None` = backend default.
2056    pub depth: Option<i64>,
2057    /// `bandwidth:` — the projected-quantum-kernel bandwidth γ (D7). `None` =
2058    /// backend default.
2059    pub bandwidth: Option<f64>,
2060    /// §Fase 69.c — `reupload:` L, the number of DATA RE-UPLOADING layers. `None`
2061    /// or `1` = no re-uploading (the data enters once → a quadratic form, provably
2062    /// classical for amplitude+Pauli, §69.b). `L ≥ 2` interleaves the data
2063    /// encoding with entangling layers L times — the ONLY provable escape from the
2064    /// quadratic bound (Havlíček-style; canonical with `encoding: angle`). The
2065    /// resulting kernel must still pass an Advantage Witness to be deployed
2066    /// claiming advantage (§69.a/b).
2067    pub reupload: Option<i64>,
2068    /// The algebraic-effect backend tag: `quant_sim` (default) or `qpu_native`
2069    /// (D1/D9). Stored as the bare backend name; §51.d injects the full
2070    /// `ots:backend:<tag>` effect into the enclosing flow's effect row.
2071    pub effect: String,
2072    /// The nested flow-body statements (parsed like `par` branches, so §51.b
2073    /// can apply the Continuous Type Invariant to real AST). Empty for an
2074    /// empty `quant {}`.
2075    pub body: Vec<FlowStep>,
2076    pub loc: Loc,
2077}
2078
2079/// §Fase 51.c.2 — one term `cₖ · Pₖ` of a Pauli-sum observable.
2080///
2081/// `coefficient` is a real scalar (parsed as `f64`); `pauli` is a Pauli string
2082/// over the closed alphabet `{I, X, Y, Z}` (one char per qubit), e.g. `"ZZ"` or
2083/// `"XI"`. A real linear combination of Pauli strings is **Hermitian by
2084/// construction** (each Pauli string is Hermitian; real-weighted sums preserve
2085/// Hermiticity), which is why the observable needs no separate Hermiticity check.
2086#[derive(Debug, Default, Clone)]
2087pub struct PauliTerm {
2088    pub coefficient: f64,
2089    pub pauli: String,
2090    pub loc: Loc,
2091}
2092
2093/// §Fase 51.c.2 — the `observable <Name> { qubits, term: cₖ·Pₖ … }` declaration
2094/// (paper §3.2; plan D5). A typed Pauli-sum `M = Σ cₖ Pₖ` that a `quant` block
2095/// measures the evolved state against. The type-checker validates the closed
2096/// `{I,X,Y,Z}` alphabet + equal term lengths + non-empty sum; Hermiticity is
2097/// guaranteed by construction (real coefficients).
2098#[derive(Debug, Default)]
2099pub struct ObservableDefinition {
2100    pub name: String,
2101    /// `qubits: n` — the register width every Pauli string must span. `None`
2102    /// = inferred from the (equal) term lengths.
2103    pub qubits: Option<i64>,
2104    pub terms: Vec<PauliTerm>,
2105    pub loc: Loc,
2106    /// Fase 14.b — leading comment trivia.
2107    pub leading_trivia: Vec<crate::tokens::Trivia>,
2108    /// Fase 14.b — trailing comment trivia.
2109    pub trailing_trivia: Vec<crate::tokens::Trivia>,
2110}
2111
2112/// §Fase 69.a — `witness <Name> { claim: <ref>  against: <baseline>
2113/// metric: <metric>  threshold: <ε>  data: <source> }`. The Advantage-Witness
2114/// proof obligation. The compiler proves it WELL-FORMED (§69.a, `axon-E0790`);
2115/// the advantage VALUE is computed on real `data` at deploy/runtime and carried
2116/// as a verdict (§69.b+). Fields are order-free `key: value` pairs.
2117#[derive(Debug)]
2118pub struct WitnessDefinition {
2119    pub name: String,
2120    /// The primitive instance whose advantage is claimed (e.g. an `observable` /
2121    /// `corpus` name, or a quant kernel reference).
2122    pub claim: String,
2123    /// The cheaper alternative the claim must beat (a closed-catalog baseline
2124    /// like `cosine` / `flat_retrieval` / `single_shot`, or a reference).
2125    pub baseline: String,
2126    /// How advantage is measured — a closed-catalog metric (`geometric_difference`,
2127    /// `kernel_target_alignment`, `ranking_lift`, `outcome_lift`).
2128    pub metric: String,
2129    /// The minimum advantage that justifies the cost (ε ≥ 0).
2130    pub threshold: f64,
2131    /// The real-data source the witness is evaluated on (a ref to an axonstore /
2132    /// corpus / labelled set). Required — advantage cannot be claimed in the abstract.
2133    pub data: String,
2134    pub loc: Loc,
2135    pub leading_trivia: Vec<crate::tokens::Trivia>,
2136    pub trailing_trivia: Vec<crate::tokens::Trivia>,
2137}
2138
2139// ── §λ-L-E Fase 13 — Mobile Typed Channels ──────────────────────────────────
2140
2141/// `channel Name { message: T, qos: X, lifetime: ℓ, persistence: π, shield: σ }`.
2142///
2143/// First-class affine resource carrying a typed message.  Direct port
2144/// of `axon.compiler.ast_nodes.ChannelDefinition`.  `message` retains
2145/// the surface spelling (e.g. `"Order"` or `"Channel<Order>"`) so the
2146/// type checker can resolve nested mobility (paper §3.3).
2147#[derive(Debug)]
2148pub struct ChannelDefinition {
2149    pub name: String,
2150    pub message: String,     // type name OR "Channel<T>" for second-order
2151    pub qos: String,         // at_most_once | at_least_once | exactly_once | broadcast | queue
2152    pub lifetime: String,    // linear | affine | persistent (D1 default: affine)
2153    pub persistence: String, // ephemeral | persistent_axonstore
2154    pub shield_ref: String,  // optional σ-shield gate for publish (D8)
2155    pub loc: Loc,
2156    /// Fase 14.b — leading comment trivia attached to this declaration
2157    /// (comments preceding the declaration's first token, since the
2158    /// previous declaration or file start). Empty by default.
2159    pub leading_trivia: Vec<crate::tokens::Trivia>,
2160    /// Fase 14.b — trailing comment trivia (same line as the
2161    /// declaration's last effective token). Empty by default.
2162    pub trailing_trivia: Vec<crate::tokens::Trivia>,
2163}
2164
2165/// `emit ChannelName(value_ref)` — π-calculus output prefix `c⟨v⟩.P`.
2166///
2167/// Direct port of `axon.compiler.ast_nodes.EmitStatement`.  Handles
2168/// both Chan-Output (scalar payload) and Chan-Mobility (channel-as-
2169/// value); the type checker dispatches based on whether `value_ref`
2170/// resolves to a `ChannelDefinition`.
2171#[derive(Debug)]
2172pub struct EmitStatement {
2173    pub channel_ref: String,
2174    pub value_ref: String,
2175    pub loc: Loc,
2176}
2177
2178/// `publish ChannelName within ShieldName` — capability extrusion.
2179///
2180/// Paper §4.3 (Publish-Ext) materialized as a flow step.  The `within
2181/// <Shield>` clause is mandatory (D8) — the parser rejects bare
2182/// `publish C`, the type checker rejects publishes whose shield does
2183/// not cover κ(message_type) (Fase 6.1 + paper §3.4).
2184#[derive(Debug)]
2185pub struct PublishStatement {
2186    pub channel_ref: String,
2187    pub shield_ref: String,
2188    pub loc: Loc,
2189}
2190
2191/// `discover ChannelName as alias` — dual of publish.
2192///
2193/// Imports a previously-published handle into a fresh affine local
2194/// binding.  The `as <alias>` is mandatory; the type checker rejects
2195/// discovery of channels that were never declared with `shield_ref`.
2196#[derive(Debug)]
2197pub struct DiscoverStatement {
2198    pub capability_ref: String,
2199    pub alias: String,
2200    pub loc: Loc,
2201}