Skip to content

feat(ogar/bridges): WoaBridge + SmbBridge + OdooBridge — close the planner→ERP convergence chain#587

Merged
AdaWorldAPI merged 1 commit into
mainfrom
claude/ogar-woa-smb-odoo-bridges
Jun 22, 2026
Merged

feat(ogar/bridges): WoaBridge + SmbBridge + OdooBridge — close the planner→ERP convergence chain#587
AdaWorldAPI merged 1 commit into
mainfrom
claude/ogar-woa-smb-odoo-bridges

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Jun 22, 2026

Copy link
Copy Markdown
Owner

What

Three new OGAR-driven port bridges in lance_graph_ogar::bridges, all thin type aliases over the existing UnifiedBridge<P: PortSpec> harness:

  • WoaBridge = UnifiedBridge<WoaPort> (namespace WorkOrder, bridge_id woa)
  • SmbBridge = UnifiedBridge<SmbPort> (namespace SMB, bridge_id smb)
  • OdooBridge = UnifiedBridge<OdooPort> (namespace Odoo, bridge_id odoo)

Consumes OGAR PR #93 (WoaPort + SmbPort) and OGAR PR #94 (OdooPort) — both already merged on OGAR main @ 08a9c979.

The convergence pin (operator value statement 2026-06-21)

"In the end planning (openproject) and ERP (odoo, YOU) should become reusable ontologies so that the planner times can align with billable hours."

That's the cross-fork convergence the codebook was built for, applied to the planner ↔ ERP seam. This PR ships it end-to-end through the entity() codebook-synthesis path:

// bridges::woa_bridge::tests::entity_resolves_stundenzettel_to_billable_work_entry_planner_convergence
WoaBridge.entity("Stundenzettel").schema_ptr.entity_type_id()      == 0x0103 BILLABLE_WORK_ENTRY
WoaBridge.entity("TimesheetActivity").schema_ptr.entity_type_id()  == 0x0103 BILLABLE_WORK_ENTRY
WoaBridge.entity("TimeEntry").schema_ptr.entity_type_id()          == 0x0103 BILLABLE_WORK_ENTRY
WoaBridge.entity("Zeiterfassung").schema_ptr.entity_type_id()      == 0x0103 BILLABLE_WORK_ENTRY

// bridges::smb_bridge::tests::entity_resolves_stundenzettel_to_billable_work_entry_planner_convergence
SmbBridge.entity("Stundenzettel").schema_ptr.entity_type_id()      == 0x0103 BILLABLE_WORK_ENTRY
SmbBridge.entity("TimeEntry").schema_ptr.entity_type_id()          == 0x0103 BILLABLE_WORK_ENTRY
SmbBridge.entity("Zeiterfassung").schema_ptr.entity_type_id()      == 0x0103 BILLABLE_WORK_ENTRY

// existing in OGAR PR #93 ports.rs (already merged):
OpenProjectPort::class_id("TimeEntry") == 0x0103 BILLABLE_WORK_ENTRY
RedminePort::class_id("TimeEntry")     == 0x0103 BILLABLE_WORK_ENTRY

All resolve to class_ids::BILLABLE_WORK_ENTRY = 0x0103. The planner→ERP integration is a codebook lookup, not a translation layer.

Commerce-block convergence (apple meets apple, second time)

Symmetric to the OpenProject ↔ Redmine pin, WoA ↔ SMB ↔ Odoo now have one too:

WoaBridge.entity("Customer").entity_type_id()  ==
SmbBridge.entity("Kunde").entity_type_id()     == 0x0204 BILLING_PARTY

WoaBridge.entity("Rechnung").entity_type_id()  ==
SmbBridge.entity("Rechnung").entity_type_id()  == 0x0202 COMMERCIAL_DOCUMENT
// + 14 more concept pairs spanning Position/LineItem, Tax/Steuer, Payment/Zahlung

