From ee9521bd85da7d0ddc86c78a102e40c01a68a3a0 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 22 Jun 2026 19:03:10 +0000 Subject: [PATCH] docs(od-ontology): cast the SurrealQL-AST-trap spellbook (consumer-owned, OGAR #99) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit od-ontology IS the diagnostic signature OGAR #99 names — `surreal_ast.rs` + `triple.rs` + `recompute_dag.rs` colocated. The spellbook has to fire in THIS domain, and only this consumer can cast it. So this lands the local mirror and activates it at the trap site. - `specs/SURREAL-AST-TRAP.md` (new): the od-ontology-local spellbook — the 90-second Q1–Q5 pre-flight mirror, the structural/behavioral two-arm frame (structure = lossy projection of `Class`, behavior = NO DDL home → `ActionDef`), the one-way-lossy roundtrip truth, diagnostic signatures (honest: this crate exhibits them mid-migration, on purpose), W3.3-as-two-lowerings remediation, and activation triggers. Single source of truth for the frame. - `src/surreal_ast.rs`: a PRE-FLIGHT guard at the very top of the trap file — the mirror fires before a session internalizes the "this is the surface" framing. "Egress adapter, not a spine; lifecycle has no DDL home." - `specs/UPSTREAM_WISHLIST.md`: the #99 probe note trimmed to a condensed reframing + a pointer to the spellbook (no duplicated frame). Doc + one module-comment only; no logic, no symbol change. clippy exit 0. Co-Authored-By: Claude Opus 4.8 --- crates/od-ontology/specs/SURREAL-AST-TRAP.md | 87 +++++++++++++++++++ crates/od-ontology/specs/UPSTREAM_WISHLIST.md | 18 ++-- crates/od-ontology/src/surreal_ast.rs | 11 +++ 3 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 crates/od-ontology/specs/SURREAL-AST-TRAP.md diff --git a/crates/od-ontology/specs/SURREAL-AST-TRAP.md b/crates/od-ontology/specs/SURREAL-AST-TRAP.md new file mode 100644 index 0000000..fc206eb --- /dev/null +++ b/crates/od-ontology/specs/SURREAL-AST-TRAP.md @@ -0,0 +1,87 @@ +# SurrealQL-AST trap — pre-flight spellbook (od-ontology local mirror) + +> **MANDATORY — read before** touching `surreal_ast.rs` as anything more than an +> egress adapter, before any W3 fork-deletion / "lower onto `ogar_vocab::Class`" +> work, before adding a `From for ActionDef`, before claiming a +> behavioral roundtrip, or before colocating a new `*_dag.rs` / `triple.rs` +> beside the AST. 90 seconds, five questions, one mirror. +> +> **Why here:** OGAR #99's spellbook (`docs/SURREAL-AST-TRAP-PREFLIGHT.md` + +> `docs/SURREAL-AST-AS-ADAPTER.md`) names **this crate** — +> `surreal_ast.rs` + `triple.rs` + `recompute_dag.rs` colocated — as *the* +> diagnostic signature of the trap. So this is exactly where a session reflexes +> in. The reflex is pre-cognitive ("sessions don't argue their way in, they +> reflex their way in"), so the mirror has to fire **before the keyboard**. + +## The five questions (any "stop" answer catches the trap pre-materialization) + +``` +Q1. What am I reading FROM? — does the source carry lifecycle vocab? +Q2. Does the source have LIFECYCLE? — @api.depends / @api.constrains / compute + / state machines / action methods +Q3. What is the TARGET IR? — ogar_vocab::Class + ActionDef, + or surreal_ast? (Class is the IR.) +Q4. Which way does my arrow point? — producer → OGAR → adapter, + or producer → DDL? (The first.) +Q5. Would the INVERSE recover? — distil DDL back; do you recover the + BEHAVIOR? (No — see one-way-lossy.) +``` + +## The two-arm split — the load-bearing frame + +SurrealQL DDL is a legitimate target for **structure** and an illegitimate one +for **behavior**. These are not the same question: + +| Arm | Can SurrealQL AST be the IR? | Why | +|---|---|---| +| **Structural** — `Class` / `Attribute` / `Association` / `Enum` | **Lossy projection, never a substitution.** `From for catalog::TableDefinition` is the durable bridge; but `Class` STAYS the IR because `dependent:` / `inverse_of:` / `polymorphic:` / mixins / decorators / STI all vanish through DDL. | DDL answers "what shape," not "what the producer knew about how the shape came to be." | +| **Behavioral** — `ActionDef` + `ActionInvocation` + `KausalSpec` + `EnterEffect` + Rubicon `Pending→Committed` FSM + `state_timeout` | **No. Period.** | DDL has *no vocabulary* for the lifecycle FSM / SPO+TeKaMoLo / Rubicon binding. `DEFINE EVENT` / `DEFINE FUNCTION` are row-trigger / stored-proc shapes, not lifecycle-crossing shapes. | + +**Roundtrip is one-way-lossy.** `emit` is bijective only on the schema-side +subset; `unmap` from DDL alone reconstructs an empty/default `Class` for +everything source-side. That is the honest version, not a bug — never claim a +behavioral `parse(emit(parse(x))) == parse(x)` through DDL. + +## Diagnostic signatures (for review — and an honest note about THIS crate) + +- `.surql` files with `DEFINE EVENT … WHEN … THEN …` doing more than row triggers +- sentinel comments: `-- @action:` / `-- @state:` / `-- @lifecycle:` +- an IR file named `surreal_ast.rs` used as a project's **spine** (not adapter) +- `From for ActionDef` / `to_action_def()` conversions +- behavioral-roundtrip claims through DDL +- a `triple.rs` / `recompute_dag.rs` cluster colocated with `surreal_ast.rs` + +**This crate currently exhibits the last signature — on purpose, mid-migration.** +`surreal_ast.rs` + `triple.rs` + `recompute_dag.rs` are the W3 transition state: +the native `ToSql` path is a *documented* gap (see `ogar_bridge.rs` module docs) +being demoted to egress, not the end state. The trap is not "this crate has the +files"; the trap is **treating `surreal_ast` as the spine** instead of routing +through `ogar_vocab::Class` + `ActionDef`. The identity/structural work already +routes correctly (`emit_via_ogar_annotated` → `Class` → canonical adapter). + +## Remediation — W3.3 is TWO separable lowerings, not one deletion + +1. **Structural** — `triple.rs` shape facts → `ogar_vocab::Class`. DDL stays a + lossy egress adapter (`ogar-adapter-surrealql`), never the IR. +2. **Behavioral** — `recompute_dag.rs` (Odoo's real compute / `@api.constrains` + / action lifecycle) → OGAR's **behavioral arm** + (`ActionDef` / `ActionInvocation` / `KausalSpec` / Rubicon FSM). **Not** + `DEFINE EVENT` — emitting lifecycle as DDL re-enters the trap. + +`surreal_ast` / `triple` / `recompute_dag` delete only **after both** land. +Lowering (2) is gated on OGAR's behavioral vocabulary being consumable from +`od-ontology` — **not verified wired today.** Route Q1–Q5 before writing code. + +## Activation triggers (READ-BY) + +Load this doc before producing output when a task mentions: `surreal_ast.rs`, +`DEFINE EVENT`, `DEFINE FUNCTION`, `.surql` as a spine, `distil from SurrealQL`, +`unmap`/`from_ddl`, `From<…> for ActionDef`, `recompute_dag`, `triple.rs` IR, +"behavioral roundtrip", or W3.3 / "delete the fork". Carried for +`core-first-architect` / `adapter-shaper` / `core-gap-auditor` / `Plan` agents. + +## Canonical upstream + +OGAR `docs/SURREAL-AST-TRAP-PREFLIGHT.md` (the spellbook) + +`docs/SURREAL-AST-AS-ADAPTER.md` (the design it extracts from), OGAR #99. +This file is the od-ontology-local mirror so the mirror fires in-repo. diff --git a/crates/od-ontology/specs/UPSTREAM_WISHLIST.md b/crates/od-ontology/specs/UPSTREAM_WISHLIST.md index 924b8a6..c0e2262 100644 --- a/crates/od-ontology/specs/UPSTREAM_WISHLIST.md +++ b/crates/od-ontology/specs/UPSTREAM_WISHLIST.md @@ -443,12 +443,18 @@ we can adopt your choice when it lands. > `sale.order` lexical-vs-alias asymmetry as its own guard. Not blocking; the > shipped readable COMMENT already delivers the operator-facing value. > -> **#99 reframing (SurrealQL-AST-trap governance):** W3.3 ("delete the -> `surreal_ast`/`triple`/`recompute_dag` fork") is NOT "grow the canonical -> adapter to emit `DEFINE EVENT`" — that would re-enter the trap (SurrealQL AST -> carrying lifecycle). The fork's reactive layer must move to OGAR -> `Class + ActionDef`; the adapter emits identity/structure DDL only. This -> probe's COMMENT work is identity-layer and stays clear of that boundary. +> **#99 reframing (SurrealQL-AST-trap governance).** W3.3 ("delete the +> `surreal_ast`/`triple`/`recompute_dag` fork") is **two separable lowerings**, +> not one deletion: (a) structural shape → `ogar_vocab::Class` (DDL stays a +> lossy egress adapter); (b) behavioral lifecycle → OGAR's behavioral arm +> (`ActionDef`/`ActionInvocation`/`KausalSpec`/Rubicon FSM), **not** a +> `DEFINE EVENT` emit (which re-enters the trap). The fork deletes only after +> both; (b) is gated on OGAR's behavioral vocabulary being consumable here (NOT +> verified wired). This probe's COMMENT work is identity-layer (a slice of the +> structural arm) and stays clear of that boundary. **Full spellbook — the +> two-arm frame, one-way-lossy roundtrip, Q1–Q5 mirror, activation triggers: +> `specs/SURREAL-AST-TRAP.md`** (the od-ontology-local mirror of OGAR #99). +> Read it before any W3 fork-deletion work. **Already shipped, no capability needed:** `emit_via_ogar_annotated` (`ogar_bridge.rs`) stamps the full APP‖class render id into the diff --git a/crates/od-ontology/src/surreal_ast.rs b/crates/od-ontology/src/surreal_ast.rs index 87eb152..02357ff 100644 --- a/crates/od-ontology/src/surreal_ast.rs +++ b/crates/od-ontology/src/surreal_ast.rs @@ -1,3 +1,14 @@ +//! > ⚠️ **PRE-FLIGHT (OGAR #99 — SurrealQL-AST trap).** Before treating this +//! > AST as the IR / spine — or adding a `From for ActionDef`, a +//! > behavioral roundtrip claim, or `DEFINE EVENT` lifecycle — read +//! > `specs/SURREAL-AST-TRAP.md` (90-second Q1–Q5 mirror). This file is an +//! > **egress adapter, not a spine.** Structure lowers through +//! > `ogar_vocab::Class` (DDL is a *lossy projection* of it, one-way); behavior +//! > (compute / `@api.constrains` / actions) has **no DDL home** and lowers to +//! > OGAR's `ActionDef` arm, never `DEFINE EVENT`. The mapping table below is +//! > the structural projection only — it is not a claim that lifecycle round- +//! > trips through DDL. +//! //! Typed SurrealQL DDL AST — the shape Odoo's ontology lowers into. //! //! This is **not** a migration target and **not** an ORM schema. It is the