feat(callcenter): odoo savant families + Layer-2 axioms + style wiring (D-ODOO-SAV-1/2/3)#414
Conversation
…g (D-ODOO-SAV-1/2/3) Picks up the cross-repo handover boundary declared in .claude/odoo/SAVANTS.md §"lance-graph handover boundary": the woa-rs session defined the 25-Savant roster + delegation tuples; this lands the lance-graph side's first three deliverables. Reasoner impls (D-ODOO-SAV-4) are scoped in the plan and deferred to a follow-up PR. Integration plan: - .claude/plans/odoo-savant-reasoners-v1.md (new) + INTEGRATION_PLANS.md prepend, per board-hygiene. D-ODOO-SAV-1 — two new OGIT families: - FAMILY_PRODUCT_CATALOG = 0x64 (100), FAMILY_HR_FOUNDATION = 0x90 (144) in odoo_alignment.rs + family_registry.ttl rows. - CORRECTION of the SAVANTS.md proposal: it named 0x63 for ProductCatalog, but 0x63 (=99) is already ogit:MRORepair in the authoritative registry. lance-graph is authoritative for the registry, so ProductCatalog gets the next free commercial-cluster byte 0x64 (=100). Documented on the constant + in family_registry.ttl + guarded by a test. - Seed rows: product.pricelist→schema:PriceSpecification, product.pricelist.item→schema:UnitPriceSpecification, uom.uom→qudt:Unit (ties into the bO-4 QUDT spine), hr.employee→vcard:Individual, hr.department→org:OrganizationalUnit, hr.job→org:Role, hr.contract→fibo:Contract (base only; payroll is Enterprise/absent). - product.template / product.product STAY on BillingCore 0x61 (billable items, not catalogue structure) — no drift of the existing seed/tests. D-ODOO-SAV-2 — Layer-2 alignment axioms (data/ontologies/odoo/alignment/ odoo-to-foundation.ttl, new): - Honest semantic alignment for account.account.tag → skos:Concept. - Documented-None-with-rationale for the genuinely cross-cutting classes (stock.move/rule/orderpoint, account.analytic.distribution.model): no foundry family minted (Option B — None stays None without an honest pivot), matching their family=None status in the savant roster. - Public OWL vocabularies referenced, never modified. D-ODOO-SAV-3 — StyleCluster wiring: - family_default_style(OgitFamily) -> Option<StyleCluster> + resolve_odoo_style(class). Pins 0x60→Direct, 0x61/0x62/0x64→Analytical, 0x80/0x90→Empathic, 0x81→Direct per SAVANTS.md inherited-style map. - dolce_odoo gains a `uom.` → Quality suffix rule. Tests: 144 lance-graph-callcenter tests pass (19 odoo_alignment incl. 9 new: new family bytes free in registry, catalogue→ProductCatalog, billable-items- stay-BillingCore deviation guard, hr→HRFoundation, live-table end-to-end for both basins, classes-still-None-after-D1, family_default_style pins, resolve_odoo_style chains, uom dolce rule). Updated the pre-existing unmapped_classes_return_none test (hr.employee no longer None). Clippy clean (only pre-existing CausalEdge64 deprecations elsewhere).
📝 WalkthroughWalkthroughThis PR implements the first phase of the odoo-savant-reasoners-v1 integration plan. It adds two new OGIT families (ProductCatalog and HRFoundation) with seed mappings for Odoo product and HR classes, introduces foundation-level OWL alignment axioms, adds style-cluster resolution functions, and includes comprehensive test coverage. ChangesOdoo Savant Reasoners v1 Family Expansion
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
`cargo test -p lance-graph-callcenter` compiles the zone-poison-fixtures test crate, generating a Cargo.lock + target/ inside it. The fixture's sources are tracked but its lock is not (no fixture lock is tracked in the repo; the workspace root Cargo.lock is the tracked one, so a blanket root ignore is not an option). A fixture-scoped .gitignore keeps the tree clean.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1a87bc0851
ℹ️ 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".
| # (absent) — only the hr base data/structure is aligned here. | ||
| ogit:HRFoundation | ||
| a ogit:FamilyNamespace ; | ||
| ogit.meta:superDomain "HR" ; |
There was a problem hiding this comment.
Map the HR family to a recognized super-domain
When loading family_registry.ttl, load_seed() only inserts rows whose ogit.meta:superDomain is accepted by parse_super_domain_name; that matcher does not include "HR", and unknown names are silently skipped. As a result, the newly added family id 0x90 is left as SuperDomain::Unknown in the hydrated family table even though resolve_odoo("hr.employee") now returns FAMILY_HR_FOUNDATION, so HR-aligned classes lose their intended domain/RBAC partition at runtime. Either add an HR super-domain mapping or place the family under an existing recognized super-domain.
Useful? React with 👍 / 👎.
| @@ -0,0 +1,84 @@ | |||
| # Odoo → Foundation/schema/qudt/vcard/org/skos alignment axioms. | |||
There was a problem hiding this comment.
Include the new foundation overlay in Odoo hydration
This new alignment file is never read by the canonical Odoo hydrator: crates/lance-graph-ontology/src/hydrators/odoo.rs still hard-codes ODOO_ALIGNMENT_RELATIVE_PATHS to only odoo-to-fibo.ttl and odoo-to-skr.ttl. In production calls to hydrate_odoo(), these D-ODOO-SAV-2 axioms and the ProductCatalog/HR pivots in this file will not be interned or exposed to the cascade, despite the comments here saying they are the authored Layer-2 axioms. Add odoo-to-foundation.ttl to that list or switch the hydrator to discover all alignment TTLs.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
crates/lance-graph-callcenter/src/odoo_alignment.rs (1)
20-28:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate module docs to remove outdated
hr.*“resolves to None” statement.After adding
FAMILY_HR_FOUNDATIONandhr.*seed mappings, this comment is no longer accurate and may misdirect future alignment changes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/lance-graph-callcenter/src/odoo_alignment.rs` around lines 20 - 28, Update the module-level doc comment to remove the outdated statement that "Classes with no existing family (`stock.move`, `sale.order`, `hr.*`, `account.reconcile.model`, …) resolve to `None`" and instead reflect that `hr.*` now has seed mappings (see FAMILY_HR_FOUNDATION) so it no longer resolves to None; edit the comment block near the top of odoo_alignment.rs that mentions the four foundry families and the legacy "resolve to None" behavior to mention the new HR mapping (FAMILY_HR_FOUNDATION) or remove `hr.*` from the examples that resolve to None so the docs match the current seed mappings.crates/lance-graph-callcenter/data/family_registry.ttl (1)
221-227:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix stale WorkOrderBilling range in basin-conflict commentary.
Line 226 still says
WorkOrderBilling 0x60-0x63, but this PR addsogit:ProductCatalogat0x64. Keeping the old range can mislead future slot-allocation checks.Suggested patch
-# WorkOrderBilling 0x60-0x63, OSINT 0x70-0x72, SMB-Foundry 0x80-0x82). +# WorkOrderBilling 0x60-0x64, OSINT 0x70-0x72, SMB-Foundry 0x80-0x82).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/lance-graph-callcenter/data/family_registry.ttl` around lines 221 - 227, Update the basin-conflict comment to reflect the new WorkOrderBilling/ogit:ProductCatalog slot allocation: replace the stale "WorkOrderBilling 0x60-0x63" text with the corrected range that acknowledges ogit:ProductCatalog at 0x64 (e.g., "WorkOrderBilling 0x60-0x64" or otherwise indicate that 0x64 is now used by ogit:ProductCatalog), so the line mentioning WorkOrderBilling and the surrounding SMB BSON-shape basin commentary accurately documents the current slot assignments (refer to the symbols WorkOrderBilling and ogit:ProductCatalog and slot 0x64).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/board/INTEGRATION_PLANS.md:
- Line 10: The documented ProductCatalog family byte is incorrect: change the
`ProductCatalog` family byte value from `0x63` to `0x64` in the entry that
currently reads "Group B — `0x63 ProductCatalog`", updating any mention of `0x63
ProductCatalog` to `0x64 ProductCatalog`; ensure related references in the same
paragraph (e.g., any layer-2 alignment axioms or Family labels) reflect `0x64`
so the constant matches the current assignment.
In @.claude/plans/odoo-savant-reasoners-v1.md:
- Line 35: Update every occurrence that pins ProductCatalog to the old
identifier 0x63 to the corrected 0x64: search for the token "0x63" and any "0x63
ProductCatalog" references in this plan and replace them with "0x64" (and "0x64
ProductCatalog" where appropriate), ensuring all mentions (including the other
occurrences flagged) are normalized so the ProductCatalog identifier is
consistently 0x64 throughout.
In `@data/ontologies/odoo/alignment/odoo-to-foundation.ttl`:
- Around line 1-21: The TTL file
data/ontologies/odoo/alignment/odoo-to-foundation.ttl was added but not wired
into the Odoo hydrator list; update the ODOO_ALIGNMENT_RELATIVE_PATHS
constant/array in the odoo hydrator
(crates/lance-graph-ontology/src/hydrators/odoo.rs) to include
"data/ontologies/odoo/alignment/odoo-to-foundation.ttl" so the hydrator will
load this new alignment file during startup/hydration; ensure the string is
added consistently with the existing entries (e.g., alongside the existing
"odoo-to-fibo.ttl" and "odoo-to-skr.ttl") and run the hydrator tests to verify
it is picked up.
---
Outside diff comments:
In `@crates/lance-graph-callcenter/data/family_registry.ttl`:
- Around line 221-227: Update the basin-conflict comment to reflect the new
WorkOrderBilling/ogit:ProductCatalog slot allocation: replace the stale
"WorkOrderBilling 0x60-0x63" text with the corrected range that acknowledges
ogit:ProductCatalog at 0x64 (e.g., "WorkOrderBilling 0x60-0x64" or otherwise
indicate that 0x64 is now used by ogit:ProductCatalog), so the line mentioning
WorkOrderBilling and the surrounding SMB BSON-shape basin commentary accurately
documents the current slot assignments (refer to the symbols WorkOrderBilling
and ogit:ProductCatalog and slot 0x64).
In `@crates/lance-graph-callcenter/src/odoo_alignment.rs`:
- Around line 20-28: Update the module-level doc comment to remove the outdated
statement that "Classes with no existing family (`stock.move`, `sale.order`,
`hr.*`, `account.reconcile.model`, …) resolve to `None`" and instead reflect
that `hr.*` now has seed mappings (see FAMILY_HR_FOUNDATION) so it no longer
resolves to None; edit the comment block near the top of odoo_alignment.rs that
mentions the four foundry families and the legacy "resolve to None" behavior to
mention the new HR mapping (FAMILY_HR_FOUNDATION) or remove `hr.*` from the
examples that resolve to None so the docs match the current seed mappings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 489e6e54-513e-4708-bdc9-151ae67b69e4
📒 Files selected for processing (6)
.claude/board/INTEGRATION_PLANS.md.claude/plans/odoo-savant-reasoners-v1.mdcrates/lance-graph-callcenter/data/family_registry.ttlcrates/lance-graph-callcenter/src/odoo_alignment.rscrates/lance-graph-callcenter/tests/zone-poison-fixtures/.gitignoredata/ontologies/odoo/alignment/odoo-to-foundation.ttl
| **Anchored iron rules:** I-VSA-IDENTITIES (savant = Layer-2 role catalogue), AGI-as-glove, board-hygiene, Iron Rule 1 (no brain-crate in customer binary), Iron Rule 7 (verhaltens-bewahrend — reasoner output is suggestion-only). | ||
|
|
||
| ### Scope | ||
| Group B — `0x63 ProductCatalog` (Analytical) + `0x90 HRFoundation` (Empathic) families + Layer-2 alignment axioms for `stock.*` / `account.analytic.distribution.model` / `account.account.tag` (land on existing pivot where honest, else documented `None`). Group C — `StyleCluster` per family (field-or-sidecar). Group A — `SavantConclusion` + 5 `Reasoner` impls (one per `ReasoningKind`) in lance-graph-callcenter, dispatching on evidence + family style, `InferenceType::default_strategy()` → QueryStrategy, NarsTruth evidence fusion. |
There was a problem hiding this comment.
Correct ProductCatalog family byte from 0x63 to 0x64.
This entry currently documents 0x63 ProductCatalog, which conflicts with the current assignment (0x64) and can propagate the wrong constant into follow-up work.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/board/INTEGRATION_PLANS.md at line 10, The documented ProductCatalog
family byte is incorrect: change the `ProductCatalog` family byte value from
`0x63` to `0x64` in the entry that currently reads "Group B — `0x63
ProductCatalog`", updating any mention of `0x63 ProductCatalog` to `0x64
ProductCatalog`; ensure related references in the same paragraph (e.g., any
layer-2 alignment axioms or Family labels) reflect `0x64` so the constant
matches the current assignment.
|
|
||
| The roster needs homes for classes that resolve to `None` today: | ||
|
|
||
| - **`0x63 ProductCatalog`** (basin: product catalogue + pricelist + UoM; |
There was a problem hiding this comment.
Update all ProductCatalog references from 0x63 to 0x64.
The plan still pins ProductCatalog to 0x63; this conflicts with the corrected allocation and creates a spec mismatch across deliverables/tests. Please normalize all references in this file to 0x64.
Also applies to: 65-65, 87-87, 114-114
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/plans/odoo-savant-reasoners-v1.md at line 35, Update every
occurrence that pins ProductCatalog to the old identifier 0x63 to the corrected
0x64: search for the token "0x63" and any "0x63 ProductCatalog" references in
this plan and replace them with "0x64" (and "0x64 ProductCatalog" where
appropriate), ensuring all mentions (including the other occurrences flagged)
are normalized so the ProductCatalog identifier is consistently 0x64 throughout.
| # Odoo → Foundation/schema/qudt/vcard/org/skos alignment axioms. | ||
| # | ||
| # Plan odoo-savant-reasoners-v1 D-ODOO-SAV-1 (ProductCatalog + HRFoundation | ||
| # basins) and D-ODOO-SAV-2 (Layer-2 axioms for the classes that resolve None | ||
| # in odoo_alignment.rs). These are NEW axioms authored on the lance-graph | ||
| # side — the upstream public OWL vocabularies (schema.org, QUDT, vCard, W3C | ||
| # org, SKOS) are referenced, never modified. | ||
| # | ||
| # Pivot choices match the Rust ODOO_SEED rows in | ||
| # crates/lance-graph-callcenter/src/odoo_alignment.rs. | ||
|
|
||
| @prefix odoo: <https://ada.world/onto/odoo#> . | ||
| @prefix owl: <http://www.w3.org/2002/07/owl#> . | ||
| @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | ||
| @prefix schema: <https://schema.org/> . | ||
| @prefix qudt: <http://qudt.org/schema/qudt/> . | ||
| @prefix vcard: <http://www.w3.org/2006/vcard/ns#> . | ||
| @prefix org: <http://www.w3.org/ns/org#> . | ||
| @prefix skos: <http://www.w3.org/2004/02/skos/core#> . | ||
| @prefix fibo-fnd-agr-ctr: <https://spec.edmcouncil.org/fibo/ontology/FND/Agreements/Contracts/> . | ||
|
|
There was a problem hiding this comment.
Wire this TTL into the Odoo hydrator overlay list.
This new file will not be hydrated unless crates/lance-graph-ontology/src/hydrators/odoo.rs adds data/ontologies/odoo/alignment/odoo-to-foundation.ttl to ODOO_ALIGNMENT_RELATIVE_PATHS. Right now, only odoo-to-fibo.ttl and odoo-to-skr.ttl are listed in the provided context.
Suggested patch (outside this file)
const ODOO_ALIGNMENT_RELATIVE_PATHS: &[&str] = &[
"data/ontologies/odoo/alignment/odoo-to-fibo.ttl",
"data/ontologies/odoo/alignment/odoo-to-skr.ttl",
+ "data/ontologies/odoo/alignment/odoo-to-foundation.ttl",
];🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@data/ontologies/odoo/alignment/odoo-to-foundation.ttl` around lines 1 - 21,
The TTL file data/ontologies/odoo/alignment/odoo-to-foundation.ttl was added but
not wired into the Odoo hydrator list; update the ODOO_ALIGNMENT_RELATIVE_PATHS
constant/array in the odoo hydrator
(crates/lance-graph-ontology/src/hydrators/odoo.rs) to include
"data/ontologies/odoo/alignment/odoo-to-foundation.ttl" so the hydrator will
load this new alignment file during startup/hydration; ensure the string is
added consistently with the existing entries (e.g., alongside the existing
"odoo-to-fibo.ttl" and "odoo-to-skr.ttl") and run the hydrator tests to verify
it is picked up.
- savants: PricelistAssignmentAgent family None → Some(0x64) (ProductCatalog, matches #414); drop dead other_kind::ANALYTIC_MODEL_MATCH const - hydrators: complete the FIBU re-parent on the runtime side — fibo_be / skr03 / skr04 / zugferd inherits_from DOLCE → FIBOFND (FND stays DOLCE); update the three hydrator smoke tests' inheritance assertions to match - cognitive_cycle example: rest message distinguishes FLOW vs round-cap - scaffold + roster plan: 0x63 → 0x64 ProductCatalog; Induction(XorBundle) → Induction https://claude.ai/code/session_017GFLBnDy23AWBqvkbHHC41
feat(callcenter): odoo savant families + Layer-2 axioms + style wiring (D-ODOO-SAV-1/2/3)
- savants: PricelistAssignmentAgent family None → Some(0x64) (ProductCatalog, matches #414); drop dead other_kind::ANALYTIC_MODEL_MATCH const - hydrators: complete the FIBU re-parent on the runtime side — fibo_be / skr03 / skr04 / zugferd inherits_from DOLCE → FIBOFND (FND stays DOLCE); update the three hydrator smoke tests' inheritance assertions to match - cognitive_cycle example: rest message distinguishes FLOW vs round-cap - scaffold + roster plan: 0x63 → 0x64 ProductCatalog; Induction(XorBundle) → Induction https://claude.ai/code/session_017GFLBnDy23AWBqvkbHHC41
Summary
Picks up the explicit cross-repo handover boundary in
.claude/odoo/SAVANTS.md§"lance-graph handover boundary". The woa-rssession completed the Odoo richness harvest (L1–L15) and defined the
25-Savant roster + delegation tuples; this PR lands the first three
lance-graph-side deliverables of the new integration plan
odoo-savant-reasoners-v1. The Reasoner impls (D-ODOO-SAV-4) are scopedin the plan and deferred to a follow-up PR after a dispatch-shape review.
Integration plan (board-hygiene)
.claude/plans/odoo-savant-reasoners-v1.md(new).claude/board/INTEGRATION_PLANS.mdprependD-ODOO-SAV-1 — two new OGIT families
FAMILY_PRODUCT_CATALOG = 0x64(100),FAMILY_HR_FOUNDATION = 0x90(144)in
odoo_alignment.rs+family_registry.ttlrows.0x63forProductCatalog, but
0x63(=99) is alreadyogit:MRORepairin theauthoritative registry. lance-graph is authoritative for the registry,
so ProductCatalog takes the next free commercial-cluster byte
0x64(=100). Documented on the constant + in the TTL + guarded by a test.
product.pricelist→schema:PriceSpecification,product.pricelist.item→schema:UnitPriceSpecification,uom.uom→qudt:Unit(ties into the bO-4 QUDT spine),hr.employee→vcard:Individual,hr.department→org:OrganizationalUnit,hr.job→org:Role,hr.contract→fibo:Contract(base only; payroll isodoo Enterprise/absent).
product.template/product.productstay on BillingCore 0x61(billable items, not catalogue structure) — no drift of existing seed/tests.
D-ODOO-SAV-2 — Layer-2 alignment axioms
New
data/ontologies/odoo/alignment/odoo-to-foundation.ttl:account.account.tag→skos:Concept.None-with-rationale for the genuinely cross-cutting classes(
stock.move/rule/orderpoint,account.analytic.distribution.model):no foundry family minted (Option B —
NonestaysNonewithout an honestpivot), matching their
family=Nonestatus in the savant roster.D-ODOO-SAV-3 — StyleCluster wiring
family_default_style(OgitFamily) -> Option<StyleCluster>+resolve_odoo_style(class). Pins0x60→Direct,0x61/0x62/0x64→Analytical,0x80/0x90→Empathic,0x81→Direct per SAVANTS.md inherited-style map.dolce_odoogains auom.→ Quality suffix rule.Deferred (own PR): D-ODOO-SAV-4
SavantConclusion+ 5Reasonerimpls (one perReasoningKind) inlance-graph-callcenter, dispatching on evidence + family style,
InferenceType::default_strategy()→ QueryStrategy, NarsTruth evidencefusion. Gated on a
/code-reviewpass of the dispatch shape per the plan.Test plan
odoo_alignment, incl.9 new: new family bytes free in registry, catalogue→ProductCatalog,
billable-items-stay-BillingCore deviation guard, hr→HRFoundation,
live-table end-to-end for both basins, classes-still-None-after-D1,
family_default_stylepins,resolve_odoo_stylechains, uom dolce rule)unmapped_classes_return_nonetest(
hr.employeeno longerNoneafter D-1)lance-graph-ontologybuilds cleanOption Binvariant heldNote on branch
This is a distinct work-line from the merged
hydrate-dolce-dul-owlbranch, so it uses a fresh feature branch (
claude/odoo-savant-reasoners),matching the repo's per-work-line pattern (#411, #412/#413). Happy to
retarget if you'd prefer the original assigned branch.
Cross-references
.claude/odoo/SAVANTS.md,BRIEFING.md,BRIEFING-GAP.mdGenerated by Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests