From 10e717d4af0374ad96978bab416c8d31ac9691e8 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 22 Jun 2026 17:11:19 +0000 Subject: [PATCH] docs+deprecate(bridges): preemptive landing shape for OGAR consumer migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `#[deprecated(note = "...")]` to every consumer-facing tenant bridge, pointing each at its OGAR PortSpec replacement. Symbols still compile; nothing removed. Companion to AdaWorldAPI/OGAR#95 (APP‖class codebook layout + per-app migration plan). Deprecated: - lance-graph-ogar::bridges — 6 per-port aliases: OpenProjectBridge, RedmineBridge, MedcareBridge, WoaBridge, SmbBridge, OdooBridge → pull via the corresponding `ogar_vocab::ports::*Port::class_id(name)` - lance-graph-ontology::bridges — 4 legacy structs: OgitBridge, WoaBridge, SpearBridge, SharePointBridge → pull via the relevant PortSpec (Spear/SharePoint require authoring a port first) NOT deprecated: the `UnifiedBridge

` harness (impl mechanism), the `*Port` types (the replacement), the OPENPROJECT_CODEBOOK / REDMINE_CODEBOOK constants (already deprecated in PR #570). Existing call sites (tests + the consumer-conformance harness) carry `#[allow(deprecated)]` so the build stays clean. cargo check green on both crates; pre-existing dead-code warnings on the `NAMESPACE` constants are unrelated. Scope this PR does NOT cover (explicitly flagged in docs/CONSUMER-BRIDGE-DEPRECATION.md, surfaced by parallel sessions): - lance-graph-rbac has no `authorize(actor, classid, op)` keystone yet. The keystone is `[H]` and gated on PROBE-OGAR-RBAC-AUTHORIZE (OGAR spec). It lands as its own PR after the probe runs green. Until then, consumers migrate the classid pull only and keep existing auth — do NOT reintroduce a bridge as an auth stopgap. - `Membership` / `Op` types not yet defined. Consumer status snapshot (`git grep` 2026-06-22): MedCare-rs: 33 files · woa-rs: 6 · smb-office-rs: 4 · odoo-rs: 0 ✓ · openproject-nexgen-rs: 0 ✓ Terminal `bridges/` deletion PR opens only after the three remaining consumers ship their migrations. No removal window announced. Co-Authored-By: Claude Opus 4.7 Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP --- .../src/lib.rs | 5 + .../src/bridges/medcare_bridge.rs | 8 + .../src/bridges/odoo_bridge.rs | 8 + .../src/bridges/openproject_bridge.rs | 9 + .../src/bridges/redmine_bridge.rs | 8 + .../src/bridges/smb_bridge.rs | 8 + .../src/bridges/woa_bridge.rs | 8 + crates/lance-graph-ogar/src/lib.rs | 13 +- .../tests/bridge_codebook_convergence.rs | 4 + .../tests/bridge_scope_lock.rs | 3 + .../tests/openproject_bridge_scope_lock.rs | 3 + .../tests/redmine_bridge_scope_lock.rs | 3 + .../lance-graph-ontology/src/bridges/mod.rs | 7 + .../src/bridges/ogit_bridge.rs | 6 + .../src/bridges/sharepoint_bridge.rs | 8 + .../src/bridges/spear_bridge.rs | 8 + .../src/bridges/woa_bridge.rs | 8 + .../tests/hydrate_real_ogit.rs | 3 + .../tests/round_trip_ttl.rs | 3 + docs/CONSUMER-BRIDGE-DEPRECATION.md | 171 ++++++++++++++++++ 20 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 docs/CONSUMER-BRIDGE-DEPRECATION.md diff --git a/crates/lance-graph-consumer-conformance/src/lib.rs b/crates/lance-graph-consumer-conformance/src/lib.rs index 6d184cb0e..3843b150a 100644 --- a/crates/lance-graph-consumer-conformance/src/lib.rs +++ b/crates/lance-graph-consumer-conformance/src/lib.rs @@ -1,3 +1,8 @@ +// Exercises the deprecated `MedcareBridge` / `OgitBridge` / `WoaBridge` +// symbols on purpose — this harness IS the conformance gate for them. +// See `docs/CONSUMER-BRIDGE-DEPRECATION.md`. +#![allow(deprecated)] + //! `lance-graph-consumer-conformance` — cross-crate registry conformance harness. //! //! This crate is the CI gate that prevents a consumer crate from shipping a diff --git a/crates/lance-graph-ogar/src/bridges/medcare_bridge.rs b/crates/lance-graph-ogar/src/bridges/medcare_bridge.rs index 7c8c74120..9ff1b6894 100644 --- a/crates/lance-graph-ogar/src/bridges/medcare_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/medcare_bridge.rs @@ -33,6 +33,13 @@ use ogar_vocab::ports::PortSpec; /// MedCare `NamespaceBridge` — alias over the generic harness, locked to /// the `Healthcare` namespace via [`HealthcarePort`]. +/// +/// **Deprecated:** pull the classid via the OGAR PortSpec instead — +/// `ogar_vocab::ports::HealthcarePort::class_id(name)`. See +/// `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[deprecated( + note = "pull the classid via `HealthcarePort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub type MedcareBridge = UnifiedBridge; /// Canonical namespace name for MedCare / Healthcare. Mirrors @@ -41,6 +48,7 @@ pub type MedcareBridge = UnifiedBridge; pub const NAMESPACE: &str = HealthcarePort::NAMESPACE; #[cfg(test)] +#[allow(deprecated)] // exercises the deprecated bridge alias on purpose mod tests { //! Co-located unit tests for the migrated alias — constructor //! success/failure, contract methods, codebook resolution, fallback diff --git a/crates/lance-graph-ogar/src/bridges/odoo_bridge.rs b/crates/lance-graph-ogar/src/bridges/odoo_bridge.rs index 5dc7381c0..6e125e842 100644 --- a/crates/lance-graph-ogar/src/bridges/odoo_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/odoo_bridge.rs @@ -25,12 +25,20 @@ use ogar_vocab::ports::PortSpec; /// Odoo `NamespaceBridge` — alias over the generic harness, locked to /// the `Odoo` namespace via [`OdooPort`]. +/// +/// **Deprecated:** pull the classid via the OGAR PortSpec instead — +/// `ogar_vocab::ports::OdooPort::class_id(name)`. See +/// `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[deprecated( + note = "pull the classid via `OdooPort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub type OdooBridge = UnifiedBridge; /// Canonical namespace name for Odoo. Mirrors `OdooPort::NAMESPACE`. pub const NAMESPACE: &str = OdooPort::NAMESPACE; #[cfg(test)] +#[allow(deprecated)] // exercises the deprecated bridge alias on purpose mod tests { use super::*; use lance_graph_ontology::bridge::{BridgeError, NamespaceBridge}; diff --git a/crates/lance-graph-ogar/src/bridges/openproject_bridge.rs b/crates/lance-graph-ogar/src/bridges/openproject_bridge.rs index cf40d6cc3..f7c3e5c1d 100644 --- a/crates/lance-graph-ogar/src/bridges/openproject_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/openproject_bridge.rs @@ -22,6 +22,14 @@ pub use ogar_vocab::ports::OpenProjectPort; use ogar_vocab::ports::PortSpec; /// OpenProject `NamespaceBridge` — alias over the generic harness. +/// +/// **Deprecated:** pull the classid via the OGAR PortSpec instead — +/// `ogar_vocab::ports::OpenProjectPort::class_id(name)`. The bridge will +/// be removed once all consumers migrate. See +/// `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[deprecated( + note = "pull the classid via `OpenProjectPort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub type OpenProjectBridge = UnifiedBridge; /// Canonical namespace name for OpenProject. Mirrors @@ -41,6 +49,7 @@ pub const NAMESPACE: &str = OpenProjectPort::NAMESPACE; pub const OPENPROJECT_CODEBOOK: &[(&str, u16)] = ogar_vocab::ports::OPENPROJECT_ALIASES; #[cfg(test)] +#[allow(deprecated)] // exercises the deprecated bridge alias on purpose mod tests { //! Co-located unit tests retained from the pre-migration shape — //! constructor success/failure, contract methods, codebook diff --git a/crates/lance-graph-ogar/src/bridges/redmine_bridge.rs b/crates/lance-graph-ogar/src/bridges/redmine_bridge.rs index 573136f26..e4ae957d0 100644 --- a/crates/lance-graph-ogar/src/bridges/redmine_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/redmine_bridge.rs @@ -17,6 +17,13 @@ use ogar_vocab::ports::PortSpec; pub use ogar_vocab::ports::RedminePort; /// Redmine `NamespaceBridge` — alias over the generic harness. +/// +/// **Deprecated:** pull the classid via the OGAR PortSpec instead — +/// `ogar_vocab::ports::RedminePort::class_id(name)`. See +/// `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[deprecated( + note = "pull the classid via `RedminePort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub type RedmineBridge = UnifiedBridge; /// Canonical namespace name for Redmine. Mirrors `RedminePort::NAMESPACE` @@ -33,6 +40,7 @@ pub const NAMESPACE: &str = RedminePort::NAMESPACE; pub const REDMINE_CODEBOOK: &[(&str, u16)] = ogar_vocab::ports::REDMINE_ALIASES; #[cfg(test)] +#[allow(deprecated)] // exercises the deprecated bridge alias on purpose mod tests { use super::*; use lance_graph_ontology::bridge::{BridgeError, NamespaceBridge}; diff --git a/crates/lance-graph-ogar/src/bridges/smb_bridge.rs b/crates/lance-graph-ogar/src/bridges/smb_bridge.rs index da4bbbcc0..c9d726be7 100644 --- a/crates/lance-graph-ogar/src/bridges/smb_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/smb_bridge.rs @@ -24,12 +24,20 @@ pub use ogar_vocab::ports::SmbPort; /// SMB `NamespaceBridge` — alias over the generic harness, locked to /// the `SMB` namespace via [`SmbPort`]. +/// +/// **Deprecated:** pull the classid via the OGAR PortSpec instead — +/// `ogar_vocab::ports::SmbPort::class_id(name)`. See +/// `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[deprecated( + note = "pull the classid via `SmbPort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub type SmbBridge = UnifiedBridge; /// Canonical namespace name for SMB. Mirrors `SmbPort::NAMESPACE`. pub const NAMESPACE: &str = SmbPort::NAMESPACE; #[cfg(test)] +#[allow(deprecated)] // exercises the deprecated bridge alias on purpose mod tests { use super::*; use lance_graph_ontology::bridge::{BridgeError, NamespaceBridge}; diff --git a/crates/lance-graph-ogar/src/bridges/woa_bridge.rs b/crates/lance-graph-ogar/src/bridges/woa_bridge.rs index 7b0c29b74..bef4fd34c 100644 --- a/crates/lance-graph-ogar/src/bridges/woa_bridge.rs +++ b/crates/lance-graph-ogar/src/bridges/woa_bridge.rs @@ -31,12 +31,20 @@ pub use ogar_vocab::ports::WoaPort; /// WoA `NamespaceBridge` — alias over the generic harness, locked to /// the `WorkOrder` namespace via [`WoaPort`]. +/// +/// **Deprecated:** pull the classid via the OGAR PortSpec instead — +/// `ogar_vocab::ports::WoaPort::class_id(name)`. See +/// `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[deprecated( + note = "pull the classid via `WoaPort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub type WoaBridge = UnifiedBridge; /// Canonical namespace name for WoA. Mirrors `WoaPort::NAMESPACE`. pub const NAMESPACE: &str = WoaPort::NAMESPACE; #[cfg(test)] +#[allow(deprecated)] // exercises the deprecated bridge alias on purpose mod tests { use super::*; use lance_graph_ontology::bridge::{BridgeError, NamespaceBridge}; diff --git a/crates/lance-graph-ogar/src/lib.rs b/crates/lance-graph-ogar/src/lib.rs index 280ba1780..45a788023 100644 --- a/crates/lance-graph-ogar/src/lib.rs +++ b/crates/lance-graph-ogar/src/lib.rs @@ -82,9 +82,18 @@ pub use ogar_vocab::Class; // which is OGIT and must not depend on ogar-vocab) ── pub mod bridges; +// Per-port bridge aliases (`MedcareBridge` / `OpenProjectBridge` / +// `RedmineBridge` / `OdooBridge` / `SmbBridge` / `WoaBridge`) are +// `#[deprecated]` (2026-06-22) — pull the classid via the corresponding +// PortSpec instead. The `Port` types and `UnifiedBridge` harness are +// NOT deprecated. See `docs/CONSUMER-BRIDGE-DEPRECATION.md` + +// AdaWorldAPI/OGAR#95. pub use bridges::{ - HealthcarePort, MedcareBridge, OpenProjectBridge, OpenProjectPort, RedmineBridge, RedminePort, - UnifiedBridge, + HealthcarePort, OdooPort, OpenProjectPort, RedminePort, SmbPort, UnifiedBridge, WoaPort, +}; +#[allow(deprecated)] +pub use bridges::{ + MedcareBridge, OdooBridge, OpenProjectBridge, RedmineBridge, SmbBridge, WoaBridge, }; /// Codebook parity-guard — the drift fuse between OGAR's authoritative codebook diff --git a/crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs b/crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs index 7fd0deedf..85c708f9c 100644 --- a/crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs +++ b/crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs @@ -1,6 +1,10 @@ // Skip under Miri — TTL fixtures use `tempfile::tempdir()` + // `std::fs::create_dir_all/write`, both blocked by Miri's isolation. #![cfg(not(miri))] +// Exercises the deprecated `OpenProjectBridge` / `RedmineBridge` aliases on +// purpose — the convergence pin is what we're testing. See +// `docs/CONSUMER-BRIDGE-DEPRECATION.md`. +#![allow(deprecated)] //! Bridge codebook convergence test — codex P1 on PR #559. //! diff --git a/crates/lance-graph-ogar/tests/bridge_scope_lock.rs b/crates/lance-graph-ogar/tests/bridge_scope_lock.rs index 75bfcc068..d2b985aaa 100644 --- a/crates/lance-graph-ogar/tests/bridge_scope_lock.rs +++ b/crates/lance-graph-ogar/tests/bridge_scope_lock.rs @@ -3,6 +3,9 @@ // isolation blocks `mkdir`/`open`. Stable and nightly without Miri run it // normally. #![cfg(not(miri))] +// Exercises the deprecated bridge aliases on purpose — see +// `docs/CONSUMER-BRIDGE-DEPRECATION.md`. +#![allow(deprecated)] //! Bridge scope-lock test. //! diff --git a/crates/lance-graph-ogar/tests/openproject_bridge_scope_lock.rs b/crates/lance-graph-ogar/tests/openproject_bridge_scope_lock.rs index 369051302..2a6c045c7 100644 --- a/crates/lance-graph-ogar/tests/openproject_bridge_scope_lock.rs +++ b/crates/lance-graph-ogar/tests/openproject_bridge_scope_lock.rs @@ -1,6 +1,9 @@ // Skip under Miri — TTL fixtures use `tempfile::tempdir()` + // `std::fs::create_dir_all/write`, both blocked by Miri's isolation. #![cfg(not(miri))] +// Exercises the deprecated `OpenProjectBridge` alias on purpose — see +// `docs/CONSUMER-BRIDGE-DEPRECATION.md`. +#![allow(deprecated)] //! `OpenProjectBridge` scope-lock test — Northstar plan §3 C4. //! diff --git a/crates/lance-graph-ogar/tests/redmine_bridge_scope_lock.rs b/crates/lance-graph-ogar/tests/redmine_bridge_scope_lock.rs index 505653b0d..8409a0d75 100644 --- a/crates/lance-graph-ogar/tests/redmine_bridge_scope_lock.rs +++ b/crates/lance-graph-ogar/tests/redmine_bridge_scope_lock.rs @@ -1,6 +1,9 @@ // Skip under Miri — TTL fixtures use `tempfile::tempdir()` + // `std::fs::create_dir_all/write`, both blocked by Miri's isolation. #![cfg(not(miri))] +// Exercises the deprecated `RedmineBridge` alias on purpose — see +// `docs/CONSUMER-BRIDGE-DEPRECATION.md`. +#![allow(deprecated)] //! `RedmineBridge` scope-lock test — Northstar plan §3 C5. //! diff --git a/crates/lance-graph-ontology/src/bridges/mod.rs b/crates/lance-graph-ontology/src/bridges/mod.rs index 636db1b41..2c9ed4f44 100644 --- a/crates/lance-graph-ontology/src/bridges/mod.rs +++ b/crates/lance-graph-ontology/src/bridges/mod.rs @@ -30,7 +30,14 @@ mod sharepoint_bridge; mod spear_bridge; mod woa_bridge; +// All four legacy per-tenant bridges are `#[deprecated]` (2026-06-22) — +// consumers should pull the classid via an OGAR PortSpec instead. See +// `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[allow(deprecated)] pub use ogit_bridge::OgitBridge; +#[allow(deprecated)] pub use sharepoint_bridge::SharePointBridge; +#[allow(deprecated)] pub use spear_bridge::SpearBridge; +#[allow(deprecated)] pub use woa_bridge::WoaBridge; diff --git a/crates/lance-graph-ontology/src/bridges/ogit_bridge.rs b/crates/lance-graph-ontology/src/bridges/ogit_bridge.rs index f0fcdc56c..91d75bd0d 100644 --- a/crates/lance-graph-ontology/src/bridges/ogit_bridge.rs +++ b/crates/lance-graph-ontology/src/bridges/ogit_bridge.rs @@ -14,6 +14,12 @@ use crate::namespace::NamespaceId; use crate::registry::OntologyRegistry; use std::sync::Arc; +/// **Deprecated:** pull the classid via the OGAR PortSpec for the +/// relevant namespace (`ogar_vocab::ports::*Port::class_id(name)`). +/// See `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[deprecated( + note = "pull the classid via the OGAR PortSpec for the namespace (e.g. `WoaPort::class_id(name)`) — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub struct OgitBridge { registry: Arc, namespace_name: String, diff --git a/crates/lance-graph-ontology/src/bridges/sharepoint_bridge.rs b/crates/lance-graph-ontology/src/bridges/sharepoint_bridge.rs index 5a57ced3c..bdd9f552e 100644 --- a/crates/lance-graph-ontology/src/bridges/sharepoint_bridge.rs +++ b/crates/lance-graph-ontology/src/bridges/sharepoint_bridge.rs @@ -30,6 +30,14 @@ use std::sync::Arc; pub const NAMESPACE: &str = "SharePoint"; +/// **Deprecated:** no OGAR PortSpec exists for `SharePoint` today; +/// consumers should author one in `ogar_vocab::ports` per the +/// `CONSUMER-MIGRATION-HOWTO.md` and then pull the classid via the +/// static port lookup. See `docs/CONSUMER-BRIDGE-DEPRECATION.md` + +/// AdaWorldAPI/OGAR#95. +#[deprecated( + note = "author a `SharePointPort` in `ogar_vocab::ports` and pull the classid via `SharePointPort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub struct SharePointBridge { registry: Arc, g_lock: NamespaceId, diff --git a/crates/lance-graph-ontology/src/bridges/spear_bridge.rs b/crates/lance-graph-ontology/src/bridges/spear_bridge.rs index d6087cbef..d9d078eb5 100644 --- a/crates/lance-graph-ontology/src/bridges/spear_bridge.rs +++ b/crates/lance-graph-ontology/src/bridges/spear_bridge.rs @@ -23,6 +23,14 @@ use std::sync::Arc; pub const NAMESPACE: &str = "EmailCorrespondance"; +/// **Deprecated:** no OGAR PortSpec exists for `EmailCorrespondance` +/// today; consumers should author one in `ogar_vocab::ports` per the +/// `CONSUMER-MIGRATION-HOWTO.md` and then pull the classid via the +/// static port lookup. See `docs/CONSUMER-BRIDGE-DEPRECATION.md` + +/// AdaWorldAPI/OGAR#95. +#[deprecated( + note = "author a `SpearPort` in `ogar_vocab::ports` and pull the classid via `SpearPort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub struct SpearBridge { registry: Arc, g_lock: NamespaceId, diff --git a/crates/lance-graph-ontology/src/bridges/woa_bridge.rs b/crates/lance-graph-ontology/src/bridges/woa_bridge.rs index 6f85184c7..6471ebe80 100644 --- a/crates/lance-graph-ontology/src/bridges/woa_bridge.rs +++ b/crates/lance-graph-ontology/src/bridges/woa_bridge.rs @@ -10,6 +10,14 @@ use std::sync::Arc; pub const NAMESPACE: &str = "WorkOrder"; +/// **Deprecated:** pull the classid via the OGAR PortSpec instead — +/// `ogar_vocab::ports::WoaPort::class_id(name)`. The codebook-aware +/// OGAR-driven bridge `lance_graph_ogar::bridges::WoaBridge` is also +/// deprecated; both share the same replacement path. See +/// `docs/CONSUMER-BRIDGE-DEPRECATION.md` + AdaWorldAPI/OGAR#95. +#[deprecated( + note = "pull the classid via `WoaPort::class_id(name)` — see AdaWorldAPI/OGAR#95 + docs/CONSUMER-BRIDGE-DEPRECATION.md" +)] pub struct WoaBridge { registry: Arc, g_lock: NamespaceId, diff --git a/crates/lance-graph-ontology/tests/hydrate_real_ogit.rs b/crates/lance-graph-ontology/tests/hydrate_real_ogit.rs index 5d7362a86..739dd3ca3 100644 --- a/crates/lance-graph-ontology/tests/hydrate_real_ogit.rs +++ b/crates/lance-graph-ontology/tests/hydrate_real_ogit.rs @@ -2,6 +2,9 @@ // Miri isolation blocks the syscalls. Stable runs it normally; the test // even skips gracefully when OGIT_FORK_PATH is unset. #![cfg(not(miri))] +// Exercises the deprecated `OgitBridge` / `WoaBridge` structs on purpose — +// see `docs/CONSUMER-BRIDGE-DEPRECATION.md`. +#![allow(deprecated)] //! Hydrate against the actual `AdaWorldAPI/OGIT` fork. //! diff --git a/crates/lance-graph-ontology/tests/round_trip_ttl.rs b/crates/lance-graph-ontology/tests/round_trip_ttl.rs index 38a003e00..fbf8aea44 100644 --- a/crates/lance-graph-ontology/tests/round_trip_ttl.rs +++ b/crates/lance-graph-ontology/tests/round_trip_ttl.rs @@ -1,6 +1,9 @@ // Skip under Miri — fixture is written to disk via tempfile + std::fs; Miri // isolation blocks the syscalls. Stable runs it normally. #![cfg(not(miri))] +// Exercises the deprecated `OgitBridge` struct on purpose — see +// `docs/CONSUMER-BRIDGE-DEPRECATION.md`. +#![allow(deprecated)] //! End-to-end TTL hydration test. //! diff --git a/docs/CONSUMER-BRIDGE-DEPRECATION.md b/docs/CONSUMER-BRIDGE-DEPRECATION.md new file mode 100644 index 000000000..390562dc2 --- /dev/null +++ b/docs/CONSUMER-BRIDGE-DEPRECATION.md @@ -0,0 +1,171 @@ +# CONSUMER BRIDGE DEPRECATION — landing shape for the OGAR migration + +> **Status:** preemptive deprecation. Symbols still compile; every use +> emits a `#[deprecated]` warning pointing here. **Nothing removed.** +> Deletion lands later, after all consumer repos have migrated. +> +> **Source of truth:** `AdaWorldAPI/OGAR` — see +> [`docs/APP-CLASS-CODEBOOK-LAYOUT.md`](https://github.com/AdaWorldAPI/OGAR/blob/claude/medcare-bridge-lance-graph-wmx76z/docs/APP-CLASS-CODEBOOK-LAYOUT.md), +> [`docs/CONSUMER-MIGRATION-HOWTO.md`](https://github.com/AdaWorldAPI/OGAR/blob/claude/medcare-bridge-lance-graph-wmx76z/docs/CONSUMER-MIGRATION-HOWTO.md), +> [`docs/CLASSID-RBAC-KEYSTONE-SPEC.md`](https://github.com/AdaWorldAPI/OGAR/blob/claude/medcare-bridge-lance-graph-wmx76z/docs/CLASSID-RBAC-KEYSTONE-SPEC.md), +> tracking PR **AdaWorldAPI/OGAR#95**. + +## Why these bridges are deprecated + +The agnostic spine (`lance-graph-*`) does NOT own consumer ontology. +The per-consumer bridges that lived here grew up before OGAR was +the AR-shaped class registry it is today; they coupled `lance-graph-ogar` +(and the OGIT cache `lance-graph-ontology`) to consumer-specific shapes +that should live entirely in the consumers, with OGAR providing the +classid + schema + grant. + +The replacement is **pull the classid via OGAR PortSpec, then enrich +locally**: + +```rust +// BEFORE — bridge constructed in the consumer: +use lance_graph_ogar::bridges::WoaBridge; +let bridge = WoaBridge::new(registry)?; +let entity = bridge.entity("Stundenzettel")?; +let class_id = entity.schema_ptr.entity_type_id(); // 0x0103 + +// AFTER — static port lookup in the consumer: +use ogar_vocab::ports::{WoaPort, PortSpec}; +let class_id: Option = WoaPort::class_id("Stundenzettel"); // Some(0x0103) +// +// Render lens (per-app) lives in the high u16: 0x0003 << 16 | 0x0103 +// = 0x0003_0103 (woa-rs's render classid for billable work entry). +// RBAC + ontology key on the low half (shared). +``` + +That's it — no `Registry`, no `hydrate`, no `OntologyRegistry` field on +the consumer. The classid pull is a pure function call; cross-fork +convergence is preserved (every consumer of `BILLABLE_WORK_ENTRY` +resolves to `0x0103` whether it's WoA's `Stundenzettel`, SMB's, +OpenProject's `TimeEntry`, or Redmine's). See OGAR +`APP-CLASS-CODEBOOK-LAYOUT.md` §1 (hi/lo split) and §3.5–3.7 +(per-app rendering, key-value content, RAG membrane). + +## What is deprecated (this PR) + +### `lance-graph-ogar::bridges` — OGAR-driven per-port aliases + +Six `UnifiedBridge

