From e6840799fa4c6c9e843ae962bef739577726efab Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Mon, 12 Oct 2026 12:48:11 +0200 Subject: [PATCH 1/6] docs: specify class-method hotplug activation and lowering --- .../plans/class-method-schema-hotplug-v1.md | 315 ++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 .claude/plans/class-method-schema-hotplug-v1.md diff --git a/.claude/plans/class-method-schema-hotplug-v1.md b/.claude/plans/class-method-schema-hotplug-v1.md new file mode 100644 index 000000000..a1b14cc2b --- /dev/null +++ b/.claude/plans/class-method-schema-hotplug-v1.md @@ -0,0 +1,315 @@ +# D-CMH-0..12 — Class × Schema × Methods hot-plug activation, with Quack and R2IL + +> **Draft RFC / documentation only, 2026-10-12.** This file authorizes **no** Rust code, OGAR Class/ActionDef or codebook mutation, new opcode, re-interpretation of persisted bytes, extension of the zero-dependency contract, or production ERP/IAM/CRM mutation. The first implementation requires named parity and disable tests. +> +> **Sibling semantic RFC:** [OGAR #357](https://github.com/AdaWorldAPI/OGAR/pull/357); *this* plan is the **physical binding/activation seam**, not another logic engine. +> **Evidence inventory:** [class-method-hotplug-existing-contracts.md](../knowledge/class-method-hotplug-existing-contracts.md); **falsifiers:** [class-method-hotplug-falsifiers-v1.md](class-method-hotplug-falsifiers-v1.md). Each [G]/[H]/[ABSENT] label is scoped to the cited code or explicit gap. + +## 0. Problem and decision + +A consumer currently may separately: +1. declare `HotPlug { consumer, classids: &[u16], covered }`; +2. receive `OgarAuthority.activate(&plug) -> Activation` containing concept/capability and contextual `ReadMode`; +3. bind ClassView / `WideFieldMask` structural fields; +4. implement Quack `Binder`: textual table/field/literal → numeric `TableId`, `Col`, `Mask` and validity; +5. author an R2IL procedure or call Quack `lower`; +6. separately resolve OGAR `MethodDecl` / `ActionDef`. + +**The missing link is one validated, per-plug, class-scoped *binding composition*, not a global class table, new catalog or runtime.** The desired runtime unit is a method *resolved against* a class reading and a versioned data source. Every consumer reuses the same process. + +### Proposed invariant D-CMH-0 + +`(OGAR class authority × OGIT canonical field identity × actual slab declaration × schema/field projection × method identity/effect) -> PreparedClass`, with **zero new hot-path name resolution** and typed, fail-closed query/procedure/action dispatch. + +One physical bulk engine: `mask-risc::Program -> ndarray::simd`. Quack and R2IL are separate **frontends/composition surfaces**, not duplicate row evaluators. Every required field is resolved or activation refuses; DO never lowers into a write-masking kernel. + +**Do not alter** the existing `HotPlug`, `CapabilityAuthority`, `Activation` and `ResolvedReading` contracts in W0/W1. In particular: +- `HotPlug.classids` uses the **canonical concept high u16**; application identity/namespace is bound separately as the low u16 of full `u32` class identity (`concept << 16 | appid`). Do not conflate `ClassId = u16` in ClassView with complete app-specific `u32` classid. +- An activation is **per plugged set**. It is never a newly hard-coded global lookup, and no global COUNT_FUSE/consumer-roster lockstep is reintroduced. +- An explicit `SlabDeclaration` wins for **persisted physical reading/value schema**, not the semantic interpretation of a current ClassView or the key tail. Old slabs remain readable under their declared physical format. +- `read_mode_for` and signed register law binding **bang** on absence/mismatch; never silently choose V1 or guess class semantics. +- **Reading-only** hot-plugs may have `covered = []` and no capability table. Do not treat every lack of ActionDef as an activation error. Permissions are not created by `HotPlug.covered`. + +## 1. Proposed activation diagram + +```text +SOURCE ONCE / COLD PLUG + Consumer HotPlug + app prefix (concepts/capability declarations) + │ + ├─ OgarAuthority (class identity, minted concepts, capability set, reading) + │ └── Activation / ResolvedReading (existing; unchanged) + ├─ OGIT OntologyRegistry (canonical field URIs, aliases, bridge ids) + ├─ OGAR Class + MethodDecl + ActionDef (source semantic surface) + ├─ ClassView ordered FieldRefs + WideFieldMask (field universe) + ├─ physical SlabDeclaration + source generation (bytes already written) + └─ ogar-loco Inventory (keyed function bodies; local FnAddr) + │ + [ClassActivationCompiler] << proposed composer, cold path + 1 identity & reading check + 2 ordered field + native/semantic mapping check + 3 type/null/units/RBAC binding + 4 methods + body/effects link + 5 lower/certify pure plans + 6 publish one immutable PreparedClass or refuse + │ + PreparedClass { schema seal, bound fields, method slots, read rules } + │ + HOT CALL: + MethodSlot + generation-checked Planes + ActorContext + ├── Query -> Quack Query / lower(_fused) -> mask-risc + ├── Procedure -> Inventory/FnAddr -> R2IL FoldDialect -> mask-risc + ├── Compute -> checked compute DAG / typed derived read + └── Action -> inert OGAR ActionInvocation -> AUTHORITY GATE + -> CapabilityExecutor + │ + Versioned result/receipt, no row-sized Context materialization +``` + +**No duplication:** OGAR *authoritatively* owns class/definition/action semantics. OGIT *authoritatively* resolves imported ontology field identity/URIs. The binder does not mint either, and Quack `Registrar` does not become a class registry. + +## 2. API sketch (illustrative Rust, NOT shipped) + +```rust +// A sidecar in the execution/binding layer, NOT a new zero-dep contract type. +struct PreparedClass { + identity: FullClassId, // canonical concept high + appid low + schema_seal: SchemaSeal, // deterministic semantic revision + reading: ResolvedReading, // existing HotPlug + SlabDeclaration + fields: BoundFieldMap, // field-key -> Col, LaneKind, validity + methods: BoundMethods, // [MethodKey] -> PreparedMethod + field_universe: WideFieldMask, // per-class projection basis +} + +struct PreparedMethod { + key: MethodKey, // stable [u8;16] identity; OGAR/substrate minted + arity_and_types: MethodSignature, + required: WideFieldMask, // property positions in this schema + produces: ResultSort, + effect: EffectClass, + body: MethodBodyRef, + law: Option, +} +enum MethodBodyRef { + Quack(BoundQueryTemplate), + R2il { inventory_key: [u8;16], local_addr: FnAddr }, + Compute(ComputeGraphRef), + OgarAction(ActionDefId), // never executable without an Invocation + Unsupported(ExplicitGapCode), +} +enum EffectClass { Pure, ReadVersion, Propose, ExternalMutate } + +fn prepare_class( + plug: &HotPlug, + authority: &impl CapabilityAuthority, + schema: &impl CanonicalFieldSource, + method_inventory: &impl MethodSource, + slab: Option<&SlabDeclaration>, +) -> Result; + +fn call_pure( + prepared: &PreparedClass, + method: MethodKey, + data: BorrowedPlanes<'_>, + context: &ReadContext, +) -> Result; +``` + +`PrepareError` must name the failure, never degrade to an empty/default program: `UnknownClass`, `UnmintedCanonicalField`, `AmbiguousAlias`, `SchemaSealMismatch`, `FieldOverflow`, `UnmappedRequired`, `MissingValidity`, `UnsupportedLane`, `MissingBody`, `MethodSignatureMismatch`, `UncertifiedRewrite`, `SlabDrift`, `NoReadScope`, `EffectNotPure`, `CapabilityMismatch`. + +W0–W2 should implement the **composer as an additive sidecar** in a layer allowed to depend on OGAR, Quack and R2IL. Do not add those dependencies to `lance-graph-contract`. Actual crate path to be selected in W1 after verifying the excluded-workspace integration constraints: `lance-graph-ogar` is a candidate, but it is workspace-excluded and must not induce a Cargo workspace-load dependency cycle. If the executable binder belongs in a consumer-facing existing crate, keep the same contracts and a separate test target; do **not** mint `lance-graph-class-registry` as a new crate for convenience. + +### 2.1 Method identity: key, slot, interpreter address are THREE things + +- **Stable identity:** keyed 16-byte function node identity from OGAR's `ogar-loco::Inventory::key_of`; a genuine key must be minted by the substrate/owner. `MethodKey` binds owner Class, schema/semantic revision and signature as a *separate verified registry relation*, not from random hashing truncated into a global classid. +- **Local dispatch:** `ogar_loco::FnAddr(u16)` is a transient ordinal inside one inventory; `VecInventory::push_keyed` and `addr_of` already work, and `Interpreter::with_inventory` resolves bodies. The inventory does **not** allocate a globally stable method ordinal. +- **CALL bytes:** current program body-reference positions use byte-sized targets and the entry address 0 is reserved. A 65,536-capacity inventory does **not** prove any one CALL can name all 65,536 methods. Validate reachable/callable address encoding or refuse. +- **C++ signatures:** `lance_graph_contract::codegen_manifest::{MethodSig,ClassMethods,methods_for}` are already a generated **signature manifest** for C++; they are not OGAR `MethodDecl` or an executable R2IL body. A preparation adapter may reuse the signature pattern, but must not silently merge three distinct authorities. +- **OGAR `MethodDecl`:** holds source name/kind/record semantics and *opaque* `body_source`. Merely harvesting a method never means it can be compiled into R2IL. Failed lifting yields `Unsupported`, not a fake implementation. +- **NARS:** `ogar-loco/src/nars.rs` already registers 34 recipe codes, but Control `body_refs=0` in its current table; recipe names alone do not create bodies. + +### 2.2 Field bindings: one canonical basis, multiple domains + +`ClassView::fields(canon_classid)` fixes an ordered per-class basis. Build stable **field identity before ordinals**: +1. Resolve source technical name, alias and URI using OGIT `OntologyRegistry` (`bridge_id, public_name` → `SchemaPtr` / canonical URI). +2. Require a **reviewed semantic mapping** from each native source field to the OGAR field identity. Same position or type in SAP/Odoo is not evidence of same meaning. Record grade `Proposed | Hypothesized | Converted | Refused` and conversion proof/version. +3. Bind each eligible canonical field onto `Quack::BoundField { col, kind, validity }` with physical carrier, null rule and explicit unit/scale. Bind derived lenses separately, with declared provenance and signature. +4. Canonicalize the **ordered** field universe *once*, mint the `WideFieldMask` from requested field positions, and record a schema seal covering IDs/order, types, conversions, validity, reading and method signature; no labels on hot path. +5. At execution, borrow `Planes::lanes` / `Planes::masks` from the dataset. Ensure plan source generation, tenant/role grants and Slab declaration match; do not materialize a row tuple for the binder. + +`FieldKey = (FullClassId, CanonicalFieldId, SchemaRevision)` is conceptual. Do not use `(classid,ordinal)` as a portable semantic identity *across* schema versions, classes or bridge mappings. An ordinal is stable only within the declared ordered field basis. + +### 2.3 What WideFieldMask canonizes, and what it does NOT + +- `WideFieldMask` is a **FIELD-position mask**. Small (<65 positions) matches `FieldMask(u64)` bit-for-bit and starts without heap allocation; >64 uses wider representation. Its `from_universe_present` constructor caps the universe at **256 positions**. An imported class with >256 fields must be split per existing OGAR-SOC rule or fail closed, not silently truncated. +- `from_universe_present` ignores present names absent from the universe by construction; the caller **must check every requested name** against the declared universe before calling it. `CatsSchema::realize_projection` does this and is the immediate precedent. +- Presence, required fields, grants and actual data-value validity are FOUR distinct notions. Proposed typed field masks: `required`, `available`, `read_allowed`, `write_declared`, plus per-field **row validity** planes. Never treat a presence bit as RBAC or a missing row value as a missing field declaration. +- Cold permission/availability criterion for a pure method: + `required ⊆ (available ∩ read_allowed)`, plus all requested fields mapped under one schema seal. The field algebra here is *not* the row-selection mask of `mask-risc`. +- Hot read mask: + `R_result = R_class ∩ R_tenant ∩ R_RBAC ∩ R_live ∩ R_method_predicate`, all referencing the **same row universe and dataset generation**. Quack SQL NULL semantics uses `BoundField.validity` (row plane): `UNKNOWN` cannot be treated as `FALSE` by arbitrary `NOT` rewriting. +- For DO, `write_declared` is only an **effect inventory** for an `ActionDef`. It never grants an actor permission. OGAR `ActionInvocation` must still pass current RBAC, guard, approval/MUL and idempotency checks. + +### 2.4 Schema revision vs snapshot identity + +Proposed `SchemaSeal` must be a deterministic hash of *semantic* schema facts: ordered canonical field IDs, native → semantic mapping/version, carrier kinds, logical types, NULL/Unknown and row-validity policy, unit/scale conversion law, derived-field provenance, schema/declaration versions, ClassView reading, method signatures and verified result/effect types. Exclude localized labels/UI cosmetics and runtime row counts. If a method body changes without a schema change, **also key the executable plan by its MethodKey/body version**. + +Cache bound code with tuple `(FullClassId, SchemaSeal, MethodKey, BodyVersion, ReadingLaw)`; bind execution against `(LanceGeneration, SlabDeclaration, Tenant/ActorContext)`. No cache entry can supply permissions. On a schema update, validate a new class activation **off-path** then atomically publish the new generation; in-flight reads either finish against their pinned slab/source or refuse/replan. Existing persisted slabs continue to decode according to their stored declaration. No implicit recarving or key migration. + +## 3. TWO lowering paths, ONE physical backend + +### 3.1 Quack direct query (existing and suitable for filtering/reporting) + +```text +method field names (cold) + -> Quack::Draft.bind(&impl Binder) + -> Query { Filter, Agg } (fixed-width; no text) + -> Quack::lower / lower_fused / grouped lowering + -> mask-risc::Program -> execute_into(borrowed planes) +``` + +The shipped Quack `Binder` supports table name, live row mask, name→`BoundField {Col, FieldKind, validity}` and literal→numeric codebook ID. The current `FieldKind` in that Binder supports `I32` and `Code/U32`; it does not mean the general mask-risc executor is limited to those lane types. It is illegal to guess U64/strided/optional fields by losing information. `Quack::Registrar` currently registers only name+width and has **no production implementation**; do not promote it into the canonical Class registry. + +### 3.2 R2IL named method (existing interpreter and missing link) + +```text +MethodKey -> OGAR-validated function inventory key + -> FnAddr (local, checked) + -> ogar-loco Interpreter::with_inventory(...) + -> FoldDialect::call (R2IL calls / existing procedures) + -> mask-risc Program per terminal / pure scalar composition +``` + +Current `lance-graph-r2il::procs` already contains `select_lt`, `filter_lt`, `sum`, `group_sum` and `margin`. R2IL is a *program composer*; its `FoldDialect` uses mask-risc for each bulk terminal, not another row loop. **One mask-risc Program has one terminal**; `margin = SUM(revenue) - SUM(cost)` requires two folded epochs and reselection. The method planner may cache legal input plan components, but it must not retain an invalid scratch mask across terminal epochs. + +The **proposed bridge** has to bind the same ordered fields/validity/read scope to both Quack `Query` and R2IL `LOAD/Predicate` call operands, then prove answer parity. A bit-identical `Program` is **not mandatory**: Quack `lower` (survivor gated) and `lower_fused` (TERNLOG) intentionally produce different instruction sequences; the contract is **identical typed results** under exact oracle, with resource counts measured separately. Only assert byte-for-byte equality for explicitly identical normalization policies. + +No generic magic conversion from arbitrary Quack `Expr` into loco exists today. No automatic body parser/PROC_DEF/PROC_CALL semantics should be claimed. The first bridge may be a static method catalog of *known working* pure R2IL procedures. + +### 3.3 Derived/computed methods + +`ClassView::ComputeEdge` and compute DAG are existing descriptors. The existing `compute_dag_is_acyclic` checks **64 positions** while `WideFieldMask` accepts **up to 256**. This mismatch is a hard guard: do not silently accept Odoo computed methods above position 63 or ignore a dependency cycle; either a separately tested **generic** wide DAG checker or a declared sub-schema partition must be provided first. A plain source-language method read is **not** the same as an `@api.depends` recomputation trigger; respect OGAR's differentiated reads/writes/calls and source-specific compute/inverse rules. + +### 3.4 Action methods: a protected, separate path + +```text +MethodBodyRef::OgarAction(ActionDefId) + -> ActionProposal (stable object ID, witness, intent, source version) + -> graph-flow-action::ActionInvocation::commit_via(...) + -> OGAR RBAC + state guard + capacity/MUL + required approval + -> graph-flow-action-ogar::GatedOgarHandler + -> external capability executor + -> idempotent receipt -> independent observed outcome +``` + +`do()` is **not** `BlendI32` and is **not** the physical masking executor writing a field. Reading/evaluating a candidate set and actually mutating a target are different authority levels. The method dispatcher must refuse `call_pure(Action)`; an agent/model cannot construct an authorized action directly. Source generations, actor scopes, guard context and dedupe identity are revalidated at the DO membrane. Missing provider idempotency requires outbox+reconciliation, not a claim of exactly-once calls. + +## 4. End-to-end examples and source-truth caveats + +### SIMAF time-entry DTO (called "CATS" in crate): the existing prototype + +Source: `crates/lance-graph-sap/{schema.rs,binder.rs,bind.rs,query.rs}`. +- `CatsSchema` has **23 fields**, append-only ordinals, technical-name/C# aliases and `ClassView::fields`, plus `realize_projection()` that prevalidates unknown field names before `WideFieldMask::from_universe_present`. +- `CatsBinder` implements `Quack::bind::Binder`; maps native NUMC/ABAP_BOOL/dictionaries and separately derived `work_day` / `billable` lenses. +- Optional CATS fields without validity planes and some U64/strided reads are **explicitly refused**; losing sentinel/NULL or lane kind is not a "helpful" fallback. +- The DTO source is **SIMAF's time-tracking DTO, not proof of actual SAP CATSDB/BAPI_CATS_INSERT runtime parity**. `hours` conversion is **batch-local scale**; a cross-batch sum needs an explicit rescale law. + +Proposed W1 method: +```text +class concept BILLABLE_WORK_ENTRY (0x0103, when resolved by appropriate port) + native CatsSchema → semantic FieldMap with grade and unit witness + method sum_billable_hours : Pure Sum + required = {billable, hours_logged} + query = live & billable==true -> Group/Sum on scaled integer lane + body = Quack query OR R2IL procedure; same scalar oracle +``` + +**Failure is valid:** the current canonical basis lacks some temporal roles; 0x0103 may have no ActionDef capabilities, so a reading-only plug stays useful. Never mint a CATS capability to satisfy the demo. + +### Odoo billing and account.move wide projection + +- Existing `lance-graph-sap/tests/view_convergence.rs` used Odoo `account.move` with **216 fields** in its harvested reference fixture; this is a **wide-mask mechanics test**, not evidence that Odoo's fields match a SAP CATS field. +- `account.analytic.line` is a different Odoo model. Its base extraction may lack `employee_id`/`project_id`/`task_id` until `hr_timesheet` / `project` expansions are harvested. Do not assume them in the registered schema. +- W2 tests: bit 0, 63, 64, 108, 215 on an ordered 216-field universe; alias equality and unknown alias refusal; computed dep>63 refusal; method sum over converted `duration` with SAP hours vs WoA minutes exactly checked, no implicit label-based correspondence. +- `D-XGP-0..8` records cross-glove basis under `0x0103`, current statuses and unmapped temporal roles. Source-to-canonical claims marked "Hypothesized" remain **non-bindable** until a demonstrated `Converted` map exists. Registry activation must **not** auto-upgrade them. +- For WoA, the hours live on `TimeSheet`, not the `TimesheetActivity` description child; see D-XGP-8. No silent team/member or parent-row conflation. + +### IAM / HubSPO pure guard, then guarded DO + +```text +IAM user class: active AND NOT licensed AND independent_grounding +HubSPO record: allowed_owner_set AND due AND stage_eligible +Rubicon: goal_accepted AND context_triggered AND NOT blocked + +==> each is a typed field-to-row mask compilation (NOT shared physical lanes). +==> simulate and propose ActionInvocation; only OGAR hard gate may perform DO. +``` + +For HubSPO, H-ADR-7 keeps workflow state and timers in Lance rows and forbids `ractor` actor-per-record as a dependency. A logical actor is a stable address plus versioned continuation, not a new runtime process. A Common Boolean form does not grant identical business semantics. + +## 5. Hotplug lifecycle and call contract + +| Moment | Owner | Action | Refusal | +|---|---|---|---| +| DISCOVER | consumer | requests only used canon concepts / covered capabilities | unknown/foreign claimed seat | +| ACTIVATE | OGAR `OgarAuthority` | resolve concept, action surface, reading law for this plug | `ActivationDrift`, never implicit V1 | +| RESOLVE SLAB | contract `Activation` | class concept × current/old slab declaration × supported layout | wrong version/law/carrier | +| BIND FIELDS | OGIT/OGAR adapter | canonical URI, source mapping grade, aliases, units, NULL, ordered schema | ambiguous/unknown, field>256, missing validity | +| LINK METHODS | OGAR + loco | link method identity/signature to body/`FnAddr` or ActionDef | duplicate/unresolved/unsupported body | +| CERTIFY | physical plan binder | verify input/output sorts, mask universes, method effect and algebraic laws | invalid rewrite, unsupported lane | +| PUBLISH | consumer | atomic immutable `PreparedClass` for schema/body version | incomplete activation never published | +| READ | Quack/R2IL + Lance | generation-bound authorized borrowed Planes | stale source, revoked access, wrong slab | +| DO | OGAR capability executor | commit-time current actor/guard/approval, deduped external effect | deny/hold/block, no direct write | +| UPDATE | OGAR producer + slab writer | new semantic activation for new writes; old slabs read by declaration | no downgrade/reinterpretation | + +**Security:** capability *availability* (`HotPlug.covered`), field-level projection, current RBAC grants, source row scope and `ActionInvocation` authorization remain orthogonal. Hot reload cannot make a previously denied field visible by mutating the method table without a new activation and fresh current authorization. Stable plan handles require cross-process identity+generation if a workflow resumes elsewhere. + +## 6. Wave plan (D-CMH-1..12) and STOP tests + +| D-ID | Work package | Owner / existing home | Exit condition | +|---|---|---|---| +| **D-CMH-0** | this RFC + inventory + falsifiers | lance-graph docs, OGAR #357 linked | no code/ISA edits | +| **D-CMH-1** | one composed PreparedClass sidecar for a reading-only plug | existing consumer/`lance-graph-ogar`, **not contract** | no second authority; 0x0103 no-capability path works | +| **D-CMH-2** | checked canonical field/alias→Quack binder with seal | OGIT registry + Quack Binder | unknown mapping/alias refusals and field-order pin | +| **D-CMH-3** | WideFieldMask read/required/allowed projection + null/row scope | ClassView + Quack | cases >64; no authorization inferred from presence | +| **D-CMH-4** | method inventory bind by 16-byte key + local FnAddr | OGAR loco + activation sidecar | missing/oversized/unreachable body refuses | +| **D-CMH-5** | a single SAP/SIMAF pure method via Quack and R2IL | lance-graph-sap + r2il/procs | same independent scalar oracle; no extra bulk executor | +| **D-CMH-6** | Odoo/WoA cross-glove conversion semantics, 216 fields | D-XGP existing glove-parity | field identity not guessed, no unit/scale drift | +| **D-CMH-7** | compute DAG wide-field boundary | ClassView/consumer | never silently drop dependency >=64 | +| **D-CMH-8** | typed method purity/effect split and OGAR action dispatch | OGAR action / graph-flow-action-ogar | denied actions never reach handler | +| **D-CMH-9** | schema/body versioned atomic reactivation and old-slab read | HotPlug reading + Lance versions | no V1 fallback, no retroactive recarve | +| **D-CMH-10** | Rig/read-only bounded method export | graph-flow-lance/Rig | no raw row/SoA Context; source+field auth | +| **D-CMH-11** | optional wide numeric or binding operations **only after insufficiency proof** | smallest physical owner | oracle failed before/green after; separate PR | +| **D-CMH-12** | decision review / acceptance of general hotplug schema-method pattern | cross-repo maintainers | all named adversarial tests green, no unreviewed ID mint | + +**Minimal first slice:** implement only D-CMH-1..5 for a **read-only** SIMAF/CATS method with a mock authority, no new opcodes or global registry, and compare Quack vs R2IL vs plain-loop answers. Do not implement W6/DO/method bytecode until this fails or passes with evidence. + +## 7. Decision ledger: do not silently settle + +1. Should `PreparedClass` live in the existing workspace-excluded `lance-graph-ogar` or a consumer-side feature? **Never** make `lance-graph-contract` depend on OGAR. +2. Who issues the stable 16-byte `MethodKey` and how does it relate to `ClassId(u16)` vs full `u32` app identity and `FnAddr(u16)`? OGAR owner mints; no hash collision by truncation. +3. How are valid R2IL bodies linked to an OGAR `MethodDecl` without interpreting arbitrary source-language bodies? "Unsupported" is permitted and must be visible. +4. Can Quack's name-based `Binder` and R2IL's numeric `LOAD` share *one* bound `FieldMap` without duplicate sources of truth? This is the core first probe. +5. What exact method result sorts (`Scalar, RowMask, GroupFold, Truth, BindingMultiset, ActionProposal`) already have legal physical representation? +6. Who certifies source→canonical mapping `Converted` and unit/scale semantics? Type equality alone cannot. +7. What is the null/validity plane encoding for CATS nullable fields, U64 and strided terms before unrefusing them? +8. Where is the canonical 256-field compute dependency checker; when should an oversized class split according to OGAR-SOC? +9. When does an existing slab bind to an old semantic schema vs new ClassView metadata, and how are migrations explicit? +10. How do we prevent generation/tenant/field ACL cache reuse after resume or read-replica changes? +11. How are Quack/R2IL method plan costs compared when one canonical answer admits different instruction sequences? +12. What is the minimal DO adapter; how are effect receipts, provider idempotency and postaction observation represented? +13. What is the exact role of codegen_manifest::ClassMethods in this binder? It is a *signature-only* C++ source today. +14. For goal-oriented NARS/Rubikon methods, ensure goal selection != OGAR technical commit, preserving lance-graph #1496/#1497/#1498 research gates. + +## 8. Sources and cross-repo boundaries + +- `crates/lance-graph-contract/src/{hotplug.rs,class_view.rs,codegen_manifest.rs}` +- `crates/lance-graph-quack/src/{bind.rs,lib.rs}` and `crates/lance-graph-r2il/src/{lib.rs,procs.rs}` +- `crates/lance-graph-sap/src/{schema.rs,binder.rs,bind.rs}` +- `crates/lance-graph-ogar/src/lib.rs` (`OgarAuthority`) +- `crates/lance-graph-ontology/src/registry.rs` (OGIT canonical bridge names) +- `crates/lance-graph-glove-parity/` and [cross-glove plan](cross-glove-business-parity-v1.md) (D-XGP, graded source mapping) +- [OGAR MethodDecl/ActionDef](https://github.com/AdaWorldAPI/OGAR/blob/main/crates/ogar-vocab/src/lib.rs), [loco Inventory](https://github.com/AdaWorldAPI/OGAR/blob/main/crates/ogar-loco/src/inventory.rs), [Interpreter](https://github.com/AdaWorldAPI/OGAR/blob/main/crates/ogar-loco/src/interpret.rs) +- [OGAR #357](https://github.com/AdaWorldAPI/OGAR/pull/357) typed-logic proposal (**draft**); [lance-graph #1496](https://github.com/AdaWorldAPI/lance-graph/pull/1496) merged NAL planning, [#1497](https://github.com/AdaWorldAPI/lance-graph/pull/1497) PLN attention draft, [#1498](https://github.com/AdaWorldAPI/lance-graph/pull/1498) Hyperon draft. +- [graph-flow-lance](https://github.com/AdaWorldAPI/rs-graph-llm/blob/main/crates/graph-flow-lance/README.md), [graph-flow-action-ogar](https://github.com/AdaWorldAPI/rs-graph-llm/blob/main/graph-flow-action-ogar/src/lib.rs), [HubSPO-rs](https://github.com/AdaWorldAPI/HubSPO-rs). + +**One-line target:** *HotPlug announces an existing concept; OGAR resolves the class and methods; ClassView/WideFieldMask seals the field projection; one binder links Quack/R2IL to the same numeric lanes; OGAR alone admits do().* From 28bca7e2572bbbe5d649386f418de1f2bc2cf88d Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Mon, 12 Oct 2026 12:50:16 +0200 Subject: [PATCH 2/6] docs: add adversarial class-method hotplug parity suite --- .../class-method-hotplug-falsifiers-v1.md | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 .claude/plans/class-method-hotplug-falsifiers-v1.md diff --git a/.claude/plans/class-method-hotplug-falsifiers-v1.md b/.claude/plans/class-method-hotplug-falsifiers-v1.md new file mode 100644 index 000000000..aaf3f13d6 --- /dev/null +++ b/.claude/plans/class-method-hotplug-falsifiers-v1.md @@ -0,0 +1,137 @@ +# D-CMH executable acceptance suite — Class activation, schema mask and method dispatch + +> **RESEARCH / proposed tests only (2026-10-12). Nothing in this plan has been executed by this PR.** Execution owners and original test directories are named; no new test, runtime, permission, codebook or ABI has been merged. Parent: [class-method-schema-hotplug-v1.md](class-method-schema-hotplug-v1.md). + +## 0. Acceptance doctrine + +The test target is **one prebound class-method activation**, not a generic runtime. For every falsifier record: pinned repo SHA and feature flags, source fixture, source-to-canonical mapping grade, classid and app prefix, schema seal, method key and local FnAddr, exact slab/row generation, actor/tenant grants, original scalar oracle, Quack and R2IL outputs, error code when refusing, hot-path allocations, mask bytes, fold count and any external mock count. + +A test is *invalid/vacuous* if the negative control does not actually change a result or force a refusal when the violated invariant matters. Disable-check a real guard and record red→green. A broad "CI green" result with no disabled arms is not semantic parity. + +Do not demand that Quack and R2IL emit **identical mask-risc opcode sequences**: Quack `lower` can skip rejected mask words while `lower_fused` can produce ternlog, and R2IL can emit multiple terminal epochs. Demand an equal **typed answer under an independent oracle** at identical data/source/permission versions. Only test physical-plan byte identity where equivalent canonical lowering was deliberately selected. + +### Baseline fixtures + +- **F-SIMAF-CATS:** existing `lance-graph-sap` 23-field DTO/`CatsBatch`, technical-name and C# name aliases, known decimal scale, `work_day`/`billable` derived lenses, nullable optional field with sentinel. This is **not** CATSDB or a BAPI integration. +- **F-ODOO-WIDE:** harvested Odoo `account.move` with **216** fields in `sap/tests/view_convergence.rs` (mask mechanics only), plus an explicit `account.analytic.line` fixture where fields from `hr_timesheet`/`project` may be absent. +- **F-CROSS-GLOVE:** OGAR `BILLABLE_WORK_ENTRY=0x0103`, Quack/OGIT canonical URIs, conversion grade provenance from D-XGP; SAP hours vs WoA minutes and optional Odoo unit_amount. Current claims "Hypothesized" must refuse binding. +- **F-ACTION-MOCK:** synthetic OGAR method with pure selector + `ActionDef`, blocked/allowed ActorContexts, source generations v,v+1, simulated provider effect ledger keyed by idempotency. +- **F-HOTPLUG:** `OgarAuthority.activate` with reading-only capability set, known and unknown classid, V3 and malformed/legacy slabs; deliberately modified register law. + +## 1. Test matrix + +| ID | Claim + fixture | Oracle / required result | Disable / adversarial failure | +|---|---|---|---| +| **CMH-P01** | Reading-only `HotPlug { classids:[0x0103], covered:[] }` resolves reading even without an ActionDef table | existing `OgarAuthority` + `ResolvedReading` | force capability-join for reading-only seat: false `NoCapabilitiesFor` should be detected | +| **CMH-P02** | A plugged unknown id or claimed palette seat owned by another consumer fails closed | `ActivationDrift::{UnknownClassid,UnexpectedConsumer}` or exact current error | remove claimed-seat/unknown guard: unauthorized activation goes green → FAIL | +| **CMH-P03** | V3 current read versus old existing slab physical reading are separately preserved | byte-exact source slab decode; `SlabDeclaration` value schema wins; key/tail reading still resolved lawfully | override old slab with current new byte reading; produce wrong result/refusal | +| **CMH-P04** | Unknown slab tag, layout version, signed register law, missing rail and no reading refuse | precise `ActivationDrift` arms | inject implicit `ReadMode::DEFAULT`/V1 fallback and detect silent acceptance | +| **CMH-P05** | Canon high u16 concept + low u16 appid are not reversed or conflated; methods bind full ID while OGAR validates concept | explicit encoded full `u32` and expected owner | swap halves, share method plans across appid; field/method isolation fails | +| **CMH-P06** | `WideFieldMask::from_universe_present` is wrapped with strict unknown-name precheck | `CatsSchema::realize_projection` reference + explicit errors | unknown present name silently discarded by raw constructor: detect false green | +| **CMH-P07** | Wide mask bits 0/63/64/108/215 for harvested Odoo `account.move` 216-field basis; zero lower-bit collisions | independent array/bitset per ordinal + full 216-field provenance | drop >=64 bit, wrap to low word, alias different schema ordinal: red | +| **CMH-P08** | Universe cap >256 fails; 256 max accepted; optional >256 class splits only with approved sub-schema | `WideMaskCapError::UniverseExceedsSocCap` or explicit split contract | silent wrap/truncation: red | +| **CMH-P09** | Same native field technical/C# alias resolves same numeric `Col` and canonical URI where grounded | existing `CatsSchema::resolve`, OGIT URI mapped source | re-order fields without changing seal or map duplicate aliases to different IDs: red | +| **CMH-P10** | Native Odoo/SAP/WoA fields with equal lane kind but **Hypothesized** equivalence are not bound to shared canonical meaning | D-XGP mapping grade oracle; `Converted` only with reviewed unit proof | auto-join by label/type/ordinal and report false cross-glove parity | +| **CMH-P11** | SAP batch-local hours decimal scale, WoA integer minutes, and Odoo unit_amount explicitly convert | exact rational/int arithmetic under bound; no premature rounding | mix scale 2 with scale 3 / treat minutes as hours: nonzero oracle delta | +| **CMH-P12** | Quack binder nullable comparison semantics over `BoundField.validity`; SIMAF optional sentinel without plane **refuses** | scalar SQL 3VL `TRUE/FALSE/UNKNOWN`, ensure WHERE only true | drop validity / treat NULL as 0; `NOT EQ` admits false row | +| **CMH-P13** | Quack Binder name→Col and R2IL LOAD use **identical BoundFieldMap** per prepared class | same value oracle across masks: empty/1/63/64/65/256/257/1000 rows | deliberately swap one lane for R2IL, must mismatch | +| **CMH-P14** | Quack `lower`, `lower_fused` and R2IL preserve answers but may differ in program length and fold epochs | exact mask/scalar oracle; report costs separately | require opcode-byte equality or reuse scratch mask after terminal; test catches malformed comparison | +| **CMH-P15** | Inventory keyed MethodKey resolves to body, local FnAddr lookup bounded and stable only for that inventory | `ogar_loco::VecInventory::{push_keyed,addr_of}`, Interpreter::with_inventory | reorder registration and persist FnAddr; wrong method must be detected | +| **CMH-P16** | Missing/duplicate/incompatible method, unencodable body ref, unsupported source method **refuse** | typed registry lookup and body-reference validity oracle | default to first method, entry address 0, or arbitrary source body: fail | +| **CMH-P17** | `ComputeEdge` target/input position >=64 is refused until a wide checker exists; 64-field DAG detects cycles | independent topo sort over declared full field universe | current 64-position checker used blindly on 216-field Odoo: adversarial >63 cycle escapes → FAIL | +| **CMH-P18** | `required ⊆ available ∩ allowed` before reading; RowMask type + generation + tenant scope separate | independent field-permission and row-policy oracle | request forbidden field; alias/NULL/method plan bypasses RBAC: fail, no data to Rig | +| **CMH-P19** | `Pure/ReadVersion/Propose/ExternalMutate` method effect boundary; OGAR ActionInvocation gate required | mock handler count 0 when denied; 1 when authorized with stable idempotency | direct write from Quack/R2IL/LLM model call reaches handler: fail | +| **CMH-P20** | Prepared schema+body version cache invalidates on changed semantic field mapping, method body or auth context; old slab read stable | two immutable activation generations + snapshot pinned external oracle | stale cache hits or new ClassView decodes old slab incorrectly: fail | +| **CMH-P21** | Crash after provider effect before local receipt, replay same logical action produces 1 observable external effect | mock provider idempotency/outbox ledger, observed target state | invocation identity tied to arrival time or repeated action sends twice: fail | +| **CMH-P22** | Class-method activation does not allocate row-sized buffers or a second runtime; hot pure method low-overhead | measure scratch/reads/calls and scalar reference; no row materialization | bridge allocates Vec or name-strings per row; fail cost/architecture gate | +| **CMH-P23** | Quack `Registrar` never becomes a second method/class authority; no new global classid mint | compare authority activation / production table binding | create_table(name,width) silently registers a new semantic class: fail | +| **CMH-P24** | Reading-only activated class may later acquire ActionDef without changing field/read semantics; DO still denied absent actor grant | two activation snapshots, same read method, different capability presence | new capability makes previously unauthorized actor able to execute: fail | + +## 2. Oracle rules and required negative data + +### 2.1 F-SIMAF-CATS scalar reference + +Generate rows for `` +0, 1, 63, 64, 65, 256, 257, 1_024 +``, fields by current `CatsBatch::lanes()`: +- billable true/nonbillable/unknown, one nonmapped value; +- hours scaled under at least two **different** batch-local decimal scales; +- derived `work_day` across UTC boundary; +- optional approval null sentinel and real 0 value to make NULL/false visibly different; +- empty/all/mixed live mask, including tail bits. + +Answer oracle `SumHours(billable=true, authorized_only, exact_scale)` by scalar iteration over source values with **exact conversion before aggregation**. Quack query and bound R2IL procedure must match **numeric answers**, not necessarily bytecode. Confirm they borrowed existing columns and did not mint an undocumented technical concept. + +### 2.2 F-ODOO-WIDE ordered projection + +For 216-field fixture, compute reference `BitVec(216)`. Include positions `{0, 63, 64, 108, 215}` plus an unknown name. The mask must preserve all five selected fields. Confirm positional identities are qualified by **schema seal** and `classid`. A re-ordered schema with same unqualified ordinal must be rejected. Never misidentify the fixture as `account.analytic.line`. + +### 2.3 F-CROSS-GLOVE semantics + +A same-name/same-lane synthetic SAP and Odoo field with different units or business meaning is *the negative control*. Do not compare only data shape or convert "already invoiced" (WoA `abgerechnet`) into "eligible for invoice" (`billable`). The first success must pin: +- exact source record class and mapping grade `Converted` for each field; +- unit/scale and normalization formula; +- null/unknown behavior; +- company/tenant scope; +- owner/actor permission; +- proof that source and target semantics refer to the same business quantity. + +Until then report `UnsupportedSemanticMapping`; **refusal is a valid outcome**. + +### 2.4 F-INVENTORY identity versus address + +Create two `VecInventory` instances with the same 16-byte method keys and bodies but different insertion order. Verify `key_of(addr)` and `addr_of(key)` resolve local addresses correctly. A cached `FnAddr(1)` from inventory A must not be blindly used in B. Check entry address `0` and body refs byte width separately; if a method key cannot be represented by current body-reference immediate, activation must either introduce a verified local trampoline with its own proof or refuse. Do **not** widen branch immediates to make the test easy. + +### 2.5 F-DO gate, hypothetical plan to real-world mutation + +```text +read candidate set -> evaluate pure method -> build inert ActionProposal +-> resolve authoritative ActionDef -> create ActionInvocation +-> verify current actor, class, target, state, source version, RBAC, approval +-> commit_via / GatedOgarHandler -> mock provider -> receipt -> read-back +``` + +Test injects: +- forged MethodKey / ActionDef id mismatch; +- unauthorized role, wrong tenant, missing field, stale source; +- same invocation redelivered, provider effect then crash before receipt; +- model-generated instructions inserted into proposal payload; +- a pure method trying to return `AuthorizedAction`. + +Any external call before hard gate is a P0 failure. Post-action read-back can fail even when provider returned success: not automatically a second identical write or positive evidence. + +## 3. Production integration and risk gates + +**Performance record**: for each matching setup report hot/cold setup time, compiled instruction count, terminal epochs, scanned/dereferenced row counts, bytes read, decoded bytes, allocated bytes/call, scratch peak, actor-permission checks, materialization bytes and API calls. Compare: +A. existing hand-written CATS Binder path; +B. prepared class lookup + Quack bound query; +C. prepared class lookup + existing R2IL procedure; +D. independent scalar reference (parity oracle, **not** necessarily faster). + +Must not infer "zero-cost" from object sizes. `WideFieldMask` grows a heap representation after position 63. Cold activation may allocate; per-call string search or Vec creation in the hot path is an explicit failure. A generic method dispatch with larger cost and no improvement to reuse/maintainability can be rejected. + +**Security criteria:** temporary project/workflow plans and generated method declarations cannot silently override OGAR entity ownership or current RBAC/field grants. Capability *names* are not authorization tokens. In-flight activation hot-swap must not change semantics of the already running plan; stale handles, schema seals and source generations must be rechecked or explicitly rejected. + +**Contract drift criteria:** no changes to `lance-graph-contract` zero-dep nature; no global count fuse; no altered FieldMask bits 0..63; no V1 fallback; no classid/appid reversal; no persisted CE64 reinterpretation; no ractor workflow dependency in HubSPO. + +## 4. Waves and required reports + +| Phase | Minimal artifact | Test gates | +|---|---|---| +| **CMH-W0** this research PR | RFC, evidence inventory, falsifiers, board index | static doc sanity only | +| **CMH-W1** existing consumer / mock authority | PreparedClass sidecar + strict field map | P01–P13, P23 | +| **CMH-W2** existing R2IL procedures | one method resolved as Quack and R2IL | P13–P16, P22 | +| **CMH-W3** wide Odoo + cross-glove | converted field identity with unit proof | P07, P08, P10, P11, P17 | +| **CMH-W4** DO and schema hot-swap mock | stable MethodKey, effect boundary, versioned activation | P18–P21, P24 | +| **CMH-W5** optional Rig / graph-flow consumer | bounded authorized read materialization; resumable call | same security and generation tests, no row/context copy | + +### Review checklist + +- [x] Existing code and missing joins listed separately in [evidence inventory](../knowledge/class-method-hotplug-existing-contracts.md). +- [x] No operational APIs or changes advertised as shipped by these documents. +- [x] Every P01–P24 has an independent expected result or current exact contract, plus a failure/disable arm. +- [x] SAP CATSDB/`BAPI_CATS_INSERT` parity explicitly NOT claimed; CATS is SIMAF DTO. +- [x] Source field semantics and authority scoped to OGAR/OGIT; consumer declares only plugged IDs. +- [ ] Executable probes, compile checks, CI, local benchmarks and customer integration **not executed in this PR**. +- [ ] Operator's review of method identity/version, wide-compute dependency and DO outbox contract **not yet obtained**. +- [ ] No merge/deployment approval until wave-specific test PRs demonstrate the invariants. From f22087853a29922526440d7201f6af94fac71a88 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Mon, 12 Oct 2026 12:52:02 +0200 Subject: [PATCH 3/6] docs: inventory existing hotplug, Quack, loco and schema seams --- ...class-method-hotplug-existing-contracts.md | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 .claude/knowledge/class-method-hotplug-existing-contracts.md diff --git a/.claude/knowledge/class-method-hotplug-existing-contracts.md b/.claude/knowledge/class-method-hotplug-existing-contracts.md new file mode 100644 index 000000000..b692f24b5 --- /dev/null +++ b/.claude/knowledge/class-method-hotplug-existing-contracts.md @@ -0,0 +1,80 @@ +# Class × Method × Schema HotPlug: code-grounded seam inventory (2026-10-12) + +> **Grading:** [G] exact type/behavior read in source; [P] proposal or documentary plan; [ABSENT] seam/code path not shown by inspected sources. *Code-existence is not integration/performance parity*. Read with [the activation proposal](../plans/class-method-schema-hotplug-v1.md) and [the falsifiers](../plans/class-method-hotplug-falsifiers-v1.md). Companion OGAR [#357](https://github.com/AdaWorldAPI/OGAR/pull/357) is **draft**. + +## 1. Critical existing bricks + +| Brick | What exists now | What the bridge still needs | +|---|---|---| +| **[G] HotPlug socket** | [`hotplug.rs`](../../crates/lance-graph-contract/src/hotplug.rs): `HotPlug {consumer, classids: &[u16], covered}`; `CapabilityAuthority::activate(&HotPlug) -> Activation`; `Activation::read_mode_for` and `register_law_for` fail closed. `resolve_for_context` composes current OGAR reading with an *optional physical* `SlabDeclaration`. `ResolvedReading::bind_register128/bind_signed_register` validate rails/laws. | A sidecar that binds a declared **field schema and executable methods** onto this activation. Do **not** add methods to `HotPlug` or OGAR dependencies to zero-dep contract to claim completion. | +| **[G] Real authority** | [`lance-graph-ogar/src/lib.rs`](../../crates/lance-graph-ogar/src/lib.rs): `OgarAuthority` implements `CapabilityAuthority` via OGAR capability registry and handles V3 reading-only domains/palette seats separately. Empty covered list is valid for reading-only. | Compose authority's existing per-consumer activation with OGAR source `Class/MethodDecl/ActionDef` + OGIT field identities after activation; no new global list. | +| **[G] ClassView fields** | [`class_view.rs`](../../crates/lance-graph-contract/src/class_view.rs): `ClassView::fields(ClassId=u16) -> &[FieldRef]` uses stable per-class ordered field basis. `FieldMask(u64)` remains unchanged, `WideFieldMask` small/wide dual representation supports 0..255 positions; `from_universe_present` max 256 and computes membership in the declared universe. | Need a shared strict alias/basis+schema-version **binder**; `WideFieldMask` is field selection, NOT row selection or RBAC. A present name missing from universe is **ignored** by raw constructor, so prevalidate requested names. | +| **[G] C++ MethodSig** | [`codegen_manifest.rs`](../../crates/lance-graph-contract/src/codegen_manifest.rs): `MethodSig { name, params, ret, is_const, is_static, overrides }` and `ClassMethods{classid:u32,methods}`, `methods_for`. Generated constant manifest, **signature only**; returned empty for missing class. | Different harvested source + no executable body; cannot claim this is OGAR MethodDecl or loco Inventory. Reuse pattern if proven, not table contents/semantics. | +| **[G] OGAR MethodDecl** | [`ogar-vocab`](https://github.com/AdaWorldAPI/OGAR/blob/main/crates/ogar-vocab/src/lib.rs): `MethodDecl{name,kind,body_source,decorators,semantics}` plus `ActionDef/ActionInvocation/KausalSpec` with declared reads/writes/calls/guards. | AST body is opaque, no automatic executable R2IL translation; link typed body ref without duplicating authority. | +| **[G] ogar-loco Inventory** | [`inventory.rs`](https://github.com/AdaWorldAPI/OGAR/blob/main/crates/ogar-loco/src/inventory.rs): `FnAddr(u16)`, `Inventory::{body,key_of,len}`, `VecInventory::{push_keyed,addr_of}`. [`interpret.rs`](https://github.com/AdaWorldAPI/OGAR/blob/main/crates/ogar-loco/src/interpret.rs) has `Interpreter::with_inventory` actually consuming it. **This is SHIPPED, not just a concept.** | Semantic link `OGAR MethodDecl ↔ stable function key ↔ source/target signature ↔ local FnAddr ↔ verified R2IL body` is missing. Call-target byte encoding is narrower than FnAddr's u16 capacity. | +| **[G] Quack Binder** | [`quack/src/bind.rs`](../../crates/lance-graph-quack/src/bind.rs): `Binder::{table,live,field,code}`, `BoundField {col,kind,validity}`, `Draft::bind -> Query`. Text disappears at boundary; SQL nullable comparisons use resident validity mask. `FieldKind` at this binder currently `I32/Code`. | Bind automatically from activated OGAR ClassView/OGIT field identity into Quack numeric keys; do not reinterpret unsupported U64/strided lanes or sentinel NULL as known values. | +| **[G] Quack physical lowering** | [`quack/src/lib.rs`](../../crates/lance-graph-quack/src/lib.rs): `Filter/Agg/Query`, `lower` and `lower_fused` to `mask_risc::Program`; `GroupBy` uses grouped lowering and equivalent folds when available. No row evaluator in Quack. | Method-shaped invocation with bound fields, checked laws and versioned source. Quack and R2IL need answer parity, **not** necessarily identical instruction bytes. | +| **[G] Quack Registrar narrowness** | `quack/src/bind.rs` `TableDeclaration -> Registrar::register(name,width)` supports only table name and row width; module says no production implementation. | It is **not** an OGAR class/method registry, and a new metadata catalog on top would create a second authority. | +| **[G] R2IL bulk dialect** | [`lance-graph-r2il/src/lib.rs`](../../crates/lance-graph-r2il/src/lib.rs): `FoldDialect` interprets R2IL over borrowed planes and invokes mask-risc for each terminal. `Val` holds scalar/slot/address, not row data. One mask-risc Program has one terminal. | Field binding to same `BoundFieldMap` Quack uses; preserve epoch/scratch validity across multiple folds. | +| **[G] R2IL procedures** | [`r2il/src/procs.rs`](../../crates/lance-graph-r2il/src/procs.rs): `select_lt/filter_lt/sum/group_sum/margin`; named Rust emitters call `FoldDialect::call` without new opcodes or hot row loops. | Registered method key -> known/verified emitter, not arbitrary `MethodDecl::body_source`. `PROC_DEF/PROC_CALL` general VM-linker semantics remain open per module doc. | +| **[G] SIMAF CATS DTO** | [`sap/schema.rs`](../../crates/lance-graph-sap/src/schema.rs): 23 fields; `CatsSchema::resolve` technical/C# aliases; `realize_projection` strict unknown precheck before WideFieldMask; [`sap/binder.rs`](../../crates/lance-graph-sap/src/binder.rs): `CatsBinder` Quack binder with `LIVE`, `work_day` and `billable` derived lenses; optional null fields and some U64 refused. | One Registered Class/Method entry instead of independent schema/binder/procedure construction. **SIMAF's DTO is not SAP CATSDB/BAPI parity**; scale is batch-local and must be converted before cross-batch or cross-glove aggregation. | +| **[G] OGIT field identity** | [`ontology/registry.rs`](../../crates/lance-graph-ontology/src/registry.rs): idempotent TTL hydration, `(bridge_id,public_name) → SchemaPtr` and public/OGIT URI lookups, optional Lance cache. | Checked native alias → canonical identity and mapping grade, with semantic unit and source provenance. Don't mint a field identity from a matching string alone. | +| **[G] Source name ↔ row mapping** | [cross-glove plan](../plans/cross-glove-business-parity-v1.md), `lance-graph-glove-parity` tests/board `D-XGP`: candidates for 0x0103, source-to-canonical mapping grades, SAP/Odoo/WoA differences. | Bind only **Converted** mappings with proof; several previously hypothesized relations remain unsupported. | +| **[G] Physical mask** | [`mask-risc/src/ir.rs`](../../crates/lance-graph-mask-risc/src/ir.rs): AND/OR/XOR/TERNLOG/NOT/ANDNOT; predicates, gated Gather/via, group folds, Keep/Count/Any/All; borrowed planes and caller-owned scratch. | Compiler chooses which of these to use; there is no license to invent an opcode per class/method. | +| **[P] Typed logic sibling** | [OGAR #357](https://github.com/AdaWorldAPI/OGAR/pull/357) RFC for algebraic logic, class/method/schema and DO effects. | This PR's *concrete activation binder*; independent implementation PR gates. | + +## 2. Important corrections to protect against false progress + +### 2.1 Inventory exists now, update the older narrative + +Previous drafts described `LocoConcept::Inventory` as minted but not implemented. That was true at the earlier gap doc version, **not** at this read. `ogar-loco::Inventory`, `VecInventory::push_keyed`, `addr_of` and `Interpreter::with_inventory` exist today. The still missing piece is method-to-body **semantic linking** with checked class/schema/authority, plus matching field bindings and plan execution. This needs a correction on review of OGAR #357; do **not** create a second inventory. + +### 2.2 Codegen manifest is a different method plane + +`MethodSig` in lance-graph-contract is C++ harvested signature metadata, intentionally `&'static` and `const`-constructible. `OGAR::MethodDecl` is language-independent harvested source method metadata and contains opaque source, while `ogar-loco::Inventory` is an executable body-address service. The final composed adapter may reference all three, but none is equivalent to the others. + +### 2.3 Same mask basis ≠ same SAP/Odoo business semantics + +[D-XGP-0](../board/entries/2026-10-10-d-xgp-0-cross-glove-inventory.md) explicitly found that the wide-mask example is Odoo `account.move`, **216 fields**, not `account.analytic.line`. SIMAF DTO is not CATSDB. A matching U32/I32 lane is not equivalent to matching a canonical business field, currency/scale, datetime timezone, analytic-line plugin provenance, account authorization or workflow action. D-XGP-8 finds WoA hours on `TimeSheet` rather than a child `TimesheetActivity`; the label "Stundenzettel" is a DTO label of an OGIT concept, not an independently minted conceptual class. + +### 2.4 Schema field masks and population masks live in different universes + +`WideFieldMask` indexes **field positions of a class**. Quack's `Mask` indexes an array of row-population mask planes. The two may share bitwise algebra without sharing sort or address identity. Proposal to bind the same scalar operator shape for NARS/IAM/CRM **must** keep their class/tenant/version/evidence semantics separate. + +### 2.5 Method dispatch must not become authority + +The available `HotPlug.covered` is capability *availability*. `ClassView`, `WideFieldMask` and OGAR declared ActionDef writes are neither permission nor approval. External DO continues through `graph-flow-action-ogar::GatedOgarHandler` / `ActionInvocation::commit_via`. A pure query must never be allowed to invoke its own action handler based on method naming or a positive reasoning confidence. + +### 2.6 The 64/256 difference is real + +`WideFieldMask` currently accepts up to 256 positions (per field universe), and its small representation is allocation-free. However `ClassView::ComputeEdge` and the existing `compute_dag_is_acyclic` implement a 64-position checker; a wide class can exceed that. A generic binding that claims automatic Odoo computed-method support must first handle or refuse positions >=64. Any plan that silently ignores them is unsound. + +### 2.7 One Program, one terminal; one bulk runtime + +Quack can fold a filtered query into one `Program`; R2IL procedures with multiple scalar folds execute multiple programs and combine scalars. This is already documented in `procs::margin`. Comparing instruction sequences as a global equality requirement is wrong; compare observable typed results and quantify measured cost. Neither path should store a row-sized intermediate in graph-flow Context. + +### 2.8 ClassId widths and canonical/app fields are different scopes + +`ClassView::ClassId = u16` addresses the canonical concept field universe; OGAR `ActionDef.object_class` and `codegen_manifest::ClassMethods.classid` have other source spellings/full class identity. The full V3 classid concept/appid split is class-specific. Do not route methods from SAP into an unrelated Odoo app simply because their canonical high half is `0x0103`. Bind both conceptual class basis and application/actor/source scope. + +## 3. Scope decision and first executable experiment + +**The minimal missing joint:** + +```text +HotPlug / OgarAuthority / ResolvedReading + + +ClassView.fields() / WideFieldMask / OGIT canonical URI + + +Quack Binder (TableId/Col/validity/code) + + +OGAR MethodDecl -> existing loco Inventory key -> FnAddr + = +PreparedClass (semantic+versioned *sidecar*, no global registry) + ├ pure read method -> Quack or known R2IL procs -> mask-risc + └ action method -> OGAR hard gate -> external effect +``` + +First experiment should be **read-only SIMAF/CATS**, a selected pure method with a matching scalar oracle, no new contract dependency/opcode, using existing data/bitmasks. Reuse `CatsBinder` and `CatsSchema` as control. Reject unknown fields and unsupported optional NULL. Then bind a known R2IL `sum` procedure to exactly the same field mapping and measure answer parity. Successful results in this subset do not imply production SAP capability. + +**Source status and falsification checklist** live in [the companion](../plans/class-method-hotplug-falsifiers-v1.md). Link to [OGAR #357](https://github.com/AdaWorldAPI/OGAR/pull/357), [#1496](https://github.com/AdaWorldAPI/lance-graph/pull/1496) (NAL plans merged), [#1497](https://github.com/AdaWorldAPI/lance-graph/pull/1497) (PLN draft) and [#1498](https://github.com/AdaWorldAPI/lance-graph/pull/1498) (Hyperon draft) for higher-order rule work; do not claim those experimental logic subsets are implemented as part of a generic HotPlug. From bbc6028e26aa967a95732fdfb8cd3d173433ed0e Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Mon, 12 Oct 2026 12:52:44 +0200 Subject: [PATCH 4/6] docs: record D-CMH-0 class-method hotplug finding --- ...d-cmh-0-class-method-hotplug-activation.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .claude/board/entries/2026-10-12-d-cmh-0-class-method-hotplug-activation.md diff --git a/.claude/board/entries/2026-10-12-d-cmh-0-class-method-hotplug-activation.md b/.claude/board/entries/2026-10-12-d-cmh-0-class-method-hotplug-activation.md new file mode 100644 index 000000000..af1d38888 --- /dev/null +++ b/.claude/board/entries/2026-10-12-d-cmh-0-class-method-hotplug-activation.md @@ -0,0 +1,20 @@ +## 2026-10-12 — D-CMH-0 — Class × Schema × Methods activation connects HotPlug, WideFieldMask, Quack and R2IL without a second registry + +**Status:** [H] RESEARCH PROPOSAL, documentation only. No runtime modification, parity fixture or benchmark executed by this PR. + +**Finding:** The hot-plug class mechanism is already split correctly: consumer declares `HotPlug`; OGAR resolves authority/capabilities and storage reading into `Activation`; `SlabDeclaration` pins already-written physical bytes; OGIT resolves canonical names; `ClassView::fields` and `WideFieldMask` provide a field basis. Quack already binds names to numeric `Col/Mask/validity` and lowers into mask-risc; `lance-graph-r2il::procs` has real named fold sequences. The missing entity is **a cold, verified, versioned method-to-field binder** shared by both frontends, not another execution engine or class registry. + +**Correction to old gaps:** OGAR `ogar-loco::Inventory`, `VecInventory::push_keyed` and `Interpreter::with_inventory` are **already implemented**. The gap is linking `MethodDecl` + semantic method signature to the existing Inventory key and a verified method body under one ClassView/Schema. `codegen_manifest::MethodSig` is a separate C++ signature surface, not a loco method body. + +**Critical fences:** +- No new zero-dep contract dependency, global count fuse, classid mint, opcode, CE64 reinterpretation, per-consumer plug crate or hidden V1 fallback. +- `WideFieldMask` indexes **fields**, Quack row masks index **rows**; presence is not authorization. Require `required ⊆ available ∩ allowed` and current RBAC/source version. +- The 23-field SIMAF "CATS" is not proof of SAP CATSDB/BAPI parity; Odoo `account.move` wide fixture is 216 fields, not an SAP-equivalent model; D-XGP conversion grades and unit mappings must be proved. Wide ComputeEdge has a 64-field gate. +- Quack and R2IL may emit different legal programs over the **same backend**; match typed results under an independent oracle, not arbitrary bytecode identity. +- `do()` remains OGAR `ActionInvocation` + hard gate; reading-only plugs without capabilities still activate. + +**First kill test CMH-P13:** bind one SIMAF/CATS pure billable-hours method against one canonical ordered field basis, run Quack and R2IL on the same borrowed dataset generation, compare exact scalar reference (including two batch-local scales and nullable cases). Deliberately swap a numeric lane in one frontend: the test MUST fail. Next prove field positions >63 in the 216-field Odoo fixture and absence of silent authority escalation. + +**Home:** [D-CMH-0..12 activation RFC](../../plans/class-method-schema-hotplug-v1.md), [24 falsifiers CMH-P01..P24](../../plans/class-method-hotplug-falsifiers-v1.md), [source inventory](../../knowledge/class-method-hotplug-existing-contracts.md). + +**Cross-repo:** [OGAR #357](https://github.com/AdaWorldAPI/OGAR/pull/357) is the semantic companion; lance-graph #1496/#1497/#1498 are NAL/PLN/Hyperon research, not a license to reinterpret bytes or mint a new evaluator. Existing D-XGP-0..8 and D-HPR rulings constrain the first method binder. From fab89e68e34d63b3f41a00be065b9c6e658fd011 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Mon, 12 Oct 2026 12:53:17 +0200 Subject: [PATCH 5/6] docs: regenerate board entry index for D-CMH-0 --- .claude/board/entries/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index 050df01a3..ebc1ad3f4 100644 --- a/.claude/board/entries/README.md +++ b/.claude/board/entries/README.md @@ -25,10 +25,11 @@ index row, (3) no duplicate entry id. Checks 1 and 2 are deliberately opposite directions; the stranding this convention prevents shows up in exactly one of them, never both. -310 entries, 2026-08-06 .. 2026-10-12. +311 entries, 2026-08-06 .. 2026-10-12. | date | entry id | finding | file | |---|---|---|---| +| 2026-10-12 | `D-CMH-0` | Class × Schema × Methods activation connects HotPlug, WideFieldMask, Quack and R2IL without a second registry | [2026-10-12-d-cmh-0-class-method-hotplug-activation.md](2026-10-12-d-cmh-0-class-method-hotplug-activation.md) | | 2026-10-12 | `D-HL-0` | CE64 hypothesis layers: plateau of the design (opaque LE bytes, 64 sparse-delta layers merged on read, Narsese-parallel validation), 8 design-vs-code conflicts, 9 unification hypotheses | [2026-10-12-ce64-hypothesis-layers-plateau.md](2026-10-12-ce64-hypothesis-layers-plateau.md) | | 2026-10-11 | `D-TELEPORT-0` | | [2026-10-11-teleport-probe-source-restriction.md](2026-10-11-teleport-probe-source-restriction.md) | | 2026-10-11 | `synergy-ledger-classid-hotplug` | | [2026-10-11-synergy-ledger-classid-hotplug.md](2026-10-11-synergy-ledger-classid-hotplug.md) | From a7a977b703b223d4960c07a76046b091e7e786b9 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Mon, 12 Oct 2026 12:54:11 +0200 Subject: [PATCH 6/6] docs: clarify population sizes in falsification fixture --- .claude/plans/class-method-hotplug-falsifiers-v1.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.claude/plans/class-method-hotplug-falsifiers-v1.md b/.claude/plans/class-method-hotplug-falsifiers-v1.md index aaf3f13d6..a23310901 100644 --- a/.claude/plans/class-method-hotplug-falsifiers-v1.md +++ b/.claude/plans/class-method-hotplug-falsifiers-v1.md @@ -51,9 +51,7 @@ Do not demand that Quack and R2IL emit **identical mask-risc opcode sequences**: ### 2.1 F-SIMAF-CATS scalar reference -Generate rows for `` -0, 1, 63, 64, 65, 256, 257, 1_024 -``, fields by current `CatsBatch::lanes()`: +Generate rows for `n ∈ {0, 1, 63, 64, 65, 256, 257, 1_024}`, fields by current `CatsBatch::lanes()`: - billable true/nonbillable/unknown, one nonmapped value; - hours scaled under at least two **different** batch-local decimal scales; - derived `work_day` across UTC boundary;