(The cross-port assertion lives in ogar_vocab::ports::tests::woa_and_smb_converge_on_commerce_block, shipped in OGAR #93.)

Tests

53/53 lance-graph-ogar lib tests pass, including the 14 new bridge-side tests:

bridges::woa_bridge::tests::new_succeeds_when_namespace_registered ............ ok
bridges::woa_bridge::tests::new_returns_unknown_namespace_when_not_registered . ok
bridges::woa_bridge::tests::bridge_id_is_lowercase_woa ........................ ok
bridges::woa_bridge::tests::entity_resolves_customer_to_canonical_billing_party_class_id ... ok
bridges::woa_bridge::tests::entity_resolves_stundenzettel_to_billable_work_entry_planner_convergence ... ok ← THE pin
bridges::woa_bridge::tests::entity_for_each_codebook_entry_returns_its_canonical_class_id ... ok
bridges::woa_bridge::tests::entity_for_non_codebook_name_falls_back_to_registry_lookup ... ok
bridges::smb_bridge::tests::* (6 tests, mirror of woa) ........................ all ok
bridges::odoo_bridge::tests::* (5 tests) ...................................... all ok

cargo fmt --check clean. Pre-existing clippy --lib -- -D warnings warnings (8 dead_code on per-bridge NAMESPACE constants — pre-migration compat shims) are NOT introduced by this PR; they affect medcare/openproject/redmine bridges identically — the new bridges follow the same pattern.

Consumer-side migrations (queued, in their own repos)

  • woa-rs: RFC-010 (Iron Rule 1 allow-list adds lance-graph-ogar) + repoint use lance_graph_ontology::bridges::WoaBridgeuse lance_graph_ogar::bridges::WoaBridge across 4 files (~50 LOC). Spec: woa-rs/.claude/board/OGAR-MIGRATION-GAP-2026-06-21.md.
  • smb-office-rs: Cargo dep + repoint crates/smb-bridge/src/unified_bridge_wiring.rs from OgitBridge to SmbBridge (~50 LOC). Spec: smb-office-rs/.claude/board/TECH_DEBT.md TD-OGAR-CONSUMER-MIGRATION-1.
  • odoo-rs + openproject-nexgen-rs: their own sessions per the medcare-rs docs(knowledge): TTS cascade session handover #168 worked example.

Drive-by

cargo fmt picked up minor formatting nits in unified.rs, medcare_bridge.rs, openproject_bridge.rs, and tests/bridge_codebook_convergence.rs — included to keep the tree fmt-clean.

Cross-refs

🤖 Generated with Claude Code

https://claude.ai/code/session_01Xzyc27Nx3f8WC5KzwfWfjx


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for three new tenant bridge integrations: Odoo, SMB, and WoA, expanding the available OGAR-driven port bridge options alongside existing OpenProject and Redmine support.
  • Chores

    • Reorganized and updated module exports to reflect new bridge types in the public API.
    • Minor import reordering and formatting adjustments across bridge modules.

…anner→ERP convergence chain

Operator value statement 2026-06-21: "in the end planning (openproject)
and ERP (odoo, YOU) should become reusable ontologies so that the
planner times can align with billable hours". OGAR PR #93 (WoaPort +
SmbPort) and PR #94 (OdooPort) landed the canonical port specs; this
PR ships the lance-graph-side type aliases that connect those ports to
the existing `UnifiedBridge<P: PortSpec>` harness.

Three new files, all ~150 LOC each, all following the medcare_bridge.rs
template:

- WoaBridge = UnifiedBridge<ogar_vocab::ports::WoaPort> (NAMESPACE
  "WorkOrder", bridge_id "woa"). Customer/Kunde resolves to
  BILLING_PARTY (0x0204); Vorgang/WorkOrder/Quote/Invoice/CreditNote
  to COMMERCIAL_DOCUMENT (0x0202); Position/LineItem to
  COMMERCIAL_LINE_ITEM (0x0201); TaxRate/Steuersatz to TAX_POLICY
  (0x0203); Payment/Zahlung to PAYMENT_RECORD (0x0205); Stundenzettel/
  TimesheetActivity/TimeEntry/Zeiterfassung to BILLABLE_WORK_ENTRY
  (0x0103).