` type aliases — the consumer-facing names. The +underlying `UnifiedBridge

` harness is **not** deprecated (it's the +implementation mechanism for `NamespaceBridge`; internal-only). + +| Deprecated symbol | Replacement | +|---|---| +| `bridges::OpenProjectBridge` | `ogar_vocab::ports::OpenProjectPort::class_id(name)` | +| `bridges::RedmineBridge` | `ogar_vocab::ports::RedminePort::class_id(name)` | +| `bridges::MedcareBridge` | `ogar_vocab::ports::HealthcarePort::class_id(name)` | +| `bridges::WoaBridge` | `ogar_vocab::ports::WoaPort::class_id(name)` | +| `bridges::SmbBridge` | `ogar_vocab::ports::SmbPort::class_id(name)` | +| `bridges::OdooBridge` | `ogar_vocab::ports::OdooPort::class_id(name)` | + +The `Port` types (`OpenProjectPort`, `WoaPort`, …) themselves are +**not** deprecated — they are the replacement. + +### `lance-graph-ontology::bridges` — legacy per-tenant structs + +Four bespoke structs. These pre-date OGAR's codebook and have no +`PortSpec` impl in `ogar-vocab::ports`. They live in the OGIT cache +crate (`lance-graph-ontology`), which by SoC rule cannot depend on +`ogar-vocab`. Consumers should pull the classid via the OGAR side and +let OGIT continue to do what it does today (legacy TTL/RDF hydration). + +| Deprecated symbol | Replacement | +|---|---| +| `lance_graph_ontology::bridges::OgitBridge` | `ogar_vocab::ports::*Port::class_id(name)` for the relevant port | +| `lance_graph_ontology::bridges::WoaBridge` (legacy struct) | `ogar_vocab::ports::WoaPort::class_id(name)` | +| `lance_graph_ontology::bridges::SpearBridge` | (no OGAR port yet — author one per `CONSUMER-MIGRATION-HOWTO.md`) | +| `lance_graph_ontology::bridges::SharePointBridge` | (no OGAR port yet — author one per `CONSUMER-MIGRATION-HOWTO.md`) | + +## What this PR does NOT do (read this — flagged by parallel sessions) + +This PR is **deprecation only**. It signals the migration target but +does **not** ship the full replacement API. Two specific gaps remain: + +### Gap 1 — `lance-graph-rbac` has no `authorize(actor, classid, op)` yet + +The keystone in `CLASSID-RBAC-KEYSTONE-SPEC.md` describes a single +`authorize(actor: &Membership, classid: u16, op: Op) -> AccessDecision` +entry point in `lance-graph-rbac`. Today (2026-06-22) the crate ships +the scaffolding (`AccessDecision::{Allow, Deny, Escalate}`, +`role`/`permission`/`policy`/`access` modules) but **no `authorize` +function and no classid-keyed signature**. So a consumer reading the +deprecation note "authorize by classid" cannot, today, *call* that — +the function does not exist. + +Why this PR doesn't add it: the keystone is graded `[H]` and gated on +**`PROBE-OGAR-RBAC-AUTHORIZE`** (OGAR `CLAUDE.md` non-negotiables; +`CLASSID-RBAC-KEYSTONE-SPEC.md` §10). Shipping the signature before +the probe locks the shape before falsification — the gate exists +exactly to prevent that. The keystone is its own PR, after the probe +runs green. + +Until the keystone ships, consumers should: +- migrate the **classid pull** off the bridges now (this PR's target — + `Port::class_id(name)`), +- keep their **existing auth** (or none) for the authorize call site, +- **NOT re-introduce a bridge as an auth stopgap**. + +### Gap 2 — no `Membership` / `Op` types yet + +The keystone's actor type (`Membership` — I-K6 in the spec) and op +type are not defined in `lance-graph-rbac` either. They land with the +keystone PR, not here. + +## What is NOT deprecated + +- **`UnifiedBridge

