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