Skip to content

ogar-from-schema follow-up: 9-domain test + XSD transcode + framings#106

Merged
AdaWorldAPI merged 4 commits into
mainfrom
claude/medcare-bridge-lance-graph-wmx76z
Jun 22, 2026
Merged

ogar-from-schema follow-up: 9-domain test + XSD transcode + framings#106
AdaWorldAPI merged 4 commits into
mainfrom
claude/medcare-bridge-lance-graph-wmx76z

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

What this is

Follow-up to #105 (OGIT 1:1 import + ogar-from-schema producer). Four
commits that were added to the branch after #105 merged. All additive,
no conflicts. Merge-base with main is the merged commit cce8420.

Commit What
f44f712 9-domain lift-surface verification + dcterms:creator authorship provenance
b598460 verb-as-class as ontological askama template (walks back a wrong framing in #105's commit message)
7d68042 Odoo digest → OGIT TTL templates → relive agnostically (the Foundry-parity collapse)
8945b7f XSD transcode of extract_classes.py — byte-faithful, closes XSD↔TTL bijection, drops Python from the oracle

Highlights

9-domain round-trip verification (f44f712)

Extends the lift-surface check from MARS-only to 10 domains: MARS +
Transport + Accounting + SalesDistribution + Credit + Cost +
ServiceManagement + WorkOrder + Compliance + Audit. 210 TTL files
across the nine new domains; all parse via one of the two existing
parsers, all round-trip. New permanent regression test
ttl_emit::tests::nine_domains_lift_surface_round_trip pins each
domain's expected TTL count so any future upstream re-vendor that
drifts the inventory fires.

Authorship verification via dcterms:creator field scan:

  • WorkOrder is fully ours — sole authors are internal agent names
    (bus-compiler, family-codec-smith). Natural prototyping ground
    for new TTL predicates before pitching them to OGIT upstream.
  • Accounting is mixed-authorshipViktor Voss (23 files,
    original arago) + a prior session's Claude extension (11 files,
    ours).
  • All other seven domains are pure-upstream (single external human
    authors).

Verb-as-class is an askama template, not a quirk (b598460)

In #105's commit message I framed WorkOrder's rdfs:Class-as-verb
convention as "an unusual choice we're free to revise to
owl:ObjectProperty." That framing was wrong; re-encoding would
strip the very property that makes WorkOrder useful — the four
template surfaces (slots, inheritance, policy, side-effect spec)
only exist on rdfs:Class.

The structural correspondence with askama / jinja is exact:

askama / jinja ontology (verb-as-class)
template.html.j2 verbs/<Verb>.ttl with a rdfs:Class
struct Context { name: String } ogit:mandatory-attributes (subject object timestamp)
{% extends "base.html.j2" %} rdfs:subClassOf ogit:AuditableAction
compile-time {{ field }} check lift-time slot validation
render() → HTML string render() → (SPO triple, audit, ACL gate)

New doc: docs/VERB-AS-CLASS-TEMPLATE.md (FRAMING v0).

Odoo digest → OGIT TTL templates → relive agnostically (7d68042)

Architecture doc for the producer↔storage↔render pipeline. Digest
(ogar-from-python, queued) → store as TTL templates in OGIT
(vocab/imports/ogit/NTO/<Domain>/ with dcterms:creator provenance) →
relive agnostically via ogar-render-askama. Python runtime is
touched only at digest time; consumers never depend on Odoo Python,
only on TTL + the askama renderer.

The Foundry-parity collapse fits in one table:

Foundry layer Our equivalent New code
Ingest ogar-from-python digest ~1500 LOC (queued)
Storage vocab/imports/ogit/NTO/<Domain>/ TTL + dcterms:creator zero (shipped)
Render ogar-render-askama::{views, actions} ~200 LOC (actions queued)
IAM + audit verb-as-class requires-perm + Lance-version-as-audit zero (shipped)
Ontology change mgmt diff -r of digest re-runs zero

New doc: docs/ODOO-DIGEST-TO-OGIT.md (FRAMING v0). Includes the v0
mapping table for the six already-minted Odoo concepts +
~nine queued for codebook mint.

