Skip to content

feat(ogar-class-view): bridge canonical Class onto lance-graph ClassView#77

Merged
AdaWorldAPI merged 1 commit into
mainfrom
claude/ogar-class-view-bridge
Jun 19, 2026
Merged

feat(ogar-class-view): bridge canonical Class onto lance-graph ClassView#77
AdaWorldAPI merged 1 commit into
mainfrom
claude/ogar-class-view-bridge

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

What

Wires the calcified inner shape (ogar_vocab::Class, codebook-keyed) onto the classview-parameterized outer materialization surface (lance_graph_contract::ClassView). The seam between the canonical layer and the askama templating layer.

lance-graph-contract::class_view already supplies the contract — ClassId / FieldMask(u64) / ObjectView / FieldRef / DisplayTemplate + the ClassView trait with project / render_rows iterators. What was missing was the adapter that lifts every promoted ogar_vocab canonical concept into an ObjectView keyed by canonical_concept_id.

This PR is that adapter.

The bridge

ogar_class_view::OgarClassView — one impl ClassView, built once at startup by walking all 32 promoted canonical class fns (26 project-mgmt + 6 commerce).

ogar_vocab::Class              ┌──► Rust struct
  (codebook id, attrs,         │
   family edges)               │──► TS interface
                  │            │
ogar_vocab::class_ids::*  ────►├──► SurrealQL TABLE
                  │            │
lance_graph_contract::         │──► OpenAPI schema
  ClassView trait               │
                  │            └──► (target N+1, classview-parameterized)
                  ▼
        ogar-class-view  (this PR)
                  │
                  ▼
        askama / jinja templates (deferred — the +5 below)

N3 stable field order

Each ClassObjectView with fields in append-only stable order:

  1. Typed attributes, in declaration order on the class fn.
  2. Family-edge associations, in declaration order on the class fn.

A test (field_order_is_attributes_then_associations) pins it. Any reorder trips the test before existing FieldMask producers silently misalign.

ClassId == canonical_concept_id

Both are u16, ratified by OD-CLASSID-WIDTH. The bridge uses them as one thing — no translation table.

Tests (8 / 8 green)

  • registry_carries_every_codebook_concept — forward gate.
  • every_codebook_id_appears_in_class_ids_all — reverse gate against class_ids::ALL.
  • field_basis_fits_in_one_u64_maskFieldMask::MAX_FIELDS = 64; widest class (billable_work_entry) well under.
  • field_order_is_attributes_then_associations — the N3 pin.
  • render_rows_skips_off_bits_under_a_real_mask — the askama input path.
  • unknown_class_id_projects_to_no_rows — no-panic on out-of-registry.
  • billable_work_entry_carries_all_12_family_edges — the 12-edge contract.
  • primary_label_is_set_for_concepts_with_a_name_attribute.

Workspace check + workspace test green.

The +5+3 roadmap

docs/integration/CLASSVIEW-MATERIALIZATION-PLAN.md documents the follow-on PR sequence this bridge unblocks:

+5 askama templates (one per artifact kind):

PR Template Target
T1 rust_struct.askama Rust struct + pub const CLASS_ID
T2 ts_interface.askama TypeScript interface + class_ids.ts
T3 surrealql_table.askama SurrealQL DEFINE TABLE
T4 openapi_schema.askama OpenAPI 3.1 component schema
T5 node_guid_routing.askama Rust match arm on ClassId

Each template is small, takes the same (OgarClassView, ClassView_bits, ClassId, FieldMask) context, and no template hardcodes a class name.

+3 consumer wirings:

PR What Repo
C1 op-codegen-projection adopts OgarClassView + askama on the templated paths currently using format! openproject-nexgen-rs
C2 redmine-canon re-exports OgarClassView (no logic; symmetric with the class_ids re-export) redmine-rs
C3 op-surreal-ast::from_class_view adapter — feeds the canonical shape into the byte-identical-pinned typed AST openproject-nexgen-rs

Each lands with three calibration gates: round-trip parse, target-toolchain compile (cargo check / tsc --noEmit / SurrealQL parse), and ClassView drift guard.

Scope note

Bridge crate has no serde and no I/O. It's a pure in-process adapter. The downstream renderers (T1-T5) handle output emission.

Wires the calcified inner shape (ogar_vocab::Class, codebook-keyed) onto the
classview-parameterized outer materialization surface
(lance_graph_contract::ClassView). The seam that unblocks the askama
templating layer the integration plan documents below.

The contract crate (lance-graph-contract::class_view) already supplies
ClassId / FieldMask(u64) / ObjectView / FieldRef / DisplayTemplate +
the ClassView trait (with project / render_rows iterators). What was
missing was the adapter that lifts every promoted ogar_vocab canonical
concept into an ObjectView keyed by canonical_concept_id.