- SmbBridge = UnifiedBridge<ogar_vocab::ports::SmbPort> (NAMESPACE
  "SMB", bridge_id "smb"). Same canonical block as WoA — Kunde→
  BILLING_PARTY, Stundenzettel→BILLABLE_WORK_ENTRY, etc. — so
  smb-office-rs gets cross-fork convergence with WoA + OpenProject +
  Odoo for free.
- OdooBridge = UnifiedBridge<ogar_vocab::ports::OdooPort> (NAMESPACE
  "Odoo", bridge_id "odoo"). Odoo's Python class names (res.partner /
  account.move / account.move.line / hr.attendance / …) resolve to
  the same canonical block. Closes the planner→ERP→billing chain at
  every hop.

The convergence pin (the operator's value statement as a bridge-side
test):
- `bridges::woa_bridge::tests::entity_resolves_stundenzettel_to_
   billable_work_entry_planner_convergence` ✓
- `bridges::smb_bridge::tests::entity_resolves_stundenzettel_to_
   billable_work_entry_planner_convergence` ✓

Both assert that `bridge.entity("Stundenzettel").schema_ptr.
entity_type_id() == 0x0103 BILLABLE_WORK_ENTRY`, the SAME id
`OpenProjectBridge.entity("TimeEntry")` and `RedmineBridge.
entity("TimeEntry")` return. The planner→ERP integration is now a
codebook lookup, not a translation layer.

