diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index aee7963..7ffe317 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -7,6 +7,121 @@ --- +## 2026-06-30 — E-ACCIDENTAL-IMPERATIVE — the hand-rolled residue = accidentally-imperative (AR verbs on AR targets, no declarative home) ∪ essentially-foreign; the body pass TRIAGES, it does not decompile + +**Status:** CONJECTURE (`[H]` — the split is operator-reasoned + grounded in the Odoo↔Rails asymmetry; the ratio is unmeasured pending the body pass). Operator-directed 2026-06-30. Builds on E-FUNCTION-CATALOG. **Update 2026-06-30:** the F17 prerequisite SHIPPED — ruff now captures per-function `writes`/`calls` (AdaWorldAPI/ruff @ `claude/odoo-rs-transcode-lf8ya5`, commit `dd70588`): `ruff_spo_triplet::Function` gains `writes`+`calls`, the closed predicate vocab gains `writes_field` (Authoritative) + `calls` (Inferred), and the `ruff_ruby_spo` body walker populates both from the Rails AST (closed `AR_MUTATORS` set; `self.x=`→write, mutator dispatch→call, else read). The "NOT writes" blocker in the Falsifier below is **cleared**; F17 is RUNNABLE — the body-triage probe is the next deliverable. Ratio still unmeasured. + +**Scope:** the "hand-rolled hook bodies" residue that E-RECIPE-BITMASK / E-FUNCTION-CATALOG leave. Why it is smaller than it looks, and the bounded thing ruff can actually do about it. + +**The split (operator).** A hook's TARGET is AR-shaped — the body sets a field / CRUDs an association / computes from relations, i.e. the SAME verbs (filter/map/project/reduce/CRUD) on AR targets. So the residue is two populations: +- **accidentally-imperative** (the big chunk): AR verbs on AR targets, written imperatively ONLY because the source had no declarative form. Proof = the Odoo↔Rails asymmetry: `total` recompute is DECLARATIVE in Odoo (`@api.depends`) and HAND-ROLLED in Rails (`before_save { total = lines.sum }`) — identical semantics, identical AR target; the imperative-ness is a property of source *expressiveness*, not logic complexity. Recoverable to `(verb, criteria)`. +- **essentially-foreign** (the small chunk): real algorithms / external / ledger semantics. The only true escape. + +So the residue is bounded below by essentially-foreign; population 1 re-declarativizes. **OGAR is the "ontology to call" those developers lacked** — forward it prevents the accidental hand-rolling; backward it re-recognizes it. + +**The body pass TRIAGES — it does not decompile (operator).** ruff cannot normalize arbitrary imperative bodies. The most it recovers is `(target classid, verb-class, order-signature)` — "something that calls an update on X, in some order" — grouped by target. So the residue becomes LEGIBLE ("47 hooks that all update WorkPackage") instead of opaque, and lands at a COARSE catalog tier: `ActionDef` keyed on `(target classid, verb-class)` + point-to-body (lossless-DO §1, the precise body preserved). + +**"random orders" is the recover/preserve GATE, not noise.** Incidental order (operations commute) → declarative form round-trips → RECOVER. Significant order (app depends on the sequence) → PRESERVE (sequenced/foreign body). Arbiter = the **round-trip-order-free parity check**: does the order-free `(verb,criteria)` reproduce the source output? Yes → order was random → recover. No → order mattered → preserve (+ RFC if behaviour diverges — "runs" can hide ordering/side-effect quirks the app now depends on; behaviour-preserving discipline, never silently "fix"). + +**Three landing tiers** (a body drops only as far as its deformity forces): clean `(verb,criteria)` → declarative emit · coarse `(target,verb-class)` + point-to-body, order-sig gates recover/preserve · foreign → full escape. + +**Falsifier (F17 / `PROBE-OGAR-BODY-TRIAGE`):** body pass → `(target, verb-class, order-sig)` per hook → round-trip-order-free each coarse group → PASS-rate = the real "how many were accidentally-imperative" number; FAIL-rate = the order-dependent/foreign tail. **Gated on a ruff extension:** capture **writes/calls** per function (today ruff captures reads/raises/traverses — NOT writes), so "calls update on X" is extractable. + +**Cross-ref:** E-FUNCTION-CATALOG, E-RECIPE-BITMASK, E-RECIPE-LABEL-DTO; lossless-DO §1 (point-to-body); the consumer behaviour-preserving / RFC discipline; F17; `openproject-nexgen-rs/.claude/knowledge/RAILS-COVERAGE-KIT.md` §6. + +--- + +## 2026-06-30 — E-FUNCTION-CATALOG — the catalog is of CRITERIA over SHIPPED deterministic verbs (filter/project/map/reduce already coded); a consumer function = `(verb, criteria)` keyed canonically + +**Status:** CONJECTURE (`[H]` — the verbs are `[G]`/CODED; the criteria-catalog + the round-trip gate are the to-wire). Operator-directed 2026-06-30. Extends E-RECIPE-LABEL-DTO; records two operator corrections of an over-scoping. + +**Scope:** "a catalog of AR-shaped functions landing on OGIT/Auth + a DTO-guided landing zone." What it actually is. + +**The verbs are SHIPPED, deterministic — nothing to build:** **filter** = the query/predicate engine (Cypher WHERE → DataFusion predicate, SigmaBandScan); **project** = the compute/recompute DAG + formula eval (`KausalSpec::Depends`); **map** = a deterministic table/lookup; **reduce** = the 15 semirings / GraphBLAS. + +**So the "catalog" is a catalog of CRITERIA, not functions.** Entry = `(verb: canonical concept id, criteria: { selection-condition + params })`, params grounded on a DOMAIN ontology (SKR / tax / Auth / OGIT / the class schema). Verb = the shipped op; criteria = EXTRACTED from source (deterministic, not authored). The DTO-guided landing zone = a criteria DTO selecting + parameterizing a shipped verb. Existing surfaces it lands on: `lance-graph-contract::action` (`actions_for`/`ClassActions`/`OgarResolver`/`ClassResolver`/`ExecutorRegistry`/`RunnerKind`), `ogar-render-askama` artifact_kinds (`html_list`/`detail`/`form` = the view landing zone), `ogar-vocab` (`canonical_concept_id`, `auth_store`, `ConceptDomain`). + +**CORRECTION 1 — map ≠ CAM-PQ (Test-0 register laziness).** Kontenerkennung (account determination) is a DETERMINISTIC relational rule resolution, NOT a similarity search: product/category default account → fiscal-position remap (contract/partner) → precedent (`reduce(filter(prior_bookings, partner×product), most-recent/modal account)`), with a priority/fallback. Natural keys ⇒ use the register (relational lookup + history query), per `I-VSA-IDENTITIES` Test 0. CAM-PQ enters ONLY for fuzzy suggestion on unseen combinations — a separate opt-in layer, never Kontenerkennung itself. + +**CORRECTION 2 — CRUD is generic, not hand-rolled.** create/update = the generic AR lifecycle (defaults → validate → hooks → persist → journal); per-class criteria = the recipe (validations/callbacks/defaults/associations) + the permission (RBAC) + the writable-field set; the controller action is a HandlerKind (`create/update-for-tenant`). Zero hand-rolled — only a genuinely non-standard hook BODY escapes (→ E-ACCIDENTAL-IMPERATIVE). + +**The only gate:** the extracted criterion must ROUND-TRIP (the parameterized verb reproduces the source output); a `map`/`project` claim that doesn't reproduce isn't one — it escapes. + +**Cross-ref:** E-RECIPE-LABEL-DTO (verbs + params are canonical concept ids + label DTOs), E-ACCIDENTAL-IMPERATIVE (the residue), E-RECIPE-BITMASK; `lance-graph-contract::action`, `ogar-render-askama`, `ogar-vocab`; `I-VSA-IDENTITIES` Test 0; `RAILS-COVERAGE-KIT.md` §6. + +--- + +## 2026-06-30 — E-RECIPE-LABEL-DTO — recipe labels are content-addressable concept ids on ONE generic ontology + per-language label DTOs; NOT a per-consumer enum zoo + +**Status:** CONJECTURE (`[H]` — the doctrine is operator-directed; the recipe-concept codebook is to-mint, the class-concept codebook + `canonical_concept_id`/`name` it extends are `[G]`/CODED). Operator-directed 2026-06-30. Extends E-RECIPE-BITMASK / E-RECIPE-BITMASK-CHAIN. + +**Scope:** the *recipe vocabulary* — the labels every consumer frontend produces for the behavioural/structural recipe (Rails callback phases `before_save`/`after_create_commit`, `ValidationKind`, `AssocKind`, the emergent controller `HandlerKind`; Odoo `MethodKind{Compute,Check}`, `KausalSpec.event` strings). How those labels land **canonically reusable** instead of an extinct per-consumer zoo. + +**The risk (operator).** Left as per-consumer enums/strings, each frontend invents its own label set → a class's recipe in Rails cannot be compared, shared, or co-resolved with the same concept in Odoo. The recipe-bitmask (E-RECIPE-BITMASK) only pays off if its slots are the **same across consumers**. + +**The fix (operator instinct, made canon).** A recipe label is **not** an enum variant — it is a **content-addressable concept id** in a shared **generic recipe ontology**, and the per-language surface string is a thin **label DTO** (`{ concept_id, lang, surface }`) pointing at that id. This is **exactly OGAR's existing class-concept doctrine — `classid` is the address, the lo-u16 is the shared concept, the hi-u16/surface name is the render skin (`canonical_concept_id` forward / `canonical_concept_name` reverse) — extended from the class vocabulary to the recipe vocabulary.** Rails `before_save` and Odoo before-persist guard resolve to ONE concept id (`LIFECYCLE_BEFORE_PERSIST`), one bitmask slot. + +**Three rules:** +1. **Bitmask slot = concept id, never a surface string** — so the per-class override vector is cross-consumer comparable. Slots are **RESERVE-DON'T-RECLAIM** (`I-LEGACY-API-FEATURE-GATED`): append concept ids; never reorder/repurpose. +2. **One ontology, N label DTOs** — a new consumer with a new surface for an existing concept emits a DTO that **reuses the slot**, mints nothing; only a genuinely-new concept mints a new id (extends, never forks). +3. **Id is truth, label is skin** — resolution/RBAC/bitmask key on the content-addressable id (stable forever); the surface is render-only/per-language. PII leaf-rename rides the DTO skin, never the id. + +**The recipe families to mint** (a recipe-concept codebook in OGAR, sibling to the class-concept codebook): lifecycle hooks · guard kinds · relation kinds · action/HandlerKinds. The ruff frontends (`ruff_ruby_spo`, `ruff_python_spo`) emit the surface; the OGAR lift resolves it to the id. Concrete first step: `KausalSpec::LifecycleTrigger{event:String}` + ruff `Callback{phase:String}` gain a `RecipeConceptId` resolved at lift time, keeping the string as the DTO surface. + +**Why it's the whole point.** "Planner times align with billable hours" IS cross-consumer concept convergence — OpenProject `TimeEntry` / Odoo `account.analytic.line` / WoA `Stundenzettel` already converge on `BILLABLE_WORK_ENTRY` (`0x0103`). The recipe vocabulary must converge the same way, or the behavioural arm fragments back into the zoo the structural arm escaped. + +**Cross-ref:** E-RECIPE-BITMASK, E-RECIPE-BITMASK-CHAIN; `ogar-vocab` `canonical_concept_id`/`canonical_concept_name` + the class-concept codebook (the pattern to mirror); `I-LEGACY-API-FEATURE-GATED` (RESERVE-DON'T-RECLAIM slots); full kit + mapping table + runbook: `openproject-nexgen-rs/.claude/knowledge/RAILS-COVERAGE-KIT.md` §5. + +--- + +## 2026-06-30 — E-RECIPE-BITMASK-CHAIN — constructor-chained `LazyLock` ClassViews resolve "out-of-slice"; the chain makes "redundant = referential identity" (not a hash test); the inheritance collapse axis MEASURED + +**Status:** FINDING (`[G]` — the inheritance-collapse axis is measured: 21.0% full / 22.7% behavioural, `odoo-rs tests/recipe_chaining_collapse.rs`) + CONJECTURE (`[H]` — the `LazyLock` constructor-chaining *impl* is operator-proposed). Extends E-RECIPE-BITMASK (same day). Operator-directed 2026-06-30. + +**Scope:** how a derived class's ClassView assembles its inherited recipe — and what that does to the recipe-bitmask's "out-of-slice" limitation and its redundancy guard. The **second** collapse axis (inheritance), orthogonal to E-RECIPE-BITMASK's within-class axis. + +**The mechanism (operator):** a derived class's ClassView is built by **chaining its base ClassViews — each a `LazyLock` constant — then layering its own delta** (constructor: `inherited(1+2) + own(1+2+3)`). This IS `classid → ClassView` made compositional; the chain is the MRO; lance-graph #533's `resolve_overrides` (nearest-base-wins BFS = Python C3 for linear mixin chains) is the chain-order resolver; the borrow-strategy rule already prescribes `LazyLock` / built-once for exactly this. + +**Two things the chain fixes:** +1. **"out-of-slice" dissolves.** The base isn't a corpus slice you need present — it's a registry constant you chain. (E-RECIPE-BITMASK's Odoo 54.3% was an UPPER bound *because* the slice's base mixins were absent; the chain resolves them regardless of slice.) +2. **"redundant = content-hash-equal-to-default" becomes REFERENTIAL IDENTITY.** The inherited part IS the same `LazyLock` constant — one allocation, shared by every subclass, pointer-identical. A clear bit literally points at the base's cached `ActionDef`; there is no copy to drift. The guard stops being a hash test and becomes structural. + +**Orthogonal to the 3×4 GUID carving — no re-carve needed.** Chaining is **value/registry-side** (`classid prefix → registry → LazyLock`, each base another classid); the 3×4 HEEL/HIP/TWIG path is **address/centroid-side**. Inheritance depth lives in the classid + registry resolve, never the path tiers — exactly the canon's *"depth beyond 12 native levels was always the hierarchy's job (registry resolve + ref-escape)."* So the operator's offered fallbacks (4×3 / 2×6 / 6×2) are NOT spent here, and the standing-watch flip condition (a measured radix/de-interleave workload) is not tripped — **3×4 stands.** + +**Two correctness constraints:** +- **chain order = the language MRO** (last writer wins the slot) — already the falsifier `F1` ("Delegation ≡ Odoo `_inherit`": the single chain AND a diamond `D(B,C),B(A),C(A)` where C3-over-`LastOrderedSet` picks C, naive parent-first picks A). +- **acyclic chain** — a `LazyLock` whose init locks another deadlocks on a cycle; inheritance is a DAG, resolve in topological order (`debug_assert`). + +**The measurement (F16 / `PROBE-OGAR-CHAINING-COLLAPSE`).** `odoo-rs tests/recipe_chaining_collapse.rs` (default build, offline) on the full Odoo inheritance manifest (388 classes, 101 with ancestors, max depth 5; 166 `inherits_from`; 3328 methods): naive flatten (own + inherited copies) 4215 vs chained (stored once) 3328 → **21.0% collapse (full recipe) / 22.7% (behavioural)**. Top sources: `mail_activity_mixin` (324 inherited copies), `account_move` (220), `mail_thread` (156). This is the inheritance axis the slice_2 probe could not see; it **STACKS** with E-RECIPE-BITMASK's within-class 54.3% (a class's genuine leftover is its own-after-shape-dedup methods, and even those are stored once and shared wherever inherited). **LOWER bound** — the corpus mixin harvest is shallow (real `mail.thread` ~100 methods, a handful captured), so richer extraction only raises it. + +**Cross-ref:** E-RECIPE-BITMASK (the axis-1 parent), D-RECIPE-BITMASK, D-RECIPE-BITMASK-CHAIN, F15, F16, F1 (chain-order falsifier), lance-graph #533 `resolve_overrides`; the borrow-strategy `LazyLock`/built-once rule; `odoo-rs tests/recipe_chaining_collapse.rs` + `data/odoo_inheritance_manifest.ndjson`. + +--- + +## 2026-06-30 — E-RECIPE-BITMASK — OGAR = Open Graph *Active Record*: the canonical "recipe" IS the AR lifecycle protocol; a class = the shared recipe + a per-class override bitmask + the genuine deltas + +**Status:** CONJECTURE (`[H]` — the mechanism is `[G]`/measured on one arm; the headline "15%→7% for best-shaped consumers" prediction is operator-proposed, falsifier RUN on the Odoo upper bound, clean Rails-AR run pending). Operator-directed 2026-06-30. + +**Scope:** the behavioural-arm compression for any AR-shaped consumer (Odoo / Rails / Redmine / OpenProject) — how much of a class's lifecycle behaviour is a shared canonical recipe vs genuine per-class content, and the per-class override **bitmask** that hides the redundant majority. The ClassView + bitmask + ERB→askama view port is the rendering tier ON TOP (the icing); the AR core is the substrate. + +**The framing (operator):** OGAR's name is the thesis — Open Graph **Active Record**. The "recipe" is not a novel compression trick; it IS the ActiveRecord lifecycle protocol (`before_save`/`after_create`/`validates`/`_compute_*`/`_check_*`/`action_*`). A consumer "shapes AR where it makes sense": AR-shaped behaviour collapses to the shared recipe + a per-class override bitmask (set bit = this class overrides, clear bit = inherited default, fall-through per the zero-fallback ladder); non-AR behaviour (chess move legality, pure arithmetic) stays a foreign-call escape. The bitmask is a **register**, not VSA (`I-VSA-IDENTITIES` Test 0 — action presence has a natural positional slot; a `u64` mask beats VSA at exact-match; cascade if it overflows, never widen). + +**The two guards (so it stays lossless, not a heuristic):** +- slot positions are **RESERVE-DON'T-RECLAIM** — a bitmask over a recipe is only valid if slot N means the same lifecycle hook forever (`I-LEGACY-API-FEATURE-GATED`; same fixed-offset discipline as classid/family in the key). Append hooks at the end; never reorder, never reclaim a slot's meaning. +- "redundant" = **content-hash-identical-to-default** — a bit is clear iff the class's body for that slot resolves to the same content-addressed `ActionDef` as the default (lossless-DO §1: the ActionDef POINTS TO its body, never inlines it). Content-addressing is what makes "hide the redundant" provably lossless rather than a heuristic that drops a real override. + +**The mechanism is already half-visible in shipped code.** `od-ontology::ogar_actions::corpus_to_actions` lifts Odoo's behaviour into exactly TWO recipe shapes: the recompute arm (`KausalSpec::Depends{paths}`) and the guard arm (`KausalSpec::LifecycleTrigger{before_save}` + `Reject`). Every guard is byte-identical except its address; every compute shares one shape and differs only in `Depends.paths`. That IS the recipe + per-class delta, in the wild. + +**The falsifier RAN (Odoo = UPPER bound).** `odoo-rs tests/recipe_redundancy_probe.rs` (default build, offline, `PROBE-OGAR-AR-RECIPE-COLLAPSE`) on the slice_2 corpus: behavioural arm 358 (47 guards + 311 computes; 141 computes reads-captured), **guard arm collapses fully (47→1 shared recipe)**, compute arm 101 distinct path-sets of 141 resolved (mostly genuine), headline **45.7% recipe-collapsible / 54.3% leftover** over the 188 resolved methods. This **REFUTES the strong reading** ("Odoo collapses to 7%") and **CONFIRMS the scoping**: 7% is the best-shaped *Rails-AR* case, not compute-heavy *Odoo-Python*. Upper bound because the slice's base mixins are out-of-slice (inherited-vs-override unmeasurable here), the live-source `ruff_python_spo` path drops `_inherit`, and method bodies aren't captured — all three can only LOWER the leftover. + +**Why Rails/OpenProject is the clean test.** `ruff_ruby_spo` captures `callbacks` / `validations` / `sti` as first-class `Model` data — the AR recipe survives into the IR exactly where Odoo's inheritance is dropped. Same `ruff_spo_triplet::ModelGraph` + `expand()` for both frontends. Handover with the concrete Ruby probe spec: `openproject-nexgen-rs/.claude/handovers/`. + +**Gate / next:** `PROBE-OGAR-AR-RECIPE-COLLAPSE` (F15) promotes D-RECIPE-BITMASK `[H]→[G]` when the Rails-AR clean run lands near the ~7% leftover target (callback-override bitmask density on `ruff_ruby_spo`'s captured `callbacks`). The Odoo bound is recorded; the Rails run is the pending half. + +**Cross-ref:** D-RECIPE-BITMASK, F15, D-VOCAB, D-HIRO-DO (lossless-DO §1 — ActionDef points to body), D-ACTION; `I-VSA-IDENTITIES` Test 0, `I-LEGACY-API-FEATURE-GATED`; the zero-fallback ladder + EdgeBlock (`CLAUDE.md` CANON); `odoo-rs tests/recipe_redundancy_probe.rs` + `docs/ODOO-OGAR-MIGRATION-SPRINT.md`; `openproject-nexgen-rs/.claude/handovers/`. + +--- + ## 2026-06-25 — E-CLASSID-ENVELOPE-PARSER — V2/V3 (and value-schema/edge-codec) are classid-defined per file+consumer; ONE reusable envelope parser reads classid → registry → parse **Status:** CONJECTURE (`[H]` — the composed parser is operator-proposed, "to be wired"; the pieces are `[G]`/CODED). Operator-directed 2026-06-25. diff --git a/docs/DISCOVERY-MAP.md b/docs/DISCOVERY-MAP.md index 54c3bbb..a0e0cf6 100644 --- a/docs/DISCOVERY-MAP.md +++ b/docs/DISCOVERY-MAP.md @@ -221,6 +221,10 @@ two halves of a cell. ADR‑026 names the cascade that ties them. | D‑PATTERN | `ogar-pattern` — recognition library + confidence (FMA‑D/FIBO/SKR/PROV‑O) | H | IDEA | (queued) | D‑TTL | | D‑ACTION | `ogar-actionable` — lifecycle → `ActionDef`/`KausalSpec` | H | IDEA | (queued) | D‑PATTERN | | D‑NSM | 4096‑dim Deep‑NSM encoder (Wierzbicka primes, `NUM_PRIMES=63`) calibration | H | IDEA | RDF‑OWL §4.10 | D‑CAM, `[per rt]` | +| D‑RECIPE‑BITMASK | OGAR = Open Graph **Active Record**: the canonical recipe IS the AR lifecycle protocol; a class stores it once + a per‑class override **bitmask** (set=override, clear=inherited default, fall‑through per the zero‑fallback ladder) + the genuine deltas → thins the "impossible 15%" behavioural leftover toward ~7% for best‑shaped (AR‑canonical) consumers. Guards: zero per‑class payload (recipe IS the spec); computes: shape + `Depends.paths` delta. Guards: bitmask=register not VSA (`I‑VSA‑IDENTITIES` T0); redundant = content‑hash‑equal‑to‑default (lossless‑DO §1); slots RESERVE‑DON'T‑RECLAIM (`I‑LEGACY‑API‑FEATURE‑GATED`). Odoo (Python, UPPER bound) RUN: guard arm 47→1 full‑collapse, compute arm 101 distinct of 141 resolved, **45.7% collapse / 54.3% leftover** — REFUTES "Odoo→7%", CONFIRMS the Rails‑AR scoping | H | EPIPHANY | E‑RECIPE‑BITMASK · F15 · `odoo-rs tests/recipe_redundancy_probe.rs` | D‑VOCAB, D‑HIRO‑DO, D‑ACTION | +| D‑RECIPE‑BITMASK‑CHAIN | the **inheritance axis** of the recipe‑bitmask: a derived ClassView is built by chaining its base `LazyLock` constants + its own delta (`classid → ClassView` compositional; chain = MRO; #533 `resolve_overrides` = order). Fixes two things — "out‑of‑slice" dissolves (the base is a registry constant, not a slice dep) and "redundant = content‑hash‑equal" becomes **referential identity** (the inherited part IS the shared cached constant, pointer‑identical, no copy to drift). Orthogonal to the 3×4 carving (value/registry‑side vs address/centroid‑side) → **3×4 stands, no re‑carve**. Chain‑order falsifier = F1; acyclic (DAG, topo order). MEASURED (full manifest, 388 classes / 166 edges / 3328 methods): naive 4215 vs chained 3328 → **21.0% collapse / 22.7% behavioural**; STACKS with the within‑class 54.3%; lower bound (shallow mixin harvest) | G (measured) / H (LazyLock impl) | EPIPHANY | E‑RECIPE‑BITMASK‑CHAIN · F16 · `odoo-rs tests/recipe_chaining_collapse.rs` | D‑RECIPE‑BITMASK, D‑VOCAB, F1 | +| D‑FUNCTION‑CATALOG | a consumer function = `(verb, criteria)`: the verbs (filter=query engine · project=compute/recompute DAG · map=deterministic lookup · reduce=semirings) are SHIPPED/`[G]`; the "catalog" is of CRITERIA (selection-condition + params, grounded on a domain ontology), EXTRACTED not authored, keyed by canonical concept id (E‑RECIPE‑LABEL‑DTO). DTO-guided landing zone = a criteria DTO selecting+parameterizing a shipped verb; lands on `lance-graph-contract::action` (actions_for/OgarResolver) + `ogar-render-askama` artifact_kinds + `ogar-vocab`. **map ≠ CAM‑PQ** (Kontenerkennung = relational rule + precedent; Test‑0 register, not ANN); **CRUD = generic lifecycle + extracted criteria**, not hand-rolled. Gate: extracted criterion must round‑trip | H | EPIPHANY | E‑FUNCTION‑CATALOG · F17 | D‑VOCAB, D‑ACTIONHANDLER‑RESOLVER, D‑RECIPE‑BITMASK | +| D‑ACCIDENTAL‑IMPERATIVE | the hand-rolled residue = **accidentally-imperative** (AR verbs on AR targets, no declarative home — recoverable; Odoo `@api.depends` vs Rails `before_save{lines.sum}` proves it is source-*expressiveness* not logic complexity) ∪ **essentially-foreign** (the only true escape). The body pass **TRIAGES** to `(target classid, verb-class, order-signature)` — NOT decompile; residue becomes legible; lands at a coarse catalog tier + point-to-body (lossless-DO §1). "random orders" = the **round-trip-order-free** recover/preserve gate. Three tiers: clean `(verb,criteria)` · coarse `(target,verb-class)` · foreign | H | EPIPHANY | E‑ACCIDENTAL‑IMPERATIVE · F17 · ruff writes/calls capture SHIPPED 2026‑06‑30 (AdaWorldAPI/ruff#38: `Function.writes`/`calls` + `writes_field`/`calls` predicates + `ruff_ruby_spo` body walker) → F17 RUNNABLE, body‑triage probe is the next deliverable; ratio still unmeasured | D‑FUNCTION‑CATALOG, D‑HIRO‑DO | ### 2.9 Domain instances (universality witnesses) diff --git a/docs/INTEGRATION-MAP.md b/docs/INTEGRATION-MAP.md index 7469aa4..2aa5e43 100644 --- a/docs/INTEGRATION-MAP.md +++ b/docs/INTEGRATION-MAP.md @@ -393,6 +393,9 @@ R2 — not D.) | F12 | **θ conditioning window** | jc P5b (Pearl 2³) + `hpc::quantized` θ-sweep | θ ∈ [1.45, 1.6] with ρ envelope [0.93..0.9973] — D‑THETA/D‑RHOENV `[H]→[G]` | | F13 | **Backend parity** | `hpc::simd_dispatch` W1c: AVX‑512 vs NEON vs scalar | identical within **1 ULP** — the correctness floor under every gate above | | F14 | **Wide-model render** | render `account.move` through `ClassView` with full presence (**>64 is the load-bearing bound; 109 declarations counted** in account_move.py, Odoo 17) | **gated: cannot RUN until Phase B** wires the field-enum into `RegistryClassView`; once runnable, fails by construction (FieldMask u64, L0b) until presence exceeds u64 — **Track X7 is the named path** | +| F15 | **AR-recipe collapse** (`PROBE-OGAR-AR-RECIPE-COLLAPSE`) | measure how much of a consumer's lifted behavioural arm folds to the shared ActiveRecord-lifecycle recipe + per-class override bitmask vs genuine per-class leftover. **Odoo upper-bound RUN** (`odoo-rs tests/recipe_redundancy_probe.rs`, default build, slice_2): guard arm 47→1 full-collapse, compute arm 101 distinct of 141 resolved, **45.7% collapse / 54.3% leftover**; clean run is Rails/OpenProject where `ruff_ruby_spo` captures `callbacks` as first-class `Model` data | D‑RECIPE‑BITMASK `[H]→[G]` when the Rails-AR clean run lands near the ~7% leftover target; the Odoo bound already refutes the strong "Odoo→7%" reading | +| F16 | **Constructor-chaining collapse** (`PROBE-OGAR-CHAINING-COLLAPSE`) | the inheritance axis: naive flatten (own + inherited copies) vs chained (stored once at the base `LazyLock` constant) over a consumer's `inherits_from` DAG. **Odoo RUN** (`odoo-rs tests/recipe_chaining_collapse.rs`, full manifest, 388 classes / 166 edges / 3328 methods): naive 4215 vs chained 3328 → **21.0% collapse / 22.7% behavioural**; top base `mail_activity_mixin` (324 copies). Chain-order correctness = F1; acyclic DAG | D‑RECIPE‑BITMASK‑CHAIN `[H]→[G]` (measured); confirms chaining resolves F15's "out-of-slice" upper bound — the real leftover sits below it; orthogonal to F15, stacks. Rails leg (concerns captured) should exceed Odoo's collapse | +| F17 | **Body-triage / accidentally-imperative ratio** (`PROBE-OGAR-BODY-TRIAGE`) | run the body pass over real hooks → `(target classid, verb-class, order-signature)` per hook → **round-trip-order-free** each coarse group (does the order-free `(verb,criteria)` reproduce the source output?). PASS-rate = the accidentally-imperative (recoverable) fraction; FAIL-rate = the order-dependent / essentially-foreign (preserve/escape) tail. Control = Odoo `_compute_*` (already declarative); test = Rails `before_*`/`after_*` | D‑ACCIDENTAL‑IMPERATIVE / D‑FUNCTION‑CATALOG `[H]→[G]`. ~~**Gated on a ruff extension:** capture writes/calls per function (today: reads/raises/traverses only) so "calls update on X" is extractable~~ **Prerequisite SHIPPED 2026-06-30** (AdaWorldAPI/ruff @ `claude/odoo-rs-transcode-lf8ya5`, commit `dd70588`): `ruff_spo_triplet::Function` gains `writes` (self.= setters → `writes_field`, Authoritative) + `calls` (lifecycle-mutator dispatches as "receiver.method" → `calls`, Inferred); the `ruff_ruby_spo` body walker populates both from the Rails AST (closed `AR_MUTATORS` set). "calls update on X" is now extractable → **F17 is RUNNABLE** (probe still to author/run). Python frontend leaves them empty (Odoo write target already declarative via `Field::emitted_by`) | (F3 already carries the D‑QUANTGATE pre/post-quantization contrast. F10–F13 restore the DISCOVERY-MAP §4.2 jc×hpc floor that v1.0 omitted —