diff --git a/Cargo.lock b/Cargo.lock index 76a70bcb..fc756cf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4915,7 +4915,6 @@ dependencies = [ "futures", "lance", "lance-graph-contract", - "ogar-vocab", "once_cell", "oxrdf", "oxrdfxml", @@ -6000,11 +5999,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "ogar-vocab" -version = "0.1.0" -source = "git+https://github.com/AdaWorldAPI/OGAR?branch=main#19a6886eda1761d2b8f8d1b9a8397549877b0711" - [[package]] name = "once_cell" version = "1.21.4" diff --git a/crates/lance-graph-ogar/Cargo.toml b/crates/lance-graph-ogar/Cargo.toml index 3713c4c3..a076c598 100644 --- a/crates/lance-graph-ogar/Cargo.toml +++ b/crates/lance-graph-ogar/Cargo.toml @@ -72,6 +72,12 @@ serde = ["ogar-vocab/serde", "ogar-adapter-surrealql/serde"] # folds ogar-class-view's transitive git contract onto it = ONE source. lance-graph-contract = { path = "../lance-graph-contract" } +# OGIT spine (the NamespaceBridge trait + registry + namespace/error types the +# OGAR-driven port bridges build on). The OGIT/OGAR seam: the bridges live HERE +# (OGAR) because they couple to ogar-vocab; the trait + registry they implement +# against live in lance-graph-ontology (OGIT). OGIT does NOT depend on OGAR. +lance-graph-ontology = { path = "../lance-graph-ontology" } + # ── OGAR Active-Record forks: git deps @ main (the canonical superset; matches # symbiont's pins so they resolve to ONE source in the golden image) ── ogar-vocab = { git = "https://github.com/AdaWorldAPI/OGAR", branch = "main" } @@ -89,3 +95,8 @@ ogar-adapter-surrealql = { git = "https://github.com/AdaWorldAPI/OGAR", branch = # the patch (see the CONSUMER REQUIREMENT note in the header). [patch."https://github.com/AdaWorldAPI/lance-graph"] lance-graph-contract = { path = "../lance-graph-contract" } + +[dev-dependencies] +# TTL fixtures for the moved bridge scope-lock / codebook-convergence tests +# stage on-disk via tempfile::tempdir() + std::fs (matches lance-graph-ontology). +tempfile = "3" diff --git a/crates/lance-graph-ontology/src/bridges/medcare_bridge.rs b/crates/lance-graph-ogar/src/bridges/medcare_bridge.rs similarity index 96% rename from crates/lance-graph-ontology/src/bridges/medcare_bridge.rs rename to crates/lance-graph-ogar/src/bridges/medcare_bridge.rs index e561f16b..9b3470fe 100644 --- a/crates/lance-graph-ontology/src/bridges/medcare_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/medcare_bridge.rs @@ -49,11 +49,11 @@ mod tests { //! Healthcare fixtures differ. use super::*; - use crate::bridge::{BridgeError, NamespaceBridge}; - use crate::error::Error; - use crate::namespace::NamespaceId; - use crate::namespace_registry::NamespaceRegistry; - use crate::registry::OntologyRegistry; + use lance_graph_ontology::bridge::{BridgeError, NamespaceBridge}; + use lance_graph_ontology::error::Error; + use lance_graph_ontology::namespace::NamespaceId; + use lance_graph_ontology::namespace_registry::NamespaceRegistry; + use lance_graph_ontology::registry::OntologyRegistry; use ogar_vocab::class_ids; // PortSpec needed in scope for `HealthcarePort::aliases()`. use ogar_vocab::ports::PortSpec; diff --git a/crates/lance-graph-ogar/src/bridges/mod.rs b/crates/lance-graph-ogar/src/bridges/mod.rs new file mode 100644 index 00000000..aec092c6 --- /dev/null +++ b/crates/lance-graph-ogar/src/bridges/mod.rs @@ -0,0 +1,58 @@ +//! OGAR-driven tenant port bridges. +//! +//! This is the OGAR side of the OGIT/OGAR separation (operator, +//! 2026-06-20). These bridges couple to `ogar_vocab::ports` / +//! `ogar_vocab::class_ids` (the OGAR codebook + `PortSpec` class schema), +//! so they live here in `lance-graph-ogar`, NOT in `lance-graph-ontology` +//! (which is OGIT and must not depend on `ogar-vocab`). The OGIT-side +//! legacy bridges (`WoaBridge` / `SpearBridge` / `SharePointBridge` / +//! `OgitBridge`) stay in `lance_graph_ontology::bridges`. +//! +//! # Two layers +//! +//! - The **generic harness** [`unified::UnifiedBridge`] is the +//! one-and-only `lance_graph_ontology::NamespaceBridge` impl for +//! OGAR-driven ports. It inherits everything that varies between ports +//! (`NAMESPACE` / `BRIDGE_ID` / public-name → class_id aliases) from +//! `ogar_vocab::ports::PortSpec`. Adding a port is `impl PortSpec for +//! FooPort {…}` in OGAR — no bridge boilerplate here. +//! - The **per-port aliases** ([`OpenProjectBridge`], [`RedmineBridge`], +//! [`MedcareBridge`]) are thin `type` aliases over the harness. +//! +//! # OGAR-driven ports (`UnifiedBridge

` aliases) +//! +//! - [`OpenProjectBridge`]: `UnifiedBridge` +//! — locks to the `OpenProject` namespace. `WorkPackage` / `TimeEntry` +//! / `Project` etc. resolve to OGAR canonical class_ids via the +//! port's alias table. +//! - [`RedmineBridge`]: `UnifiedBridge` — +//! locks to the `Redmine` namespace. `Issue` / `TimeEntry` / `Project` +//! etc. resolve to the SAME OGAR canonical class_ids as the +//! OpenProject equivalents, so cross-fork convergence is the default +//! not the exception. +//! - [`MedcareBridge`]: `UnifiedBridge` +//! — locks to the `Healthcare` namespace. `Patient` / `Diagnosis` / +//! `LabValue` / `Medication` / `Treatment` / `Visit` / `VitalSign` +//! resolve to the `0x09XX` Health codebook (Northstar T9). + +pub mod unified; + +mod medcare_bridge; +mod openproject_bridge; +mod redmine_bridge; + +pub use medcare_bridge::{HealthcarePort, MedcareBridge}; +pub use openproject_bridge::{OpenProjectBridge, OpenProjectPort}; +pub use redmine_bridge::{RedmineBridge, RedminePort}; +pub use unified::UnifiedBridge; + +// Compatibility shims for the pre-migration constants. `bridges` +// previously re-exported `OPENPROJECT_CODEBOOK` / `REDMINE_CODEBOOK` +// directly; both now live in `ogar_vocab::ports::*_ALIASES` (the +// canonical layer is the single source of truth). The re-exports here +// are `#[deprecated]` in the per-port modules and forward to the OGAR +// constants — existing consumers keep compiling (codex P2 on PR #570). +#[allow(deprecated)] +pub use openproject_bridge::OPENPROJECT_CODEBOOK; +#[allow(deprecated)] +pub use redmine_bridge::REDMINE_CODEBOOK; diff --git a/crates/lance-graph-ontology/src/bridges/openproject_bridge.rs b/crates/lance-graph-ogar/src/bridges/openproject_bridge.rs similarity index 95% rename from crates/lance-graph-ontology/src/bridges/openproject_bridge.rs rename to crates/lance-graph-ogar/src/bridges/openproject_bridge.rs index a9de0116..5cfdb166 100644 --- a/crates/lance-graph-ontology/src/bridges/openproject_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/openproject_bridge.rs @@ -49,11 +49,11 @@ mod tests { //! `UnifiedBridge` instead of a local struct. use super::*; - use crate::bridge::{BridgeError, NamespaceBridge}; - use crate::error::Error; - use crate::namespace::NamespaceId; - use crate::namespace_registry::NamespaceRegistry; - use crate::registry::OntologyRegistry; + use lance_graph_ontology::bridge::{BridgeError, NamespaceBridge}; + use lance_graph_ontology::error::Error; + use lance_graph_ontology::namespace::NamespaceId; + use lance_graph_ontology::namespace_registry::NamespaceRegistry; + use lance_graph_ontology::registry::OntologyRegistry; use ogar_vocab::class_ids; // PortSpec needed in scope for `OpenProjectPort::aliases()` (the // method is a trait item — codex P1 on PR #570). diff --git a/crates/lance-graph-ontology/src/bridges/redmine_bridge.rs b/crates/lance-graph-ogar/src/bridges/redmine_bridge.rs similarity index 95% rename from crates/lance-graph-ontology/src/bridges/redmine_bridge.rs rename to crates/lance-graph-ogar/src/bridges/redmine_bridge.rs index fbb8ced5..573136f2 100644 --- a/crates/lance-graph-ontology/src/bridges/redmine_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/redmine_bridge.rs @@ -35,11 +35,11 @@ pub const REDMINE_CODEBOOK: &[(&str, u16)] = ogar_vocab::ports::REDMINE_ALIASES; #[cfg(test)] mod tests { use super::*; - use crate::bridge::{BridgeError, NamespaceBridge}; - use crate::error::Error; - use crate::namespace::NamespaceId; - use crate::namespace_registry::NamespaceRegistry; - use crate::registry::OntologyRegistry; + use lance_graph_ontology::bridge::{BridgeError, NamespaceBridge}; + use lance_graph_ontology::error::Error; + use lance_graph_ontology::namespace::NamespaceId; + use lance_graph_ontology::namespace_registry::NamespaceRegistry; + use lance_graph_ontology::registry::OntologyRegistry; use ogar_vocab::class_ids; // PortSpec needed in scope for `RedminePort::aliases()` (the method // is a trait item — codex P1 on PR #570). diff --git a/crates/lance-graph-ontology/src/bridges/unified.rs b/crates/lance-graph-ogar/src/bridges/unified.rs similarity index 97% rename from crates/lance-graph-ontology/src/bridges/unified.rs rename to crates/lance-graph-ogar/src/bridges/unified.rs index 80f9ab38..ba485a28 100644 --- a/crates/lance-graph-ontology/src/bridges/unified.rs +++ b/crates/lance-graph-ogar/src/bridges/unified.rs @@ -45,11 +45,11 @@ //! `P::NAMESPACE`), so downstream context-based routing can //! distinguish per-port data from the default (unbound) context. -use crate::bridge::{BridgeError, BridgeFromRegistry, EntityRef, NamespaceBridge}; -use crate::error::{Error, Result}; -use crate::namespace::{NamespaceId, OgitUri, SchemaKind, SchemaPtr}; -use crate::namespace_registry::NamespaceRegistry; -use crate::registry::OntologyRegistry; +use lance_graph_ontology::bridge::{BridgeError, BridgeFromRegistry, EntityRef, NamespaceBridge}; +use lance_graph_ontology::error::{Error, Result}; +use lance_graph_ontology::namespace::{NamespaceId, OgitUri, SchemaKind, SchemaPtr}; +use lance_graph_ontology::namespace_registry::NamespaceRegistry; +use lance_graph_ontology::registry::OntologyRegistry; use ogar_vocab::ports::PortSpec; use std::marker::PhantomData; use std::sync::Arc; diff --git a/crates/lance-graph-ogar/src/lib.rs b/crates/lance-graph-ogar/src/lib.rs index c2278fd4..280ba178 100644 --- a/crates/lance-graph-ogar/src/lib.rs +++ b/crates/lance-graph-ogar/src/lib.rs @@ -78,6 +78,15 @@ pub use ogar_class_view::OgarClassView; /// The calcified canonical AR shape (attributes + family `Association`s). pub use ogar_vocab::Class; +// ── OGAR-driven tenant port bridges (moved out of lance-graph-ontology, +// which is OGIT and must not depend on ogar-vocab) ── +pub mod bridges; + +pub use bridges::{ + HealthcarePort, MedcareBridge, OpenProjectBridge, OpenProjectPort, RedmineBridge, RedminePort, + UnifiedBridge, +}; + /// Codebook parity-guard — the drift fuse between OGAR's authoritative codebook /// (`ogar_vocab::class_ids::ALL`) and the contract's zero-dep wire mirror /// (`lance_graph_contract::ogar_codebook::CODEBOOK`). Two depths so it cannot be diff --git a/crates/lance-graph-ontology/tests/bridge_codebook_convergence.rs b/crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs similarity index 98% rename from crates/lance-graph-ontology/tests/bridge_codebook_convergence.rs rename to crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs index 4f02d914..aaa78c46 100644 --- a/crates/lance-graph-ontology/tests/bridge_codebook_convergence.rs +++ b/crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs @@ -18,7 +18,7 @@ //! `REDMINE_CODEBOOK`) keyed off the shared //! `lance_graph_ontology::bridges::codebook::*` constants. -use lance_graph_ontology::bridges::{OpenProjectBridge, RedmineBridge}; +use lance_graph_ogar::bridges::{OpenProjectBridge, RedmineBridge}; use ogar_vocab::class_ids as codebook; use lance_graph_ontology::{NamespaceBridge, OntologyRegistry}; use std::fs; diff --git a/crates/lance-graph-ontology/tests/bridge_scope_lock.rs b/crates/lance-graph-ogar/tests/bridge_scope_lock.rs similarity index 98% rename from crates/lance-graph-ontology/tests/bridge_scope_lock.rs rename to crates/lance-graph-ogar/tests/bridge_scope_lock.rs index b4b71a8f..75bfcc06 100644 --- a/crates/lance-graph-ontology/tests/bridge_scope_lock.rs +++ b/crates/lance-graph-ogar/tests/bridge_scope_lock.rs @@ -11,7 +11,8 @@ //! or `BridgeError::NotInScope` (the latter when the namespace itself is //! present but the public name was filed under a different bridge id). -use lance_graph_ontology::bridges::{MedcareBridge, OgitBridge, WoaBridge}; +use lance_graph_ogar::bridges::MedcareBridge; +use lance_graph_ontology::bridges::{OgitBridge, WoaBridge}; use lance_graph_ontology::{NamespaceBridge, OgitUri, OntologyRegistry}; use std::fs; use std::sync::Arc; diff --git a/crates/lance-graph-ontology/tests/openproject_bridge_scope_lock.rs b/crates/lance-graph-ogar/tests/openproject_bridge_scope_lock.rs similarity index 98% rename from crates/lance-graph-ontology/tests/openproject_bridge_scope_lock.rs rename to crates/lance-graph-ogar/tests/openproject_bridge_scope_lock.rs index 84675d01..36905130 100644 --- a/crates/lance-graph-ontology/tests/openproject_bridge_scope_lock.rs +++ b/crates/lance-graph-ogar/tests/openproject_bridge_scope_lock.rs @@ -11,7 +11,7 @@ //! Woa/Medcare pair — symmetric coverage so the addition can't //! silently relax the scope-lock guarantee. -use lance_graph_ontology::bridges::{MedcareBridge, OpenProjectBridge}; +use lance_graph_ogar::bridges::{MedcareBridge, OpenProjectBridge}; use lance_graph_ontology::{NamespaceBridge, OgitUri, OntologyRegistry}; use std::fs; use std::sync::Arc; diff --git a/crates/lance-graph-ontology/tests/redmine_bridge_scope_lock.rs b/crates/lance-graph-ogar/tests/redmine_bridge_scope_lock.rs similarity index 98% rename from crates/lance-graph-ontology/tests/redmine_bridge_scope_lock.rs rename to crates/lance-graph-ogar/tests/redmine_bridge_scope_lock.rs index ad9727f0..505653b0 100644 --- a/crates/lance-graph-ontology/tests/redmine_bridge_scope_lock.rs +++ b/crates/lance-graph-ogar/tests/redmine_bridge_scope_lock.rs @@ -9,7 +9,7 @@ //! cross-fork convergence (pinned in `bridge_codebook_convergence.rs`) //! lands on a substrate that refuses cross-namespace leaks by default. -use lance_graph_ontology::bridges::{OpenProjectBridge, RedmineBridge}; +use lance_graph_ogar::bridges::{OpenProjectBridge, RedmineBridge}; use lance_graph_ontology::{NamespaceBridge, OgitUri, OntologyRegistry}; use std::fs; use std::sync::Arc; diff --git a/crates/lance-graph-ontology/Cargo.toml b/crates/lance-graph-ontology/Cargo.toml index fee493b9..fe1e4bf1 100644 --- a/crates/lance-graph-ontology/Cargo.toml +++ b/crates/lance-graph-ontology/Cargo.toml @@ -11,19 +11,6 @@ keywords = ["ontology", "ogit", "ttl", "rdf", "lance"] # / SchemaExpander. Zero-dep crate by design — we depend on it, not the reverse. lance-graph-contract = { path = "../lance-graph-contract" } -# Canonical class schema (codebook + Class fns + PortSpec). The -# `UnifiedBridge` harness in `crate::bridges::unified` is -# parameterised by `ogar_vocab::ports::PortSpec`, so per-port bridges -# (OpenProjectBridge, RedmineBridge, …) are type aliases over the -# harness — the namespace / bridge_id / public-name-alias data all -# come from OGAR class schema, not from this crate. -# OGAR `main` carries `ports::PortSpec` + the project-mgmt ports AND the -# `HealthcarePort` + 0x09XX Health codebook that -# `MedcareBridge = UnifiedBridge` needs (OGAR #91 merged). -# Tracks `main`, matching the sibling `lance-graph-ogar` / `cognitive-stack` -# / `symbiont` pins — one OGAR source for the whole graph. -ogar-vocab = { git = "https://github.com/AdaWorldAPI/OGAR", branch = "main" } - # TTL parser. oxttl is the smallest streaming Turtle parser in the workspace's # dependency graph and matches the shape of OGIT's per-entity .ttl files. # Pinned to the same oxrdf version as oxrdfxml below — duplicate-version diff --git a/crates/lance-graph-ontology/src/bridges/mod.rs b/crates/lance-graph-ontology/src/bridges/mod.rs index a917bfe3..636db1b4 100644 --- a/crates/lance-graph-ontology/src/bridges/mod.rs +++ b/crates/lance-graph-ontology/src/bridges/mod.rs @@ -1,38 +1,15 @@ -//! Default tenant bridge implementations. +//! Default tenant bridge implementations (OGIT side). //! -//! # Two layers +//! These are the **legacy per-tenant bridges** with a bespoke struct +//! shape, locked to one OGIT namespace each and routing resolution +//! through the shared registry. They predate OGAR's codebook and have +//! no `PortSpec` impl in `ogar-vocab::ports`. //! -//! - The **generic harness** [`unified::UnifiedBridge`] is -//! the one-and-only NamespaceBridge impl for OGAR-driven ports. It -//! inherits everything that varies between ports -//! (`NAMESPACE` / `BRIDGE_ID` / public-name → class_id aliases) from -//! [`ogar_vocab::ports::PortSpec`]. Adding a port is `impl PortSpec -//! for FooPort {…}` in OGAR — no bridge boilerplate here. -//! - The **legacy per-tenant bridges** ([`WoaBridge`], [`SpearBridge`], -//! [`SharePointBridge`], [`OgitBridge`]) keep their bespoke struct -//! shape for now. They predate OGAR's codebook and don't yet have a -//! `PortSpec` impl in `ogar-vocab::ports`. When the WorkOrder / -//! EmailCorrespondance / SharePoint namespaces get promoted into the -//! codebook, these collapse the same way OpenProject, Redmine, and -//! MedCare already did. -//! -//! # OGAR-driven ports (`UnifiedBridge

` aliases) -//! -//! - [`OpenProjectBridge`]: `UnifiedBridge` -//! — locks to the `OpenProject` namespace. `WorkPackage` / `TimeEntry` -//! / `Project` etc. resolve to OGAR canonical class_ids via the -//! port's alias table. -//! - [`RedmineBridge`]: `UnifiedBridge` — -//! locks to the `Redmine` namespace. `Issue` / `TimeEntry` / `Project` -//! etc. resolve to the SAME OGAR canonical class_ids as the -//! OpenProject equivalents, so cross-fork convergence is the default -//! not the exception. -//! - [`MedcareBridge`]: `UnifiedBridge` -//! — locks to the `Healthcare` namespace. `Patient` / `Diagnosis` / -//! `LabValue` / `Medication` / `Treatment` / `Visit` / `VitalSign` -//! resolve to the `0x09XX` Health codebook (Northstar T9). Single- -//! tenant today; a future FMA / SNOMED curator converges on the same -//! ids. +//! The OGAR-driven port bridges (the generic `UnifiedBridge` +//! harness and its `OpenProjectBridge` / `RedmineBridge` / `MedcareBridge` +//! aliases) live in the `lance-graph-ogar` crate (`lance_graph_ogar::bridges`) +//! — they couple to `ogar_vocab::ports` / `ogar_vocab::class_ids`, which is +//! OGAR, not OGIT. This crate (OGIT) must not depend on `ogar-vocab`. //! //! # Per-tenant bridges (legacy struct shape) //! @@ -48,32 +25,12 @@ //! its own auth + per-customer scoping concerns that need a separate //! design pass. -pub mod unified; - -mod medcare_bridge; mod ogit_bridge; -mod openproject_bridge; -mod redmine_bridge; mod sharepoint_bridge; mod spear_bridge; mod woa_bridge; -pub use medcare_bridge::{HealthcarePort, MedcareBridge}; pub use ogit_bridge::OgitBridge; -pub use openproject_bridge::{OpenProjectBridge, OpenProjectPort}; -pub use redmine_bridge::{RedmineBridge, RedminePort}; pub use sharepoint_bridge::SharePointBridge; pub use spear_bridge::SpearBridge; -pub use unified::UnifiedBridge; pub use woa_bridge::WoaBridge; - -// Compatibility shims for the pre-migration constants. `bridges` -// previously re-exported `OPENPROJECT_CODEBOOK` / `REDMINE_CODEBOOK` -// directly; both now live in `ogar_vocab::ports::*_ALIASES` (the -// canonical layer is the single source of truth). The re-exports here -// are `#[deprecated]` in the per-port modules and forward to the OGAR -// constants — existing consumers keep compiling (codex P2 on PR #570). -#[allow(deprecated)] -pub use openproject_bridge::OPENPROJECT_CODEBOOK; -#[allow(deprecated)] -pub use redmine_bridge::REDMINE_CODEBOOK; diff --git a/crates/lance-graph-ontology/src/lib.rs b/crates/lance-graph-ontology/src/lib.rs index f9050598..21407fe3 100644 --- a/crates/lance-graph-ontology/src/lib.rs +++ b/crates/lance-graph-ontology/src/lib.rs @@ -17,8 +17,9 @@ //! - [`NamespaceBridge`] is the trait every tenant bridge implements. Default //! methods do the heavy lifting: a typical tenant bridge is ~15-20 lines //! that lock to one namespace and route resolution through the shared -//! registry. See [`bridges::WoaBridge`], [`bridges::MedcareBridge`], -//! [`bridges::OgitBridge`]. +//! registry. See [`bridges::WoaBridge`], [`bridges::OgitBridge`]. The +//! OGAR-driven port bridges (OpenProject / Redmine / MedCare) live in +//! the `lance-graph-ogar` crate (OGAR), not here (OGIT). //! - [`MappingProposal`] is the producer-side DTO. TTL hydration emits //! proposals; schema scanners (MySQL/MSSQL, future) and customer admin //! forms emit proposals; everything funnels through one append path.