XSD transcode of extract_classes.py (8945b7f)

The MARS XSD classification extractor from arago/MARS-Schema/tools/
(~360 lines: ~140 extraction logic + ~150 table formatting) is now a
faithful Rust transcode at crates/ogar-from-schema/src/xsd.rs,
behind an optional xsd feature (pulls roxmltree, pure-Rust
read-only XML DOM; the default TTL path stays zero-parser-deps).

Three things this lands:

  1. Byte-for-byte transcode proof. xsd::to_asciidoc() reproduces
    the Python -F asciidoc output exactly — 628 lines, including
    verbatim XSD-documentation whitespace and the
    printAsciiDocFooter trailing newline.
    xsd::tests::asciidoc_matches_python_oracle diffs against the
    cached _oracle/classifications.adoc.
  2. XSD↔TTL bijection closed (was "queued" in
    MARS-TRANSCODING.md §2). xsd::tests::xsd_classes_match_ttl_enum
    asserts full bidirectional set-equality between the
    XSD-extracted Application value set and the TTL
    validation-parameter enum.
  3. Python dependency removed from the calibration path.
    cargo test --features xsd is the whole oracle now; no python3
    interpreter needed. extract_classes.py stays vendored in
    _oracle/ as the provenance witness, not a runtime dep.

Test footprint

  • 16/16 tests with default features (cargo test -p ogar-from-schema)
  • 20/20 tests with --features xsd (16 default + 4 XSD)
  • 210 TTL files across 9 new domains round-trip cleanly
  • 29 MARS TTLs + 176 SGO verbs continue to round-trip
  • XSD-vs-TTL Application value set: bidirectional equality enforced
  • Clippy-clean (--no-deps), fmt-clean for the new code

Docs touched

  • docs/MARS-TRANSCODING.md — bijection marked closed; Python-dep
    removal noted; Rust extractor added to the oracle direction table
  • docs/OGIT-DOMAIN-LIFT-CATALOGUE.md — 10 rows promoted to
    Lift-tested with per-row authorship provenance; verification recipe
    added (the dcterms:creator scan)
  • docs/VERB-AS-CLASS-TEMPLATE.md — new (FRAMING v0)
  • docs/ODOO-DIGEST-TO-OGIT.md — new (FRAMING v0)
  • .claude/board/EPIPHANIES.md — four new FINDING / FRAMING entries
    (newest first)

Generated by Claude Code

claude added 4 commits June 22, 2026 22:06
Extend the lift-surface verification from MARS-only to 10 domains:
MARS + Transport + Accounting + SalesDistribution + Credit + Cost +
ServiceManagement + WorkOrder + Compliance + Audit.

Coverage:

* 210 TTL files across 9 new domains (in addition to MARS's 29) — all
  parse, all round-trip via the generic `assert_domain_roundtrip`
  helper. Zero unparseable shapes; zero round-trip failures.
* `ttl_emit::tests::nine_domains_lift_surface_round_trip` is the
  permanent regression gate. Pins each domain's expected TTL count
  so an upstream re-vendor that drifts the inventory fires the test.

Authorship verification (per the operator's suggestion to check
`dcterms:creator`):

* WorkOrder is FULLY OURS — sole authors are internal agent names
  (`bus-compiler`, `family-codec-smith`). The unusual `rdfs:Class`-as-verb
  convention is ours to revise toward `owl:ObjectProperty` without
  external coordination.
* Accounting is MIXED-AUTHORSHIP — Viktor Voss (23 files, original arago)
  + a prior session's Claude extension (11 files, our local additions).
* All other 7 domains are pure-upstream (single external human authors:
  chris.boos@almato.com, Marek Meyer, Peter Larem, Ola Irgens Kylling,
  Aymen Ayoub, …).

This makes WorkOrder the natural prototyping ground for new TTL
predicates OGAR wants to ship before pitching them to OGIT upstream.

Doc updates:

* `docs/OGIT-DOMAIN-LIFT-CATALOGUE.md` — 10 rows promoted to Lift-tested
  with per-row authorship provenance. Adds a verification recipe
  (`§ Verifying domain authorship`) so future sessions can re-run the
  `dcterms:creator` scan in one Python heredoc.
* `.claude/board/EPIPHANIES.md` — new FINDING on author-provenance as
  a who-can-change-what discriminator.

Test footprint: 16/16 in ogar-from-schema (was 15/15; the new test
adds one). Workspace-wide: nothing else touched.
…haped action template, not a quirk

WorkOrder's 12 verbs/*.ttl are declared as `a rdfs:Class`, not
`owl:ObjectProperty`. The prior commit framed this as "an unusual
convention we're free to revise" — wrong framing.

The encoding is load-bearing. A `rdfs:Class` verb carries a typed
slot list (`ogit:mandatory-attributes`), an inheritance chain
(`rdfs:subClassOf`), and policy metadata (`ogit:requires-perm`,
`ogit:emits-audit`). That makes each verb a compile-time-validated
action template — the ontological counterpart to askama (Rust) and
jinja (Python) HTML templating.

Structural correspondence is exact:

* TTL file = template (.html.j2 equivalent)
* mandatory-attributes = struct field list (askama context shape)
* per-call binding = struct instance
* render = SPO triple emit + declared side effects (audit, ACL gate)
* rdfs:subClassOf = template inheritance ({% extends %})
* lift-time slot validation = askama's compile-time {{ field }} check

The existing ogar-render-askama crate is the natural landing — it
already renders Class views (noun-shaped); the verb-as-class encoding
is the parallel render path for Class actions (verb-shaped). Same
engine, different output medium.

Foundry-parity sharpens: Foundry's "action types" carry typed
parameters + slot validation + declared side effects + inheritance —
sold as a paid platform feature. Verb-as-class TTL + ogar-render-askama
gives the same four from open-source schemas and Rust templates.

Adds:

* docs/VERB-AS-CLASS-TEMPLATE.md (FRAMING v0) — analogy table, worked
  example on WorkOrder/verbs/AccessesPortal.ttl, render flow,
  cross-references to the existing render-askama crate.
* docs/OGIT-DOMAIN-LIFT-CATALOGUE.md (WorkOrder row): walks back the
  "we can re-author to owl:ObjectProperty" framing — the convention
  is deliberate and load-bearing for the action-render path.
* .claude/board/EPIPHANIES.md: FINDING entry with the correction
  citing the prior commit, the analogy table, and the implications
  for the ogar-render-askama actions submodule.

No code changes. Lift-tested round-trip count unchanged (16/16);
verb-as-class TTLs already parse cleanly via ttl::parse_file as
entities and round-trip via ttl_emit::emit_entity.
…oundry-parity collapse

The operator's framing — "digest Odoo and store it in TTL Jinja
Templates in OGIT and relive it agnostically for any verb/entity as
a class" — crystallizes the four pieces shipped across this PR (TTL
mirror, schema lift, verb-as-class template, dcterms:creator
provenance) into one coherent pipeline:

  Odoo source → ogar-from-python (AST schema filter) → Class IR
              → ttl_emit → OGIT TTL templates at
                vocab/imports/ogit/NTO/<Domain>/ with
                dcterms:creator = bus-compiler
              → ogar-render-askama → any consumer instantiates any
                entity-or-verb-as-class with a fresh binding;
                Python runtime touched only at digest time.

Why store digests in OGIT NTO (not a parallel vocab/imports/odoo/):
the dcterms:creator author-scan from this same session gives clean
provenance — internal-agent authors (bus-compiler, family-codec-smith)
signal "ours to revise"; external-human authors signal "upstream-arago,
coordinate". The precedent exists today: Accounting/ already has 11
Claude-digested files alongside 23 Viktor Voss originals.

The Foundry-parity collapse (the punchline) — Foundry's four-layer
platform pitch maps to four pieces in this repo:

  Foundry ingest        → ogar-from-python digest (~1500 LOC, queued)
  Foundry storage       → vocab/imports/ogit/NTO/ TTL (exists)
  Foundry render        → ogar-render-askama::{views, actions} (~200 LOC for actions)
  Foundry IAM+audit     → verb-as-class requires-perm slot + Lance-version-as-audit (exists)
  Foundry change mgmt   → diff -r of digest re-runs (exists)