`** — implementation harness, not consumer surface. +- **`ogar_vocab::ports::*Port`** — these are the replacement. +- **Internal lance-graph bridges** (`unified_bridge.rs` in callcenter, + `*_bridge.rs` in thinking-engine / learning / cognitive-shader-driver) + — these are internal cognitive seams, not consumer-migration targets. +- **`OPENPROJECT_CODEBOOK` / `REDMINE_CODEBOOK` constants** — already + deprecated in prior PR #570 pointing at `ogar_vocab::ports::*_ALIASES`. + +## Removal timeline + +Deletion of the deprecated symbols is **gated on every consumer being +green**. Per `git grep` at this PR's filing (2026-06-22): + +| Consumer | Files still importing `lance_graph_{ontology,ogar}::bridges` | +|---|---| +| MedCare-rs | 33 | +| woa-rs | 6 | +| smb-office-rs | 4 | +| odoo-rs | 0 ✓ | +| openproject-nexgen-rs | 0 ✓ | + +The terminal `bridges/` deletion PR opens only after MedCare-rs, +woa-rs, and smb-office-rs ship their migrations. No removal window +is announced — the deprecation is a beacon, not a deadline. + +## How to migrate (one-page recipe) + +1. Confirm your OGAR `PortSpec` exists (`ogar_vocab::ports::*`). All + six ports above already exist. +2. Replace the bridge construction call with a static port lookup: + ```rust + let cid: u16 = YourPort::class_id(entity_name) + .ok_or_else(|| /* concept not in your port's alias table */)?; + ``` +3. Form your render classid by stamping your app's high-u16 prefix + (per OGAR's `APP-CLASS-CODEBOOK-LAYOUT.md` §2 allocation table — + `0x0001` OpenProject · `0x0002` Odoo · `0x0003` WoA · `0x0004` SMB · + `0x0005` Medcare · `0x0007` Redmine): + ```rust + const APP: u32 = 0x0003_0000; // e.g. woa-rs + let render_classid: u32 = APP | (cid as u32); + ``` +4. Enrich + render by `render_classid`; authorize by `cid` (the low + half — shared grant lattice). +5. Delete the bridge import + any hand-rolled registry/hydration in + your repo. + +DoD: no `XBridge` / `UnifiedBridge<…>` symbol from `lance_graph_*` +survives in your repo's grep; the classid pull is a pure function call; +your diff touches only OGAR (a port, if new) + your own crate. The +spine is byte-for-byte unchanged.