Skip to content

Commit feb8be5

Browse files
committed
fix(odoo): PR #433 council + tester findings — rename OdooStyleRecipe, FNV exemption doc, clippy
Addresses findings from the PR #433 review wave (brutally-honest-tester + epiphany-council dto-soa-savant on the E-INTERPRET-NOT-STORE-1 draft): ## dto-soa-savant (MINOR drift): StyleRecipe name collision `odoo_blueprint::StyleRecipe` shadowed `lance_graph_contract::recipe::StyleRecipe` — both `Vec<(atom, weight)>` cognitive fingerprints, different layers (contract = runtime thinking- style over the 33-TSV/I4x32 basis; ours = codegen-time IR over the Odoo-specific 12-DAtom basis). Renamed ours → `OdooStyleRecipe`. Cascade-impact-savant confirmed 0 consumers, so the rename is free now and avoids forced `use` aliasing once the codegen crate (which reads both contract + ontology) lands. Added a module-doc section spelling out the two-layer distinction + the iron rule that the Odoo DAtom basis must NEVER be fused into the canonical atom layer (per atom-basis-inventory: "business is not an atom — it rides as an OGIT/Marking::Financial sidecar"). ## creative-explorer + prior-art (tension): recipe_id FNV exemption `recipe_id` uses FNV-1a, which sits in tension with `E-CODEBOOK-INHERITS-FROM-OGIT` pt.4 ("no FNV-seeded IDs; identity resolves through OntologyRegistry"). Documented the exemption: recipe_id is NOT an identity — it's an ephemeral content-addressed collapse key for codegen-time dispatcher dedup, never stored in the graph, never crossing a mailbox boundary, never naming a row. If it ever became a stored/transmitted identity the exemption lapses and it routes through OntologyRegistry. ## brutally-honest-tester (P2) + clippy - AGENT_LOG test count corrected 12 → 13 (the reviewer-added `all_matches_discriminant_order` test landed after the log was written). - clippy `manual_contains`: `t.guards.iter().any(|g| *g == name)` → `t.guards.contains(&name)`. - Removed unused imports `OdooDecorator` + `OdooDecoratorKind` (the cascade reads kind/return_kind/triggers/fields/regulation/ state_machine; decorators are a Stage-2 enrichment signal not yet consumed). ## Toolchain (orchestrator-run; agents stayed code-only per disk discipline) - `cargo test ...style_recipe` → 13/13. - `cargo clippy -p lance-graph-ontology --lib` → 0 findings in style_recipe.rs (remaining doc-indent warnings are pre-existing in l5/l13/l15). - geiger-equivalent: 0 unsafe blocks in the entire ontology crate. - machete-equivalent: every declared dep referenced; this PR adds zero new deps (Cargo.toml untouched). brutally-honest-tester verdict: LAND (anti-pattern + conventions layer; toolchain confirmed green by orchestrator).
1 parent 41a289b commit feb8be5

2 files changed

Lines changed: 49 additions & 18 deletions

File tree

.claude/board/AGENT_LOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
- `crates/lance-graph-ontology/src/odoo_blueprint/style_recipe.rs` (+~600 LOC, post-review)
55
- `crates/lance-graph-ontology/src/odoo_blueprint/mod.rs` (+1 line, `pub mod style_recipe`)
66

7-
**Tests:** `cargo test -p lance-graph-ontology --lib odoo_blueprint::style_recipe`12/12 passed (d_atom_ids_unique_and_stable, every_recipe_carries_entity_anchor, compute_method_gets_compute_atom, constrain_method_gets_validate_atom, money_return_emits_both_money_and_emit_amount, action_return_boosts_action_atom, field_cross_reference_lifts_field_kind_atoms, regulation_iri_lifts_law_atom_and_anchors, recipe_id_is_deterministic_and_collapses_identical_shapes, recipe_id_differs_when_atoms_differ, corpus_derivation_is_sorted_and_deterministic, shipped_corpus_resolves_kind_driven_atoms_today).
7+
**Tests:** `cargo test -p lance-graph-ontology --lib odoo_blueprint::style_recipe`13/13 passed (d_atom_ids_unique_and_stable, all_matches_discriminant_order, every_recipe_carries_entity_anchor, compute_method_gets_compute_atom, constrain_method_gets_validate_atom, money_return_emits_both_money_and_emit_amount, action_return_boosts_action_atom, field_cross_reference_lifts_field_kind_atoms, regulation_iri_lifts_law_atom_and_anchors, recipe_id_is_deterministic_and_collapses_identical_shapes, recipe_id_differs_when_atoms_differ, corpus_derivation_is_sorted_and_deterministic, shipped_corpus_resolves_kind_driven_atoms_today). Type renamed `StyleRecipe``OdooStyleRecipe` (PR #433 dto-soa-savant: avoid collision with `contract::recipe::StyleRecipe`).
88

99
**Outcome:** DONE. The Odoo-static interpretation layer is in place. 12-variant `DAtom` catalogue + `StyleRecipe { method_id, atoms, regulation_iris, return_kind, recipe_id }` + 7-rule deterministic cascade + content-addressed FNV-1a `recipe_id` for dispatcher collapse. Shipped-corpus test honest-flags the Stage-2 gap: 5 atoms fire today (Entity/Compute/Validate/Onchange/Action), 6 are gated on Stage-2 extractor enrichment (Money/Quantity/ApplyRate/EmitAmount/Event/FiscalCtx).
1010

crates/lance-graph-ontology/src/odoo_blueprint/style_recipe.rs

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
//! Style-recipe derivation — the **interpretation step** from typed Odoo
55
//! SoA (`OdooEntity` / `OdooMethod` / `OdooField` / `OdooDecorator`) into a
6-
//! cognitive-fingerprint [`StyleRecipe`] suitable for SoC synergy
6+
//! cognitive-fingerprint [`OdooStyleRecipe`] suitable for SoC synergy
77
//! compilation and downstream Op-codegen.
88
//!
99
//! # Where this fits in the pipeline
@@ -15,7 +15,7 @@
1515
//! Typed Rust SoA ← extracted/{account,sale,…}.rs (OdooEntity[ ])
1616
//! │ (THIS MODULE — interpretation, no new triplets stored)
1717
//! ▼
18-
//! StyleRecipe[ ] ← cognitive fingerprint per method
18+
//! OdooStyleRecipe[ ] ← cognitive fingerprint per method
1919
//! │ (atom weights + regulatory anchors + dispatch hints)
2020
//! ▼
2121
//! Askama bucket templates (next commit) → Rust Ops + const recipes
@@ -48,15 +48,47 @@
4848
//!
4949
//! # Determinism
5050
//!
51-
//! Pure function from `(&OdooEntity, &OdooMethod)` to [`StyleRecipe`]. No
51+
//! Pure function from `(&OdooEntity, &OdooMethod)` to [`OdooStyleRecipe`]. No
5252
//! allocation beyond the recipe's own `Vec`s. Atom order in the output is
5353
//! `DAtom` declaration order (the matching is by enum discriminant, not
5454
//! by hash). `recipe_id` is a content-addressed FNV-1a over the sorted
5555
//! atom-weight tuples — stable across runs, stable across machines.
56+
//!
57+
//! # Naming — NOT the contract `StyleRecipe`
58+
//!
59+
//! [`OdooStyleRecipe`] is deliberately named to NOT collide with
60+
//! `lance_graph_contract::recipe::StyleRecipe`. They are different layers:
61+
//!
62+
//! - `contract::recipe::StyleRecipe` — a RUNTIME cognition object over the
63+
//! canonical 33-TSV / `I4x32` atom basis; composes into personas;
64+
//! dispatches through `cognitive-shader-driver` (reduces to a dot
65+
//! product). It is a thinking-style fingerprint.
66+
//! - `odoo_blueprint::OdooStyleRecipe` (this type) — a CODEGEN-TIME IR over
67+
//! a SEPARATE, Odoo-specific 12-`DAtom` basis. Owned `String`/`Vec`,
68+
//! never a runtime SoA row.
69+
//!
70+
//! The two `DAtom`/`Atom` bases must NEVER be fused: per
71+
//! `atom-basis-inventory.md`, **business is not a canonical atom** — it
72+
//! rides as an OGIT/`Marking::Financial` sidecar. The Odoo `DAtom` basis
73+
//! is a domain codegen basis, not a 13th canonical TSV dimension.
74+
//!
75+
//! # `recipe_id` is NOT an OGIT identity (FNV exemption)
76+
//!
77+
//! `E-CODEBOOK-INHERITS-FROM-OGIT` (EPIPHANIES.md) bans FNV-seeded /
78+
//! hashed IDs for **identity** — every row identity must resolve through
79+
//! `OntologyRegistry` (OGIT URI → stable codebook code). `recipe_id` is
80+
//! exempt because it is NOT an identity: it is an ephemeral
81+
//! content-addressed *collapse key* the dispatcher uses to deduplicate
82+
//! structurally-identical recipes at codegen time. It is never stored in
83+
//! the graph, never crosses a mailbox boundary, and never names a row.
84+
//! Two methods sharing a `recipe_id` share a generated Op body — that is
85+
//! the intended (and only) semantic. If `recipe_id` ever became a stored
86+
//! or transmitted identity, this exemption would no longer hold and it
87+
//! would have to route through `OntologyRegistry` instead.
5688
5789
use crate::odoo_blueprint::{
58-
OdooDecorator, OdooDecoratorKind, OdooEntity, OdooField, OdooFieldKind, OdooMethod,
59-
OdooMethodKind, OdooReturnKind, OdooSemanticRole,
90+
OdooEntity, OdooField, OdooFieldKind, OdooMethod, OdooMethodKind, OdooReturnKind,
91+
OdooSemanticRole,
6092
};
6193

6294
// ---------------------------------------------------------------------------
@@ -65,7 +97,7 @@ use crate::odoo_blueprint::{
6597

6698
/// One basis vector of the cognitive-fingerprint space.
6799
///
68-
/// A method's [`StyleRecipe`] is a sparse weighted vector over these
100+
/// A method's [`OdooStyleRecipe`] is a sparse weighted vector over these
69101
/// atoms. The 12 atoms span the Odoo-method dispatch axis; downstream SoC
70102
/// synergy compilation projects them into the runtime palette.
71103
///
@@ -160,7 +192,7 @@ impl DAtom {
160192
}
161193

162194
// ---------------------------------------------------------------------------
163-
// StyleRecipe — the cognitive fingerprint
195+
// OdooStyleRecipe — the cognitive fingerprint
164196
// ---------------------------------------------------------------------------
165197

166198
/// Per-method cognitive fingerprint — a sparse weighted vector over
@@ -174,7 +206,7 @@ impl DAtom {
174206
/// to the same atom-weight set share the same recipe (a useful collapse
175207
/// for the dispatcher).
176208
#[derive(Debug, Clone, PartialEq, Eq)]
177-
pub struct StyleRecipe {
209+
pub struct OdooStyleRecipe {
178210
/// Fully-qualified method id: `"account.move._compute_amount"`.
179211
pub method_id: String,
180212
/// Sorted, deduplicated `(atom, weight)` tuples. Sorted by atom enum
@@ -194,7 +226,7 @@ pub struct StyleRecipe {
194226
pub recipe_id: u32,
195227
}
196228

197-
impl StyleRecipe {
229+
impl OdooStyleRecipe {
198230
/// Whether this recipe carries a regulatory-anchor signal. Codegen
199231
/// uses this to decide whether to emit the `// per <law>` doc-comment.
200232
#[must_use]
@@ -207,7 +239,7 @@ impl StyleRecipe {
207239
// Derivation — the deterministic projection
208240
// ---------------------------------------------------------------------------
209241

210-
/// Project one method into its [`StyleRecipe`] given its parent entity.
242+
/// Project one method into its [`OdooStyleRecipe`] given its parent entity.
211243
///
212244
/// # Derivation rules (priority cascade, atoms accumulate)
213245
///
@@ -242,7 +274,7 @@ impl StyleRecipe {
242274
/// All weights are `max`-merged (the strongest signal wins per atom);
243275
/// zero-weight atoms drop out of the output `Vec`.
244276
#[must_use]
245-
pub fn derive_style_recipe(entity: &OdooEntity, method: &OdooMethod) -> StyleRecipe {
277+
pub fn derive_style_recipe(entity: &OdooEntity, method: &OdooMethod) -> OdooStyleRecipe {
246278
let mut weights: [u8; 12] = [0; 12];
247279

248280
// 1. Structural anchor
@@ -321,8 +353,7 @@ pub fn derive_style_recipe(entity: &OdooEntity, method: &OdooMethod) -> StyleRec
321353
// 7. State-machine participation
322354
if let Some(sm) = entity.state_machine {
323355
let participates = sm.transitions.iter().any(|t| {
324-
t.trigger == method.name
325-
|| t.guards.iter().any(|g| *g == method.name)
356+
t.trigger == method.name || t.guards.contains(&method.name)
326357
});
327358
if participates {
328359
bump(&mut weights, DAtom::FiscalCtx, 6);
@@ -343,7 +374,7 @@ pub fn derive_style_recipe(entity: &OdooEntity, method: &OdooMethod) -> StyleRec
343374
let method_id = format!("{}.{}", entity.model_name, method.name);
344375
let recipe_id = fnv1a_recipe(&atoms);
345376

346-
StyleRecipe {
377+
OdooStyleRecipe {
347378
method_id,
348379
atoms,
349380
regulation_iris,
@@ -357,8 +388,8 @@ pub fn derive_style_recipe(entity: &OdooEntity, method: &OdooMethod) -> StyleRec
357388
/// Output order: stable — sorted by `method_id` ascending. Two runs
358389
/// produce byte-identical Vecs.
359390
#[must_use]
360-
pub fn derive_corpus_recipes(entities: &[&OdooEntity]) -> Vec<StyleRecipe> {
361-
let mut recipes: Vec<StyleRecipe> = entities
391+
pub fn derive_corpus_recipes(entities: &[&OdooEntity]) -> Vec<OdooStyleRecipe> {
392+
let mut recipes: Vec<OdooStyleRecipe> = entities
362393
.iter()
363394
.flat_map(|e| {
364395
e.methods
@@ -482,7 +513,7 @@ mod tests {
482513
}
483514
}
484515

485-
fn weight_of(recipe: &StyleRecipe, atom: DAtom) -> u8 {
516+
fn weight_of(recipe: &OdooStyleRecipe, atom: DAtom) -> u8 {
486517
recipe
487518
.atoms
488519
.iter()

0 commit comments

Comments
 (0)