Skip to content

feat(odoo_blueprint): Stage 1 TIER-1 source extraction (D-ODOO-EXT-1..6)#426

Merged
AdaWorldAPI merged 33 commits into
mainfrom
claude/activate-lance-graph-att-k2pHI
May 28, 2026
Merged

feat(odoo_blueprint): Stage 1 TIER-1 source extraction (D-ODOO-EXT-1..6)#426
AdaWorldAPI merged 33 commits into
mainfrom
claude/activate-lance-graph-att-k2pHI

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented May 28, 2026

Copy link
Copy Markdown
Owner

Summary

Ships Stage 1 of .claude/plans/odoo-source-extraction-v1.md (D-ODOO-EXT-1..6 — the sub-plan unfolding D-ODOO-BP-1f of odoo-business-logic-blueprint-v1). Adds source-extracted OdooConfidence::Extracted backing for the L-doc-curated lane entities that shipped in D-ODOO-BP-1b Wave 1-3.

71 files / +115,680 / −1 — most of it auto-generated typed const data, not hand-written code:

Bucket Files Lines What
extracted/*.rs (12 TIER-1 addons + chart + Kennzahlen) 13 ~99,352 Auto-generated OdooEntity / OdooAccountTemplate / OdooUstvaKennzahl consts
tools/odoo-blueprint-extractor/ (Python ast extractor + CSV/XML data extractor) ~24 ~2,967 New stdlib-only Python 3 package
odoo_blueprint/mod.rs + extracted/{mod,pairing,coverage}.rs 4 ~1,200 New typed surfaces + pairing table + coverage gate
Lane modules l{1..15}.rs back-fill 15 ~150 kind: OdooEntityKind::Model + regulation_iri: &[] per existing const
.claude/plans/ + .claude/board/ (plan + AGENT_LOG/INTEGRATION_PLANS) ~7 ~877 Plan file + 6 AGENT_LOG entries + status updates

Deliverables (closes EXT-1..6)

D-id What Output
EXT-1 Python stdlib-ast extractor scaffold + uom smoke test (substitutes the absent tree-sitter) tools/odoo-blueprint-extractor/ (19 files / 1 669 LOC)
EXT-3 OdooEntityKind::{Model,Transient,Abstract} + OdooProvenance.regulation_iri slot + back-fill 72 lane consts + tree-sitter → ast doc-comment fix odoo_blueprint/mod.rs + l{1..15}.rs
EXT-2 Wave A (base/uom/product/analytic) 149 models, 26 332 LOC, 1.7 % fallback; 2 extractor bugs fixed (dedup + OdooFieldKind::Other) extracted/{base,uom,product,analytic}.rs
EXT-2 Wave B (account/account_payment/purchase/sale/stock) 141 models, 41 691 LOC, 0.9 % fallback extracted/{account,account_payment,purchase,sale,stock}.rs
EXT-2 Wave C (l10n_de/account_peppol/account_edi_ubl_cii) 34 models, ORM only — closes EXT-2 (12/12 TIER-1 addons) extracted/{l10n_de,account_peppol,account_edi_ubl_cii}.rs
EXT-4 l10n_de substance (CSV + XML — not visible to ast): 1 274 SKR03 + 1 192 SKR04 accounts, 37 UStVA Kennzahlen, GoBD wiring; new typed surfaces OdooAccountTemplate/OdooUstvaKennzahl/OdooGobdWiring extracted/{l10n_de_chart,l10n_de_kennzahlen}.rs + OdooSkrChart/OdooKennzahlKind enums
EXT-5 Curated-vs-extracted pairing table: 48 pairings linking l{1..15} lane consts to their EXT_* source-backed counterparts; largest delta account.move 24f/27m → 142f/352m extracted/pairing.rs
EXT-6 Honest-coverage report + per-lane gate test: 100 % eligible coverage across L1-L13 + L15; 5 explicit TIER-2 deferrals (4 hr.* in L14 + stock.valuation.layer in L13) extracted/{COVERAGE.md,coverage.rs}

Audit-by-construction (per I-VSA-IDENTITIES + E-CODEBOOK-INHERITS-FROM-OGIT)

Every extracted entity carries its (addon path, line range) source provenance + a regulation_iri: &'static [&'static str] of OGIT-codebook IRIs when a German rule anchors its semantics. The 37 UStVA Kennzahlen are NOT projected as OdooEntity rows (they're report lines, not models) — they get their own first-class OdooUstvaKennzahl typed surface so the regulatory boundary stays sharp.

What stays open (Stage 2)

The 5 TIER-2 exemptions catalogued in extracted/COVERAGE.md close when Stage 2 extracts hr (4 entities → L14) + stock_account (1 entity → L13). Follow-on TIER-2 candidates: crm, project, mrp_account, point_of_sale. Separate plan when prioritised.

Test plan

  • cargo test -p lance-graph-ontology --lib203 tests green (was 192 baseline post-EXT-3; EXT-4 added 7 sanity tests + EXT-5/6 added 4 more)
  • cargo check -p lance-graph-ontology — clean (only pre-existing oxrdf::Subject deprecation warnings)
  • Per-addon <5% OdooFieldKind::Other fallback gate (EXT-2 plan requirement) — held throughout
  • Per-lane 80 % eligible-coverage gate (EXT-6 plan requirement) — 100 % across L1-L13 + L15; L14 wholly exempt (all 4 entities deferred)
  • Aggregate sanity: 53 curated entities, 48 eligible after exemptions, 48 backed → aggregate_coverage_reports_correctly test asserts this

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Typed Odoo entity blueprints covering lanes L1–L15 (accounting, stock, sales, purchase, HR, tax, UoM, etc.)
    • Automated Odoo extraction toolchain with CLI, audit logging, CSV/XML importers and Rust emitters
    • Curated-vs-extracted pairing table and an extracted-backing coverage gate (Stage‑1 ~90.6%)
    • German accounting support: SKR charts, UStVA Kennzahlen, and GoBD wiring
    • Canonical identity/catalog primitives for savant URIs and role-key fallbacks
  • Documentation

    • New plans, blueprints, integration roadmaps, status board entries and extraction coverage reports

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds callcenter identity catalogs, a typed Odoo DTO substrate with curated lanes L1–L15, generated extracted entity modules with pairing and coverage gates, a Python stdlib AST extractor toolchain (CLI, emitters, data extractors, audit), and program-board documentation (plans/status/epiphanies).

Changes

Odoo DTO and Extraction Stack

Layer / File(s) Summary
Callcenter identity catalogs
crates/lance-graph-contract/src/callcenter/*
Adds ogit_uris and role_keys catalogs, public lookup helpers, slice constants, SAVANT_ROLE_KEYS/SAVANT_OGIT_URIS, tests, and exposes RoleKey::generate publicly.
Ontology DTO surface
crates/lance-graph-ontology/src/odoo_blueprint/mod.rs, crates/lance-graph-ontology/src/lib.rs
Introduces odoo_blueprint typed DTO API (OdooEntity, fields/methods/decorators/state machines/constraints, provenance, SKR/UStVA/GoBD DTOs) and exports the module from the crate root.
Curated lanes L1–L15
crates/lance-graph-ontology/src/odoo_blueprint/l1.rsl15.rs
Adds per-lane OdooEntity consts, ENTITIES slices, state machines, constraints, provenance, and unit tests for lanes L1–L15.
Auto-generated extracted modules
crates/lance-graph-ontology/src/odoo_blueprint/extracted/*
Adds generated extracted module root and many EXT_ constants (uom, account_*, peppol, analytic, l10n_de, etc.), a pairing.rs curated↔extracted table, coverage.rs gate with exemptions/floor constants and tests, and COVERAGE.md report.
Python AST extractor toolchain
tools/odoo-blueprint-extractor/**
Adds stdlib-only Python extractor package, CLI (cli.py, main), emitters (emitters/rust.py,module.py), data extractors (csv_chart.py, xml_kennzahl.py, gobd_company.py), audit fallback logger, README, and file-output/testing helpers.
Program board docs & git attrs
.claude/*, .gitattributes
Prepends agent log ephemerides, integration plans, status-board entries, detailed plan docs for extraction/savant/blueprint, and sets merge=union for governance append-only files.

Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs:

  • AdaWorldAPI/lance-graph#416: Introduced the savant roster (crate::savants::SAVANTS) used by the new callcenter catalogs; likely code-level dependency.

"A rabbit in the codewood sings,
Constants sprout like springtime things.
OGIT lights the midnight trail,
Extractors hum and tests prevail.
Lanes align, the graphs extend—
One small hop to compile and mend." 🐇✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/activate-lance-graph-att-k2pHI

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 353fac0dfc

ℹ️ 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".

Comment on lines +36 to +37
if key not in seen or _richness(ent) > _richness(seen[key]):
seen[key] = ent

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Merge duplicate Odoo model fragments instead of dropping them

When an addon defines the same model_name in multiple _inherit fragments, this keeps only the single “richest” fragment and discards fields/methods from the others; the generated files already hit this path (for example account.rs, base.rs, and l10n_de.rs contain duplicate-model notes). That makes the extracted source registry incomplete exactly for extension-heavy Odoo models, so downstream pairings and coverage counts are based on truncated business logic rather than the additive ORM view.

Useful? React with 👍 / 👎.

Comment on lines +126 to +128
# Extract depends list (for computed fields via @api.depends — see decorators parser;
# here we capture the `depends` keyword if present as a direct kw arg)
depends: List[str] = []

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Populate computed-field dependencies from the source

For any computed field that depends on @api.depends(...) (or even a direct depends= kwarg), this always returns an empty list, so every generated OdooField.depends is emitted as &[] despite the source carrying dependency information. Consumers that use the blueprint to reason about compute invalidation or evidence provenance will therefore miss the inputs for computed amounts, states, and regulatory fields.

Useful? React with 👍 / 👎.

Comment on lines +44 to +50
for p in CURATED_EXTRACTED_PAIRS {
v.push((p.model_name, lane_of(p.curated.provenance.l_doc)));
}
// Exempt entities: lane is hand-coded below (they're absent from
// the pairing table by definition — no extracted backing yet)
for (model_name, _) in COVERAGE_EXEMPTIONS {
v.push((*model_name, lane_of_exempt(model_name)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Build coverage from the actual lane entities

The coverage gate derives its “curated” universe from the generated pairings plus the exemption list, not from the lane modules themselves. If a curated lane entity is missing from both CURATED_EXTRACTED_PAIRS and COVERAGE_EXEMPTIONS, it is invisible to this test, so the advertised per-lane coverage can remain green while an uncovered curated model exists.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/lance-graph-ontology/src/odoo_blueprint/l1.rs (1)

51-513: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add focused lane-local tests in this module.

This new implementation file defines core lane entities but has no #[cfg(test)] coverage next to the constants.

✅ Minimal test scaffold
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn entities_slice_has_expected_models() {
+        let models: Vec<&str> = ENTITIES.iter().map(|e| e.model_name).collect();
+        assert_eq!(
+            models,
+            vec!["account.move", "account.move.line", "account.journal"]
+        );
+    }
+
+    #[test]
+    fn account_move_uses_shared_state_machine() {
+        assert!(ACCOUNT_MOVE.state_machine.is_some());
+        assert_eq!(ACCOUNT_MOVE.state_machine.unwrap().state_field, "state");
+    }
+}

As per coding guidelines, "Add Rust unit tests alongside implementations via #[cfg(test)] modules; prefer focused scenarios over broad integration tests".

🤖 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-ontology/src/odoo_blueprint/l1.rs` around lines 51 - 513,
Add a small #[cfg(test)] mod tests next to the entity constants that exercises
focused scenarios: assert ENTITIES contains ACCOUNT_MOVE, ACCOUNT_MOVE_LINE and
ACCOUNT_JOURNAL; check a couple of important field properties (e.g. ACCOUNT_MOVE
has a field named "name" with computed Some("_compute_name"), ACCOUNT_MOVE_LINE
has "balance" computed by "_compute_balance", and ACCOUNT_JOURNAL has required
"code" and "name"); and include one simple invariants test such as
ENTITIES.len() >= 3. Place the tests in the same module (after the constants) so
they compile-only under cfg(test) and keep them minimal and specific to the
symbols ACCOUNT_MOVE, ACCOUNT_MOVE_LINE, ACCOUNT_JOURNAL, and ENTITIES.
🧹 Nitpick comments (4)
.claude/plans/odoo-source-extraction-v1.md (1)

117-135: 💤 Low value

Markdown: specify language for fenced code block.

The code block showing the directory structure lacks a language identifier. Adding text or tree would silence the linter.

📝 Proposed fix
-```
+```text
 parsers/
   classes.py       — visits ClassDef; classifies as Model/Transient/Abstract by base

As per coding guidelines (static analysis hint: markdownlint MD040).

🤖 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-source-extraction-v1.md around lines 117 - 135, The
fenced code block that begins with "parsers/" and lists classes.py, fields.py,
methods.py, emitters/, audit/ etc. needs a language identifier on the opening
``` to satisfy MD040; update the opening fence to e.g. ```text or ```tree
(retain the same block contents) so the directory-structure snippet is
explicitly marked as plain text/tree.
.claude/plans/odoo-business-logic-blueprint-v1.md (1)

48-56: 💤 Low value

Markdown: specify language for fenced code block.

The code block lacks a language identifier. Adding text or plaintext would silence the linter and improve rendering consistency.

📝 Proposed fix
-```
+```text
 Odoo source (exact = ground truth)
   → typed Odoo entity DTOs        ← THIS PLAN

As per coding guidelines (static analysis hint: markdownlint MD040).

🤖 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-business-logic-blueprint-v1.md around lines 48 - 56, The
fenced code block in the plan lacks a language identifier causing markdownlint
MD040 failures; update the triple-backtick fence that wraps the lines starting
with "Odoo source (exact = ground truth)" to include a language tag (for example
`text` or `plaintext`) so the block becomes ```text ... ``` and the
linter/rendering will be satisfied; ensure you update the opening fence only and
leave the inner content (the lines containing "typed Odoo entity DTOs ← THIS
PLAN" etc.) unchanged.
crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs (1)

59-64: 💤 Low value

Consider failing loudly on parse errors instead of silent fallback.

The unwrap_or(0) fallback at line 63 silently maps unparseable l_doc strings to lane 0. Since lanes are numbered 1..=15, entities with lane 0 will be silently excluded from coverage checks. If a malformed l_doc is introduced (e.g., due to a future refactor or generator bug), the test will pass without detecting the issue.

Consider either:

  1. Using expect("l_doc must start with L{N}-") to fail explicitly, or
  2. Documenting that lane 0 is an intentional "skip" sentinel for malformed entries

Given the comment "should never happen post-EXT-3" suggests this is expected to always succeed, failing explicitly would be safer.

🔍 Proposed hardening (optional)
 fn lane_of(l_doc: &str) -> u8 {
-    // Strip the leading 'L', collect ASCII digits until the first '-'
     let stripped = l_doc.trim_start_matches('L');
     let digits: String = stripped.chars().take_while(|c| c.is_ascii_digit()).collect();
-    digits.parse().unwrap_or(0)
+    digits.parse().expect("l_doc must follow 'L{N}-...' format")
 }
🤖 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-ontology/src/odoo_blueprint/extracted/coverage.rs` around
lines 59 - 64, The lane_of function silently returns 0 on parse failure; change
this to fail loudly by replacing the current unwrap_or(0) behavior in lane_of
(which parses digits from l_doc) with an explicit expect (e.g.,
digits.parse::<u8>().expect("l_doc must be of form 'L{N}-...' and parse to a
lane 1..=15")) so malformed l_doc values cause a clear panic rather than
producing a silent lane 0; ensure the expect message mentions l_doc and the
expected format so debugging is straightforward.
tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py (1)

95-105: ⚡ Quick win

Remove the unused total_methods parameter from fallback_rate.

Line 95 accepts total_methods, but Lines 103-105 never use it, which makes the API contract misleading.

Proposed fix
-    def fallback_rate(self, total_fields: int, total_methods: int) -> float:
+    def fallback_rate(self, total_fields: int) -> float:
🤖 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
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py`
around lines 95 - 105, The fallback_rate function declares an unused parameter
total_methods; remove total_methods from the signature of fallback_rate and
update its docstring to stop referencing methods (keep explanation about fields
and ::Other), then search for and update all call sites that pass total_methods
to call fallback_rate with only total_fields (or adapt callers if needed) so the
API and usages remain consistent; refer to the fallback_rate method to locate
the change and ensure tests/places invoking it are adjusted.
🤖 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 3: Replace the misleading phrase "Stage 2 closes the 5 HR/stock_account
gaps" in the INTEGRATION_PLANS.md summary with wording that matches the TIER-2
scope defined in the plan (TIER-2: POS, HR, website, fleet, maintenance, non-DE
l10n, payment providers); update the Stage 2 line to read something like "Stage
2 addresses TIER-2 addons (POS, HR, website, fleet, maintenance, non-DE l10n,
payment providers)" so the "Stage 2" and "TIER-2" terminology aligns exactly
with the `.claude/plans/odoo-source-extraction-v1.md` definition and remove the
numeric "5 HR/stock_account gaps" wording.
- Line 3: The board shows "Status: SHIPPED (Stage 1 — EXT-1..6 complete)" but
the deliverables table still marks D-ODOO-EXT-* items as "Queued", and
.claude/plans/odoo-source-extraction-v1.md also claims SHIPPED—reconcile these
by choosing the true state: if EXT-1..6 are shipped, update each D-ODOO-EXT-*
row to "Shipped" and add evidence (commit range 9507b36..2aca3e3 and per-lane
gate test `extracted::coverage`), otherwise change the top-line "Status:
SHIPPED" in this file and in .claude/plans/odoo-source-extraction-v1.md to
"Active" or "In progress" and add a note about queued deliverables; ensure both
files match and reference the same evidence or next steps for Stage 2.

In @.claude/plans/odoo-business-logic-blueprint-v1.md:
- Line 129: Update the D-ODOO-BP-1f row in
.claude/plans/odoo-business-logic-blueprint-v1.md to replace the phrase "parse
Python AST for ORM classes via tree-sitter" with "parse Python AST for ORM
classes via Python stdlib ast module" so the deliverable matches the actual
implementation plan; also verify the wording is consistent with
.claude/plans/odoo-source-extraction-v1.md and the doc comment in
odoo_blueprint/mod.rs (around the mod.rs:321 doc) to avoid the stale
"tree-sitter" reference.

In @.claude/plans/odoo-source-extraction-v1.md:
- Line 3: The status line in .claude/plans/odoo-source-extraction-v1.md
incorrectly claims "SHIPPED (Stage 1 complete 2026-05-28; EXT-1..6 landed)"
which contradicts the tracking in .claude/board/INTEGRATION_PLANS.md and
.claude/board/STATUS_BOARD.md; either update this plan to a truthful state
("Active" or "In progress") or add verifiable evidence (PR numbers or commit
hashes) and update the board files to mark Stage 1/EXT-1..6 as shipped; ensure
the plan entry that unfolds D-ODOO-BP-1f matches the same status and includes
the same shipment identifiers as the board files.

In `@crates/lance-graph-contract/src/grammar/role_keys.rs`:
- Around line 100-103: RoleKey::generate currently uses debug_assert! for bounds
(start <= end and end <= VSA_DIMS) which are stripped in release builds; replace
those with runtime checks that enforce the invariants in all builds (for example
use assert! or explicit if-checks that panic with a clear message) before
creating the words Box<[u64; VSA_WORDS]> and computing word/bit indices, so you
never index words[word] or compute widths with start > end or end > VSA_DIMS;
keep the function signature but ensure the checks reference RoleKey::generate,
VSA_DIMS, VSA_WORDS and validate start/end up front.

In `@crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs`:
- Line 230: The provenance currently embeds an absolute local path in the
odoo_source OdooSourceRef entry (the array element containing path:
"/home/user/odoo/addons/uom/models/uom_uom.py"), which must be made
repository-relative and portable; update the OdooSourceRef.path value to a
repo-relative path (e.g., "odoo/addons/uom/models/uom_uom.py" or otherwise
computed from a known repo root), preserve the line_range tuple and the
OdooSourceRef structure, and ensure any code that constructs this path uses the
repo root or a relative resolver instead of embedding the user’s home directory.

In `@crates/lance-graph-ontology/src/odoo_blueprint/l8.rs`:
- Line 103: Rename the public constant currently declared as UOM_UUM to the
correct UOM_UOM wherever it's defined and exported (the OdooEntity constant
declaration), and update all internal references and re-exports/tests that use
UOM_UUM (including the other two occurrences) to the new name; ensure the symbol
visibility and any doc comments remain the same so public API and consumers now
refer to UOM_UOM.

In `@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__init__.py`:
- Line 9: The public constant __version__ is missing a type annotation; update
the module-level export by adding an explicit string type annotation for the
__version__ symbol so the public API is type-annotated (i.e., mark __version__
as a string in the assignment), keeping the existing value and formatting
consistent with project Python style.

In `@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py`:
- Around line 147-150: The audit write block can raise FileNotFoundError if the
audit file's parent directory doesn't exist; before calling emit_audit_json and
Path(audit_path).write_text in the audit_path branch, ensure the parent
directory exists by creating Path(audit_path).parent with mkdir(parents=True,
exist_ok=True), then proceed to generate audit_json with
emit_audit_json(pairings) and write it; keep the existing print to stderr
unchanged.

In
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/csv_chart.py`:
- Around line 105-110: The code currently defaults any non-"skr03" value to
SKR04; update the branch that sets prefix and chart_variant to explicitly
validate the chart variable (e.g., check if chart == "skr03" or chart ==
"skr04") and handle unexpected values by raising a clear exception or logging an
error instead of silently mapping to SKR04; change the block that assigns prefix
and chart_variant so it only accepts "skr03" and "skr04" and emits a helpful
error for other inputs.

In
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py`:
- Around line 83-87: verify_gobd_wiring currently marks the DE compute wiring
present whenever _find_compute_method returns a method for
"_compute_force_restrictive_audit_trail" but doesn't validate the method body,
which causes false positives because trigger_pattern is assumed to be
"country_code == 'DE'"; change the logic in verify_gobd_wiring to inspect the
returned method's body/source (e.g., method["body"] or method["source"]) and
only set result["l10n_de_compute_found"] and result["l10n_de_compute_lineno"] if
that body contains the trigger pattern (or a robust regex match for country_code
== 'DE'), and optionally record a new flag like result["l10n_de_trigger_found"]
when the pattern is present instead of relying solely on method existence.

In
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py`:
- Around line 204-205: The XML parsing in xml_kennzahl.py uses the stdlib
xml.etree.ElementTree (ET.parse and tree.getroot) on files from a CLI-provided
addons dir and must be hardened: change the import from xml.etree.ElementTree to
defusedxml's ElementTree (i.e., replace the module import so ET.parse(...) still
works but via defusedxml) and add defusedxml as a runtime dependency in
tools/odoo-blueprint-extractor/pyproject.toml so the package is installed.

---

Outside diff comments:
In `@crates/lance-graph-ontology/src/odoo_blueprint/l1.rs`:
- Around line 51-513: Add a small #[cfg(test)] mod tests next to the entity
constants that exercises focused scenarios: assert ENTITIES contains
ACCOUNT_MOVE, ACCOUNT_MOVE_LINE and ACCOUNT_JOURNAL; check a couple of important
field properties (e.g. ACCOUNT_MOVE has a field named "name" with computed
Some("_compute_name"), ACCOUNT_MOVE_LINE has "balance" computed by
"_compute_balance", and ACCOUNT_JOURNAL has required "code" and "name"); and
include one simple invariants test such as ENTITIES.len() >= 3. Place the tests
in the same module (after the constants) so they compile-only under cfg(test)
and keep them minimal and specific to the symbols ACCOUNT_MOVE,
ACCOUNT_MOVE_LINE, ACCOUNT_JOURNAL, and ENTITIES.

---

Nitpick comments:
In @.claude/plans/odoo-business-logic-blueprint-v1.md:
- Around line 48-56: The fenced code block in the plan lacks a language
identifier causing markdownlint MD040 failures; update the triple-backtick fence
that wraps the lines starting with "Odoo source (exact = ground truth)" to
include a language tag (for example `text` or `plaintext`) so the block becomes
```text ... ``` and the linter/rendering will be satisfied; ensure you update
the opening fence only and leave the inner content (the lines containing "typed
Odoo entity DTOs ← THIS PLAN" etc.) unchanged.

In @.claude/plans/odoo-source-extraction-v1.md:
- Around line 117-135: The fenced code block that begins with "parsers/" and
lists classes.py, fields.py, methods.py, emitters/, audit/ etc. needs a language
identifier on the opening ``` to satisfy MD040; update the opening fence to e.g.
```text or ```tree (retain the same block contents) so the directory-structure
snippet is explicitly marked as plain text/tree.

In `@crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs`:
- Around line 59-64: The lane_of function silently returns 0 on parse failure;
change this to fail loudly by replacing the current unwrap_or(0) behavior in
lane_of (which parses digits from l_doc) with an explicit expect (e.g.,
digits.parse::<u8>().expect("l_doc must be of form 'L{N}-...' and parse to a
lane 1..=15")) so malformed l_doc values cause a clear panic rather than
producing a silent lane 0; ensure the expect message mentions l_doc and the
expected format so debugging is straightforward.

In
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py`:
- Around line 95-105: The fallback_rate function declares an unused parameter
total_methods; remove total_methods from the signature of fallback_rate and
update its docstring to stop referencing methods (keep explanation about fields
and ::Other), then search for and update all call sites that pass total_methods
to call fallback_rate with only total_fields (or adapt callers if needed) so the
API and usages remain consistent; refer to the fallback_rate method to locate
the change and ensure tests/places invoking it are adjusted.
🪄 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: b73af7c6-4a10-41a1-90ea-2c470953bbd5

📥 Commits

Reviewing files that changed from the base of the PR and between e7d733f and 353fac0.

📒 Files selected for processing (71)
  • .claude/board/AGENT_LOG.md
  • .claude/board/EPIPHANIES.md
  • .claude/board/INTEGRATION_PLANS.md
  • .claude/board/STATUS_BOARD.md
  • .claude/plans/odoo-business-logic-blueprint-v1.md
  • .claude/plans/odoo-savant-reasoners-v2.md
  • .claude/plans/odoo-source-extraction-v1.md
  • crates/lance-graph-contract/src/callcenter/mod.rs
  • crates/lance-graph-contract/src/callcenter/ogit_uris.rs
  • crates/lance-graph-contract/src/callcenter/role_keys.rs
  • crates/lance-graph-contract/src/grammar/role_keys.rs
  • crates/lance-graph-contract/src/lib.rs
  • crates/lance-graph-ontology/src/lib.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/COVERAGE.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_edi_ubl_cii.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_payment.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_peppol.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/analytic.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/base.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de_chart.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de_kennzahlen.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/mod.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/pairing.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/product.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/purchase.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/sale.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/stock.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l1.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l10.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l11.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l12.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l13.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l14.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l15.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l2.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l3.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l4.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l5.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l6.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l7.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l8.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l9.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/mod.rs
  • tools/odoo-blueprint-extractor/README.md
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__main__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/csv_chart.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/module.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/rust.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/pairing.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/classes.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/constraints.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/decorators.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/fields.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/methods.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/regulation.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/state_machine.py
  • tools/odoo-blueprint-extractor/pyproject.toml
  • tools/odoo-blueprint-extractor/tests/test_smoke_uom.py

Comment thread .claude/board/INTEGRATION_PLANS.md Outdated
Comment thread .claude/plans/odoo-business-logic-blueprint-v1.md Outdated
Comment thread .claude/plans/odoo-source-extraction-v1.md Outdated
Comment thread crates/lance-graph-contract/src/grammar/role_keys.rs
Comment thread crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs Outdated
Comment thread tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__init__.py Outdated
Comment thread tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py
@AdaWorldAPI AdaWorldAPI force-pushed the claude/activate-lance-graph-att-k2pHI branch from 353fac0 to 61896b1 Compare May 28, 2026 11:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py (1)

32-32: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use hardened XML parsing for CLI-supplied input paths.

ET.parse(...) from stdlib on external XML paths is flagged by Ruff S314; switch to defusedxml and add the runtime dependency for this tool package.

Suggested fix
-import xml.etree.ElementTree as ET
+from defusedxml import ElementTree as ET

You can verify this stays clean with:

#!/bin/bash
set -euo pipefail
rg -n "xml.etree.ElementTree|ET.parse\(" tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py
rg -n "defusedxml" tools/odoo-blueprint-extractor/pyproject.toml

Also applies to: 204-205

🤖 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
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py`
at line 32, The code uses xml.etree.ElementTree (ET.parse) on CLI-supplied XML
which is unsafe; replace usages with a hardened parser by importing
defusedxml.ElementTree as ET and updating calls (e.g., XML parsing in
xml_kennzahl.py where ET.parse(...) is used) to use that import; also add
defusedxml as a runtime dependency in the tool package (pyproject.toml) so the
import is available, and repeat the same replacement for the other occurrences
noted (around the other ET.parse uses at the referenced lines).
🤖 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/plans/odoo-business-logic-blueprint-v1.md:
- Around line 48-56: Add a fence language to the shown Markdown code block to
satisfy MD040; update the triple-backtick opening fence in the block containing
"Odoo source (exact = ground truth) ..." to include a language tag (e.g.,
"text") so it becomes ```text, leaving the block contents unchanged.

In @.claude/plans/odoo-source-extraction-v1.md:
- Around line 117-135: The fenced code block that lists the parsers/ emitters/
audit tree (the block starting with "parsers/" and ending with
"fallback_log.py") lacks a language tag causing markdownlint MD040; update that
triple-backtick fence to include a language (e.g., ```text) so the block is
explicitly marked and the linter warning is resolved.

---

Duplicate comments:
In
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py`:
- Line 32: The code uses xml.etree.ElementTree (ET.parse) on CLI-supplied XML
which is unsafe; replace usages with a hardened parser by importing
defusedxml.ElementTree as ET and updating calls (e.g., XML parsing in
xml_kennzahl.py where ET.parse(...) is used) to use that import; also add
defusedxml as a runtime dependency in the tool package (pyproject.toml) so the
import is available, and repeat the same replacement for the other occurrences
noted (around the other ET.parse uses at the referenced lines).
🪄 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: 4a586924-d1d2-4c39-937c-022faa6918bc

📥 Commits

Reviewing files that changed from the base of the PR and between 353fac0 and 61896b1.

📒 Files selected for processing (71)
  • .claude/board/AGENT_LOG.md
  • .claude/board/EPIPHANIES.md
  • .claude/board/INTEGRATION_PLANS.md
  • .claude/board/STATUS_BOARD.md
  • .claude/plans/odoo-business-logic-blueprint-v1.md
  • .claude/plans/odoo-savant-reasoners-v2.md
  • .claude/plans/odoo-source-extraction-v1.md
  • crates/lance-graph-contract/src/callcenter/mod.rs
  • crates/lance-graph-contract/src/callcenter/ogit_uris.rs
  • crates/lance-graph-contract/src/callcenter/role_keys.rs
  • crates/lance-graph-contract/src/grammar/role_keys.rs
  • crates/lance-graph-contract/src/lib.rs
  • crates/lance-graph-ontology/src/lib.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/COVERAGE.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_edi_ubl_cii.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_payment.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_peppol.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/analytic.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/base.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de_chart.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de_kennzahlen.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/mod.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/pairing.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/product.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/purchase.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/sale.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/stock.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l1.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l10.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l11.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l12.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l13.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l14.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l15.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l2.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l3.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l4.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l5.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l6.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l7.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l8.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l9.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/mod.rs
  • tools/odoo-blueprint-extractor/README.md
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__main__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/csv_chart.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/module.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/rust.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/pairing.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/classes.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/constraints.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/decorators.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/fields.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/methods.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/regulation.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/state_machine.py
  • tools/odoo-blueprint-extractor/pyproject.toml
  • tools/odoo-blueprint-extractor/tests/test_smoke_uom.py
💤 Files with no reviewable changes (1)
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/rust.py
✅ Files skipped from review due to trivial changes (16)
  • crates/lance-graph-contract/src/lib.rs
  • crates/lance-graph-ontology/src/lib.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/init.py
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/init.py
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_payment.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/pairing.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/init.py
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/analytic.rs
  • .claude/plans/odoo-savant-reasoners-v2.md
  • .claude/board/INTEGRATION_PLANS.md
  • .claude/board/AGENT_LOG.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_peppol.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de.rs
  • .claude/board/STATUS_BOARD.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de_kennzahlen.rs
🚧 Files skipped from review as they are similar to previous changes (29)
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/main.py
  • crates/lance-graph-contract/src/grammar/role_keys.rs
  • crates/lance-graph-contract/src/callcenter/ogit_uris.rs
  • crates/lance-graph-contract/src/callcenter/mod.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/module.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/init.py
  • .claude/board/EPIPHANIES.md
  • crates/lance-graph-ontology/src/odoo_blueprint/l4.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py
  • crates/lance-graph-ontology/src/odoo_blueprint/l8.rs
  • crates/lance-graph-contract/src/callcenter/role_keys.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l7.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py
  • crates/lance-graph-ontology/src/odoo_blueprint/l15.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l5.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l13.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/csv_chart.py
  • crates/lance-graph-ontology/src/odoo_blueprint/l14.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/mod.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/mod.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l11.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l12.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l2.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l6.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l3.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l10.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l1.rs

Comment thread .claude/plans/odoo-business-logic-blueprint-v1.md Outdated
Comment thread .claude/plans/odoo-source-extraction-v1.md Outdated
AdaWorldAPI pushed a commit that referenced this pull request May 28, 2026
…ped)

Group A — board + plan governance
- INTEGRATION_PLANS.md: reconcile Stage-2 terminology with plan's TIER-2 scope
- BP-1 plan: D-ODOO-BP-1f row — tree-sitter → Python stdlib ast (matches reality)
- EXT-1 plan: Status line gets commit-range evidence (15b63ce..b54a743)

Group B — Rust source fixes
- grammar/role_keys.rs: debug_assert! → assert! (release-build safety)
- extracted/*.rs: emitter now strips /home/user/ prefix → repo-relative paths;
  all 12 TIER-1 addons + l10n_de chart/kennzahlen regenerated
- l8.rs: UOM_UUM typo → UOM_UOM (+ pairing.rs reference update)
- extracted/coverage.rs: lane_of unwrap_or(0) → expect (fail loud on malformed l_doc)

Group C — Python tooling
- __init__.py: __version__: str type annotation
- cli.py: mkdir(parents=True, exist_ok=True) before audit write in pair + ORM paths
- data_extractors/csv_chart.py: explicit SKR03/SKR04 validation (no silent default)
- data_extractors/gobd_company.py: verify_gobd_wiring inspects method body for
  country_code == 'DE' trigger (no longer false-positive on naked method existence)
- data_extractors/xml_kennzahl.py: defusedxml drop-in for ET (XXE/billion-laughs
  hardening on Odoo-vendored XML). New runtime dep in pyproject.toml.
- tests/test_smoke_uom.py: update fallback_rate call sites (drop total_methods arg)

Group D — nitpicks
- 2 plan files: add 'text' language tag on directory-tree fenced blocks (MD040)
- audit/fallback_log.py: drop unused total_methods from fallback_rate signature

SKIPPED with rationale (1/17):
- l1.rs unit tests for ENTITIES contents: tests would echo static const data,
  not defend invariants. The cross-cutting properties (kind/confidence/l_doc)
  are already enforced by extracted::coverage::tests' aggregate gate.

Tests: cargo test -p lance-graph-ontology --lib green (203 tests).
Python smoke test: ALL TESTS PASS.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
claude added 23 commits May 28, 2026 11:55
…ition over CausalEdge64 + Tactic + role_keys (E-SAVANT-COMPOSITION-1)

v1 (shipped PR #420 with a "MED on dispatch shape" caveat) review resolved:
the Reasoner trait surface fails CLAUDE.md "P-1 The Click" + "P0 AGI-as-glove"
litmus tests verbatim:

1. "new capability lands as a new column, not a new layer"
   → the Reasoner trait IS a new layer
2. "free function on a carrier's state = reject"
   → build_conclusion(savant, ctx) is the named anti-pattern
3. "wrap the axes in a new struct = breaks the SIMD sweep"
   → SavantConclusion + SavantSuggestion duplicate CausalEdge64

v2 routes the canonical path through the agnostic substrate that already exists:
- CausalEdge64 (zero-dep crates/causal-edge, v2 layout — the savant's decision
  IS the emitted edge: SPO palette + NARS truth + Pearl 2³ + inference mantissa)
- Tactic trait + 34 kernels (PR #411 — "the Elixir-like recipe layer that later
  fronts the real fingerprint substrate via cognitive-shader-driver with no
  change to the 34 call sites")
- 33-TSV atom layer (PR #411 contract::atoms::CANONICAL_ATOMS)
- Role-key catalogues (I-VSA-IDENTITIES names callcenter/role_keys.rs as future
  Layer-2 home)

Deliverables (Queued):
- D-ODOO-SAV-5a: SavantPattern + TacticInvocation + EdgeEmissionSpec +
  AtomTouchMask primitives in lance-graph-contract (Group D)
- D-ODOO-SAV-5b: callcenter/role_keys.rs with 25 disjoint Vsa16kF32 slices
  + lookup-by-OdooSavant + slice manifest (Group E)
- D-ODOO-SAV-5c: 25 typed SavantPattern consts drawn from
  .claude/odoo/savants/<N>.md slot 1/4 + .claude/odoo/L*.md (Group F)
- D-ODOO-SAV-5d: #[deprecated] + legacy-reasoner feature gate + migration
  pointers on v1 Reasoner surface, per I-LEGACY-API-FEATURE-GATED (Group G)
- D-ODOO-SAV-5e: end-to-end test (FiscalPositionResolver SavantPattern →
  expected CausalEdge64 row, SPO + NARS + v2 signed mantissa)

Execution: 5a + 5b parallel (additive, zero churn) → 5c after both → 5d after
5c (migration pointers name real targets) → 5e throughout. woa-rs consumer
migration OUT OF SCOPE but UNBLOCKED by 5d.

Board hygiene per CLAUDE.md: plan file + INTEGRATION_PLANS PREPEND +
STATUS_BOARD section + EPIPHANIES E-SAVANT-COMPOSITION-1 all in this commit.

v1 surface (Reasoner trait, 4 *Reasoner impls, SavantConclusion,
SavantSuggestion, build_conclusion) stays compiling under the legacy-reasoner
feature with #[deprecated] migration pointers until woa-rs migrates its
Reasoner::reason() call sites to SavantPattern resolution. Removal in a
follow-up PR after the migration.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…strate for OGIT/OWL/DOLCE/FIBU normalization + JITson codegen (prerequisite for v2 Group F)

The user-named pipeline:

  Odoo source (exact = ground truth)
    → typed Odoo entity DTOs        ← THIS PLAN
    → normalize: Odoo → OGIT → OWL → DOLCE → FIBU/FIBO inheritance chain
    → recipes (34 Tactic kernels) + JITson / Cranelift codegen
    → DTO-ish NARS atoms (33-TSV) — low-entropy typed surface
    → cognitive-shader-driver fans across the SoA at 10000×10000
    → CausalEdge64 emissions in EdgeColumn = the conclusions

PREREQUISITE for odoo-savant-reasoners-v2 Group F (per E-SAVANT-COMPOSITION-1):
v2's SavantPattern consts compose *over normalized typed DTOs*. Without this
blueprint they would be ad-hoc interpretations of L-doc prose. This plan
establishes the missing layer between Odoo prose curation and the agnostic
shader substrate.

Today every downstream layer (OGIT classifier, OWL hydrator, DOLCE classifier,
FIBU/FIBO alignment) string-keys against model_name. The typed OdooEntity +
sub-types replaces those ad-hoc string maps with a single typed surface the
inheritance chain operates on.

Scope (ratified 2026-05-28):
- Source: BOTH passes — L-docs first as curated savant-relevant filter;
  /home/user/odoo source extraction follows as exhaustive backing
- Lane coverage: ALL 15 lanes (L1–L15), complete typed blueprint

Typed surface — new module lance-graph-ontology::odoo_blueprint:
- OdooEntity (model_name + fields + methods + decorators + state_machine +
  constraints + provenance)
- OdooField (kind, target, required, computed, depends, semantic_role)
- OdooMethod (kind, return_kind, triggers)
- OdooDecorator (kind, targets) — covers @api.depends, @api.constrains,
  @api.onchange, @api.model_create_multi, etc.
- OdooStateMachine (state_field, states, transitions)
- OdooConstraint (kind, condition, source_method)
- OdooProvenance (l_doc, l_doc_lines, odoo_source path:line, confidence:
  Curated/Extracted/Conjecture)

Deliverables (Queued):
- D-ODOO-BP-1a: OdooEntity + sub-types typed surface (zero-dep, const-only,
  no serde) — ships with this commit per board hygiene
- D-ODOO-BP-1b: L-doc projection in Waves — one OdooEntity const per entity
  per lane, 15 lanes, ~150-300 consts total
- D-ODOO-BP-1c: OGIT classifier wired to &OdooEntity (replaces string-keyed
  resolve_odoo)
- D-ODOO-BP-1d: OWL hydrator wired to &OdooEntity (relational → edges,
  computed → SHACL constraints, decorators → axioms)
- D-ODOO-BP-1e: DOLCE + FIBU/FIBO wired to &OdooEntity (closes D-ODOO-SAV-2
  None-class alignment over typed input)
- D-ODOO-BP-1f: Odoo source extraction tool (tree-sitter Python AST →
  candidate consts; validates + extends 1b)
- D-ODOO-BP-1g: JITson → recipes wiring (jit::JitCompiler compiles Tactic
  kernels parameterized by &OdooEntity → DTO-ish NARS in shader-driver)

THEN odoo-savant-reasoners-v2 Group F unblocks. v2 Groups D/E/G remain
unblocked (ship independently; F is the only group blocked on the blueprint).

Board hygiene per CLAUDE.md: plan + INTEGRATION_PLANS PREPEND +
STATUS_BOARD section in this commit. No new EPIPHANIES (extends
E-SAVANT-COMPOSITION-1 which landed in 741a25c).

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…OO-SAV-5b 25 savant role keys

Two parallel additive deliverables — both zero-churn surfaces opened by
the v2 reshape (PR #420 deprecation) + blueprint plan (commits 741a25c
+ 6d2466e):

## D-ODOO-BP-1a — typed Odoo entity DTOs (lance-graph-ontology::odoo_blueprint)

New module `crates/lance-graph-ontology/src/odoo_blueprint.rs` carrying
the typed surface the OGIT → OWL → DOLCE → FIBU/FIBO inheritance chain
will operate on (replacing today's ad-hoc string-keyed maps against
`model_name`).

Types: OdooEntity + OdooField + OdooMethod + OdooDecorator +
OdooStateMachine + OdooState + OdooTransition + OdooConstraint +
OdooProvenance + OdooSourceRef.

Enums: OdooFieldKind (17 variants), OdooSemanticRole (12), OdooMethodKind
(10), OdooReturnKind (10), OdooDecoratorKind (7), OdooStateSemantic (7),
OdooConstraintKind (3), OdooConfidence (3 — Curated/Extracted/Conjecture).

Tests: 3 — sample_entity_compiles_as_const (FiscalPosition shape),
state_machine_entity_compiles (Invoice draft→posted→cancel),
empty_entity_compiles (zero case).

Per-lane consts (L1–L15) land in D-ODOO-BP-1b; OGIT/OWL/DOLCE/FIBU
wiring lands in 1c/d/e; source extraction in 1f; JITson + recipes in 1g.

## D-ODOO-SAV-5b — 25 savant role keys (contract::callcenter::role_keys)

New module `crates/lance-graph-contract/src/callcenter/{mod,role_keys}.rs`
per I-VSA-IDENTITIES Layer-2 catalogue doctrine (sibling of
`contract::grammar::role_keys`, NOT in the separate lance-graph-callcenter
crate — path correction from the v2 plan).

Slice layout: 25 savants × 90 dims = 2250 dims in the SMB headroom
[14096..16346), with 38 dims of headroom remaining. FNV-64 seeded from
each savant's name (lookup matches SAVANTS const order). LazyLock<[RoleKey; 25]>
lookup by id or name.

Tests: 7 — slices_disjoint_and_in_bounds, savant_zone_fits_in_smb_headroom
(2250 dims + 38 headroom = 2288), id_lookup_matches_name_lookup,
id_16_absent (the intentional gap), last_savant_is_backorder_judge,
deterministic_pseudo_random_bits, no_overlap_with_grammar_slices.

## Supporting change

`RoleKey::generate` made `pub` in `contract::grammar::role_keys` so
sibling per-domain Layer-2 catalogues (callcenter today; persona, others
later) can construct their own role keys with disjoint slice allocations
— per I-VSA-IDENTITIES. Documented in the doc-comment.

## Tests + integration

- lance-graph-contract: 7 new callcenter::role_keys tests pass; 454 prior
  contract lib tests unaffected
- lance-graph-ontology: 3 new odoo_blueprint tests pass; 43 lib tests total

## Followups

- D-ODOO-SAV-5a (BusinessGrammarTemplate primitive) — design pass
  complete (4-surface integration map: DeepNSM SpoTriple shape + ractor
  ModuleEntry + AriGraph SpoRecord/TruthValue + ReasoningWitness64).
  Code lands next, with the 7-field shape: PatternMatchSpec +
  AtomTouchMask + MailboxSpawnSpec + RecipeComposition + EdgeEmissionSpec
  + EpisodicWitnessSpec + TemplateProvenance.
- D-ODOO-BP-1b — per-lane entity consts, L1–L15 Wave (one subagent per lane).

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…P-1b waves) + v2 path correction

Restructures crates/lance-graph-ontology/src/odoo_blueprint.rs into a
directory module with one sub-module per L-doc:

  odoo_blueprint/
    mod.rs                 # typed OdooEntity surface (unchanged from feaa587)
    l1.rs  ... l15.rs      # per-lane const ENTITIES: &[OdooEntity] = &[] stubs

Each lN.rs is a minimal stub pending the D-ODOO-BP-1b projection wave.
Stubs declare an empty ENTITIES const and reference super::OdooEntity so
the wave fills in the content without touching mod.rs or each other (per
the autoattended-multiagent-pattern unique-file-write iron rule).

Also fixes the v2 plan's Group E path:
- crates/lance-graph-callcenter/src/role_keys.rs (wrong: that's the
  external-membrane crate)
- → contract::callcenter::role_keys (correct: sibling of
  contract::grammar::role_keys, per the per-domain Layer-2 catalogue
  doctrine; this is where SAV-5b actually landed in feaa587).

Plus fixes the Vsa16kF32 language: Vsa16kF32 is the deprecated f32
carrier; the actual SAV-5b shape uses RoleKey { words: Box<[u64; 256]> }
which IS the Binary16K bitpacked format. Per the 2026-05-28 doctrinal
update (user), bitpacked is a "desperation bucket"; the canonical
identity architecture is LE-byte SoA with codebook inherited from OGIT
(because the SoA doesn't guess). SAV-5b stays compiled as the
desperation-bucket fallback; the canonical OGIT-codebook form lands in
a separate follow-up commit (see next message in this PR).

Tests: 3 odoo_blueprint unit tests pass; 40 ontology lib tests total.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…rojections (5 lanes, 32 lane tests, +4008 lines)

Self-orchestrated harvest wave per the 2026-05-28 directive. 5 parallel
Sonnet agents projected the L1–L5 lane docs into typed OdooEntity const
declarations in their assigned per-lane files (unique-file-write rule).

Wave outputs (all 32 lane tests pass; 43 prior ontology lib tests
unaffected = 75 total ontology tests green):

- l1.rs (K3-POST, 506 lines): account.move, account.journal,
  account.move.line, account.lock.exception, ir.sequence entities.
  Drives savants AutopostRecommender, LockDateAdvancer,
  SequenceGapAnomalyDetector.
- l2.rs (K3-RECON, 571 lines): account.move.line, account.partial.reconcile,
  account.bank.statement, account.bank.statement.line +
  account.reconcile.model with full reconcile-rule fields. Drives savants
  ReconcileMatchSelector, BankStatementMatcher, PaymentToInvoiceMatcher.
- l3.rs (K7-TAX, 1172 lines): account.tax, account.tax.group,
  account.tax.repartition.line, account.fiscal.position,
  account.fiscal.position.tax, account.fiscal.position.account,
  account.account.tag, plus tax-exigibility selection details. Drives
  savants TaxExigibilitySuggestor, FiscalPositionResolver, repartition
  semantics for L15.
- l4.rs (K8K9-REPORTS-DATEV, 633 lines): account.account.tag (with
  USt-VA / GuV / Bilanz routing tags), account.account (l10n_de
  code-lock), account.tax (DATEV Steuerschlüssel), product.template
  (income/expense routing), res.company + account.journal (l10n_de
  GoBD audit trail).
- l5.rs (PAY-TERMS-MATCH, 1126 lines): account.payment (with full
  draft→in_process→paid→canceled→rejected state machine + 7 transitions
  + guards), account.payment.term + .line, account.payment.method +
  .line, account.reconcile.model + .line. Drives savants
  ReconcileMatchSelector, BankStatementMatcher, PaymentToInvoiceMatcher.

All entities carry OdooProvenance with real L-doc line ranges (no
fabricated provenance), OdooConfidence::Curated, and Odoo source
cross-references where verified. Cross-cutting / overlap notes preserved
in source comments (e.g. l5.rs notes the L2 candidacy of reconcile.model).

Wave 2 (L6–L10) + Wave 3 (L11–L15) follow after the codebook foundation
commit lands, per the user's 2026-05-28 "codebook for everything inherited
from OGIT" doctrine. SAV-5b's bitpacked RoleKey form is the
desperation-bucket fallback; canonical OGIT-URI codebook foundation
lands in the next commit.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…tion + E-CODEBOOK-INHERITS-FROM-OGIT

Per the 2026-05-28 user-given doctrine (distilled across four messages):
"every data is now LE-byte contract SoA in each mailbox / bitpacked is
also only a desperation bucket / normally LE SoA should have codebook
for everything including semantic ontology graph / inherited from OGIT
because the SoA doesn't guess."

Adds the canonical identity layer that supersedes the bitpacked RoleKey
form shipped in feaa587:

**New: crates/lance-graph-contract/src/callcenter/ogit_uris.rs (8 tests)**
- SAVANT_OGIT_BASE = "https://ogit.adaworldapi.com/callcenter/savants#"
- SAVANT_OGIT_URIS: LazyLock<[String; 25]> — one URI per savant, roster order
- savant_ogit_uri(id) / savant_ogit_uri_by_name(name) — lookup helpers
- 8 unit tests: uris_match_savant_count, uris_use_canonical_namespace,
  id_1_resolves_to_fiscal_position_resolver, id_16_is_absent,
  id_26_resolves_to_backorder_judge, id_lookup_matches_name_lookup,
  nonexistent_name_returns_none, every_savant_in_roster_has_a_uri

Resolves through `lance-graph-ontology::registry::OntologyRegistry`
(infrastructure already shipped — PR #407/#408 hydrators, PR #412 DOLCE
classifier, PR #416 FIBU/FIBO alignment, the canonical lingua-franca path).
The OntologyRegistry resolves the URI to a stable u32 codebook code; the
LE-byte mailbox SoA columns store the code. The Baton (u16, CausalEdge64)
carries the code across mailbox boundaries.

**Updated: contract::callcenter::role_keys (doc-only update)**
Module-level documentation now explicitly flags the bitpacked RoleKey
slices as the desperation-bucket fallback per the new doctrine; canonical
savant identity is via the OGIT URI in ogit_uris. Code unchanged (still
compiled, 7 tests still pass) — usable for ephemeral in-mailbox Hamming
compare where codebook lookup is unavailable.

**Updated: contract::callcenter::mod.rs**
Re-exports the new ogit_uris module + adds the two-identity-layer rationale
in the module doc (canonical OGIT URI + desperation-bucket RoleKey).

**Prepended: .claude/board/EPIPHANIES.md — E-CODEBOOK-INHERITS-FROM-OGIT**
Captures the full doctrine across all four 2026-05-28 messages:
Vsa16kF32 deprecated, LE-byte SoA per mailbox, codebook for everything,
inheritance from OGIT, Kontenerkennung-style multi-dim rich codebook
(parent chain + NARS confidence per link + business × transaction × form
× regulation × law × entity × product), audit query layer (episodic +
AriGraph SPO-G + regulation-ontology + NARS confidence threshold).

**Queued (separate D-ids, captured in the EPIPHANIES entry):**
- (a) data/ontologies/ogit/callcenter/savants.ttl + OntologyRegistry
  hydration for the 25 savants
- (b) Kontenerkennung-style inheritance struct with NARS confidence per
  parent link
- (c) regulation-ontology codebook (HGB / GoB / AO / UStG / IFRS / GoBD)
- (d) audit-threshold dispatch in cognitive-shader-driver (NARS confidence
  vs audit_floor → CausalEdge64 emission or escalation Baton)

Tests: 15 callcenter tests total (8 new ogit_uris + 7 existing role_keys);
454 prior contract lib tests unaffected.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…ped OdooEntity projections (4 lanes, 37 lane tests, +5164 lines)

Wave 2 of the self-orchestrated harvest. 5 parallel Sonnet agents
dispatched for L6–L10; 4 returned productive outputs, 1 (L9) is still
the 11-line stub (apparent quota-burn or silent failure — re-spawned with
tighter scope in the next pass).

Productive outputs (all 37 lane tests pass; 69 lane tests total across
Wave 1 + Wave 2; 75 total ontology tests green):

- l6.rs (SALE-PURCHASE, 1551 lines): sale.order, sale.order.line,
  purchase.order, purchase.order.line, product.pricelist,
  product.pricelist.item entities with state machines + invoicing
  policy. Drives savants UpsellActivityTrigger, PricelistRecommender
  (the AXIS-B dispatch surface for partner-pricelist resolution).
  Notes L8 pricelist overlap.
- l7.rs (STOCK, 1549 lines): stock.move, stock.move.line, stock.quant,
  stock.picking, stock.location, stock.rule, stock.warehouse with the
  draft→confirmed→assigned→done state machine + reservation logic +
  removal strategy. Drives savants RemovalStrategySelector,
  MoveAssignmentPrioritizer, BackorderJudge.
- l8.rs (PRODUCT-UOM-PRICELIST, 1314 lines): product.category,
  uom.uom, uom.category, product.template, product.product,
  product.pricelist, product.pricelist.item — with the closure-table
  parent_path on category, UoM factor conversion semantics, pricelist
  item applicability + computed price. Drives savant
  PricelistAssignmentAgent.
- l10.rs (ANALYTIC, 750 lines): account.analytic.plan,
  account.analytic.account, account.analytic.applicability,
  account.analytic.line, account.analytic.distribution.model — with
  the policy-scoring _get_distribution method that's the AXIS-B
  delegation point for AnalyticDistributionSuggester +
  AnalyticModelScorer. Notes the absent `analytic` base addon and
  one Char-as-JSON workaround.

All entities carry OdooProvenance with real L-doc line ranges,
OdooConfidence::Curated, and verified Odoo source cross-references.
Per-lane tests assert entity-count + provenance + key field/method
shape spot-checks (the agents went beyond my "no tests" brief and
added their own — the additional coverage is welcome).

File sizes exceed the per-lane budget (≤500–650 each was the target);
agents were thorough rather than terse. Still well within Rust
compilation comfort.

Wave 2.5 (re-spawn L9-PARTNER-FISCALPOS with tighter scope) + Wave 3
(L11-L15) queued.

Per E-CODEBOOK-INHERITS-FROM-OGIT (prior commit): identity layer for all
these entities resolves through OntologyRegistry from model_name (the
OGIT key) — the typed OdooEntity declarations are content carriers, not
identity layout.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…CALPOS projection (the FiscalPositionResolver canonical lane)

L9 agent returned late (after the Wave 2-partial commit landed); this
commit closes the gap so Wave 2 is fully shipped (all 5 lanes L6–L10
populated).

L9 is the canonical lane for the FiscalPositionResolver savant — the
e2e proof-of-concept savant per the v2 plan + the load-bearing entity
for the partner-side fiscal-position SELECTION pipeline.

Entities projected (6, ~1000+ lines):
- account.fiscal.position — the partner-facing fiscal-position record
  with the 5-predicate priority-ranked auto-detection (vat_required +
  country_id + country_group_id + state_ids + zip_from/zip_to range);
  drives FiscalPositionResolver dispatch
- account.fiscal.position.account — account-side mapping rows
- res.partner — the partner extension with property_account_position_id
  + trust + payment_method + property_payment_term_id; drives both
  FiscalPositionResolver (via fiscal-position computation) AND
  PartnerTrustAdvisor (via the trust field)
- res.country, res.country.group — geography predicates the
  auto-detection walks
- account.payment.term (reference shape; full coverage is L5)

L3 overlap noted in source comments: L3 owns tax-repartition INTERNALS
(account.tax.*, repartition lines, _compute_tax_base_amount); L9 owns
SELECTION (which fiscal position applies, map_tax/map_account, partner
property fields). Fields owned by L3 intentionally absent.

Wave 2 status: 5/5 lanes complete. Wave 3 (L11–L15) spawning in
parallel after this commit.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…nt trims (L6-L9) — all 15 lanes populated

Closes the L-doc-curated baseline. 15 lanes now carry typed OdooEntity
content; ~11482 lines total; all lane tests pass (cargo test
-p lance-graph-ontology --lib odoo_blueprint:: green).

## Wave 3 (L11-L15) — new projections

- l11.rs (COA-JOURNALS-LOCKDATES, 818 lines): account.account (19-value
  account_type enum, code-hierarchy, reconcile constraints),
  account.account.tag, account.journal (type taxonomy + GoBD
  restrict_mode_hash_table + default accounts), res.company (lock-date
  extension: 5 lock-date fields drive LockDateAdvancer savant).
- l12.rs (MULTICOMPANY-CURRENCY, 938 lines): res.currency (rounding,
  three-rate representation, _get_rates), res.currency.rate,
  res.company (multi-company tree, root delegation, FX exchange
  accounts drive ExchangeAccountSelector), res.users (allowed_company_ids
  drives UserCompanyAccessAdvisor), account.account (FX exchange role).
- l13.rs (STOCK-VALUATION-PROCUREMENT, 983 lines): stock.valuation.layer
  (SVL contract; absent from community clone — interface specced),
  stock.warehouse.orderpoint (drives ReorderTimingAdvisor +
  ReplenishmentReportAdvisor), stock.rule (procurement-priority,
  drives ProcurementRuleSelector + RouteTiebreaker), stock.lot,
  res.company (anglo-saxon vs continental config).
- l14.rs (HR-BASE, 962 lines): hr.employee (org hierarchy, statutory
  IDs, version pointer, contract dates), hr.department (recursive,
  manager propagation), hr.job (headcount), hr.contract.type (community
  stub; payroll Enterprise/absent flagged).
- l15.rs (TAX-REPARTITION, 560 lines): the repartition deep-dive over
  L3 — repartition-line + tag-side fields driving TaxExigibilitySuggestor.

## Post-Wave-2 agent trims (L6, L7, L8, L9)

Each Wave-2 agent re-trimmed its file post-completion to hit the per-lane
size brief (the original 1500+ line outputs were thorough but over budget).
Final per-agent line counts:
- L6: 689 (was 1551) — sale + purchase order entities, 9 tests pass
- L7: 591 (was 1549) — stock.move + quants + locations, 15 tests pass
- L8: 568 (was 1314) — product catalogue + UoM + pricelist, 7 tests pass
- L9: 615 (was 1190) — fiscal-position + res.partner, 16 tests pass

Per-entity content semantically preserved; verbose inline comments
trimmed against field-name self-documentation.

## What's next (per user 2026-05-28 direction)

The L-doc-curated baseline (this PR) is the cross-reference layer for
Stage 1. The user's clarifications today reshape the next move:

1. **"Stage 1 = literally extract EVERYTHING from Odoo"** — promote BP-1f
   (Odoo source extraction, was queued as follow-up validation) to Stage
   1 main. The inventory agent currently mapping /home/user/odoo will
   report scope honesty (addon census, German concept anchors for
   Kontenerkennung / Jahresabschluss / Steuererklärung / Rechnungstyp /
   Vorsteuer vs Mehrwertsteuer / Kleinunternehmen / GoBD / ELSTER,
   tree-sitter availability, code volume).
2. **"audit while doing so"** — every extracted entity must carry
   audit-by-construction provenance: Odoo source path:line +
   regulation IRI links (UStG §15 for Vorsteuerabzug, UStG §19 for
   Kleinunternehmen, HGB §242 for Jahresabschluss, GoBD §238/239
   Festschreibung). Initial OdooConfidence::Extracted.
3. **"additive NARS migration"** — as the system observes pattern
   repetitions, NARS truth (frequency + confidence) grows per entry;
   each migration step lifts MORE entries across the audit_floor →
   confident pattern repetition. Below floor stays in audit mode
   (LLM / human resolves the <25% tail per CLAUDE.md "The Click").

The inventory agent's report will scope the literal-parsing tool. The
implementation lands as a separate plan (`odoo-source-extraction-v1`)
when the inventory is back.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
L15 agent (TAX-REPARTITION) re-trimmed its output after the Wave 3
commit landed (e86e0b3). Same shape, fewer redundant inline comments.

Tests pass.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
L15 agent made another late refinement after the previous trim commit
(198ba1d). Tests still pass.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
L15 agent's last notification (after 335s, the slowest of Wave 3)
finalized the file at 501 effective lines. 9 tests pass.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…-ODOO-BP-1f

Adds `.claude/plans/odoo-source-extraction-v1.md` — a 6-deliverable
Stage-1 plan (D-ODOO-EXT-1..6) for extracting `OdooConfidence::Extracted`
backing across 12 TIER-1 addons (account, account_payment, l10n_de,
product, stock, uom, base, analytic, purchase, sale, account_peppol,
account_edi_ubl_cii) of the 622 in `/home/user/odoo/addons/`.

Substitutes Python stdlib `ast` for the absent `tree-sitter` referenced
in `odoo_blueprint/mod.rs:321`. Inventory grounds the scope: 622 addons,
3 141 ORM classes, 989 K Python LOC; 8/9 German concept anchors located
in source (ELSTER is Enterprise-only and absent).

Enhances `OdooProvenance` with `regulation_iri: &'static [&'static str]`
per `E-CODEBOOK-INHERITS-FROM-OGIT` (UStG §15 / HGB §238 / GoBD / AO
§146a / EN 16931 IRIs into OGIT codebook). Adds `OdooEntityKind` variant
(Model/Transient/Abstract).

Board-hygiene rule satisfied: INTEGRATION_PLANS.md PREPENDed in the
same commit.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…provenance slot

Adds `OdooEntityKind::{Model,Transient,Abstract}` variant to classify ORM
base class, exposed as `OdooEntity.kind`. Defaults to `Model` for the
Wave 1-3 back-fill — every existing lane const projects a `models.Model`.

Adds `OdooProvenance.regulation_iri: &'static [&'static str]` slot per
`E-CODEBOOK-INHERITS-FROM-OGIT` — German tax/accounting law anchors
(UStG / HGB / GoBD / AO / EN 16931) as IRIs into the OGIT-inherited
regulation codebook. Back-filled `&[]` across all existing consts;
populated by D-ODOO-EXT-4 for l10n_de entities.

Corrects the stale `tree-sitter` reference in `OdooConfidence::Extracted`
doc comment — Python stdlib `ast` is the extraction substrate per
`D-ODOO-EXT-1` / `D-ODOO-EXT-2`.

Plan: `.claude/plans/odoo-source-extraction-v1.md`.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
… test

Adds `tools/odoo-blueprint-extractor/`, a stdlib-only Python 3 package that
parses Odoo ORM classes via `ast` (substituting the absent tree-sitter)
and emits candidate `OdooEntity` consts as Rust source text for
`OdooConfidence::Extracted` backing.

Layout:
- `parsers/{classes,fields,methods,decorators,state_machine,constraints,regulation}.py`
- `emitters/{rust,module}.py`
- `audit/fallback_log.py`
- `tests/test_smoke_uom.py`

CLI: `python -m odoo_blueprint_extractor --addons <dir> --addon uom --out -`

Smoke-tested on `/home/user/odoo/addons/uom/`: emits `EXT_UOM_UOM`
correctly; 0% `::Other` field fallback, 0% `::Helper` method fallback.

D-ODOO-EXT-2 will scale this across the 12 TIER-1 addons in 3 waves.

Plan: `.claude/plans/odoo-source-extraction-v1.md`.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
AGENT_LOG entry: scaffold created, 6/6 smoke tests pass, 0% ::Other
field fallback, commit 29e918c.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…ct/analytic

Extracted 4 foundation TIER-1 addons via `tools/odoo-blueprint-extractor`
(D-ODOO-EXT-1) into `odoo_blueprint::extracted::*` modules with
`OdooConfidence::Extracted` and `EXT_*` const prefixes.

Counts:
- base:    114 models, 19 563 LOC, 750 fields, 1.6% ::Other fallback rate
- uom:       1 model,    235 LOC,   9 fields, 0.0% ::Other fallback rate
- product:  25 models,  5 248 LOC, 231 fields, 4.3% ::Other fallback rate
- analytic:  9 models,  1 286 LOC,  55 fields, 0.0% ::Other fallback rate

All four pass the <5% field fallback gate.

Extractor fixes shipped in this commit:
1. `emitters/module.py` — added `_dedup_by_model_name()`: when multiple
   Python classes share the same model_name (common for `_inherit` extension
   classes spread across files), keep the richest (most fields+methods).
   Fixes compile error: `EXT_BASE` and `EXT_RES_USERS` defined twice in base.
   base had 2 duplicate model_names merged.
2. `crates/.../mod.rs` — added `OdooFieldKind::Other` variant for
   unrecognized field types (fields.Image × 8, fields.Properties × 1,
   fields.PropertiesDefinition × 1 in product). These log to the fallback
   audit; value is still usable with a wildcard match.

`_inherit`-as-list policy: when a class has only `_inherit` (no `_name`),
the first element of the inherit list is used as model_name. Multiple-inherit
classes are emitted once with the first parent as model_name; extension-fragment
merging is deferred to D-ODOO-EXT-5's `pairing.rs`.

All 192 `lance-graph-ontology` tests stay green; `cargo check` clean.
Wave B (`account`/`account_payment`/`purchase`/`sale`/`stock`) follows
once this lands.

Plan: `.claude/plans/odoo-source-extraction-v1.md`.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…t_payment/purchase/sale/stock

Extracted the 5 value-flow-chain TIER-1 addons via `tools/odoo-blueprint-extractor`
into `odoo_blueprint::extracted::{account,account_payment,purchase,sale,stock}`
with `OdooConfidence::Extracted` and `EXT_*` const prefixes.

Counts:
- account: 66 models, 21340 LOC, 919 fields, 0.8% field-fallback
- account_payment: 7 models, 663 LOC, 17 fields, 0.0% field-fallback
- purchase: 15 models, 3080 LOC, 144 fields, 0.0% field-fallback
- sale: 20 models, 4588 LOC, 174 fields, 1.1% field-fallback
- stock: 33 models, 12020 LOC, 606 fields, 1.2% field-fallback

No extractor fixes were required for Wave B. All field fallback rates
are well under the 5% gate. `OdooFieldKind::Other` hits (7+2+7=16 total
across account/sale/stock) are exotic field types (fields.Json,
fields.Properties variants) already handled by the Wave A Other variant.

`_inherit` extension-fragment loss (richest-wins dedup from Wave A)
preserved; EXT-5 pairing pass reconciles against the L-doc curated set
on conflict.

mod.rs updated: Wave A modules sorted alphabetically, Wave B group
appended with comment header.

All 192 `lance-graph-ontology` tests stay green; `cargo check` clean.
Wave C (`l10n_de`/`account_peppol`/`account_edi_ubl_cii`) follows.

Plan: `.claude/plans/odoo-source-extraction-v1.md`.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…t_peppol/account_edi_ubl_cii

Extracted the 3 DE-specific + EU e-invoice TIER-1 addons via
`tools/odoo-blueprint-extractor` into
`odoo_blueprint::extracted::{l10n_de,account_peppol,account_edi_ubl_cii}`.

Counts:
- l10n_de: 8 models, 335 LOC, 0% field-fallback (ORM only — SKR03/04
  chart + UStVA Kennzahlen are D-ODOO-EXT-4; 57.1% Helper rate from
  chart-template Python helpers is natural and documented)
- account_peppol: 10 models, 1 446 LOC, 2.4% field-fallback (1 Other
  field; 50.9% Helper rate is natural — heavy _inherit/partner-extension
  pattern with XML/proxy API helpers)
- account_edi_ubl_cii: 16 models, 3 703 LOC, 0% field-fallback (483/515
  = 93.8% Helper rate is expected: these are Python wrappers around XML
  rendering for UBL 2.0 + CII 2.2 e-invoice formats; documented per plan)

D-ODOO-EXT-2 COMPLETE — all 12 TIER-1 addons extracted across 3 waves.
Total `extracted/` LOC (all 12 addons + mod.rs): ~73 534 LOC.

l10n_de intentional narrowness: the Python `ast` extractor sees only
the ~8 ORM model-extension files. The bulk of l10n_de substance —
1 274 SKR03 + 1 192 SKR04 chart-of-accounts (CSV), 242×2 tax
templates (CSV), and 1 106-line UStVA `account.report` XML with
17 Kennzahlen Kz.81..95 — is D-ODOO-EXT-4 scope (CSV/XML parser).

account_edi_ubl_cii skipped 1 class (FloatFmt — non-Odoo utility,
correctly excluded). Helper rate >5% documented per plan: "if >5%,
document in commit but don't fight it."

No extractor fixes required for Wave C — extractor absorbed all edge
cases cleanly (German docstrings were absent from emitted output;
0 double-escaping issues found).

All 192 `lance-graph-ontology` tests stay green; `cargo check` clean.
Next: D-ODOO-EXT-4 (l10n_de SKR03/04 + UStVA Kennzahlen + GoBD wiring).

Plan: `.claude/plans/odoo-source-extraction-v1.md`.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
claude added 10 commits May 28, 2026 11:55
…t + UStVA Kennzahlen + GoBD wiring

Adds the three German-accounting typed surfaces that the Python ast
extractor cannot reach (l10n_de's substance lives in CSV + XML, not in
ORM Python):

- `OdooAccountTemplate` + `OdooSkrChart::{Skr03,Skr04}` — emitted as
  `SKR03_CHART` (1 274 accounts) and `SKR04_CHART` (1 192 accounts)
  static arrays from `/home/user/odoo/addons/l10n_de/data/template/account.account-de_skr0{3,4}.csv`
- `OdooUstvaKennzahl` + `OdooKennzahlKind::{Base,Tax,Derived}` — emitted as
  `USTVA_KENNZAHLEN` static array (37 Kennzahlen, covering Kz.81..95 plus
  full UStVA sections B-I: Vorsteuer, §13b, ig Erwerbe, ergänzende Angaben)
  from `account_account_tags_data.xml`
- `OdooGobdWiring::GOBD_WIRING` — the `restrictive_audit_trail` force-on-DE
  semantics per `account/models/company.py:268` + `l10n_de/models/res_company.py:32`

Note: plan mentioned "17+ Kz.81..95" — actual XML contains 37 Kennzahlen
because the file covers the full UStVA return (not just output-tax boxes).
All 7 canonical boxes (81/86/87/35/41/44/49) confirmed present.

All carry `regulation_iri` anchors: UStG §1a/4/13/13b/15/18 / HGB §238/266 /
GoBD / AO §146a.

Extractor extension: adds `tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/{csv_chart,xml_kennzahl,gobd_company}.py`
+ `data` CLI subcommand. Stdlib-only (csv, xml.etree.ElementTree).

Tests: `cargo test -p lance-graph-ontology --lib` green (199 tests, +7 new):
  - skr03_chart_has_expected_size (1274)
  - skr04_chart_has_expected_size (1192)
  - skr03_chart_entries_have_codes
  - skr04_chart_entries_have_codes
  - ustva_kennzahlen_cover_canonical_boxes
  - ustva_kennzahlen_non_empty (37)
  - gobd_wiring_has_correct_trigger

Next: D-ODOO-EXT-5 (curated-vs-extracted pairing) + D-ODOO-EXT-6 (coverage report).

Plan: `.claude/plans/odoo-source-extraction-v1.md`.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…xtracted pairing table

Builds the cross-reference table that links every L-doc curated lane
entity (`l{1..15}::*`, `OdooConfidence::Curated`) to its source-extracted
counterpart (`extracted::*::EXT_*`, `OdooConfidence::Extracted`) when
both exist for the same `model_name`.

Outputs:
- `crates/lance-graph-ontology/src/odoo_blueprint/extracted/pairing.rs`
  exposes `pub static CURATED_EXTRACTED_PAIRS: &[OdooEntityPairing]` —
  48 pairings (53 curated model_names × 229 extracted in TIER-1).
- `/tmp/pairings.json` (out-of-tree) records field/method count deltas
  per pairing for human review.

Scanner: stdlib `re` over the generated Rust source; lives in
`tools/odoo-blueprint-extractor/odoo_blueprint_extractor/pairing.py`
with a `pair` CLI subcommand (`python -m odoo_blueprint_extractor pair`).

Const selection rules (both sides):
- Curated: highest field+method count wins (handles indirect-ref files
  like l3.rs that reference separate const slices); alphabetical const_name
  on tie. This correctly picks l9.rs over l3.rs for `account.fiscal.position`
  (17+11 vs 0+0 counted inline fields/methods).
- Extracted: most fields+methods wins (picks richest coverage when a
  model appears in multiple addons, e.g. `uom.uom` in uom.rs preferred
  over account.rs/product.rs/stock.rs appearances).

Side-effect: promoted 17 module-private (`const`) lane entities to
`pub const` in l3.rs, l5.rs, l7.rs, l13.rs so they're accessible
from `crate::odoo_blueprint::<lane>::<CONST>` paths. These consts
were only reachable via the `ENTITIES` slice before; making them pub
is additive (no tests change) and required for the pairing reference.

Most striking deltas (curated savant-relevant subset vs full ORM):
  account.move:      24f/27m → 142f/352m (+118f/+325m)
  account.move.line: 20f/14m → 87f/146m  (+67f/+132m)
  sale.order:        22f/13m → 65f/141m  (+43f/+128m)
  stock.move:        23f/14m → 74f/130m  (+51f/+116m)
  account.tax:        3f/0m  → 36f/113m  (+33f/+113m)

5 curated model_names have NO TIER-1 extracted backing (EXT-6 gap rows):
  hr.contract.type, hr.department, hr.employee, hr.job, stock.valuation.layer
These are TIER-2 addons (hr, account_asset) — expected leakage.

Curated stays canonical on conflict (per BP-1 plan §"merge ordering");
extracted is the audit backing.

Tests: 2 new (`pairing_table_is_well_formed`, `pairing_table_has_expected_size`);
all 199 pre-existing ontology tests stay green (201 total).

Next: D-ODOO-EXT-6 (coverage report — uses this pairing table to
quantify lane-level extracted-backing).

Plan: `.claude/plans/odoo-source-extraction-v1.md`.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…rt + gate test

Closes D-ODOO-EXT-1..6 (Stage 1 of `odoo-source-extraction-v1`).

Outputs:
- `extracted/COVERAGE.md` — human-readable per-lane coverage report,
  TIER-2 deferral catalogue (5 entries: hr.* + stock.valuation.layer),
  TIER-1 surplus inventory, Stage 2 recommendation.
- `extracted/coverage.rs` — `COVERAGE_EXEMPTIONS` + `COVERAGE_FLOOR = 0.80`
  + 2 gate tests:
  - `every_lane_meets_coverage_floor`: per-lane eligible coverage ≥ 80%
  - `aggregate_coverage_reports_correctly`: 53 curated, 48 eligible, 48 backed

Final Stage 1 numbers:
- 12 TIER-1 addons extracted (Wave A: base/uom/product/analytic;
  Wave B: account/account_payment/purchase/sale/stock;
  Wave C: l10n_de/account_peppol/account_edi_ubl_cii)
- 1 274 SKR03 + 1 192 SKR04 accounts (EXT-4)
- 37 UStVA Kennzahlen (EXT-4)
- 229 extracted entities total, 48 paired with curated lane consts
- 90.6% raw coverage, 100% eligible coverage (TIER-2 exempt set: 5 entities)

Plan + INTEGRATION_PLANS status flipped to SHIPPED. Stage 2 (TIER-2
addons: `hr`, `stock_account`, plus follow-ons) opens a separate plan.

Plan: `.claude/plans/odoo-source-extraction-v1.md`.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
Prepend AGENT_LOG.md entry for Stage 1 close: 203 tests green, commit
2937c04, plan + INTEGRATION_PLANS flipped to SHIPPED.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…ped)

Group A — board + plan governance
- INTEGRATION_PLANS.md: reconcile Stage-2 terminology with plan's TIER-2 scope
- BP-1 plan: D-ODOO-BP-1f row — tree-sitter → Python stdlib ast (matches reality)
- EXT-1 plan: Status line gets commit-range evidence (15b63ce..b54a743)

Group B — Rust source fixes
- grammar/role_keys.rs: debug_assert! → assert! (release-build safety)
- extracted/*.rs: emitter now strips /home/user/ prefix → repo-relative paths;
  all 12 TIER-1 addons + l10n_de chart/kennzahlen regenerated
- l8.rs: UOM_UUM typo → UOM_UOM (+ pairing.rs reference update)
- extracted/coverage.rs: lane_of unwrap_or(0) → expect (fail loud on malformed l_doc)

Group C — Python tooling
- __init__.py: __version__: str type annotation
- cli.py: mkdir(parents=True, exist_ok=True) before audit write in pair + ORM paths
- data_extractors/csv_chart.py: explicit SKR03/SKR04 validation (no silent default)
- data_extractors/gobd_company.py: verify_gobd_wiring inspects method body for
  country_code == 'DE' trigger (no longer false-positive on naked method existence)
- data_extractors/xml_kennzahl.py: defusedxml drop-in for ET (XXE/billion-laughs
  hardening on Odoo-vendored XML). New runtime dep in pyproject.toml.
- tests/test_smoke_uom.py: update fallback_rate call sites (drop total_methods arg)

Group D — nitpicks
- 2 plan files: add 'text' language tag on directory-tree fenced blocks (MD040)
- audit/fallback_log.py: drop unused total_methods from fallback_rate signature

SKIPPED with rationale (1/17):
- l1.rs unit tests for ENTITIES contents: tests would echo static const data,
  not defend invariants. The cross-cutting properties (kind/confidence/l_doc)
  are already enforced by extracted::coverage::tests' aggregate gate.

Tests: cargo test -p lance-graph-ontology --lib green (203 tests).
Python smoke test: ALL TESTS PASS.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
…ant (clippy::assertions_on_constants)

CI clippy (`-D warnings`) caught a const-only `assert!` on the
SAVANT_SLICE_END <= VSA_DIMS invariant inside the
`savant_zone_fits_in_smb_headroom` test. Both operands are
compile-time constants, so the right shape is `const { assert!(..) }`
— compile-time check, no runtime work, no lint.

Lines 170-172 (SUBJECT_KEY.slice_end ≤ SAVANT_SLICE_START etc.) use
the same pattern but aren't flagged by clippy 1.95 (struct field
accesses on const RoleKey values aren't const-evaluated by this
lint); leaving them as runtime asserts pending future clippy upgrade.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
AGENT_LOG / EPIPHANIES / INTEGRATION_PLANS are PREPEND-ONLY per the
CCA2A pattern (CLAUDE.md mandatory board-hygiene rule). When two
branches concurrently prepend entries, the right semantic resolution
is to keep both — there is no overwrite by construction. Declaring
`merge=union` avoids manual conflict resolution on every rebase.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
@AdaWorldAPI AdaWorldAPI force-pushed the claude/activate-lance-graph-att-k2pHI branch from 4b44928 to b3fc9c7 Compare May 28, 2026 11:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py`:
- Around line 43-58: The body_source string literal is broken when constructing
the function body text in the method-finding code (ast.parse loop that checks
isinstance(node, ast.FunctionDef) and sets end, lines, body_lines); fix the
unterminated string by replacing the invalid split across lines with a proper
newline join (e.g. use a valid escaped newline like "\n" in the join) when
assigning body_source so the module parses correctly and returns the method
dict.
- Around line 95-99: The result dict sometimes lacks the l10n_de_trigger_found
key when method is falsy; ensure the key is always present by defaulting it to
False when no method is found (or set it in the else branch). Concretely, in the
block around method, result, and the checks for "country_code"/"DE" (symbols:
method, result, l10n_de_compute_found, l10n_de_compute_lineno,
l10n_de_trigger_found), set result["l10n_de_trigger_found"] = False before the
conditional or assign it in the else so the returned schema always contains that
key.
🪄 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: 86b1106c-6463-4cae-bae3-1f462d9589db

📥 Commits

Reviewing files that changed from the base of the PR and between 61896b1 and 4b44928.

📒 Files selected for processing (29)
  • .claude/board/AGENT_LOG.md
  • .claude/board/INTEGRATION_PLANS.md
  • .claude/plans/odoo-business-logic-blueprint-v1.md
  • .claude/plans/odoo-source-extraction-v1.md
  • crates/lance-graph-contract/src/grammar/role_keys.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_edi_ubl_cii.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_payment.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_peppol.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/analytic.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/base.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/pairing.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/product.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/purchase.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/sale.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/stock.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l8.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/csv_chart.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/rust.py
  • tools/odoo-blueprint-extractor/pyproject.toml
  • tools/odoo-blueprint-extractor/tests/test_smoke_uom.py
✅ Files skipped from review due to trivial changes (11)
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de.rs
  • .claude/plans/odoo-business-logic-blueprint-v1.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/pairing.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/analytic.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/init.py
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_payment.rs
  • .claude/board/AGENT_LOG.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_peppol.rs
  • .claude/board/INTEGRATION_PLANS.md
  • .claude/plans/odoo-source-extraction-v1.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • crates/lance-graph-contract/src/grammar/role_keys.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/rust.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/csv_chart.py
  • crates/lance-graph-ontology/src/odoo_blueprint/l8.rs

Comment on lines +43 to +58
"""Find a method definition and return its line range + source text."""
tree = ast.parse(source)
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == method_name:
end = getattr(node, "end_lineno", node.lineno)
# Extract source lines for body inspection
lines = source.splitlines()
body_lines = lines[node.lineno - 1:end]
body_source = "
".join(body_lines)
return {
"name": method_name,
"lineno": node.lineno,
"end_lineno": end,
"source": body_source,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import ast
from pathlib import Path

path = Path("tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py")
source = path.read_text(encoding="utf-8")
ast.parse(source)
print("Syntax OK:", path)
PY

Repository: AdaWorldAPI/lance-graph

Length of output: 426


🏁 Script executed:

#!/bin/bash
set -euo pipefail
python - <<'PY'
from pathlib import Path
path = Path("tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py")
lines = path.read_text(encoding="utf-8").splitlines()
for i in range(40, 61):
    print(f"{i+1:4d}: {lines[i]}")
PY

Repository: AdaWorldAPI/lance-graph

Length of output: 937


Fix invalid Python string literal in body_source construction

tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py has an unterminated string at lines 51-52 (body_source = " / ".join(...)), causing a module import-time SyntaxError.

Suggested fix
-            body_source = "
-".join(body_lines)
+            body_source = "\n".join(body_lines)
🧰 Tools
🪛 Ruff (0.15.14)

[warning] 51-51: missing closing quote in string literal

(invalid-syntax)


[warning] 52-52: missing closing quote in string literal

(invalid-syntax)


[warning] 53-53: Unexpected indentation

(invalid-syntax)

🤖 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
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py`
around lines 43 - 58, The body_source string literal is broken when constructing
the function body text in the method-finding code (ast.parse loop that checks
isinstance(node, ast.FunctionDef) and sets end, lines, body_lines); fix the
unterminated string by replacing the invalid split across lines with a proper
newline join (e.g. use a valid escaped newline like "\n" in the join) when
assigning body_source so the module parses correctly and returns the method
dict.

Comment on lines +95 to +99
body = method.get("source", "")
has_trigger = "country_code" in body and "DE" in body
result["l10n_de_compute_found"] = has_trigger
result["l10n_de_compute_lineno"] = method.get("lineno") if has_trigger else None
result["l10n_de_trigger_found"] = has_trigger

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Always return l10n_de_trigger_found in the result schema.

l10n_de_trigger_found is only set in the if method: branch. When the method/file is absent, the key is missing from the returned dict.

Suggested fix
     result = {
         "base_field_found": False,
         "force_field_found": False,
         "l10n_de_compute_found": False,
         "l10n_de_compute_lineno": None,
         "trigger_pattern": "country_code == 'DE'",
+        "l10n_de_trigger_found": False,
     }
🤖 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
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py`
around lines 95 - 99, The result dict sometimes lacks the l10n_de_trigger_found
key when method is falsy; ensure the key is always present by defaulting it to
False when no method is found (or set it in the else branch). Concretely, in the
block around method, result, and the checks for "country_code"/"DE" (symbols:
method, result, l10n_de_compute_found, l10n_de_compute_lineno,
l10n_de_trigger_found), set result["l10n_de_trigger_found"] = False before the
conditional or assign it in the else so the returned schema always contains that
key.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py (1)

50-52: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix unterminated string literal causing SyntaxError in gobd_company.py

body_source is currently split across two lines (body_source = " ... ".join(body_lines)), resulting in SyntaxError: unterminated string literal (line 51). Replace it with a properly escaped newline join.

🐛 Proposed fix
             lines = source.splitlines()
             body_lines = lines[node.lineno - 1:end]
-            body_source = "
-".join(body_lines)
+            body_source = "\n".join(body_lines)
             return {
🤖 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
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py`
around lines 50 - 52, The assignment to body_source is split across two lines
causing an unterminated string literal; fix it by replacing the broken split
with a proper newline join of body_lines (use an escaped newline join when
joining body_lines) so body_source is a single valid string expression; update
the code around the body_lines and body_source variables (the block that uses
node.lineno and builds body_source) to use the corrected join.
🤖 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.

Duplicate comments:
In
`@tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py`:
- Around line 50-52: The assignment to body_source is split across two lines
causing an unterminated string literal; fix it by replacing the broken split
with a proper newline join of body_lines (use an escaped newline join when
joining body_lines) so body_source is a single valid string expression; update
the code around the body_lines and body_source variables (the block that uses
node.lineno and builds body_source) to use the corrected join.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5af23d7e-496b-444d-9c7e-ab9596f90ecb

📥 Commits

Reviewing files that changed from the base of the PR and between 4b44928 and b3fc9c7.

📒 Files selected for processing (72)
  • .claude/board/AGENT_LOG.md
  • .claude/board/EPIPHANIES.md
  • .claude/board/INTEGRATION_PLANS.md
  • .claude/board/STATUS_BOARD.md
  • .claude/plans/odoo-business-logic-blueprint-v1.md
  • .claude/plans/odoo-savant-reasoners-v2.md
  • .claude/plans/odoo-source-extraction-v1.md
  • .gitattributes
  • crates/lance-graph-contract/src/callcenter/mod.rs
  • crates/lance-graph-contract/src/callcenter/ogit_uris.rs
  • crates/lance-graph-contract/src/callcenter/role_keys.rs
  • crates/lance-graph-contract/src/grammar/role_keys.rs
  • crates/lance-graph-contract/src/lib.rs
  • crates/lance-graph-ontology/src/lib.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/COVERAGE.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_edi_ubl_cii.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_payment.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_peppol.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/analytic.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/base.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de_chart.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de_kennzahlen.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/mod.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/pairing.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/product.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/purchase.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/sale.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/stock.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l1.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l10.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l11.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l12.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l13.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l14.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l15.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l2.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l3.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l4.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l5.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l6.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l7.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l8.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l9.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/mod.rs
  • tools/odoo-blueprint-extractor/README.md
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/__main__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/csv_chart.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/gobd_company.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/module.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/rust.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/pairing.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/__init__.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/classes.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/constraints.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/decorators.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/fields.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/methods.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/regulation.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/parsers/state_machine.py
  • tools/odoo-blueprint-extractor/pyproject.toml
  • tools/odoo-blueprint-extractor/tests/test_smoke_uom.py
💤 Files with no reviewable changes (4)
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/init.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/module.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/emitters/rust.py
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/xml_kennzahl.py
✅ Files skipped from review due to trivial changes (19)
  • .gitattributes
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/init.py
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/uom.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/init.py
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/mod.rs
  • crates/lance-graph-contract/src/callcenter/mod.rs
  • crates/lance-graph-ontology/src/lib.rs
  • .claude/plans/odoo-business-logic-blueprint-v1.md
  • .claude/board/EPIPHANIES.md
  • .claude/board/INTEGRATION_PLANS.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_payment.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/analytic.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/init.py
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/pairing.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de_kennzahlen.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/l10n_de.rs
  • .claude/board/AGENT_LOG.md
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/account_peppol.rs
  • .claude/board/STATUS_BOARD.md
🚧 Files skipped from review as they are similar to previous changes (25)
  • crates/lance-graph-contract/src/lib.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/extracted/coverage.rs
  • crates/lance-graph-contract/src/grammar/role_keys.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/cli.py
  • crates/lance-graph-ontology/src/odoo_blueprint/l6.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l10.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/main.py
  • crates/lance-graph-contract/src/callcenter/ogit_uris.rs
  • .claude/plans/odoo-savant-reasoners-v2.md
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/data_extractors/csv_chart.py
  • crates/lance-graph-ontology/src/odoo_blueprint/l15.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l12.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l8.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/mod.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l4.rs
  • tools/odoo-blueprint-extractor/odoo_blueprint_extractor/audit/fallback_log.py
  • crates/lance-graph-contract/src/callcenter/role_keys.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l1.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l5.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l2.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l11.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l14.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l9.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l7.rs
  • crates/lance-graph-ontology/src/odoo_blueprint/l3.rs

@AdaWorldAPI AdaWorldAPI merged commit 6797e54 into main May 28, 2026
6 checks passed
AdaWorldAPI pushed a commit that referenced this pull request May 28, 2026
…tries

Post-merge board hygiene for two PRs merged in this wave:

- **#425** (mine, lance-graph deps cleanup + [patch.crates-io] ndarray
  declared intent; merge commit 1a3abfb). Locks in the lance 6.0.1
  block reasoning (lancedb 0.29.0 transitive ='6.0.0') and the
  ndarray patch's "declared but unused" effect.
- **#427** (bindspace→mailbox migration wave A1-A4; merge commit
  8429611). Authored by a peer session; per-deliverable AGENT_LOG
  entries were prepended at branch HEAD pre-merge, but the
  LATEST_STATE / PR_ARC tier of governance was left for follow-up —
  this commit fills it. Records the 7 ratified plan §10 findings +
  the 2 surviving OQs (OQ-MBX-8 persisted_row vs Lance native
  versioning; OQ-MBX-15′ container scoping).

Both via tee -a (the 8 bookkeeping files deny Edit/Write); dated
framing preserves the rule-#1 PREPEND convention.

No code touched. No new types proposed.

Outstanding: #426 (odoo blueprint Stage 1, +115K lines) also lacks a
LATEST_STATE/PR_ARC row; defer to the authoring session for the rich
sub-deliverable breakdown (D-ODOO-EXT-1..6 + EXT-3 + BP-1a/b) — a
peer session writing #426 governance would either summarize too
coarsely or duplicate the per-deliverable AGENT_LOG entries that
already exist on main.

https://claude.ai/code/session_01FMooFcE7hgRWWvknNr2N4i
AdaWorldAPI pushed a commit that referenced this pull request May 28, 2026
…ped)

Group A — board + plan governance
- INTEGRATION_PLANS.md: reconcile Stage-2 terminology with plan's TIER-2 scope
- BP-1 plan: D-ODOO-BP-1f row — tree-sitter → Python stdlib ast (matches reality)
- EXT-1 plan: Status line gets commit-range evidence (15b63ce..b54a743)

Group B — Rust source fixes
- grammar/role_keys.rs: debug_assert! → assert! (release-build safety)
- extracted/*.rs: emitter now strips /home/user/ prefix → repo-relative paths;
  all 12 TIER-1 addons + l10n_de chart/kennzahlen regenerated
- l8.rs: UOM_UUM typo → UOM_UOM (+ pairing.rs reference update)
- extracted/coverage.rs: lane_of unwrap_or(0) → expect (fail loud on malformed l_doc)

Group C — Python tooling
- __init__.py: __version__: str type annotation
- cli.py: mkdir(parents=True, exist_ok=True) before audit write in pair + ORM paths
- data_extractors/csv_chart.py: explicit SKR03/SKR04 validation (no silent default)
- data_extractors/gobd_company.py: verify_gobd_wiring inspects method body for
  country_code == 'DE' trigger (no longer false-positive on naked method existence)
- data_extractors/xml_kennzahl.py: defusedxml drop-in for ET (XXE/billion-laughs
  hardening on Odoo-vendored XML). New runtime dep in pyproject.toml.
- tests/test_smoke_uom.py: update fallback_rate call sites (drop total_methods arg)

Group D — nitpicks
- 2 plan files: add 'text' language tag on directory-tree fenced blocks (MD040)
- audit/fallback_log.py: drop unused total_methods from fallback_rate signature

SKIPPED with rationale (1/17):
- l1.rs unit tests for ENTITIES contents: tests would echo static const data,
  not defend invariants. The cross-cutting properties (kind/confidence/l_doc)
  are already enforced by extracted::coverage::tests' aggregate gate.

Tests: cargo test -p lance-graph-ontology --lib green (203 tests).
Python smoke test: ALL TESTS PASS.

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
AdaWorldAPI added a commit that referenced this pull request May 28, 2026
…att-k2pHI

feat(odoo_blueprint): Stage 1 TIER-1 source extraction (D-ODOO-EXT-1..6)
AdaWorldAPI pushed a commit that referenced this pull request May 28, 2026
…CodeRabbit P1)

PR #426's `body_source = "<literal newline>".join(body_lines)` was a
SyntaxError that escaped the smoke test because the smoke test only
exercises uom (the ORM-only path), not l10n_de's data extractor.

CodeRabbit flagged this in the final review at `25e8d2b6` as a
"duplicate" comment carried forward; it remained unresolved through
merge. Fix: `"\n".join(body_lines)` — the intended one-char escape.

Now `python -m ast` parses gobd_company.py cleanly. Smoke test still
passes (no regression).

https://claude.ai/code/session_017gZ6sPRXYPj5n7uJ7NBtRv
AdaWorldAPI pushed a commit that referenced this pull request May 28, 2026
…tries

Post-merge board hygiene for two PRs merged in this wave:

- **#425** (mine, lance-graph deps cleanup + [patch.crates-io] ndarray
  declared intent; merge commit a5f3e8d). Locks in the lance 6.0.1
  block reasoning (lancedb 0.29.0 transitive ='6.0.0') and the
  ndarray patch's "declared but unused" effect.
- **#427** (bindspace→mailbox migration wave A1-A4; merge commit
  a21d577). Authored by a peer session; per-deliverable AGENT_LOG
  entries were prepended at branch HEAD pre-merge, but the
  LATEST_STATE / PR_ARC tier of governance was left for follow-up —
  this commit fills it. Records the 7 ratified plan §10 findings +
  the 2 surviving OQs (OQ-MBX-8 persisted_row vs Lance native
  versioning; OQ-MBX-15′ container scoping).

Both via tee -a (the 8 bookkeeping files deny Edit/Write); dated
framing preserves the rule-#1 PREPEND convention.

No code touched. No new types proposed.

Outstanding: #426 (odoo blueprint Stage 1, +115K lines) also lacks a
LATEST_STATE/PR_ARC row; defer to the authoring session for the rich
sub-deliverable breakdown (D-ODOO-EXT-1..6 + EXT-3 + BP-1a/b) — a
peer session writing #426 governance would either summarize too
coarsely or duplicate the per-deliverable AGENT_LOG entries that
already exist on main.

https://claude.ai/code/session_01FMooFcE7hgRWWvknNr2N4i
AdaWorldAPI pushed a commit that referenced this pull request May 29, 2026
…gnitive fingerprint)

The Odoo-static interpretation layer that reads typed `OdooEntity` /
`OdooMethod` / `OdooField` SoA into per-method `StyleRecipe` records:
sparse weighted vectors over 12 D-Atom basis vectors + regulatory
anchors + dispatch hints. This is the bridge between the PR #426 typed
extraction and the upcoming askama bucket-dispatch codegen.

## Where this fits

```
  Odoo source
    │  (Stage 1, PR #426 — odoo-blueprint-extractor)
    ▼
  Typed Rust SoA  ← extracted/{account,sale,…}.rs (OdooEntity[ ])
    │  (THIS COMMIT — interpretation, no triplets stored)
    ▼
  StyleRecipe[ ]  ← cognitive fingerprint per method
    │              (atom weights + regulatory anchors + dispatch hints)
    ▼
  Askama bucket templates (next commit) → Rust Ops + const recipes
    │
    ▼
  PaletteCompose SpMV at runtime (cognitive-shader-driver path)
```

## The user-anchored rule

> "Business logic stays in the triplets, but you have to interpret it.
> The interpretation of Odoo lies in Odoo-static [code] that needs to
> be ported."

The triplets (`lance_graph::graph::spo::odoo_ontology` + typed SoA)
stay lossless — we do NOT emit a `has_recipe` triple. The recipe is
re-derived deterministically every codegen run. That's the
"interpretation" half of the rule. Belongs in `lance-graph-ontology`'s
`odoo_blueprint` because that's where Odoo-static interpretation lives;
a Rails frontend writes its own `style_recipe.rs` targeting the same
downstream SoC compiler.

## What lands

- **`DAtom` (12 variants)** — closed basis-vector catalogue: Entity,
  Law, FiscalCtx, EmitAmount, ApplyRate, Quantity, Money, Event,
  Action, Compute, Validate, Onchange. The architecture diagram excerpt
  showed 9; extended by 3 for Odoo-specific dispatch (Onchange cascade,
  Compute-vs-Validate split, Helper utility).

- **`StyleRecipe`** — `{ method_id, atoms: Vec<(DAtom, u8)>,
  regulation_iris, return_kind, recipe_id: u32 }`. `recipe_id` is a
  content-addressed FNV-1a 32-bit digest over the sorted atom-weight
  tuples — equivalent methods collapse to one recipe (the dispatcher
  exploits this).

- **`derive_style_recipe(&OdooEntity, &OdooMethod) -> StyleRecipe`** —
  7-rule deterministic cascade (kind → return_kind → triggers →
  field cross-ref → regulation_iri → state_machine participation).
  Atom weights are `max`-merged; zero-weight atoms drop out.

- **`derive_corpus_recipes(&[&OdooEntity]) -> Vec<StyleRecipe>`** —
  walks an entity corpus, sorted by `method_id` ascending, byte-
  deterministic across runs.

## Tests (12 today)

Synthetic fixtures: every D-Atom anchor case + recipe_id determinism
+ atom collapse + corpus sort. Shipped-corpus test
(`shipped_corpus_resolves_kind_driven_atoms_today`) pins both halves of
the Stage-1 reality:

- **must fire today**: Entity, Compute, Validate, Onchange, Action
  (kind-driven; resolvable from current extractor output).
- **must NOT fire today**: Money, Quantity, ApplyRate, EmitAmount,
  Event, FiscalCtx (need Stage-2 extractor enrichment —
  `OdooMethod::return_kind` is mostly Unit, `triggers` empty,
  `state_machine` None, `OdooField::computed` cross-refs sparse).

When Stage-2 lands the second list shrinks; the test asks reviewers to
flip atoms from `stage2` to `must` as enrichment lands.

## Architecture invariants

- `lance-graph-ontology` stays light (no new external deps; serde-only
  not needed because StyleRecipe doesn't serialise — it's the in-process
  codegen IR).
- `lance-graph` itself untouched (Odoo-specific interpretation belongs
  in `lance-graph-ontology` per the layering split).

## Review pattern

Built with `/// work` markers → opus-4.8 reviewer (code-only, no
cargo) → orchestrator-run cargo verify.
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