ogar-class-view::OgarClassView is that adapter:
- Walks all 32 promoted class fns (26 project-mgmt + 6 commerce).
- N3 stable field order: typed attributes first (declaration order),
  then family-edge associations (declaration order). Append-only contract.
- ClassId == canonical_concept_id (same u16). Unknown ids project to
  empty field set (no panic).
- DisplayTemplate::Detail default; primary_label set to "name" when the
  class carries a typed `name` attribute.
- dolce_category_id returns 0 (the OGIT cache supplies live DOLCE; this
  adapter sits below it).

Tests (8 / 8 green):
- registry_carries_every_codebook_concept (forward gate).
- every_codebook_id_appears_in_class_ids_all (reverse gate against the
  class_ids::ALL pin).
- field_basis_fits_in_one_u64_mask (FieldMask::MAX_FIELDS=64; widest
  promoted class is well under).
- field_order_is_attributes_then_associations (N3 pin).
- render_rows_skips_off_bits_under_a_real_mask (the askama input path).
- unknown_class_id_projects_to_no_rows (no-panic on out-of-registry).
- billable_work_entry_carries_all_12_family_edges (the 12-edge contract).
- primary_label_is_set_for_concepts_with_a_name_attribute.

Workspace check + workspace test green. No new runtime deps beyond
lance-graph-contract (zero-dep at runtime; serde_yaml is build-only).

Also adds docs/integration/CLASSVIEW-MATERIALIZATION-PLAN.md documenting
the +5+3 follow-on roadmap (5 askama templates + 3 consumer wirings) that
this bridge unblocks.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37989e7542

ℹ️ 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".

/// downstream consumers that want to iterate every class (e.g. emit
/// one Rust struct per class).
pub fn known_class_ids(&self) -> impl Iterator<Item = ClassId> + '_ {
self.by_id.keys().copied()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return class ids in a stable order

When downstream renderers use known_class_ids() to emit all class materializations, this iterator inherits HashMap's randomized iteration order, so the generated structs/interfaces or drift-guard snapshots can reorder across process runs without any schema change. Since the public API is documented for bulk emission, return ids from a stable source such as class_ids::ALL, a sorted Vec, or a BTreeMap instead.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in follow-up #79known_class_ids() now iterates ogar_vocab::class_ids::ALL in codebook order with a regression test pinning both stability and second-call-equals-first.

@AdaWorldAPI AdaWorldAPI merged commit 5fd4359 into main Jun 19, 2026
1 check passed
AdaWorldAPI pushed a commit that referenced this pull request Jun 19, 2026
Adds the build-time askama codegen harness over the calcified canonical
layer. Structurally a mirror of AdaWorldAPI/woa-rs crates/codegen
(RFC-v02-006): the same shape WoA-rs uses for its route codegen, but the
typed input is ogar_vocab::Class instead of a JSON-loaded RouteSpec.

The kit:
- enum ArtifactKind { RustStruct, TsInterface, SurrealqlTable,
  OpenapiSchema, NodeGuidRoutingArm } — append-only.
- trait ArtifactEmitter — one fn `emit(spec) -> Result<String, askama::Error>`.
- artifact_kinds::for_kind(kind) -> Box<dyn ArtifactEmitter> — dispatcher.
- templates/dispatch/<kind>.askama — one template per kind, no class name
  ever hardcoded.

Phase-0 (this PR):
- ArtifactKind::RustStruct: REAL emitter + template. Renders a Rust
  struct + `pub const CLASS_ID: u16` + family-edge fields from the
  canonical class, mapping Rails-side type names to coarse Rust types
  (downstream consumers specialise per their precision needs).
- The other 4 kinds: Stub emitter — compilable, emits a marker comment,
  exercises the full pipeline (lookup + dispatch + return) before the
  concrete templates land.

The 800 -> 7-70 collapse: adding a new canonical concept costs ZERO new
templates (flows through the existing kit). Adding a new target is one
ArtifactKind variant + one askama template; every promoted concept emits
through it automatically.

Decoupled from ogar-class-view (PR #77):
- ogar-render-askama is BUILD-TIME (consumes Class, emits source files).
- ogar-class-view is RUN-TIME (resolves SoA rows through ClassView trait
  to render rows for live projection).
Both pipelines are askama-templated; both share the N3 field order
convention; they consume different shapes — they don't compete.

A2UI integration (AdaWorldAPI/A2UI v0.8) carried as T6 on the roadmap
only — same northstar from the output side, deferred. DUSK_Solution /
MUIBridge noted as design lineage, no active deps.

Tests: 6/6 unit + 1 doctest (ignored — askama derive). Workspace check
and workspace test green.
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