Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .claude/board/AGENT_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,3 +459,11 @@ W11 [2026-05-14T12:29] test-plan-unification: spec at .claude/specs/sprint-10-te
**Outcome:** D-ODOO-1 ready for review. Workspace compiles; both touched crates green. NOT pushed (orchestrator reviews + pushes).

---

## [main / Opus] [DOCS-IMPORT] odoo savant briefing pack -> .claude/odoo (2026-05-27)
Imported the 18-file Odoo savant material verbatim from woa-rs/.claude/odoo:
SAVANTS.md (roster) + BRIEFING.md + BRIEFING-GAP.md + 15 lane distillations
(L1-L15: odoo model -> K-module mappings, e.g. L1-K3-POST, L3-K7-TAX,
L4-K8K9-REPORTS-DATEV, L11-COA-JOURNALS-LOCKDATES, L15-TAX-REPARTITION).
Reference material for lance-graph-side ontology/alignment work (companion to
the merged D-ODOO-1 hydrator + the four_way_alignment_seam spec). No code impact.
81 changes: 81 additions & 0 deletions .claude/odoo/BRIEFING-GAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Odoo Richness Harvest — GAP Lanes (L8–L15) + Savant-Agent Goal

> Companion to `.claude/odoo/BRIEFING.md` (read it first — the dual-axis
> classification, ontology shape, reading discipline, and output template all
> apply unchanged). This file defines the **remaining** lanes after L1–L7 and
> the end-goal those lanes feed: **Savant agents**.
>
> You are ONE read-only analysis lane. Output is a markdown spec draft only.
> **No cargo, no `src/` edits, no git.** Write exactly one file to
> `/home/user/woa-rs/.claude/odoo/<your-lane>.md`. First line MUST be
> `RICHNESS-LANE-OK`; last section MUST be the depth-proof footer
> (`Read: <file> lines=<n> depth=full` per file).

## What L1–L7 already covered (do NOT re-harvest)

| Lane | Covered |
|---|---|
| L1 | K3 double-entry posting (`account.move` state machine, `_check_balanced`, hash) |
| L2 | K3 reconciliation matching (open-item ↔ payment) |
| L3 | K7 USt/VAT compute + fiscal-position mapping (tax compute core) |
| L4 | K8 German report line-mappings + K9 DATEV export |
| L5 | Payments, payment terms, reconcile-model matching rules |
| L6 | Sale + Purchase order → invoice flow (Vorgang lifecycle) |
| L7 | Inventory: stock moves, picking, quant valuation + reservation |

## The remaining lanes (assigned per agent)

Odoo community source root: `/home/user/odoo/addons/` — present modules:
`account, hr, l10n_de, product, purchase, sale, stock`. Enterprise modules
(`account_asset`, `hr_payroll`, `account_reports`, `account_consolidation`)
are **absent** — flag, do not hallucinate; spec only base data/structure.

| Lane | Subsystem | Primary odoo files (read FULLY) | woa-rs K-target |
|---|---|---|---|
| **L8** | Product + UoM + Pricelist + costing | `product/models/product_template.py`, `product_product.py`, `product_category.py`, `product_pricelist.py`, `product_pricelist_item.py`, `uom/models/uom_uom.py` | data foundation; pricing (Vorgang line price), costing config (K3 valuation) |
| **L9** | Partner accounting properties + fiscal-position assignment | `account/models/partner.py` (res.partner extensions: `property_account_receivable_id`, `property_payment_term_id`, `property_account_position_id`, `_get_fiscal_position`, `commercial_partner_id`), base `res.partner` accounting fields | data foundation; partner→tax-mapping inference (AXIS-B) |
| **L10** | Analytic accounting (Kostenstellen) | `analytic/models/analytic_account.py`, `analytic_line.py`, `analytic_plan.py`, `analytic_distribution_model.py`; `account/models/account_move_line.py` analytic_distribution | new K-area: cost-centre allocation; distribution-model rules (AXIS-B) |
| **L11** | Chart of accounts + journals + lock dates + sequences | `account/models/account_account.py` (`account_type`, `reconcile`, `internal_group`), `account_group.py`, `account_journal.py`, `account/models/company.py` lock-date logic (`fiscalyear_lock_date`, `tax_lock_date`, `_get_violated_lock_dates`), `sequence_mixin.py` | K11 lock-date semantics + K3 sequence format families |
| **L12** | Multi-company + multi-currency | base `res.company`, `res.currency` + `res.currency.rate` (`_convert`, `_get_conversion_rate`, rounding), `account_move_line.py` `amount_currency`/`balance` compute, multi-company record rules | K15 Mehrfirma + multi-currency |
| **L13** | Stock↔Accounting valuation bridge + procurement | `stock/models/stock_valuation_layer.py`, `product/models/product.py` valuation (`_run_fifo`, `_run_average`, standard), `stock/models/stock_rule.py`, `stock_warehouse_orderpoint.py`, `stock_lot.py` | bridges stock→K3 (inventory GL postings); reordering (AXIS-A formula + AXIS-B) |
| **L14** | HR base data (employee/org/contract structure) | `hr/models/hr_employee.py`, `hr_department.py`, `hr_job.py`, `hr_contract.py` (base only) | K13 **data foundation** only — payroll ENGINE is Enterprise (absent) → built fresh; flag |
| **L15** | Tax repartition + tax groups + price_include + cash-basis | `account/models/account_tax.py` (`repartition_line_ids`, `_compute_amount`, `price_include`/`include_base_amount` ordering, `account_tax_group.py`, cash-basis transition) | deepens K7/L3 — the base/tax %-split to accounts+tags |