Tests: 53/53 lance-graph-ogar lib tests pass, including the 14 new
tests (5 per bridge minus 1 missing in odoo). Cargo lock updated to
pull OGAR main @ 08a9c979 (post #93+#94 merge).

Unrelated drive-by: cargo fmt picked up minor formatting nits in
unified.rs / medcare_bridge.rs / openproject_bridge.rs / tests/
bridge_codebook_convergence.rs — included to keep the tree fmt-clean.

Pre-existing clippy `--lib -- -D warnings` errors in lance-graph-
ontology and the OGAR bridges (8 `dead_code` warnings on the per-
bridge `pub const NAMESPACE` constants — pre-migration compat shims
that aren't used inside the crate) are NOT introduced by this PR and
affect medcare_bridge.rs / openproject_bridge.rs / redmine_bridge.rs
identically — the new bridges follow the same pattern.

Consumer-side migrations queued (next, in their own repos):
- woa-rs: RFC-010 (Iron Rule 1 allow-list: add `lance-graph-ogar`) +
  switch `use lance_graph_ontology::bridges::WoaBridge` →
  `use lance_graph_ogar::bridges::WoaBridge` across 4 files (~50 LOC).
- smb-office-rs: Cargo dep + repoint
  `crates/smb-bridge/src/unified_bridge_wiring.rs` from `OgitBridge`
  to `SmbBridge` (~50 LOC).
- odoo-rs / openproject-nexgen-rs: their own sessions per the
  medcare-rs #168 worked example pattern.

Cross-refs: OGAR PR #93 (WoaPort + SmbPort, merged), OGAR PR #94
(OdooPort, merged), lance-graph PR #585 (the OGIT/OGAR separation
that gated this work), EPIPHANIES `E-OGAR-AR-MIGRATION-IS-SEVERITY`,
ISSUES `OGAR-AR-MIGRATION-WOA-SMB-OPEN`, woa-rs
`.claude/board/OGAR-MIGRATION-GAP-2026-06-21.md`, smb-office-rs
`.claude/board/TECH_DEBT.md` `TD-OGAR-CONSUMER-MIGRATION-1`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xzyc27Nx3f8WC5KzwfWfjx
@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.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 94212a14-88dd-4fa3-af18-fc764fe15930

📥 Commits

Reviewing files that changed from the base of the PR and between fc7b2c9 and 2decb2f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • crates/lance-graph-ogar/src/bridges/medcare_bridge.rs
  • crates/lance-graph-ogar/src/bridges/mod.rs
  • crates/lance-graph-ogar/src/bridges/odoo_bridge.rs
  • crates/lance-graph-ogar/src/bridges/openproject_bridge.rs
  • crates/lance-graph-ogar/src/bridges/smb_bridge.rs
  • crates/lance-graph-ogar/src/bridges/unified.rs
  • crates/lance-graph-ogar/src/bridges/woa_bridge.rs
  • crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs

📝 Walkthrough

Walkthrough

Three new OGAR-driven tenant bridge modules are added (odoo_bridge, smb_bridge, woa_bridge), each defining a thin type alias over UnifiedBridge<P> and a NAMESPACE constant. bridges/mod.rs is extended with matching submodule declarations and re-exports. Each new bridge includes comprehensive in-file tests. Remaining changes are import-order and formatting-only fixes across existing bridge files and the convergence integration test.

Changes

New OGAR Tenant Bridges

Layer / File(s) Summary
Bridge type aliases, NAMESPACE constants, and mod.rs wiring
crates/lance-graph-ogar/src/bridges/odoo_bridge.rs, crates/lance-graph-ogar/src/bridges/smb_bridge.rs, crates/lance-graph-ogar/src/bridges/woa_bridge.rs, crates/lance-graph-ogar/src/bridges/mod.rs
Defines OdooBridge, SmbBridge, and WoaBridge as pub type aliases over UnifiedBridge<P> with exported NAMESPACE constants; mod.rs adds the three new submodule declarations and pub use re-exports for each bridge and port type, and expands module-level docs to enumerate all four per-port aliases.
In-file test suites for Odoo, SMB, and WoA bridges
crates/lance-graph-ogar/src/bridges/odoo_bridge.rs, crates/lance-graph-ogar/src/bridges/smb_bridge.rs, crates/lance-graph-ogar/src/bridges/woa_bridge.rs
Each bridge module includes tests that build an in-memory OntologyRegistry from a TTL fixture, then assert new() success/failure for registered vs. unregistered namespaces, bridge_id() casing, codebook alias resolution to canonical class IDs, BILLABLE_WORK_ENTRY convergence for time-entry names, full alias iteration via aliases(), and BridgeError::NotInScope for non-codebook names.

Formatting and import-order fixes

Layer / File(s) Summary
Import reordering and line-wrap reformatting
crates/lance-graph-ogar/src/bridges/medcare_bridge.rs, crates/lance-graph-ogar/src/bridges/openproject_bridge.rs, crates/lance-graph-ogar/src/bridges/unified.rs, crates/lance-graph-ogar/tests/bridge_codebook_convergence.rs
Reorders pub use/use imports in medcare_bridge and openproject_bridge, reformats SchemaPtr chain and entity_by_uri assignment in unified.rs, and reorders use statements and reflowing one assert_eq! in the convergence test. No functional changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • AdaWorldAPI/lance-graph#570: Introduced the UnifiedBridge<P: PortSpec> harness that the new OdooBridge, SmbBridge, and WoaBridge type aliases directly parameterize.
  • AdaWorldAPI/lance-graph#585: Established the lance-graph-ogar::bridges module layout and bridges/mod.rs wiring pattern that this PR extends with additional per-port bridge aliases.

Poem

🐇 Hop, hop, three new bridges appear,
Odoo, SMB, WoA — crystal clear!
Each a thin alias, neat and precise,
UnifiedBridge wraps them, oh so nice.
Codebooks converge to class IDs true,
A rabbit's delight — the graph grows new! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: introducing three new bridge implementations (WoaBridge, SmbBridge, OdooBridge) that establish ERP-planner convergence, which aligns with the PR's core objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AdaWorldAPI AdaWorldAPI merged commit f56caf3 into main Jun 22, 2026
6 checks 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