Skip to content

Commit a4f36b6

Browse files
committed
Address codex/CodeRabbit review on PR #416
- 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
1 parent 03ff307 commit a4f36b6

10 files changed

Lines changed: 28 additions & 25 deletions

File tree

.claude/odoo/savants/_SCAFFOLD-EVIDENCE-CONTRACT.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
- **`contract::savants`** — the 25-savant roster as data: each `Savant { id, name, family, kind, inference, semiring, style, lane, decides }`. The dispatch tuple is **fixed**; `query_strategy()` rides `InferenceType::default_strategy()`.
1010
- **`reasoning::{Reasoner, ReasoningContext, ReasoningKind, EvidenceRef, Budget}`** — the delegation surface (shipped).
11-
- **#414**: OGIT families `0x63 ProductCatalog` / `0x90 HRFoundation` + Layer-2 alignment axioms (stock.* / analytic.distribution.model / account.account.tag) + StyleCluster wiring.
11+
- **#414**: OGIT families `0x64 ProductCatalog` / `0x90 HRFoundation` + Layer-2 alignment axioms (stock.* / analytic.distribution.model / account.account.tag) + StyleCluster wiring.
1212
- FIBU subtree now inherits `fibofnd` (zugferd/fibobe/skr0x).
1313

1414
## What I need carved out — 4 slots per savant
@@ -45,13 +45,13 @@ impl Reasoner for <Kind>Reasoner {
4545
| 4 | AnalyticDistributionSuggester | 0x62 | NextBestAction | Induction | L10 | suggested cost-centre distribution for a move line |
4646
| 15 | TaxExigibilitySuggestor | 0x62 | NextBestAction | Induction | L15 | tax exigibility (on-invoice vs on-payment / cash-basis) |
4747

48-
**Tier 2 — partner / pricing (0x80 / 0x81 / 0x63):**
48+
**Tier 2 — partner / pricing (0x80 / 0x81 / 0x64):**
4949

5050
| id | savant | family | kind | infer | lane | decides |
5151
|---|---|---|---|---|---|---|
5252
| 1 | FiscalPositionResolver | 0x80 | CustomerCategory | Deduction | L9 | which fiscal position (tax mapping) for a partner |
5353
| 2 | PartnerTrustAdvisor | 0x80 | CustomerCategory | Revision | L9 | partner trust / dunning-risk from payment history |
54-
| 3 | PricelistAssignmentAgent | 0x63 | Other(PRICELIST_ASSIGNMENT) | Revision | L8 | partner pricelist when no explicit property |
54+
| 3 | PricelistAssignmentAgent | 0x64 | Other(PRICELIST_ASSIGNMENT) | Revision | L8 | partner pricelist when no explicit property |
5555
| 23 | PricelistRecommender | 0x81 | NextBestAction | Synthesis | L6 | which pricelist rule when multiple candidates apply |
5656
| 22 | UpsellActivityTrigger | 0x81 | NextBestAction | Induction | L6 | qty_delivered>ordered ⇒ upsell TODO |
5757
| 10 | UserCompanyAccessAdvisor | 0x80 | CustomerCategory | Induction | L12 | branch-access subset by user role/context |
@@ -76,7 +76,7 @@ impl Reasoner for <Kind>Reasoner {
7676
| 12 | ReorderTimingAdvisor | None | NextBestAction | Induction | L13 | reorder timing under demand/supplier uncertainty |
7777
| 13 | ReplenishmentReportAdvisor | None | NextBestAction | Induction | L13 | real shortfall vs demand noise |
7878
| 14 | RouteTiebreaker | None | NextBestAction | Abduction | L13 | equal-sequence route tiebreak |
79-
| 24 | RemovalStrategySelector | None | NextBestAction | Induction(XorBundle) | L7 | quants to bind to a reservation (FIFO/FEFO/LIFO) |
79+
| 24 | RemovalStrategySelector | None | NextBestAction | Induction | L7 | quants to bind to a reservation (FIFO/FEFO/LIFO) |
8080
| 25 | MoveAssignmentPrioritizer | None | NextBestAction | Induction | L7 | which confirmed moves to satisfy first |
8181
| 26 | BackorderJudge | None | NextBestAction | Abduction | L7 | partial fulfilment ⇒ backorder vs cancel |
8282

.claude/plans/odoo-savant-roster-v1.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This plan is the **lance-graph implementation** of the handover (SAVANTS.md §"l
1818
|---|---|---|---|
1919
| **D-ODOO-1** | the 25-savant roster as data + dispatch tuple + lookups | `contract::savants` |**DONE this PR** (3 tests) |
2020
| **D-ODOO-2** | `Reasoner` impls per `ReasoningKind` (CustomerCategory / PostingAnomaly / NextBestAction / InvoiceCompleteness / MailIntent + the 6 `Other` codes) — the AXIS-B experts | planner / a new reasoner crate | Queued |
21-
| **D-ODOO-3** | two new OGIT families **`0x63 ProductCatalog`** + **`0x90 HRFoundation`** in `OgitFamilyTable` + inherited `StyleCluster` per family | `lance-graph-ontology` + `contract::build.rs` | Queued |
21+
| **D-ODOO-3** | two new OGIT families **`0x64 ProductCatalog`** + **`0x90 HRFoundation`** in `OgitFamilyTable` + inherited `StyleCluster` per family | `lance-graph-ontology` + `contract::build.rs` | Queued |
2222
| **D-ODOO-4** | Layer-2 alignment axioms for the `None` classes (`stock.*`, `account.analytic.distribution.model`, `account.account.tag`) so the 11 `unaligned()` savants resolve a family | `lance-graph-ontology` `data/ontologies/odoo/alignment/` | Queued |
2323
| **D-ODOO-5** | delegation call-site conformance: `ReasoningContext` + Arrow `EvidenceRef` schemas per savant; woa-rs↔lance-graph contract test | `contract` + conformance harness | Queued |
2424

@@ -28,11 +28,11 @@ This plan is the **lance-graph implementation** of the handover (SAVANTS.md §"l
2828
- **Deterministic guard stays in woa-rs** (balance==0, residual, sign, prefix-match…); lance-graph only sees the ambiguous core.
2929
- **BBB-allowed crates only** (`lance-graph-contract`, `-ontology`, `-callcenter`); no brain-crate in the customer binary (Iron Rule 1).
3030
- The savant **tuple fully determines dispatch**; `SemiringChoice` selects evidence fusion (NarsTruth = NARS revision, the common case).
31-
- **Business = OGIT-inherited sidecar** (charter D1): odoo classes inherit existing FIBO/SKR family slots (PR #412), they do not get a bespoke CAM family — `0x63`/`0x90` are the only *new* families and must be ratified.
31+
- **Business = OGIT-inherited sidecar** (charter D1): odoo classes inherit existing FIBO/SKR family slots (PR #412), they do not get a bespoke CAM family — `0x64`/`0x90` are the only *new* families and must be ratified.
3232

3333
## Open questions
3434

35-
- Ratify families `0x63 ProductCatalog` / `0x90 HRFoundation` (or fold into existing slots?).
35+
- Ratify families `0x64 ProductCatalog` / `0x90 HRFoundation` (or fold into existing slots?).
3636
- Where do the `Reasoner` impls live — `lance-graph-planner` (has NARS engine + MUL) or a dedicated reasoner crate? (AriGraph-circular-dep caveat applies; see CLAUDE.md p64 convergence note.)
3737
- `ReasoningKind::Other(u32)` code registry — `contract::savants::other_kind` holds the 6 codes; promote to a named enum if the set stabilizes.
3838

crates/lance-graph-contract/examples/cognitive_cycle.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,12 @@ fn main() {
6767
gate_state(ctx.sd), ctx.sd, ctx.free_energy, ctx.confidence);
6868
}
6969

70-
println!("== rest == the shader stopped because gate reached {:?} (SD={:.3} < FLOW {SD_FLOW}).",
71-
gate_state(ctx.sd), ctx.sd);
70+
if gate_state(ctx.sd) == GateState::Flow {
71+
println!("== rest == the shader stopped because gate reached Flow (SD={:.3} < FLOW {SD_FLOW}).", ctx.sd);
72+
} else {
73+
println!("== rest == round cap reached ({round} rounds) before FLOW; gate={:?}, SD={:.3}.",
74+
gate_state(ctx.sd), ctx.sd);
75+
}
7276
println!("final: conf={:.2}, {} candidate(s) survived pruning, {} beliefs.",
7377
ctx.confidence, ctx.candidates.len(), ctx.beliefs.len());
7478
println!("\nKey: Gate-bucket tactics (TCP/CDT/TCF/CUR) skip while in FLOW — the markers,");

crates/lance-graph-contract/src/savants.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use crate::thinking::StyleCluster;
2222
/// Stable codes for the `ReasoningKind::Other(u32)` savants (SAVANTS.md).
2323
pub mod other_kind {
2424
pub const PRICELIST_ASSIGNMENT: u32 = 1;
25-
pub const ANALYTIC_MODEL_MATCH: u32 = 2;
2625
pub const CHART_ACCOUNT_MAPPING: u32 = 3;
2726
pub const CONSOLIDATION_RATE_POLICY: u32 = 4;
2827
pub const RECONCILE_MATCH: u32 = 5;
@@ -62,7 +61,7 @@ pub const SAVANTS: [Savant; 25] = [
6261
// ── L8–L15 gap lanes (15) ──
6362
Savant { id: 1, name: "FiscalPositionResolver", family: Some(0x80), kind: CustomerCategory, inference: Deduction, semiring: NarsTruth, style: Analytical, lane: "L9", decides: "which fiscal position (tax mapping) applies to a partner" },
6463
Savant { id: 2, name: "PartnerTrustAdvisor", family: Some(0x80), kind: CustomerCategory, inference: Revision, semiring: NarsTruth, style: Empathic, lane: "L9", decides: "partner trust / dunning-risk from payment history" },
65-
Savant { id: 3, name: "PricelistAssignmentAgent", family: None, kind: Other(other_kind::PRICELIST_ASSIGNMENT), inference: Revision, semiring: NarsTruth, style: Analytical, lane: "L8", decides: "partner pricelist when no explicit property (country-group/config fallback)" },
64+
Savant { id: 3, name: "PricelistAssignmentAgent", family: Some(0x64), kind: Other(other_kind::PRICELIST_ASSIGNMENT), inference: Revision, semiring: NarsTruth, style: Analytical, lane: "L8", decides: "partner pricelist when no explicit property (country-group/config fallback)" },
6665
Savant { id: 4, name: "AnalyticDistributionSuggester", family: Some(0x62), kind: NextBestAction, inference: Induction, semiring: NarsTruth, style: Analytical, lane: "L10", decides: "suggested cost-centre distribution for a move line" },
6766
Savant { id: 5, name: "AnalyticModelScorer", family: None, kind: CustomerCategory, inference: Deduction, semiring: HammingMin, style: Analytical, lane: "L10", decides: "which analytic.distribution.model matches (priority-scored)" },
6867
Savant { id: 6, name: "SequenceGapAnomalyDetector", family: Some(0x62), kind: PostingAnomaly, inference: Abduction, semiring: NarsTruth, style: Analytical, lane: "L11", decides: "journal sequence gaps ⇒ deleted posted entries (GoBD)" },

crates/lance-graph-ontology/src/hydrators/fibo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ pub fn hydrate_fibo_be_from(
130130
g: OGIT::FIBOBE_V1.0,
131131
version: OGIT::FIBOBE_V1.1,
132132
domain_name: "fibobe".to_string(),
133-
inherits_from: Some(OGIT::DOLCE_V1.0),
133+
inherits_from: Some(OGIT::FIBOFND_V1.0),
134134
starting_entity_id: 100,
135135
};
136136
hydrator.hydrate_many(&path_refs, registry)?;

crates/lance-graph-ontology/src/hydrators/skr_datev.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub fn hydrate_skr03_from(
4646
g: OGIT::SKR03_V1.0,
4747
version: OGIT::SKR03_V1.1,
4848
domain_name: "skr03".to_string(),
49-
inherits_from: Some(OGIT::DOLCE_V1.0),
49+
inherits_from: Some(OGIT::FIBOFND_V1.0),
5050
starting_entity_id: 100,
5151
iri_prefix: SKR03_IRI_PREFIX.to_string(),
5252
};
@@ -92,7 +92,7 @@ pub fn hydrate_skr04_from(
9292
g: OGIT::SKR04_V1.0,
9393
version: OGIT::SKR04_V1.1,
9494
domain_name: "skr04".to_string(),
95-
inherits_from: Some(OGIT::DOLCE_V1.0),
95+
inherits_from: Some(OGIT::FIBOFND_V1.0),
9696
starting_entity_id: 100,
9797
iri_prefix: SKR04_IRI_PREFIX.to_string(),
9898
};

crates/lance-graph-ontology/src/hydrators/zugferd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub fn hydrate_zugferd_from(
8383
g: OGIT::ZUGFERD_V1.0,
8484
version: OGIT::ZUGFERD_V1.1,
8585
domain_name: "zugferd".to_string(),
86-
inherits_from: Some(OGIT::DOLCE_V1.0),
86+
inherits_from: Some(OGIT::FIBOFND_V1.0),
8787
starting_entity_id: 100,
8888
};
8989
hydrator.hydrate_many(&path_refs, registry)?;

crates/lance-graph-ontology/tests/fibo_be_hydrator_smoke.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ fn fibo_be_hydrator_smoke() {
2121
assert_eq!(bundle.domain_name, "fibobe");
2222
assert_eq!(
2323
bundle.inherits_from,
24-
Some(OGIT::DOLCE_V1.0),
25-
"FIBO-BE inherits_from must be DOLCE"
24+
Some(OGIT::FIBOFND_V1.0),
25+
"FIBO-BE inherits_from must be FIBOFND (BE → FND → DOLCE, PR #416)"
2626
);
2727

2828
let entity_count = bundle.entity_count();
@@ -69,13 +69,13 @@ fn fibo_be_canonical_iris_resolve() {
6969
}
7070

7171
#[test]
72-
fn fibo_be_inherits_from_dolce() {
73-
// BE declares inherits_from: dolce directly today. A future PR may
74-
// chain BE → FND → DOLCE once multi-parent inheritance lands.
72+
fn fibo_be_inherits_from_fibofnd() {
73+
// BE now chains BE → FND → DOLCE (FND itself inherits DOLCE); re-parented
74+
// from dolce-direct in PR #416 (FIBU subtree under fibofnd).
7575
let registry = OntologyRegistry::new_in_memory();
7676
hydrate_fibo_be(&registry).expect("FIBO-BE hydrates");
7777
let bundle = registry
7878
.bundle_for(OGIT::FIBOBE_V1.0)
7979
.expect("bundle registered");
80-
assert_eq!(bundle.inherits_from, Some(OGIT::DOLCE_V1.0));
80+
assert_eq!(bundle.inherits_from, Some(OGIT::FIBOFND_V1.0));
8181
}

crates/lance-graph-ontology/tests/skr_hydrator_smoke.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn skr03_hydrator_smoke() {
2727
.expect("ContextBundle registered at SKR03_V1");
2828
assert_eq!(bundle.g, OGIT::SKR03_V1.0);
2929
assert_eq!(bundle.domain_name, "skr03");
30-
assert_eq!(bundle.inherits_from, Some(OGIT::DOLCE_V1.0));
30+
assert_eq!(bundle.inherits_from, Some(OGIT::FIBOFND_V1.0));
3131
assert!(
3232
bundle.entity_count() >= 1400,
3333
"expected >= 1400 canonical SKR 03 accounts, got {}",
@@ -46,7 +46,7 @@ fn skr04_hydrator_smoke() {
4646
.expect("ContextBundle registered at SKR04_V1");
4747
assert_eq!(bundle.g, OGIT::SKR04_V1.0);
4848
assert_eq!(bundle.domain_name, "skr04");
49-
assert_eq!(bundle.inherits_from, Some(OGIT::DOLCE_V1.0));
49+
assert_eq!(bundle.inherits_from, Some(OGIT::FIBOFND_V1.0));
5050
assert!(
5151
bundle.entity_count() >= 1200,
5252
"expected >= 1200 SKR 04 accounts, got {}",

crates/lance-graph-ontology/tests/zugferd_hydrator_smoke.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ fn zugferd_hydrator_smoke() {
2626
assert_eq!(bundle.domain_name, "zugferd");
2727
assert_eq!(
2828
bundle.inherits_from,
29-
Some(OGIT::DOLCE_V1.0),
30-
"ZUGFeRD inherits_from must be DOLCE"
29+
Some(OGIT::FIBOFND_V1.0),
30+
"ZUGFeRD inherits_from must be FIBOFND (PR #416)"
3131
);
3232

3333
// EN16931 profile covers 4 XSD files: top-level CrossIndustryInvoice,

0 commit comments

Comments
 (0)