## End-goal these lanes feed: Savant agents

Every rule you tag **AXIS-B (heuristic → delegate)** is a candidate **Savant
agent**: a specialised reasoner defined by three coordinates. Make the
delegation tuple explicit (per `BRIEFING.md`) so the synthesis pass can mint
the Savant directly:

1. **Ontology** — the odoo class → OWL pivot → OGIT family (8-bit) via
`resolve_odoo_to_family()`. State the expected family (e.g. `0x61
BillingCore`, `0x62 SMBAccounting`) or `None` (→ "ontology-unmapped, needs
a Layer-2 alignment axiom").
2. **Use case** — the K-step / business question (`ReasoningKind` ∈
{CustomerCategory, PostingAnomaly, NextBestAction, InvoiceCompleteness,
MailIntent, Other(label)}).
3. **Thinking** — `InferenceType` ∈ {Deduction, Induction, Abduction,
Revision, Synthesis}; `SemiringChoice` ∈ {Boolean, HammingMin, NarsTruth,
XorBundle, CamPqAdc}; `ThinkingStyle`-cluster ∈ {Analytical, Creative,
Empathic, Direct, Exploratory, Meta} **inherited from the OGIT family**.

For each AXIS-B rule, end its entry with a one-line **Savant seed**:
`SAVANT: name=<x> family=<0x..|None> reasoning=<Kind> inference=<Type>
semiring=<Choice> style=<cluster> — <1-line why-delegated>`.

AXIS-A rules need no Savant — they are deterministic Rust ports; just give
the rich-AST sketch so an Opus porter can reproduce them.

## Reading discipline (Iron Rule 4 / Op-rule №3)

Read the odoo Python **fully** with the `Read` tool (whole file or
offset/limit chunks covering the entire method). `grep`/`sed`/`head` are
locators only. Quote `file:line-range` for every rule. Odoo source is
canonical; where it's odd, note it, don't "improve".

## Hard rules

- NO `cargo`, NO `src/` edits, NO git. Markdown only, to your one drafts file.
- First line `RICHNESS-LANE-OK`; depth-proof footer last.
- If a subsystem is Enterprise-only, say so and spec only base data/structure.
165 changes: 165 additions & 0 deletions .claude/odoo/BRIEFING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Odoo Richness Harvest — Shared Lane Briefing

> Read this fully before starting. You are ONE read-only analysis lane in a
> parallel fan-out. Output is a markdown spec draft only. **No cargo, no
> `src/` edits, no git.** Write exactly one file to
> `/home/user/woa-rs/.claude/board/odoo-richness/drafts/<your-lane>.md`.
Comment on lines +5 to +6

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 Update the imported briefing paths for lance-graph

When future agents follow this newly added lance-graph-side briefing, the output target still points at /home/user/woa-rs/..., so their drafts will be written outside this repository (or fail if that path is absent) instead of landing under .claude/odoo/.claude/board here. The same stale woa-rs target is repeated in BRIEFING-GAP.md, so the imported instructions need either a lance-graph-local path or an explicit note that they are historical reference-only.

Useful? React with 👍 / 👎.


## Mission (two stacked user directives)

1. **"Wherever odoo is richer, take the old shape and export so rich AST
details that we can reproduce the rich business logic in Rust (woa-rs),
and possibly later in Python (WoA — not yet)."**
→ Where odoo's logic is *richer* than woa-rs's current ERP state, capture
the FULL behaviour — control flow, branches, field computes, ordering,
rounding, edge cases, constraints — faithfully enough that an Opus porter
can reproduce it in Rust **without re-reading the odoo source**. Keep the
ontology shape (below) attached to every concept.

2. **"Check also for NARS patterns that can be delegated to thinking in
lance-graph and OGIT-inherited thinking styles for business heuristics."**
→ Classify every business rule on a DUAL axis (below). Deterministic logic
gets the rich-AST treatment for a Rust port. Heuristic/inferential logic
gets flagged for *delegation* to lance-graph's thinking surface instead of
being hard-coded as Rust if/else.

## The dual-axis classification (do this for EVERY rule you extract)

For each method / computed field / constraint, tag it:

- **AXIS-A — DETERMINISTIC → Rust port.** A closed-form rule: a balance
check, a sequence format, a tax = base × rate, a residual = debit − credit.
Output: rich-AST spec (see template) so it can be ported verbatim.

- **AXIS-B — HEURISTIC / INFERENTIAL → delegate to lance-graph thinking.**
Evidence-weighted, multi-factor, ambiguous, or "best guess" logic:
reconciliation *matching* (which open item pairs with which payment),
fiscal-position *resolution* (which tax mapping applies to this partner),
next-best-action, anomaly detection, stock reservation choice, dunning
escalation judgement. These should NOT be reproduced as brittle Rust
branches — they are delegated.

When you tag AXIS-B, fill the **delegation tuple** using the
`lance-graph-contract` surface (these enums already exist and are
customer-binary-safe / BBB-allowed):

- `ReasoningKind` ∈ { CustomerCategory, PostingAnomaly, NextBestAction,
InvoiceCompleteness, MailIntent, Other(u32) } — pick the closest; if none
fits, propose an `Other` label.
- `InferenceType` ∈ { Deduction (exact lookup), Induction (pattern/"things
like X"), Abduction (root-cause/"why"), Revision (belief update on change),
Synthesis (cross-domain join) }.
- `SemiringChoice` ∈ { Boolean, HammingMin, NarsTruth, XorBundle, CamPqAdc }
— how evidence combines (NarsTruth = evidence fusion is the common case).
- `ThinkingStyle` cluster ∈ { Analytical, Creative, Empathic, Direct,
Exploratory, Meta }. **This is INHERITED from the OGIT family**, not
chosen freely: the odoo class resolves to an OGIT `FamilyEntry` via
`resolve_odoo_to_family()` (the cache we just built — see Ontology shape),
and the family carries the default style. State which family you'd expect
and therefore which cluster; if the family is unmapped (returns `None`),
say so and propose a cluster with a one-line rationale.

A rule can be **hybrid**: a deterministic guard wrapping a heuristic core
(e.g. "balance MUST be zero" [AXIS-A] gating "suggest which lines to adjust"
[AXIS-B]). Tag both halves.

## Ontology shape (keep it attached — directive 1's "old shape")

We already built the OGIT→OWL→odoo cache:
`lance-graph/crates/.../lance-graph-callcenter/src/odoo_alignment.rs` and a
mirror in `woa-rs/crates/skr_data/src/odoo_alignment.rs`. The chain is:

```
odoo class ──owl:equivalentClass──► OWL pivot (fibo/ubl/vcard/schema) ──► OGIT family (8-bit) + slot (16-bit) ──► FamilyEntry (carries thinking style)
resolve_odoo() OgitFamilyTable.lookup() = O(1)
resolve_odoo_to_family(class, &table) chains both legs end-to-end, O(1)
```

Seed rows already mapped: `res.partner.Company`→fibo:LegalEntity,
`account.move`→fibo:Transaction, `account.move.line`→fibo:JournalEntryLine,
`account.account`→fibo:Account, `product.*`→schema:Product, SKR concepts→
fibo:Account. Families in use: 0x61 BillingCore, 0x62 SMBAccounting,
0x80 SmbFoundryCustomer, 0x81 SmbFoundryInvoice. **Option B**: no new CAM
family, no new slot — odoo classes INHERIT an existing OGIT slot via the OWL
pivot. Classes with no existing family (`stock.move`, `sale.order`,
`hr.*`, `account.reconcile.model`, …) currently resolve to `None` — if your
lane touches one, FLAG it as "ontology-unmapped, needs a Layer-2 alignment
axiom" rather than inventing a family.

For each odoo concept your lane covers, record: `odoo:<class>` →
`owl:equivalentClass <pivot>` → expected OGIT family (or `None`). The
DOLCE marker (Endurant/Perdurant/Quality/Abstract) comes from `dolce_odoo()`
suffix rules; note it where non-obvious.

## Reading discipline (Iron Rule 4 / woa-rs Op-rule №3)

- Read the odoo Python **fully** with the `Read` tool — whole file or
offset/limit chunks that cover the entire method. `grep`/`sed`/`head` are
LOCATORS only, never comprehension. A snippet read produces a paraphrase
spec that the porter then has to redo.
- Quote the odoo `file:line-range` for every rule you spec. The porter will
spot-check against the source.
- Odoo's source is **canonical** for these semantics (we are stealing them).
Where odoo is buggy or odd, note it; do not silently "improve".

## ERP gap context (what woa-rs is missing — the K-steps)

| K-step | Subsystem | woa-rs state |
|---|---|---|
| K3 | Double-entry posting + reconciliation | engine partial / view 501 |
| K7 | USt-Voranmeldung / tax compute / ELSTER | missing |
| K8 | German reports (BWA/SuSa/EÜR/GuV/Bilanz) | missing — engine built FRESH (odoo `account_reports` is Enterprise; only l10n_de **data/line-mappings** are stealable) |
| K9 | DATEV export | partial |
| K11 | Festschreibung (GoBD period lock) | missing |
| K12 | Anlagen (asset depreciation) | missing — odoo `account_asset` is **Enterprise**, NOT in community source |
| K13 | Lohn / payroll | missing — odoo `hr_payroll` is **Enterprise**, NOT in community (only `hr` base is present) |
| K15 | Mehrfirma (multi-company) | missing |

**Enterprise boundary — flag, do not hallucinate.** account_asset,
account_reports, hr_payroll, account_consolidation are NOT in the community
clone. If your lane's subsystem is Enterprise-only, say so explicitly and
spec only what IS present (base models, data, report STRUCTURE) — the engine
gets built fresh on the woa-rs side.

## Output template (one file, `drafts/<lane>.md`)

```markdown
# Lane <ID> — <subsystem>

## Sources read (file : line-range : depth)
- odoo/addons/.../x.py : L<a>-<b> : full
- ...

## Ontology rows
| odoo class | owl pivot | OGIT family (or None) | DOLCE |
|---|---|---|---|

## Rules extracted
### R<n> — <name> [AXIS-A | AXIS-B | HYBRID]
- **odoo source**: file:Lx-Ly
- **What it does** (rich): <control flow, branches, ordering, rounding, edge
cases — enough to reproduce>
- **woa-rs target**: <which K-step / which model/route this lands in>
- (AXIS-A) **Rust sketch**: <signature + key branches; Decimal/money rules; no
hand-waving on rounding or sign>
- (AXIS-B) **Delegation tuple**: ReasoningKind=… InferenceType=… Semiring=…
ThinkingStyle-cluster=… (inherited from OGIT family <fam>) — rationale 1 line
- **Parity notes / gotchas**: <German-tax specifics, GoBD, multi-currency, etc.>

## Enterprise gaps flagged
- <module> : <what's missing> : <what we spec from data/structure instead>

## Open questions for the Opus porter
- ...
```

## Sentinel + depth-proof (required — the agent prompts reference these)
- **First line of your draft MUST be:** `RICHNESS-LANE-OK`
- **Last section MUST be a depth-proof footer**, one line per file:
`Read: <file> lines=<n> depth=full`

## Hard rules
- NO `cargo` (no build/check/clippy/test). NO `src/` edits. NO git ops.
- Markdown output only, to your one drafts file.
- If two lanes would overlap on a file, still read it fully for your angle;
the Opus review pass dedups.
Loading