feat(knowable-from): wire schema_ddl_hint via surrealql-hint feature + ADR-023#33
Conversation
…+ ADR-023 Two thematic things bundled — the framing principle (ADR-023: IR-as-wire-truth) and its receipt (the registry now carries the producer's `Class` IR projected into SurrealQL DDL). # 1. The schema_ddl_hint loop closure PR #25 introduced `KnowableFromStore::register(class_identity, schema_ddl_hint: Option<&str>)` with the docstring claim *"so the registry is self-describing"*. PR #32 landed `emit_surrealql_ddl`. This PR wires the two together: - New optional feature `surrealql-hint` on `ogar-knowable-from`. - When ON: `register_class_knowable_from` renders the DDL via `ogar_adapter_surrealql::emit_surrealql_ddl(std::slice::from_ref (class))` and passes `Some(ddl)` to `store.register`. - When OFF (default): `None` is passed, preserving the lightweight path (no adapter dep pulled in). Cargo.toml — optional dep + feature: surrealql-hint = ["dep:ogar-adapter-surrealql"] ogar-adapter-surrealql = { path = "...", optional = true } Tests (both paths, conditionally compiled): - `default_path_passes_none_for_schema_ddl_hint` (feature-off): asserts `calls[0].1.is_none()`. - `surrealql_hint_feature_renders_ddl_into_registry` (feature-on): asserts the registry received DDL containing `DEFINE TABLE Account SCHEMAFULL;` + `DEFINE FIELD email ON Account TYPE string;`. Plus: existing `register_simple_class_returns_store_version` made axis-agnostic on the hint (the hint axis now has dedicated tests for each feature path). # 2. ADR-023 — IR-as-wire-truth New ADR in `docs/ARCHITECTURAL-DECISIONS-2026-06-04.md`. Pins the framing principle that ADR-022 (The Firewall) has implicitly relied on but hadn't named: source-language ASTs (Elixir quoted form, SurrealQL DDL, Ruby AR macro tree, Odoo Python, ClickHouse CREATE TABLE, OWL TTL triples) are *input dialects*; the canonical OGAR IR (`Class`/`Attribute`/`Association`/`EnumDecl`/`ActionDef`/ `KausalSpec`/`Identity` (`NiblePath`)) is *wire truth*. The aphorism: "Elixir AST is input dialect; the canonical IR is wire truth." Generalizes to any source dialect. Consequences pinned: - Same IR -> same hash -> same actor routing -> same Lance row -> same audit dimension. Content-addressing primitive. - Adapters pluggable, IR fixed. - Round-trip is the adapter contract. - `schema_ddl_hint` loop closes here (this PR is the receipt). - Cross-session triangulation: bardioc PR #19's `substrate-b-shadow::EdgeDecoder<E>` IS the pattern in code — its decoders return `ActionInvocation` regardless of source. Change policy: adding a new source dialect (new adapter crate) is routine; changing the IR is substrate-wide (requires Option<…> backward-compat default + round-trip preservation in all adapters + runtime-session consultation). # 3. CI floor extended `.github/workflows/ci.yml` adds: cargo test -p ogar-knowable-from --features surrealql-hint Same crate-scoped pattern as #32's `surrealdb-parser` step. # Verification - `cargo test --workspace` (default) -> clean (10/10 for ogar-knowable-from on the feature-off path). - `cargo test -p ogar-knowable-from --features surrealql-hint` -> 10/10 (the feature-on test now lands and the feature-off test is cfg'd out). - `cargo check --workspace --all-targets` -> clean. PII abort-guard (word-boundary): CLEAN on all four touched files. https://claude.ai/code/session_01PBTGaPCSnnt6u3pjXpbLwY
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3bdfdc54ac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // gets wired into the call site. | ||
| #[cfg(feature = "surrealql-hint")] | ||
| { | ||
| let ddl = ogar_adapter_surrealql::emit_surrealql_ddl(std::slice::from_ref(class)); |
There was a problem hiding this comment.
Escape OGAR class names before emitting DDL hints
When surrealql-hint is enabled this now renders a DDL hint for every registered Class, but register_class_knowable_from accepts OGAR class names such as sale.order via the documented ogit-erp/sale.order identity path. Those names are not safe SurrealQL bare identifiers, and emit_surrealql_ddl currently formats them directly as DEFINE TABLE {class.name}, so enabling this feature for Odoo-style classes stores an invalid schema hint instead of a self-describing registry entry. Please normalize or quote identifiers before passing the hint, or only enable the hint for classes already known to be SurrealQL identifier-safe.
Useful? React with 👍 / 👎.
Summary
Two thematic threads bundled — the framing principle (ADR-023: IR-as-wire-truth) and its receipt (the registry now carries the producer's
ClassIR projected into SurrealQL DDL).1. The
schema_ddl_hintloop closesPR #25 introduced
KnowableFromStore::register(class_identity, schema_ddl_hint: Option<&str>)with the docstring claim "so the registry is self-describing". PR #32 landedemit_surrealql_ddl. This PR wires the two together.Mechanism — opt-in feature flag (keeps the lightweight default):
Tests (both paths, conditionally compiled):
default_path_passes_none_for_schema_ddl_hintcalls[0].1.is_none()surrealql_hint_feature_renders_ddl_into_registryDEFINE TABLE Account SCHEMAFULL;+DEFINE FIELD email ON Account TYPE string;Existing
register_simple_class_returns_store_versionmade axis-agnostic on the hint (dedicated tests above cover each feature path).2. ADR-023 — IR-as-wire-truth
New ADR in
docs/ARCHITECTURAL-DECISIONS-2026-06-04.md. Pins the framing principle ADR-022 (The Firewall) has implicitly relied on but hadn't named.The aphorism: Elixir AST is input dialect; the canonical IR is wire truth.
Generalizes to any source dialect — Elixir quoted form, SurrealQL DDL, Ruby AR macros, Odoo Python
models.Model, ClickHouse CREATE TABLE, OWL TTL triples — all are input dialects lifted into the canonical IR (Class/Attribute/Association/EnumDecl/ActionDef/KausalSpec/Identity (NiblePath)).Consequences pinned in the ADR:
ogar-adapter-surrealql,ogar-adapter-ttlplanned,ogar-from-elixir,ogar-from-ectoproposed). TheClassIR doesn't change; only the lift code does.schema_ddl_hintloop closes here — this PR IS the receipt.substrate-b-shadow::EdgeDecoder<E>IS the pattern materialized in runtime-side code; its decoders returnActionInvocationregardless of source dialect.Change policy: adding a new source dialect (new adapter crate) is routine; changing the IR is substrate-wide — requires
Option<…>backward-compat default, round-trip preservation in all adapters, and runtime-session consultation.ADR-023 generalizes ADR-016's claim ("SurrealQL DDL AST is not the universal IR") from SurrealQL to all source dialects.
3. CI floor extended
Same crate-scoped pattern as #32's
surrealdb-parserstep. Both feature-gated test steps now part of the CI floor.Verification
PII abort-guard (word-boundary): CLEAN on all four touched files.
Position in the queue
Per
docs/RDF-OWL-ALIGNMENT.md §10+ the queue refresh after bardioc #19:schema_ddl_hintloop + ADR-023 (smallest concrete next step)ogar-adapter-ttlscaffoldogar-from-ecto+ogar-adapter-clickhouse-ddl(composes with bardioc docs: SurrealQL AST as universal adapter — feasibility, beauty, brutal honesty #19'sEdgeDecoder<E>)https://claude.ai/code/session_01PBTGaPCSnnt6u3pjXpbLwY