Total marginal code: <2000 LOC for what Foundry charges $$$ for.

Adds:

* docs/ODOO-DIGEST-TO-OGIT.md (FRAMING v0, 8 sections):
  pipeline diagram; why-store-in-OGIT-NTO; the four shapes the
  digester produces (entity-as-class, datatype attribute, association,
  verb-as-class); v0 mapping table from the 6 already-minted commerce
  concepts + 9 queued for codebook mint; drift-detector recipe;
  blockers; Foundry-parity collapse table; cross-references.

* .claude/board/EPIPHANIES.md FRAMING entry: the pipeline, the
  storage-location rationale, the parity-collapse table, and the
  two concrete next-step deliverables (ogar-from-python +
  ogar-render-askama::actions) that ship independently in
  follow-up PRs.

No code changes. The architecture has been latent the whole time;
this commit makes it visible as one shape.
…es XSD↔TTL bijection, drops the Python oracle dep

The MARS XSD classification extractor (arago/MARS-Schema/tools/extract_classes.py,
~360 lines: ~140 extraction logic + ~150 table formatting) is now a
faithful Rust transcode at crates/ogar-from-schema/src/xsd.rs, behind
an optional `xsd` feature (pulls roxmltree, pure-Rust read-only XML
DOM; the default TTL path stays zero-parser-deps).

Not huge — the transcode is ~350 LOC Rust including tests. And it
doubles as the seed of the broader XSD → Class front-end: the same
walk that extracts classifications is the structural-arm lift for any
XSD schema.

What it lands:

* BYTE-FOR-BYTE transcode proof. xsd::to_asciidoc() reproduces the
  Python `-F asciidoc` output exactly — 628 lines, including verbatim
  XSD-documentation whitespace and the printAsciiDocFooter trailing
  newline. Test xsd::tests::asciidoc_matches_python_oracle diffs
  against the cached _oracle/classifications.adoc.

* XSD↔TTL BIJECTION CLOSED (was "queued" in MARS-TRANSCODING.md §2).
  xsd::tests::xsd_classes_match_ttl_enum asserts full bidirectional
  set-equality between the XSD-extracted Application value set and the
  TTL validation-parameter enum — not just one-directional membership.
  Two independent encodings of one taxonomy, provably equal both ways.

* PYTHON DEPENDENCY REMOVED from the calibration path. `cargo test
  --features xsd` is the whole oracle now; no python3 interpreter
  needed. extract_classes.py stays vendored in _oracle/ as the
  provenance witness (what the transcode was proven against), not a
  runtime dep.

Transcode discipline (faithful to the Python semantics):

* getAttribute("xml:lang") returns "" for absent (not None); lang
  filter is "absent OR en". roxmltree resolves xml: to the xml
  namespace, matched on attribute.name() == "lang".
* getXMLText concatenates DIRECT text-node children only (not
  recursive); the documentation's internal whitespace is load-bearing
  for the byte-match.
* :revdate: is datetime.now() in Python (non-deterministic); the Rust
  to_asciidoc(c, revdate) takes it as a parameter so output is
  reproducible and testable.
* The two-level extension chain (master complexType carries NodeType,
  intermediate complexType carries Class, leaf element carries
  SubClass) + the post-process phase that stitches base→element is
  reproduced exactly, including the master_types gate.

Tests: 20/20 with --features xsd (16 default + 4 new xsd); 16/16 on
default (xsd code fully feature-gated). Clippy-clean (--no-deps),
fmt-clean.

Docs:

* docs/MARS-TRANSCODING.md §2 — bijection marked closed; Python-dep
  removal noted; the Rust extractor added to the oracle-direction table.
* .claude/board/EPIPHANIES.md — FINDING with the transcode-discipline
  notes for the next source→Rust port.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@AdaWorldAPI AdaWorldAPI merged commit e578fbe into main Jun 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants