diff --git a/.claude/board/ISSUES.md b/.claude/board/ISSUES.md index 9e7929b8a..e47db1ee9 100644 --- a/.claude/board/ISSUES.md +++ b/.claude/board/ISSUES.md @@ -2,10 +2,10 @@ **Status:** OPEN. **Basis:** VERIFIED-IN-CODE; DECISION by operator 2026-10-10 (the V3 marker is a fossil; only `hotplug.rs` and the slab metadata envelope decide whether a slab is `Facet96` (32 + 96) or `Register128` (128, classid via SPOG/plug)). Record: `entries/2026-10-10-classid-layout-ruling.md`, plan `cross-glove-business-parity-v1.md` §C.9.3. -- `canonical_node::classid_read_mode(classid)` (`canonical_node.rs:1813`) reads `BUILTIN_READ_MODES` (`:1743`), keyed by the full classid, including the `*_V3` keys carrying classview `0x1000`. +- `canonical_node::classid_read_mode(classid)` (`canonical_node.rs:1850`, re-measured 2026-10-11 on `1116c120`; was `:1813`) reads `BUILTIN_READ_MODES` (`:1773`, was `:1743`), keyed by the full classid, including the `*_V3` keys carrying classview `0x1000`. - Callers: `ocr.rs:105/124`, `aiwar.rs:119`, `nan_projection.rs:167`, `soa_graph.rs:204/457`. - `hotplug.rs` states it is the ONE resolution path ("there is no second registry"); this table is a second one. -- **What closes it:** route those callers through `Activation::resolve_for_context`, keep the legacy keys readable for slabs already written with them (an explicit `SlabDeclaration` wins for existing data), then retire the `0x1000` keys on corpus proof that no row needs them. +- ⊘ **What closes it** (regraded 2026-10-11): the earlier text ended "then retire the `0x1000` keys on corpus proof that no row needs them". SUPERSEDED by the operator ruling of 2026-10-10 (*"1000 isn't hurting, just document and Mark it as deprecated. No need to force evict"*), recorded as rule 5 of plan `v3-mandatory-hotplug-reading-v1.md`. The legacy keys stay. The issue closes when (a) no NEW reading is selected through this table — every mint path takes its reading from an `Activation` or a `SlabDeclaration` (D-HPR-3), and (b) an unknown classid no longer falls back to `ReadMode::DEFAULT` (D-HPR-6b, operator decision). The table then survives only as the reader of stored legacy keys (D-HPR-5). ## ISS-EPI5-CODEBOOK-LACKS-P7A-CONJUNCTIONS — P7a certifications with no canonical EpistemicState5 code (2026-10-07) diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index 9c4dbfd94..399ffb1cd 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -6,11 +6,11 @@ Plan: `.claude/plans/v3-mandatory-hotplug-reading-v1.md`. |---|---|---|---| | **D-HPR-0** | Ruling + plan + caller inventory | Shipped (#1464) | — | | **D-HPR-1** | Contract modules (`ocr`, `aiwar`, `nan_projection`, `soa_graph`) take the reading as a parameter | Shipped (#1464; 4 `_with`/`_plugged` forms, disable runs 4/4 red) | new form returns the handed reading even where `classid_read_mode` disagrees | -| **D-HPR-2** | Canon domain readings move into `OgarAuthority::concept_override` | In PR (5 concept arms; red with an arm removed) | `read_mode_for(concept)` == today's `classid_read_mode()` per domain | -| **D-HPR-3** | Consumers move (lance-graph, q2, MedCare); `classid_read_mode` deprecated | Queued | no production caller left | -| **D-HPR-4** | `0x1000` / render prefixes documented as deprecated, kept (no eviction) | Shipped (#1464; doc notes on `CLASSID_*_V3` + `classid_read_mode`) | — | -| **D-HPR-5** | Stored legacy keys keep resolving; a `SlabDeclaration` may override for its own data; no forced removal | Queued | — | -| **D-HPR-6** | No V1 default for an unknown classid; `guid-v3-tail` not a gate | Queued | unknown classid → `NoReadingFor` | +| **D-HPR-2** | Canon domain readings move into `OgarAuthority::concept_override` | Shipped (#1465; 5 concept arms, red with an arm removed; codex P1 fix: canon domains also activate through the public `activate` path) | `read_mode_for(concept)` == today's `classid_read_mode()` per domain | +| **D-HPR-3** | Consumers move (lance-graph, q2, MedCare); `classid_read_mode` deprecated | Queued (2026-10-11 census: MedCare has 0 callers; q2's are offline bake mints; deepnsm-v2 is blocked on a concept mint, not code) | no NEW reading selected through the table (rule 5 keeps stored keys readable) | +| **D-HPR-4** | `0x1000` / render prefixes documented as deprecated, kept (no eviction) | Shipped for `0x1000` (#1464; doc notes on `CLASSID_*_V3` + `classid_read_mode`); render prefixes, `NodeGuid::read_mode` and OGAR/q2 sites still carry no note | — | +| **D-HPR-5** | Stored legacy keys keep resolving; a `SlabDeclaration` may override for its own data; no forced removal | Holds today (status quo). Caveat: a `SlabDeclaration` overrides `value_schema` only, never the tail, so it cannot protect a V1/V2-tail slab (`hotplug.rs:231-257, 392`) | — | +| **D-HPR-6** | No V1 default for an unknown classid; `guid-v3-tail` not a gate | Queued — split: **6a** un-gate `guid-v3-tail` (default-on, and no fleet consumer disables it, so only `--no-default-features` builds change; there the 5 V3 fossils read `DEFAULT` today); **6b** unknown classid → error (behaviour change, operator) | unknown classid → `NoReadingFor` | ## D-XGP — Cross-glove business parity: Odoo × SAP over one Quack algebra (2026-10-10) @@ -20,9 +20,9 @@ Plan: `plans/cross-glove-business-parity-v1.md`. Board entry: `entries/2026-10-1 |---|---|---|---| | **D-XGP-0** | Read-only inventory across lance-graph, OGAR, ruff, odoo-rs, lgj, SIMAF | Shipped (analysis) | every row carries `file:line` at the pins in plan §0 | | **D-XGP-1** | ~~`lance-graph-contract::glove` types + laws 1–5~~ ⊘ superseded (plan §C): CATS `impl Binder` (dir-sim `UserBinder` shape) + registry canonical-name front | Shipped (#1448; fixture URIs, superseded by the authority basis per plan §C.9) | probe Q1: canonical-name path gives the same `Col`s, `Program` and sums as `CatsQuery`; N-a..N-d | -| **D-XGP-2** | ~~`BILLABLE_WORK_ENTRY` basis v1 in `ogar-class-view`~~ ⊘ superseded: canonical attribute URIs for `0x0103` fields ⊘ superseded (§C.9, lockstep deprecated): SAP/Odoo `HotPlug` consts + native-field mapping onto OGAR's promoted `BillableWorkEntry` (13 `ClassView` positions) | In PR (`lance-graph-glove-parity::basis`: plugs refuse `NoCapabilitiesFor(0x0103)`, 9 claims all `Hypothesized`; open: temporal role, an OGAR change) | probe Q2: shared `entity_type_id` per field; one-sided fields resolve `None` on the other side | +| **D-XGP-2** | ~~`BILLABLE_WORK_ENTRY` basis v1 in `ogar-class-view`~~ ⊘ superseded: canonical attribute URIs for `0x0103` fields ⊘ superseded (§C.9, lockstep deprecated): SAP/Odoo `HotPlug` consts + native-field mapping onto OGAR's promoted `BillableWorkEntry` (13 `ClassView` positions) | Shipped (#1455; `lance-graph-glove-parity::basis`: plugs refuse `NoCapabilitiesFor(0x0103)`, 9 claims all `Hypothesized`; open: temporal role, an OGAR change) | probe Q2: shared `entity_type_id` per field; one-sided fields resolve `None` on the other side | | **D-XGP-3** | `lance-graph-glove-parity` probe: P1–P4, N1–N7 ⊘ first rung (§C.9.2): SAP `billing_indicator` → `billable` Converted via derived lens `lance-graph-sap::bind::BILLABLE` | Shipped (#1459; first `Converted` claim). ⊘ "9/12 edge targets unminted" was a misreading: they lack only a SHARED codebook id; a classid is `domain(8)|appid(8)|concept(16)`: domain immutable, appid ≡ concept byte (`0xDDCC` = domain:appid), 64k handed out per domain:appid (§C.9.3); reversing `render_classid` audited and ruled out (§C.9.4). Next: anchor `performed_by`/`tenant`/`duration`/work date on WoA's own concepts | equal `Program`s for literal-free queries; N1/N2/N5/N6 red without the conversion | -| **D-XGP-8** | WoA anchors: `TimeSheet` claims `performed_by` / `duration` / `tenant` (§C.9.5) | In PR (all `Hypothesized`; finding: OGAR `WoaPort` pins `0x0103` on `TimesheetActivity`, the description row; `ogit.WorkOrder:TimeSheet`/`User`/`Tenant` are minted in OGIT but have no OGAR id or `WoaPort` alias; "Stundenzettel" is a DTO label of TimeSheet) | each glove claims each anchor once; two-sided WoaPort pin | +| **D-XGP-8** | WoA anchors: `TimeSheet` claims `performed_by` / `duration` / `tenant` (§C.9.5) | Shipped (#1460, OGIT correction #1462; all `Hypothesized`; finding: OGAR `WoaPort` pins `0x0103` on `TimesheetActivity`, the description row; `ogit.WorkOrder:TimeSheet`/`User`/`Tenant` are minted in OGIT but have no OGAR id or `WoaPort` alias; "Stundenzettel" is a DTO label of TimeSheet) | each glove claims each anchor once; two-sided WoaPort pin | | **D-XGP-4** | Odoo analytic-line pivot + behavior classification (Odoo session) | Queued | pivot validates; mapping `unit_amount` as Exact is rejected | | **D-XGP-5** | Report `Catalog` from `CanonicalBasis` | Queued | one report plan, identical cells over both lane views | | **D-XGP-6** | lgj ↔ quack convergence cases for canonical-bound queries | Queued | `lowering_convergence.rs` byte-equality per case | diff --git a/.claude/board/entries/2026-10-11-coresearch-labels-address-lifetime.md b/.claude/board/entries/2026-10-11-coresearch-labels-address-lifetime.md new file mode 100644 index 000000000..eb7809fcd --- /dev/null +++ b/.claude/board/entries/2026-10-11-coresearch-labels-address-lifetime.md @@ -0,0 +1,159 @@ +# Coresearch — concept addresses, labels per language, source-id mapping and id lifetime (2026-10-11) + +**Status:** OPEN — exploration map. It ratifies nothing; the operator chooses. +Plan context: `v3-mandatory-hotplug-reading-v1.md` rules 3–5, O1, O2. + +## The question, after the premise audit + +The draft asked where "Stundenzettel / TimeSheet / Zeiterfassung" live as +labels of one concept. The audit found four category errors and re-asked it: + +- `0x0103` is the cross-app concept `billable_work_entry`. + `ogit.WorkOrder:TimeSheet` is WoA's own class. They are two entities related + by a **mapping** (O2), not two spellings of one id. +- OGAR's port alias column is not a label table. Its rows mix words in a + language, source-class ids, another app's class and collapsed subtypes. +- The `0x1000` marker and the render prefixes sit on the **reading** axis. + They left this question. +- The immutable address today is the **u16** concept. The u32 classid's low + half is app-owned. + +Three questions remain. **Q1 lexical:** where do per-language labels of a u16 +live? **Q2 mapping:** how does a source id (class name, OGIT CURIE) relate to a +u16, with which relation kinds, and who owns the mapping? **(c) lifetime:** how +is an id deprecated but still resolvable, and what separates an address from a +positional ordinal? + +## The shape the rows converge on + +1. **One lifecycle ledger in `ogar-vocab`** (X2, X3, X21). It is a golden list + of every shipped `(concept, u16)` pair, plus a successor list keyed by the + u16 (`ReplacedBy` / `Consider` / `Tombstone`). A renumber or a reuse becomes + a red test. The ledger is data in OGAR, never a mirrored column in the + contract (that would be a lockstep table) and never `#[deprecated]`. +2. **`PortSpec` is the mapping set** (X14, X17, X18, X19, X20). The port's + namespace identifies the set. Each alias row gains a relation kind, and + CURIEs resolve as `ogit.:` → the port with that namespace → + `class_id(local)`. An unmapped name stays `None`, and no mapping row ever + feeds `is_a`. +3. **Labels as u16-keyed rows in `ogar-vocab`** (X8, X9, X13, X10): `(address, + BCP-47 tag, pref|alt|hidden, text)`, with fallback at lookup time. They are + consumed at projection; the contract gets only the type and a lookup trait. + A customer binary gets labels as codegen output, never by linking OGAR. +4. **Ordinals stay per-load and are named as such** (X5, X7, X22, X23). The + three u16 spaces get distinct names: the codebook address, the registry + surrogate and the load ordinal. Every load records the git ref of its + source tree as a provenance receipt, never as a gate. + +## Verdicts + +`F` is the firewall verdict: PASS, C (fits only through a named seam), or TRAP. +"probe" names the falsifier result, where one was run. + +| row | idea | F | verdict | probe / reason | +|---|---|---|---|---| +| X1 | the u16 is an opaque surrogate except for the domain byte | PASS | OPERATOR (with X6) | **KILLED.** One production reader gives the low byte a second meaning: `is_palette_seat` (`lance-graph-ogar/src/lib.rs:504`) reads `0x17xx` low byte ≥ `0x17` as a consumer palette seat. OGAR's own doc says the slot is the shared concept (`ogar-vocab lib.rs:1576-1580`). The 6 domain-byte readers are permitted. | +| X2 | never renumber: test shipped ids against a frozen list | PASS | ADOPT-NOW | Not run (cross-repo). Today a lockstep renumber passes every gate. The test lives in `ogar-vocab`; the contract's value pins check the same list. | +| X3 | deprecation as data with a successor pointer | C | ADOPT with X2 | **Half KILLED.** "Deprecated, kept = resolvable" holds in the default build: 9/9 fossils read like their successor. Under `--no-default-features` the 5 V3 fossils read `DEFAULT`, the same as a never-minted key. No successor function exists. `flip_classid` is an order flip, not a successor, and misses 4 of 9 because the V3 appid was renormalised (`0x0100_1000` vs `0x0101_1000`). | +| X4 | an obsolete id resolves but leaves the rails | C | PARK (codebook) / PROBE (ogar-obo) | No production `is_a_parent` exists, so the codebook has no rail to leave (P-X19 precondition). `ogar-obo` already drops obsolete terms from rails and crosswalk; it lacks `replaced_by`. P-X4 not run. | +| X5 | record the source version per load | C | PROBE | Provenance receipt only (OGIT's version fields are placeholders). Gating on it would be an internal pin. P-X5 not run (needs history). | +| X6 | writer namespaces (two writers on one u16) | C | OPERATOR | **SURVIVED as a measured collision.** 3 of 114 codebook ids are also code-minted appid heads: `0x0101` project / OpenProject, `0x0202` commercial_document / Odoo, `0x0A01` anatomical_structure / q2. Live consequence: `concept_override` (`lance-graph-ogar lib.rs:489-492`) gives any consumer plugging these **concepts** the head's storage reading (`PROJECT_V3`, `ERP_V3`, `FMA_V3`), not `PLUG_AND_PLAY_V3`. Ports alias `0x0202` from WoA, SMB, Odoo and HubSpo. Latent today (no plug names them). | +| X7 | address and ordinal are different types | PASS | ADOPT-NOW (rename first) | New: the contract declares `ClassId` twice, `u32` (`rbac.rs:331`) and `u16` (`class_view.rs:54`). P-X7 not run. | +| X8 | language-tagged labels on the concept | C | ADOPT shape, new type | **KILLED as "absorb the three shapes":** 0/3. `Label` has no u16, `LabelDTO` has no language and holds a key, `FieldRef` is a field label. The twin holds (`"Kunde"` → `0x0204, de, alt`). The label row is new data, not a merge of existing shapes. | +| X9 | fallback at lookup, never stored copies | PASS | ADOPT-NOW (latent) | **SURVIVED.** `Label::en_only` yields a German DTO equal to the key with no fallback flag. Production ontologies pass real German, so the defect is latent. | +| X10 | shared pool, ClassView selects | C | OPERATOR | **KILLED premise:** the `ClassView` trait has no class-level label and is keyed by the u16, not the u32 (`E0599` / `E0308`). The ruled label home ("ClassView carries labels", keyed by the full classid) does not exist in the trait. | +| X11 | a label never carries a relation | PASS | ADOPT-NOW | Curation rule; see X18. | +| X12 | external per-language lexicon (OntoLex) | C | PARK | **KILLED:** German coverage is 5/114 (6 lenient), no third language. | +| X13 | absence per language is representable | PASS | ADOPT with X8 | **SURVIVED:** `en_only("project") == new("project","project","project")`. The closed `Label` cannot express absence. | +| X14 | name lookup is scoped by source | C | ADOPT in `PortSpec` | Not run. Homonym known by reading: "User" → project_actor globally, OSM_USER in `OsmPort`. | +| X15 | locale reaches entities | C | PROBE after X7 | **SURVIVED:** locale reaches only the ontology name; entity names are the same in De and En. New: `EntityTypeDto.id` (`ontology_dto.rs:193`) exports the registry's append-order counter. The cache re-mints it on invalidation (`lance_cache.rs:119-133`), so an outside app persisting it holds a cache-lifetime ordinal. | +| X16 | an ingest that keeps language tags | C | PARK until X8 | Both readers drop tags (verified by reading). OGIT has 0 tagged `rdfs:label`. | +| X17 | typed, one-way, provenance-bearing mapping rows | C | ADOPT in OGAR | Not run. | +| X18 | split the alias column by relation kind | C | ADOPT, with explicit re-pins | **Four kinds KILLED as complete; vocabulary SURVIVED.** 188 rows: source class 128, subtype 5, discriminator value 8, other app 3, word in a language 32, OGIT IRI 9, unknown 3. WoA's Quote/Order/Invoice/CreditNote and their German forms are `doc_type` values of one class, not subtypes. OpenProject is 25/28 source classes (the twin). | +| X19 | mappings stay out of the hierarchy | PASS | PARK (rule for the first mapping store) | **SURVIVED:** no production `is_a_parent` and no mapping store exist. The twin sees a real `is_a` edge. | +| X20 | an unmapped entity carries `None` | PASS | ALREADY-HAVE | Not run. | +| X21 | mapping lifetime follows the source release | PASS | PARK | **KILLED:** 0 of 6 WoA source-class rows are stale. One is semantically wrong: `TimesheetActivity` holds no hours; they live on `TimeSheet`, which has no alias. | +| X22 | ordinals are per-scope positions, never addresses | PASS | ALREADY-HAVE (rule) | Not run. OgitTables documents ids as stable per tree. | +| X23 | the registry's append log as a stable surrogate | TRAP | SKIP | **SURVIVED mechanically, failed in substance:** TimeSheet kept id 1926, but one inserted file moved 14 other entities. Hydration walks `read_dir` order (LIFO stack), not names, so ids depend on the filesystem. The cache also deletes itself on any schema change. | +| X24 | lifecycle on the identity row, not the label | PASS | ADOPT (deferred guard) | No OBO label ingest exists yet. | + +## Defects found on the way (no decision needed) + +- `ClassId` is two types in one contract (`u32` and `u16`). +- `EntityTypeDto.id` exports a cache-lifetime ordinal to PostgREST, Phoenix + and downstream apps. +- `Label::en_only` fabricates a German label (latent). +- Both TTL ingest paths drop language tags; OGAR keeps only the first + `rdfs:label`. +- No test pins the history of shipped codebook ids. + +## Open points for the operator + +- **Two writers on three u16s (X6, X1).** `0x0101`, `0x0202` and `0x0A01` are + both concepts and consumer appid heads, and since D-HPR-2 the head's storage + reading wins for anyone plugging the concept. Options: + - (a) key the storage readings by a consumer-owned value, not the concept; + - (b) move the appid heads off occupied concept slots; + - (c) accept the collision and document that plugging these concepts means + that domain's storage model. + `0x17` palette seats are the same shape in a domain with no codebook rows. +- **Label home (X10).** The trait cannot carry the ruled home. Choose between a + u16-keyed pool in `ogar-vocab` that the ClassView selects from, and a + class-level label method on `ClassView` keyed by the full classid. +- **O2 refined (X18, X21).** The hours row is `TimeSheet`; `TimesheetActivity` + holds none. Does `ogit.WorkOrder:TimeSheet` map to `0x0103` as exact or + close, and is "Stundenzettel" a German label of `0x0103` or only of WoA's + class? +- **Narrowing (X18).** WoA's document words are `doc_type` values. Do they stay + one concept (`0x0202`), or do `invoice` / `quote` / `credit` become their own + concepts? + +## What was not searched + +The W3C OntoLex and SSSOM specs were read through papers only. SNOMED CT and +UMLS were used as structural patterns only; nothing about their terms is +recorded here. OGIT history was not fetched (depth 1), so X5 is unmeasured. +Probes P-X2, X4, X5, X7, X11, X14, X17, X20, X22 were specified but not run. + +--- + +## Crosswalk — labels per language, source-id mapping, id lifetime (coresearch Phase 2, 2026-10-10) + +Built by the main thread from 50 scout items (code, prior art, literature, systems, concepts). Self-contained: each row carries the mechanism and the evidence. Grades: outside READ-IN-FULL / SECTION-READ / ABSTRACT-ONLY / SECONDHAND; inside VERIFIED-IN-CODE / CLAIMED / ABSENT (closed search named). Relation: ALREADY-HAVE / PARTIAL / NEW / CONFLICTS-ANCHOR. + +### Corrections the scouts made to the brief (all from reads) +- `OntologyDto::project(registry, namespace, key, label, locale)` EXISTS in lance-graph (`lance-graph-callcenter/src/ontology_dto.rs:80-112`), not in OGAR; its locale picks only the ONTOLOGY's own name through the closed 2-locale `Label{key,en,de}`; entity names are never localised. RDF-OWL-ALIGNMENT §5 ("SKOS-prefLabel projection") is overstated, not absent. +- OGIT: the 12 `@en` tags are all on `dcterms:description` in `ogit.ttl`; 0 of 3693 `rdfs:label` carry a language tag; 0 `@de`. `ogit:hide` = hidden-from-documentation (true on the meta-classes Entity/Attribute/Verb), NOT an obsolete marker. OGIT has 0 `owl:deprecated`, 0 `isReplacedBy`, 0 `end=`, 0 `owl:versionIRI`; `owl:versionInfo "__OGIT_VERSION__"` is a placeholder. Deprecation in OGIT appears only in prose (MARSNode) or Turtle `#` comments (isoCode, LegalSection, Region), which are not in the RDF graph. +- SKOS does NOT keep mappings apart from the hierarchy: `skos:broadMatch` is a sub-property of `skos:broader` (S41). Keeping mappings out of `is_a` is our design choice, not a SKOS guarantee. +- OgitTables' `KNOWN_REJECTED` includes `NTO/WorkOrder/verbs/`, so `LogsTime.ttl` is not loaded. Side finding (scratch run): OGIT's own `validate.sh` fails on an undefined `ogit.Compliance` prefix. +- Two independent u16 assignment spaces exist besides the codebook: the registry's append-order `EntityTypeId` and OgitTables' sort-order `TypeId`. +- The brief's constraint "a label names exactly one address" is STRICTER than every outside lexical model read (SKOS restricts prefLabel per concept per tag, not across concepts; Wikidata requires uniqueness only of label+description for items). Homonyms are real here too ("User" → PROJECT_ACTOR in OpenProject/Redmine/HubSpo, → OSM_USER in OsmPort). + +### Rows + +| id | row | idea | mechanism and evidence (outside, grade) | nearest inside surface (grade) | relation | +|---|---|---|---|---|---| +| X1 | IDENTITY | Opaque, meaning-free id; meaning lives in metadata | Local id carries no meaning; labels are metadata for humans; a type may be embedded only if indisputable, unchangeable and never reused across types (McMurry 2017 PLoS Biol L4, SECTION-READ). An id changes when information inside it changes, so classification/status stay out of it (Cool URIs 1998, READ-IN-FULL; OBO ID policy). SNOMED concept id carries no term (SECTION-READ). | u16 codebook address is a surrogate key whose high byte is a domain (the "embedded type" McMurry permits only if never reused) — `ogar_codebook.rs` (VERIFIED). OGIT identity is a name-bearing PURL `purl.org//`: a rename is a new identity (`NTO/PURL_ID_Registration.md`, READ). | PARTIAL (the u16 is the opaque key; the OGIT PURL is a natural key; the domain byte is out of scope per A4) | +| X2 | IDENTITY | Never delete, never reuse, never renumber — enforced against history | Deprecate, never delete or reassign; removed record resolves to a tombstone (McMurry L7, SECTION-READ). PostgreSQL enum labels: only ADD/RENAME, no removal; identity = OID, not position (SECTION-READ). OBO fp-003: a namespace must not have been used before (READ-IN-FULL). | Ruled: E-OGAR-NORTHSTAR-1 "append-only ClassIds, mint once, never renumber, tombstone" (CLAIMED — no tombstone carrier). Enforced only as uniqueness, non-zero, present-tense mirror parity, `MirrorDrift` by concept NAME, and a few value pins (`0x0103` at OGAR `lib.rs:2588,5958`); no test compares against a frozen list of shipped ids, so a lockstep renumber passes every gate (`ogar_codebook.rs:577-588,998-1039`, `hotplug.rs:600-649`, VERIFIED). Counter-precedent: OSINT rows `0x0700/0x0701` were DELETED (67→65) and u16 `0x0701` now means an appid (D-OSINT-APPID-NOT-CONCEPT; VERIFIED). | PARTIAL (rule exists; history not enforced; one deletion+reuse precedent) | +| X3 | IDENTITY | Deprecation as queryable DATA with a typed replacement pointer | `owl:deprecated true` is an annotation with no logical effect (OWL 2 §5.5, SECTION-READ). OBO fp-019: obsolete = flag + `IAO:0100001 term replaced by` (one exact) or `oboInOwl:consider` (several) + reason (READ-IN-FULL). SNOMED: inactive component stays; typed association REPLACED BY / SAME AS / POSSIBLY EQUIVALENT TO / PARTIALLY EQUIVALENT TO / MOVED TO / WAS A (SECTION-READ). Wikidata merge → redirect (`owl:sameAs`), never deleted or reused; inbound statements rewritten later by a bot (SECTION-READ). Cool-URIs-for-FAIR-KGs: tombstone (no successor / split, human reason) vs morph/merge with `dcterms:isReplacedBy` both directions (arXiv 2407.09237, SECTION-READ). KGCL: NodeObsoletion ≠ NodeDeletion (arXiv 2409.13906, READ-IN-FULL). | Only prose: `CLASSID_*_V3` "Deprecated, kept" doc notes; `*_LEGACY` pre-flip consts still resolve via `BUILTIN_READ_MODES`; `Membership` kept as a synonym of `Member` by comment + test (OGAR `ports.rs:176-185`); `ogar-obo` `obsolete: bool`; `lance-graph-ontology` `MappingRow.active` (soft-delete). Closed search (`deprecated:`/`replaced_by`/`superseded_by`/`obsolete`/`#[deprecated` over contract src + ogar-vocab src): no replacement pointer anywhere (VERIFIED). | PARTIAL (resolvable-kept practice exists; no machine-readable marker, no successor kind) | +| X4 | IDENTITY | An obsolete id still resolves but leaves the rails (hierarchy, mappings) | OBO fp-019: an obsolete term loses ALL logical axioms incl. `is_a`, every use is rewritten to the replacement; the dashboard ERRORs on an obsolete term with axioms (READ-IN-FULL). SSSOM: obsolete terms must not appear in mappings (arXiv 2112.07051, SECTION-READ). | `ClassView::is_a_parent` has no production implementation (closed search, ABSENT); kept fossils keep reading and rendering (A3 is reading-axis only, out of scope). No notion of "resolves but inert". | NEW | +| X5 | IDENTITY | A version id for the source ontology | OWL ontology IRI names a series, versionIRI one version; old versions stay reachable; an import closure must not hold two versions of one series (OWL 2 §3.1-3.4, SECTION-READ). SSSOM records subject/object source version per mapping set (SECTION-READ). | OGIT has no version IRI (`__OGIT_VERSION__` placeholder; `versioning/version.info` id + placeholder + git ref). OgitTables loads a floating checkout; its determinism test runs two loads of ONE checkout (`tests/ogit_tables.rs:196-203`, VERIFIED). | NEW | +| X6 | IDENTITY | Writer namespaces for independent minters (the two-writer question) | SNOMED: meaning-free namespace id per authorised issuer inside the identifier, so writers mint in disjoint spaces (SECTION-READ). SAP: customers append to SAP-owned fixed-value ranges in place (SECTION-READ). Opposite answers, both real. | C.9.3 makes appid ≡ concept byte, so u16 `0x0101` = concept `project` AND OpenProject's own appid (two writers on one address); OSINT `0x0701` concept→appid precedent (VERIFIED). | PARTIAL (domain byte partitions; the low byte is shared by two writers) — raised to the operator, not decided | +| X7 | IDENTITY | Address and ordinal are different TYPES | PostgreSQL: identity = OID, order = separate `enumsortorder` float, so position is not identity (SECTION-READ). | `ClassId` (`class_view.rs:54`) and `EntityTypeId` (`ontology.rs:81`) are both bare `pub type = u16`; `EntityTypeId` has two assignment rules (positional `idx+1` in `ontology.rs:75-91` / `ontology_dto.rs:116-123`, and append-order in the registry); only OgitTables uses newtypes (`TypeId/AttrId/VerbId`, which are ordinals) (VERIFIED). | PARTIAL | +| X8 | LEXICAL | Language-tagged labels on the concept: one preferred + n alternates per language | SKOS: labels are BCP-47-tagged literals; ≤1 `prefLabel` per tag per concept (S14); pref/alt/hidden pairwise disjoint (S13); `hiddenLabel` search-only; a concept may lack a prefLabel (READ §5.1-5.6). Wikibase fingerprint per language: ≤1 label, ≤1 description, n aliases (SECTION-READ). Odoo 16+: translatable field = jsonb `{lang: value}` on the row, en_US base, open language set, one value per language (SECTION-READ, LGPL-3). SAP text table keyed by check-table key + LANG (SECTION-READ, proprietary pattern only). SNOMED: descriptions are separate components with ids; language refsets mark preferred/acceptable per language/dialect/context (SECTION-READ). Gillis-Webber & Keet: three label-layer variants; a language that splits a concept (Fleuve/Rivière) makes distinct concepts, not labels (arXiv 2210.02807, SECTION-READ). | `ontology::Label{key,en,de}` is one closed EN/DE pair per whole ONTOLOGY, no per-concept label (`ontology.rs:28-60`, VERIFIED); `FieldRef.label` English only (`ontology.rs:463-478`); `ClassView::field_label` only, no class-label method (`class_view.rs:1066-1083`, closed search); `LabelDTO` has no language (`ogar_codebook.rs:812-840`); OGAR per-field `label: Option` + `translate: Option` + `EnumSource::Static (key,label)` all untagged (`ogar-vocab lib.rs:884-889,963-981`). OGIT: one untagged `rdfs:label`; "Stundenzettel" only inside `dcterms:description` (`TimeSheet.ttl:10-11`). | PARTIAL (field/ontology labels exist; no per-concept, per-language label anywhere) | +| X9 | LEXICAL | Fallback across languages happens at LOOKUP, never by storing copies | SKOS §5.6.5: fallback through BCP-47 matching at lookup (READ). Odoo: read falls back from context language to en_US base (SECTION-READ). | `Label::en_only` writes the key into the `de` slot — a German label nobody gave (`ontology.rs:44-69`, VERIFIED). Draft plan `unified-bridge-consumer-migration-v1.md` §4.4 copies a parent's label into a child `FamilyEntry` (Draft, never built; ABSENT) — one label would name two addresses. | CONFLICTS (with our own constraint, not an anchor): `en_only` and the draft inheritance store copies | +| X10 | LEXICAL | Shared label pool + context-scoped PREFERENCE sets | SNOMED language reference sets: the same descriptions, marked preferred/acceptable per language, dialect or narrower context (e.g. a specialty) (SECTION-READ). | Operator-locked slot-purity rule (le-contract §2, E-V3-FACET-4-PLUS-12): "the ClassView carries labels", never a payload slot (CLAIMED in docs; label carriage not verified in the trait). APP-CLASS-CODEBOOK-LAYOUT §3 puts the label set in the ClassView keyed on the FULL u32 (app/render side, SPEC). `LabelDTO.label` is consumer-local. | PARTIAL — and a TENSION to raise: the ruled label home is the app-side ClassView (u32), while the ruling "languages are labels of one concept" points at the concept (u16). A shared u16-keyed pool that the ClassView SELECTS from (SNOMED shape) satisfies both; nobody has ruled it. | +| X11 | LEXICAL | A label never carries a relation: scoped synonyms (narrow/broad) are mappings, not labels | OBO/KGCL synonym scope exact/narrow/broad/related: only the exact one is a label in the SKOS sense; narrow/broad synonyms are sub/supertype relations riding on a lexical row (arXiv 2409.13906, READ-IN-FULL). SKOS-XL makes a label a resource when it needs its own metadata (provenance, "DTO label") (SECTION-READ). | `WOA_ALIASES` collapses 9 subtypes (Quote/Angebot/Order/Auftrag/Invoice/Rechnung/CreditNote/Gutschrift/RecurringInvoice) onto COMMERCIAL_DOCUMENT; `canonical_concept` mixes source-class ids, German words, spelling/plural variants and collapsed subtypes with a lexical fallback that can produce a non-codebook string (`ogar-vocab lib.rs:2898-2950,3258-3276`, VERIFIED). | NEW (no relation kind on any name row) | +| X12 | LEXICAL | External per-language lexicon that denotes the concept by reference | OntoLex-Lemon: one lexicon per language outside the ontology; a sense has exactly one reference; cost: more files, sync, per-language grammar at render (arXiv 2210.02807 §3.2, SECTION-READ; W3C spec not read). | none | NEW | +| X13 | LEXICAL | Per-language labels go absent and stale independently | Wikidata: tail entities lack most languages; ~20% of sampled names judged incorrect; languages drift independently (arXiv 2311.15781, SECTION-READ). | Closed `Label{en,de}` cannot represent an absent or stale language label (VERIFIED). | NEW (design constraint) | +| X14 | LEXICAL | Name lookup returns candidates scoped by source, not one address | SKOS has no cross-concept label uniqueness; Wikidata enforces uniqueness only on label+description (items) (SECTION-READ). | Global `canonical_concept("User")` → project_actor vs port-scoped `OsmPort` "User" → OSM_USER; `canonical_concept_in_domain` gates between them (`ogar-vocab`, VERIFIED). | PARTIAL (scoping exists for routing; the brief's lexical constraint is stricter than practice) | +| X15 | LEXICAL | A locale parameter on the projection | (outside: SKOS lookup-time fallback, X9) | `OntologyDto::project(…, locale)` exists, localises only the ontology name (`ontology_dto.rs:80-112`, VERIFIED). | ALREADY-HAVE (the plumbing) / PARTIAL (no per-entity reach) | +| X16 | LEXICAL | An ingest path that keeps tagged labels | (SKOS/OWL label literals are plain literals with tags) | OGAR TTL reader keeps the FIRST `rdfs:label` only, strips `@lang`, and `into_class` DROPS label and description from `Class` (`ogar-from-schema ttl.rs:85-135`, `lib.rs:169-210`, VERIFIED). lance-graph `OwlHydrator` never interns literals, so tagged labels are dropped at hydration (`hydrators/owl.rs:185-245`, VERIFIED). | PARTIAL (both ingest paths exist; both drop the label) | +| X17 | MAPPING | Typed, one-direction, provenance-bearing mapping rows | SSSOM: subject_id, predicate_id (SKOS exact/close/broad/narrow/related, OWL equivalentClass/subClassOf), object_id, match_type, author/creator/reviewer, source versions, versioned mapping set; walking untyped xrefs is unsound (OxO limb→extremities) (arXiv 2112.07051, SECTION-READ). UMLS: each source string is an atom with its source (SAB) and source code (CODE/SCUI/SAUI), grouped under one CUI; closed REL kinds SY/RB/RN/RO/RQ/XR (SECTION-READ). Odoo `ir.model.data`: (module,name) → (model,res_id), many-to-one (SECTION-READ, LGPL-3). OGIT `ogit:original` = "less strict than owl:sameAs", 369 uses (361 OSLC), no kind (READ-IN-FULL). | `PortSpec::aliases()`: 188 `(public_name,u16)` rows across 11 ports, exact-string scan, no relation kind; "TimeSheet" in no table, so `WoaPort::class_id("TimeSheet") == None` (`ports.rs:51-131,358-397`, VERIFIED). `ogar-adapter` canonical→target string map, map direction only (VERIFIED). `odoo_alignment::resolve_odoo` = one `owl:equivalentClass` pivot, None when unmapped (VERIFIED). `LabelDTO.label` holds source-class names ("account.analytic.line"). | PARTIAL (mapping tables exist; none states a kind, a version or an owner) | +| X18 | MAPPING | Split the alias column by relation kind | Combine X11 + X17: a word in a language → LEXICAL label; a source-class id → exact/close match; a subtype → broadMatch (or is_a if a concept). | `WOA_ALIASES` 25 rows → 6 ids: 10 German words, 15 English names, 1 other app's class (TimeEntry), 9 collapsed subtypes (VERIFIED). | NEW | +| X19 | MAPPING | Keep the mapping graph out of the concept hierarchy | SKOS S41: broadMatch ⊂ broader, so a match asserted in the same graph as is_a entails hierarchy (WoA:Quote broadMatch 0x0202 would pull a source class into is_a); §10.6.1 calls mappings a provenance convenience, "no substitute for provenance mechanisms" (READ). | `lance-graph-ontology` SKOS hydrator loads exact/close/broad/narrow/relatedMatch + pref/alt/hiddenLabel only as edge-type IRIs into its own G slot; no code asserts a match from a source class to a codebook u16 (closed search, `hydrators/skos.rs:1-113`, VERIFIED). | NEW (constraint for any mapping store) | +| X20 | MAPPING | An unmapped source entity carries None, never a mint | (UMLS: every atom sits under some CUI — counter-model) | `resolve_odoo` None test-pinned for `stock.move` = "author an alignment axiom, never mint" (Option B LOCKED); `WoaPort::class_id("TimeSheet")` None; plug/reading/ClassView are u16-keyed, so a CURIE-only entity can be mapped and labelled but not plugged, read or rendered (VERIFIED). | ALREADY-HAVE (None semantics) | +| X21 | MAPPING | Mapping lifetime follows the SOURCE release, the address does not | Odoo: an external id missing from updated module data is deleted with its record (not a never-delete address) (SECTION-READ). SSSOM pins subject/object source version (SECTION-READ). | Alias tables are compile-time consts with no source version; OGIT has no version IRI (X5) (VERIFIED). | NEW | +| X22 | REPRESENTATION | Dictionary codes / ordinals are per-scope positions, never addresses | Arrow: dictionary id per stream/file; a non-delta batch replaces and renumbers (spec example moves 'C' 2→1) (SECTION-READ, Apache-2.0). Lance 13: dictionary chosen and built per page (source read, Apache-2.0). DuckDB ENUM codes = definition order (MIT). Monotone MPHF returns rank, which shifts on a smaller insert (arXiv 2506.06536, SECTION-READ). SAP DD07T keys fixed-value TEXT by VALPOS, a position (SECONDHAND). | OgitTables `TypeId` = row index after sorting by `(domain_of(curie), curie)`; any earlier-sorting insert (a domain before WorkOrder, the SGO core pinned first, a WorkOrder name before TimeSheet, or a change in accepted files) shifts TimeSheet's id; the test pins no TypeId (`ogit.rs:201-305,559-608`, `tests/ogit_tables.rs:14-62`, VERIFIED). `LabelCodebook` token ids are corpus-sort ordinals (`soa_bake/label_codebook.rs:180-197`). `IdentityCodebook` ordinals (ISS-IDENTITY-CODEBOOK-ORDINAL-STABILITY OPEN). Positional `entity_type_id`/`from_ontology idx+1` still live, flagged "v1 path to gate" in E-MINT-TRACE-1, never gated; `OwlHydrator` first-seen interning depends on file order. Rule already ruled: ClassView doc forbids a stored ordinal as a location (`class_view.rs:1226-1228`); E-W2 DECISION (2026-10-10) moves space ordinals out of the classid. | ALREADY-HAVE (the rule) / PARTIAL (positional ids still live, ungated) | +| X23 | REPRESENTATION→IDENTITY | A persisted, append-only CURIE→id log turns an ordinal into a stable surrogate | (pattern: PostgreSQL OID per label; Odoo res_id surrogate + external-id table) | `lance-graph-ontology` registry mints `EntityTypeId` in append order: dedup by OGIT URI, monotone, never reused, gaps allowed, tests pin this; stability rests on the append-only `lance_cache`, not on the tree (`registry.rs:586-607,847-875`, `lance_cache.rs:11-12`, VERIFIED). OgitTables does NOT use it. | ALREADY-HAVE (in lance-graph-ontology) — synergy: OgitTables could key off it | +| X24 | IDENTITY | Lifecycle belongs on the identity row, not in the label | OBO prefixes an obsolete term's label with "obsolete " (fp-019, READ-IN-FULL) — lifecycle leaking into the lexical row. | Our filing rule keeps lifecycle on IDENTITY (brief). | CONFLICTS (outside convention vs our filing rule; not an anchor) | diff --git a/.claude/board/entries/2026-10-11-synergy-ledger-classid-hotplug.md b/.claude/board/entries/2026-10-11-synergy-ledger-classid-hotplug.md new file mode 100644 index 000000000..27cdf1f51 --- /dev/null +++ b/.claude/board/entries/2026-10-11-synergy-ledger-classid-hotplug.md @@ -0,0 +1,166 @@ +# Synergy ledger — classid reading, hotplug, cross-glove parity (2026-10-11) + +**Status:** OPEN — revision of the 24-point listing (P1–P24) against source in +lance-graph, OGAR, OGIT, odoo-rs, q2, MedCare-rs and the fleet. Eight scouts +read the code (113 items; 108 shown, 5 private-repo items omitted). One +adversarial re-reader per scout checked every item against its cited lines: +106 hold, 7 were refuted or corrected (5 of them shown). The +completeness critic was not run (stopped to save tokens), so the ranking below +is the main thread's. + +## Leverage ranking (open items) + +**Low fruit (hours, no operator needed):** +1. `contract-ogar-reading-only-partition-vs-0x0103` — probe "reading is not a + capability" in `lance-graph-ogar`. A plug with `covered` empty succeeds for + a concept that has a capability table. This unblocks the SAP/Odoo `0x0103` + plugs, q2 geo and deepnsm-v2 (rated high because it changes activation; the + probe itself is hours). +2. `contract-slab-declaration-has-no-tail` — one doc sentence in `hotplug.rs`: + a slab declaration wins for `value_schema` only, never the tail. +3. `fleet-sibling-plugs-skip-reading-socket` — sibling plug tests call + `resolve_hotplug` directly and never assert a reading. Add a test-only + `OgarAuthority.activate` check. +4. `fleet-lance-graph-ogar-lint-fmt-gate` — clippy and fmt lines for + `lance-graph-ogar` in CI (6 pre-existing clippy errors to clear first). +5. `glove-p19-cats-validity-plane` — Quack already has `BoundField.validity`; + `CatsBinder` can serve optional fields instead of refusing them. +6. `glove-p9-…` — D-XGP-6's gate is answer equality, not byte equality. +7. Board hygiene: the `board-*` rows (duplicates, retire wording, stale cells). + +**High (a PR with a probe, or one operator answer):** +- Coresearch O3 (X6): `concept_override` keyed by concept collides with three + appid heads. Operator: (a) / (b) / (c). +- `glove-p8-report-catalog-from-basis` (D-XGP-5) and + `glove-draft-has-no-range-or-group` (Quack Draft has only Eq/Ne and + Count/Rows). +- `ogar-p18-capability-table-0x0103` together with + `odoo-capability-0x0103-consumer-tension`. Operator: are capabilities on a + shared concept declared per concept or per consumer? +- `ogar-billable-work-entry-no-customer-edge` and the P20 work date — an OGAR + `Class` change. +- `odoo-hr-timesheet-harvest-missing`, `odoo-analytic-model-source-unvendored`. + +**Heavy (cross-repo or blocked on data):** +- `contract-deepnsm-corpus-has-no-concept` (a concept mint), + `glove-p6b-…` (WoA rows), `glove-p10-sap-behaviour-oracle` (no trace), + `ogit-workorder-dialect-divergence`, `odoo-storage-writer-would-persist-0x0002`, + `q2-medcare-geo-plug-unreachable`, D-HPR-6b (operator). + +## Ledger + +`holds` = the re-reader's verdict. Refuted items keep the scout's text, and +the correction follows it. + +| id | status | fruit | ref | item | +|---|---|---|---|---| +| `board-p14-iss-regrade` | open | low | P14 | ISS-CLASSID-READ-MODE-IS-A-SECOND-RESOLUTION-PATH: 'retire the 0x1000 keys' contradicts two rulings; basis and caller list predate D-HPR | +| `board-p17-status-cells-stale` | open | low | P17 | STATUS_BOARD cells stale vs merged PRs; D-XGP-2 shipped in #1455, not #1460 | +| `contract-board-regrade-iss-plan-status` | open | low | P14, P17 | ISSUES top entry, plan 'Where things stand', and STATUS_BOARD D-HPR-2 all carry text the 2026-10-10 no-eviction refinement superseded (plus drifted line numbers) | +| `contract-domainspec-v3-consts-are-the-bake-readers` | open | low | P24 | soa_graph DomainSpec consts still key on CLASSID_*_V3 and `project_snapshot` filters rows by `key.classid() == domain.classid` — this IS the stored-bake population W5 protects; by-ruling it stays, only a doc note is missing — **corrected:** The cited lines are accurate: soa_graph.rs:91/117/134/155 hold the V3 consts; the :259/:414 filters are exact classid matches; q2 body.rs:44/81, fma.rs:72-73/144/177, body-soa-wire:27/65 and geo/src/bso2.rs:22/148-154 read as quoted; MedCare graph_feed.rs:25 h… | +| `contract-hpr3-legacy-reader-inventory` | open | low | P1 | D-HPR-3 (W3): every caller of classid_read_mode / CLASSID_*_V3 in lance-graph classified; in-repo W3 is nearly empty, the real population is q2/MedCare | +| `contract-hpr5-legacy-keys-stay` | open | low | P2 | D-HPR-5 (W5): stored 0x1000 / pre-flip keys keep resolving via BUILTIN_READ_MODES — true; but 'a SlabDeclaration may override for its own data' only covers value_schema, never the tail | +| `contract-ogar-crate-has-no-clippy-gate` | open | low | P15 | lance-graph-ogar: CI runs `cargo test` only for the workspace-excluded crate; no clippy line exists, so the reported pre-existing clippy errors cannot be caught | +| `fleet-lance-graph-ogar-lint-fmt-gate` | open | low | P15 | lance-graph-ogar has no clippy and no fmt gate in lance-graph CI; the existing TD row is stale and q2 has already been broken by it | +| `glove-p19-cats-validity-plane` | open | low | P19 | Validity plane for optional CATS fields: Quack already ships the mechanism (BoundField.validity + Filter::sql_where), and only the CATS side is missing | +| `glove-p9-lgj-convergence-gate-is-answers-not-bytes` | open | low | P9 | D-XGP-6: lowering_convergence.rs exists and already covers count + grouped sum. The plan/board gate 'byte-equality' contradicts the file's own scope (it compares answers), and a canonical-bound case needs a dependency decision. | +| `ogar-label-mechanism` | open | low | new | Q1: OGAR has a label DTO but no class-level i18n label table; the TTL lift parses rdfs:label and drops it | +| `ogar-lo-u16-two-readings` | open | low | new | NEW: OGAR's ledger and ports.rs still define the lo u16 as the APP_PREFIX render skin (+0x0006 reserved for q2), while the 2026-10-10 ruling makes it 64k app-owned mask space and calls the render prefixes a likely fossil — OGAR carries no entry for the ruling | +| `ogar-p11-fossil-notes` | open | low | P11 | P11: no 0x1000 'fossil' note in ogar-osm/ro/dismech/loco or in ports.rs; ogar-osm::geo_identity_classid is a LIVE producer of 0x0F01_1000, not just a test literal — **corrected:** The core of P11 holds and every cited line reads as claimed: osm.rs:60-67 documents CLASSVIEW_V3_SUBSTRATE as 'the V3 marker form the codebook already uses' with no fossil wording; ogar-ro:424-428 and ogar-dismech:526-531 use 0x1000 only as a test app_prefix;… | +| `ogar-p20-work-date-attribute` | open | low | P20 | P20/Q3: no temporal-role pattern exists in OGAR; the convention on promoted classes is a typed attribute (date/datetime) — BillableWorkEntry has only `billable`, and 9 of its 12 edge targets (incl. Duration) are unminted | +| `ogar-p23-ogit-tables-ordinals` | open | low | P23 | P23: OGAR #350 OgitTables landed; its TypeId is a per-load row ordinal, not an address — TimeSheet sits ~789th of 791 with WorkOrder the last of 79 domains, so almost any tree edit shifts it | +| `ogar-p5-timesheet-alias-and-label` | open | low | P5 | P5: Stundenzettel→0x0103 already landed as a port alias; what is missing is the OGIT name `TimeSheet`, the global normalizer, and the label path | +| `ogit-minuten-unit-and-rounding` | open | low | P6 | P6 caveat from OGIT: minuten is raw integer minutes; WoA bills in 15-minute rounded-up units | +| `ogit-p23-ogittables-ordinals` | open | low | P23 | P23: OGAR #350 landed; TimeSheet gets a u16 TypeId without a vocab mint, but it is a load-local ordinal over a moving tree, not an address | +| `ogit-p5-woa-hours-row-identity` | open | low | P5 | O2/P5: the WoA hours row in OGIT is ogit.WorkOrder:TimeSheet; OGAR pins 0x0103 on TimesheetActivity, which OGIT does not model | +| `q2-medcare-p1-q2-mint-callers` | open | low | P1 | P1 (q2 part): every q2 classid_read_mode call is an offline bake MINT path on CLASSID_FMA_V3; no q2 reader calls it | +| `q2-medcare-p11-q2-geo-doc` | open | low | P11 | P11 (q2 part): q2 geo and body docs still treat classview 0x1000 as meaningful, and two of them recommend minting a new contract constant | +| `q2-medcare-p24-stored-population` | open | low | P24 | P24 revised: q2's stored FMA/OSINT bakes are mostly PRE-FLIP forms, not 0x0A01_1000; no q2 or MedCare code reads them through soa_graph or classid_read_mode | +| `contract-hpr6-no-v1-default` | open | high | P3 | D-HPR-6 (W6): unknown classid → ReadMode::DEFAULT (V1 / Full / CoarseOnly) today; making it an error touches 4 production signatures and ~8 anti-vacuity pins; guid-v3-tail is already default-on and its off-arms are untested dead code | +| `glove-p6a-duration-sap-lens-needs-unit-ruling` | open | high | P6 | Converted grade for duration, SAP half: needs a canonical unit, then a derived minutes lens in CatsBatch::bind. It does not need WoA. — **corrected:** The gap is real: SAP hours_logged→duration is Hypothesized, the two basis notes assume different units, and the SAP side does not need WoA to be graded. But three things do not survive a re-read. (1) The basis.rs citations :183-187 and :244-248 point past the… | +| `glove-p8-report-catalog-from-basis` | open | high | P8 | D-XGP-5 report Catalog: the shipped precedent exists (report boundary::Catalog + a Catalog-backed Quack Binder test). The named input type CanonicalBasis does not exist, and the cross-glove gate is blocked on a second population. | +| `ogar-billable-work-entry-no-customer-edge` | open | high | new | NEW: BillableWorkEntry has no billing-party/customer edge, but WoA's TimeSheet is booked against a mandatory Customer — the WoA glove's one mandatory FK has no canonical slot | +| `ogar-p18-capability-table-0x0103` | open | high | P18 | P18: a capability declaration on 0x0103 = one new ogar-vocab domain table (ActionDefs whose object_class ends in the literal `billable_work_entry`, expected executors = every glove, appended to domain_tables) — with the per-table gate forcing one shared capability set | +| `q2-medcare-p3-evidence` | open | high | P3 | P3 evidence: both consumers have already hit the V1 default for an unregistered classid; neither calls the lookup on such keys, so NoReadingFor would break no current caller in q2 or MedCare | +| `fleet-capability-tables-crm-and-billable` | open | heavy | P18 | OGAR has four capability tables (ocr, geo, healthcare, document); with no CRM table and no 0x0103 table, HubSPO's HOT_PLUG and the SAP/Odoo glove plugs all report NoCapabilitiesFor | +| `glove-p10-sap-behaviour-oracle` | open | heavy | P10 | SAP behaviour oracle (D-XGP-7): SIMAF holds no CATS trace; the only BAPI 'behaviour' in it is a unit-test mock. Stays blocked. | +| `glove-p18-capabilities-on-0x0103` | open | heavy | P18 | Capabilities on BILLABLE_WORK_ENTRY: an OGAR domain table would end NoCapabilitiesFor(0x0103), but the authority's own rule says to declare capabilities only once a consumer implements them, and the gloves implement none | +| `glove-p20-no-temporal-role` | open | heavy | P20 | BillableWorkEntry has no temporal role (confirmed at OGAR b4f5a36). The SAP date conversion is already done; only the authority field is missing. | +| `glove-p6b-duration-cross-glove-woa-rows` | open | heavy | P6 | Cross-glove duration anchor (SAP hours×60 == WoA TimeSheet.minuten): blocked on WoA rows and a WoA lane binder, and neither exists here | +| `odoo-xgp4-analytic-pivot` | open | heavy | P7 | D-XGP-4 Odoo analytic-line mapping + behaviour: what odoo-rs now has vs still lacks | +| `ogit-p20-work-date` | open | heavy | P20 | P20 from OGIT: no vendor-neutral work-date concept; WoA's datum is undefined in TimeSheet.ttl and defined twice elsewhere with other meanings | +| `board-0x1000-retirement-wording-contradicted` | new | low | new | Three copies of 'its retirement is the plan's P4 operator checkpoint' and other pre-refinement retire/decide wording contradict two rulings | +| `board-d-hpr-0-entry-contradicts-plan` | new | low | new | D-HPR-0 ruling entry keeps 'retire/remove' and wave texts the refinement and the plan contradict | +| `board-d-hpr-2-codex-p1-unrecorded` | new | low | new | D-HPR-2 shipped text omits the codex-P1 behaviour change: canon domains now activate reading-only | +| `board-d-hpr-4-render-prefix-note-missing` | new | low | new | STATUS_BOARD D-HPR-4 says render prefixes are documented deprecated; only the 0x1000 constants are | +| `board-d-xgp-entries-stale-opens` | new | low | new | D-XGP entries and LATEST_STATE keep OPEN lines and claims later sections closed or corrected | +| `board-dup-fossil-block-x3` | new | low | new | Same 25-line classview/fossil block verbatim in entry, plan §C.9.3 and the knowledge doc; layout ruling in 4 places | +| `board-dup-render-audit-summary` | new | low | new | Plan §C.9.4 re-lists the audit findings in different wording beside the canonical entry | +| `board-dup-second-resolution-path` | new | low | new | 'classid_read_mode is a second resolution path' stated six times with three different caller lists | +| `board-dup-woa-block-x2` | new | low | new | WoA anchors finding verbatim twice; O2 restated in five places | +| `board-epiphanies-july-0x1000-vs-v3-mandatory` | new | low | new | EPIPHANIES row E-V3-DUAL-SCHEMA-0x1000-IS-PERMANENT-1 (CURRENT) disagrees in meaning with D-HPR-0; neither cites the other | +| `board-integration-plans-and-plan-headers-stale` | new | low | new | INTEGRATION_PLANS and the cross-glove plan header contradict the rulings and the shipped code | +| `board-latest-state-pr-arc-missing` | new | low | new | LATEST_STATE / PR_ARC_INVENTORY carry none of the arc's merged PRs; three LATEST_STATE entries still say 'unmerged' | +| `board-missing-d-ids` | new | low | new | Work the plans name as next or open has no D-id or STATUS_BOARD row; plan D-id range omits D-XGP-8; D-XGP-4 gate is already satisfied | +| `board-plan-v3-w3-vs-w4` | new | low | new | Plan v3 contradicts itself (W3 '#[deprecated]' vs W4 'not #[deprecated]'; 'must go' vs 'kept'); D-HPR-3 gate is eviction-shaped | +| `board-stale-line-cites` | new | low | new | Line citations into lance-graph-ogar/src/lib.rs drifted after #1465 | +| `contract-slab-declaration-has-no-tail` | new | low | new | NEW: the slab envelope cannot declare a key tail — SlabReading has Facet96/Register128/signed-register variants only, so 'the slab wins for existing data' stops at the value slab | +| `contract-w4-doc-note-gaps` | new | low | new | NEW: W4 doc notes landed on the five CLASSID_*_V3 consts + classid_read_mode only; NodeGuid::read_mode, the DomainSpec consts, and two stale Cargo.toml feature comments still describe the legacy path as current | +| `fleet-contract-reach-matrix` | new | low | new | How a lance-graph-contract change on main reaches each sibling: immediately for most, frozen for openproject (a lock at a commit no longer on main) and a2ui (a lock behind the D-HPR/D-V3M commits) | +| `fleet-expected-executors-unplugged` | new | low | new | OGAR names expected executors for geo ('osm-soa-bake') and document ('paperless-kv') that no consumer crate in the fleet declares a HotPlug for — **corrected:** The geo half is refuted. 'osm-soa-bake' is a real crate in the sibling repo openstreetmap-website-rs (Cargo.toml:13 `name = "osm-soa-bake"`), which q2 consumes (q2 Cargo.lock:7297; test-suite.yml:58). Its src/capability.rs:43-113 sets CONSUMER = "osm-soa-bake"… | +| `fleet-glove-parity-trigger-gap` | new | low | new | glove-parity CI does not re-run when lance-graph-ogar changes, has no push or schedule trigger, and resolves OGAR at main HEAD with no lockfile | +| `fleet-guid-v3-tail-default-everywhere` | new | low | new | guid-v3-tail is a contract default and no fleet consumer disables defaults, so un-gating it (P3) changes no sibling's feature set, and q2's comment saying v3 is off is wrong | +| `fleet-hotplug-adoption-matrix` | new | low | new | Which siblings already follow the plug pattern: HotPlug in MedCare, HubSPO and tesseract; RbacPlug in MedCare, HubSPO and spear; a2ui consumes a binding; q2, odoo-rs and openproject use classid tables or PortSpec only | +| `fleet-main-main-coupling-no-cron` | new | low | new | lance-graph and OGAR depend on each other's main HEAD with no lockfile and no scheduled run; only spear and tesseract-rs detect sibling drift daily | +| `fleet-no-ci-openproject-odoo` | new | low | new | openproject-nexgen-rs and odoo-rs have no CI, so their classid pins and builds are checked nowhere (and MedCare's own CI header says it may be inert) | +| `fleet-q2-wasm-needs-nightly` | new | low | new | q2's two WASM crates need nightly (`#![feature]`, `-Z` rustflag, build-std), but the only toolchain file pins stable 1.99.0 | +| `fleet-report-ogar-no-ci` | new | low | new | lance-graph-report-ogar (workspace-excluded, path-deps OGAR) has 4 tests and no CI step | +| `fleet-sibling-plugs-skip-reading-socket` | new | low | new | All three sibling HotPlug consumers activate through `resolve_hotplug`, which returns no readings, instead of `CapabilityAuthority::activate`, which carries `read_mode_for` | +| `fleet-spear-dual-contract-source` | new | low | new | spear pulls the contract and lance-graph-rbac from two sources (git main and sibling path) with no [patch] to unify them | +| `fleet-toolchain-pin-bypass-and-prose-drift` | new | low | new | Two lance-graph jobs float on `stable` instead of the 1.99.0 pin; several sibling workflows restate the version or describe the wrong one | +| `glove-basis-grades-not-wired-to-canonical-front` | new | low | new | The authority basis (basis::*_FIELDS grades, keyed by ClassView names) and the canonical-name front (CanonicalBinder, keyed by OGIT URIs in OntologyRegistry) are disconnected | +| `glove-billable-ne-keeps-unknown` | new | low | new | The only Converted claim (billing_indicator→billable) is three-valued for '=' only: 'billable <> true' selects BILLABLE_UNKNOWN rows | +| `glove-ogit-datum-polysemous` | new | low | new | OGIT ogit.WorkOrder:datum is one property URI defined twice with different meanings, and TimeSheet reuses it with no definition of its own | +| `glove-sap-baseline-waves-untracked` | new | low | new | sap-glove-quack-v1 W1–W6 are unbuilt and have no STATUS_BOARD rows; W1's PR-D targets the superseded glove::GlovePivot | +| `glove-xgp3-gate-names-unbuilt-controls` | new | low | new | STATUS_BOARD D-XGP-3 (Shipped) carries the gate 'N1/N2/N5/N6 red without the conversion', but none of N1–N7 exists as a test | +| `odoo-analytic-behavior-classification-inputs` | new | low | new | Prefix classifier misfiles on_change_unit_amount, and the manifest lists 4 of the 8 analytic methods | +| `odoo-bundle-graph-ids-wrong` | new | low | new | ODOO_BUNDLE_ID 0x0002 / FIBO 0x0007 mix the app-prefix space into OGIT g-slots (real: ODOO 50, FIBOFND 20) | +| `odoo-nav-vendor-version-skew` | new | low | new | Vendored Odoo nav files come from two upstream versions | +| `odoo-project-task-user-aliases` | new | low | new | OdooPort has no labels for project.project / project.task / res.users / res.company, though hr.employee is aliased | +| `odoo-stale-preflip-docs` | new | low | new | odoo-rs docs still describe the pre-flip order and deleted APIs | +| `odoo-xgp4-handoff-stale` | new | low | new | D-XGP-4 handoff is superseded twice and still asks for app_prefix 0x0002 — **corrected:** The staleness is real, but the headline claim is wrong. The app_prefix=0x0002 row (:58) sits in handoff §2, and the handoff's own correction block (:10) already supersedes §1, §2, §5 and §8.1-2, so the handoff does not 'still ask' for app_prefix. What is actua… | +| `ogit-alias-name-sets-disagree` | new | low | new | Three disjoint name sets for one concept: OGIT local name, WoaPort aliases, canonical_concept promotions | +| `ogit-german-label-in-ogit` | new | low | new | A German label can be written in OGIT today only as a plain RDF language-tagged rdfs:label; OGIT has no precedent or convention for it | +| `ogit-timesheet-attribute-drift` | new | low | new | OGIT TimeSheet carries 7 of the WoA model's 14 fields; start/end times and the pause marker are missing | +| `q2-medcare-contract-cargo-doc-drift` | new | low | new | Cross-dimension observation: lance-graph-contract Cargo.toml says V2/V3 mints fall back to V1 without features; the code panics instead | +| `q2-medcare-hotplug-model` | new | low | new | Is MedCare's HOT_PLUG the model for SAP/Odoo plugs? For the capability side yes; for the reading side no | +| `q2-medcare-osint-scene-v2-tail-under-v1-registry` | new | low | new | q2 runtime OSINT scene is stored with a V2 tail under classids whose builtin reading is V1, so BUILTIN_READ_MODES answers wrongly for it | +| `contract-ogar-reading-only-partition-vs-0x0103` | new | high | new | NEW synergy with P18: lance-graph-ogar routes only the five hard-listed canon storage domains around the capability join; 0x0103 (BILLABLE_WORK_ENTRY) goes to the join and `NoCapabilitiesFor` refuses the whole SAP/Odoo plug | +| `glove-draft-has-no-range-or-group` | new | high | new | Quack Draft expresses only Eq/Ne and Count/Rows, so every canonical fold (date range, sum duration by …) is hand-built from bound Cols | +| `odoo-analytic-model-source-unvendored` | new | high | new | No analytic-line model .py in odoo-rs, so no ClassView ordinals, source pins or decorator kausal | +| `odoo-hr-timesheet-harvest-missing` | new | high | P7 | hr_timesheet employee_id/project_id/task_id are not harvested anywhere; methods keyed on a non-model subject | +| `ogit-label-readers-drop-tags` | new | high | new | ogar-from-schema reads rdfs:label and dcterms:description into EntityDecl, but drops language tags and extra labels, and into_class never carries either into Class | +| `ogit-workorder-dialect-divergence` | new | high | new | NTO/WorkOrder is written in a dialect the rest of OGIT and OGAR's reader do not use | +| `q2-medcare-cpic-local-guid` | new | high | new | q2 cpic crate keeps a parallel local NodeGuid (V1 u24 tail) and uses the classid low u16 as a kind ordinal | +| `contract-deepnsm-corpus-has-no-concept` | new | heavy | new | NEW: deepnsm-v2 `promote::key_at` is a production mint that cannot move to the plug path — its corpus has no OGAR concept, so it borrows CLASSID_OSINT_V3 for the V3 tail only | +| `odoo-capability-0x0103-consumer-tension` | new | heavy | P18 | A capability table on shared 0x0103 that names one executor refuses every other glove | +| `odoo-storage-writer-would-persist-0x0002` | new | heavy | new | The unwired od-server lance sink would persist concept\|\|0x0002 keys that classid_read_mode reads as V1 DEFAULT | +| `odoo-xgp4-mapping-ownership-split` | new | heavy | new | Where the Odoo field mapping lives: plan says odoo-rs, shipped code says lance-graph glove-parity | +| `ogit-timesheet-customer-has-no-role` | new | heavy | new | WoA books hours against a Customer (mandatory); BillableWorkEntry has no customer or billing-party edge | +| `q2-medcare-geo-plug-unreachable` | new | heavy | new | q2 geo mints under osm_node 0x0F01 but can never obtain a plug reading: the reading is gated by capability-consumer identity | +| `q2-medcare-p2-slab-declaration-cannot-override-tail` | new | heavy | P2 | P2 revised: a SlabDeclaration can override value_schema only, not the tail, so it cannot protect stored V1/V2-tail rows under a concept the plug reads as V3 | +| `board-d-hpr-5-is-status-quo` | closed | low | P2 | D-HPR-5 'Queued' describes behaviour that already holds: BUILTIN_READ_MODES still resolves and SlabDeclaration already wins on the plug path | +| `board-p13-render-classid-reversal` | closed | none | P13 | Reversing ogar_codebook::render_classid: audited and ruled out; every record agrees | +| `fleet-toolchain-sweep-1-99` | closed | none | P22 | Fleet toolchain sweep to Rust 1.99.0 is complete in all ten repos; lance 13 / lancedb 0.40 pinned where used | +| `odoo-analytic-views-vendored` | closed | none | P7 | Analytic parent views vendored + region corpus regenerated (#42, #43) | +| `odoo-toolchain-1-99` | closed | none | P22 | odoo-rs on Rust 1.99.0 (toolchain + Dockerfile) | +| `ogar-q4-no-read-mode-consumers` | closed | none | new | Q4: OGAR has zero code consumers of lance-graph's classid_read_mode / CLASSID_*_V3 / ReadMode family and never enables guid-v3-tail explicitly — nothing to migrate in W3/W6 on the OGAR side | +| `q2-medcare-p1-medcare-no-callers` | closed | none | P1 | P1 (MedCare part): MedCare has zero classid_read_mode calls; its V3 mints already pass TailVariant::V3 directly | +| `q2-medcare-p22-toolchain` | closed | none | P22 | P22 confirmed for q2 and MedCare: Rust 1.99.0 and lance 13 / lancedb 0.40; MedCare pins exact, q2 floats | +| `fleet-coderabbit-cap` | excluded | none | P16 | CodeRabbit org spending cap (1 review/hour) — external, non-code | +| `fleet-hubspo-spear-not-billable-gloves` | excluded | none | new | HubSPO-rs and spear have no billable-work concept (0x0103 / TimeSheet), so there is no fourth or fifth glove | +| `odoo-0x0002-render-prefix-pins` | excluded | none | P12 | odoo-rs pins the fossil render prefix 0x0002 in the classview bits | +| `ogit-no-other-timeentry-concept` | excluded | none | new | No OGIT time-entry concept outside NTO/WorkOrder for BILLABLE_WORK_ENTRY to converge on | +| `q2-medcare-osint-classview-literal` | excluded | none | P1 | q2 osint_classview 0x0701_1000 literal is a test; the production reader of stored OSINT V3 keys reads only the concept half | + +Five MedCare-rs-internal items (private repository) are left out of this public ledger. The only MedCare fact used above: it has 0 `classid_read_mode` callers. diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index 8b958a4aa..41d9396a3 100644 --- a/.claude/board/entries/README.md +++ b/.claude/board/entries/README.md @@ -25,10 +25,12 @@ 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. -300 entries, 2026-08-06 .. 2026-10-11. +302 entries, 2026-08-06 .. 2026-10-11. | date | entry id | finding | file | |---|---|---|---| +| 2026-10-11 | `synergy-ledger-classid-hotplug` | | [2026-10-11-synergy-ledger-classid-hotplug.md](2026-10-11-synergy-ledger-classid-hotplug.md) | +| 2026-10-11 | `coresearch-labels-address-lifetime` | | [2026-10-11-coresearch-labels-address-lifetime.md](2026-10-11-coresearch-labels-address-lifetime.md) | | 2026-10-11 | `coresearch-instance-authz` | | [2026-10-11-coresearch-instance-authz.md](2026-10-11-coresearch-instance-authz.md) | | 2026-10-10 | `D-XGP-8` | | [2026-10-10-woa-anchors-timesheet.md](2026-10-10-woa-anchors-timesheet.md) | | 2026-10-10 | `D-HPR-0` | | [2026-10-10-v3-mandatory-hotplug-reading.md](2026-10-10-v3-mandatory-hotplug-reading.md) | diff --git a/.claude/plans/v3-mandatory-hotplug-reading-v1.md b/.claude/plans/v3-mandatory-hotplug-reading-v1.md index 11d86cf64..b5e40c3f8 100644 --- a/.claude/plans/v3-mandatory-hotplug-reading-v1.md +++ b/.claude/plans/v3-mandatory-hotplug-reading-v1.md @@ -22,7 +22,7 @@ What it means, in rules: **The plug path already exists.** `lance-graph-ogar::plug_readings` (`lib.rs:452`) gives every plugged concept `ReadMode::PLUG_AND_PLAY_V3` unless `concept_override` (`lib.rs:477`) names an exception. `Activation::read_mode_for` fails closed (`NoReadingFor`), never defaulting. -**The second path that must go:** `canonical_node::classid_read_mode(classid)` (`canonical_node.rs:1813`) looks the full `u32` up in `BUILTIN_READ_MODES` (`:1743`). It has two faults: +**The second path, which stops selecting new readings** (⊘ the heading read "The second path that must go", which contradicts rule 5; regraded 2026-10-11 — the path stays as the reader of stored legacy keys, it stops being where a NEW reading comes from): `canonical_node::classid_read_mode(classid)` (`canonical_node.rs:1850`; `:1813` when written) looks the full `u32` up in `BUILTIN_READ_MODES` (`:1773`; was `:1743`). It has two faults: - the V3 reading is chosen by the `0x1000` marker in the classview bits (the `*_V3` keys); - an unknown classid falls through to `ReadMode::DEFAULT`, which is a **V1** tail. That is exactly the silent V1 fallback the 2026-09-07 ruling forbade on the plug path. @@ -55,16 +55,26 @@ What it means, in rules: - [x] **W2 — D-HPR-2: the canon domains get their reading from the authority.** The domain value models (`OSINT`/`PROJECT`/`ERP` Cognitive, `FMA`/`CPIC` Compressed) move into `concept_override`, keyed by concept, all on a V3 tail. `OgarAuthority` then answers for those concepts with no classview involved. - **Shipped:** `lance-graph-ogar::concept_override` arms `0x0701`/`0x0A01`/`0x0E01`/`0x0101`/`0x0202` → `ReadMode::{OSINT,FMA,CPIC,PROJECT,ERP}_V3`. Test `canon_domains_read_from_the_plug_as_the_classid_table_reads_them` pins each equal to `classid_read_mode(CLASSID_*_V3)`; red with an arm removed. No consumer plugs these concepts today (`grep` of every `HotPlug` in lance-graph, OGAR, MedCare-rs, q2, odoo-rs, openproject-nexgen-rs, HubSPO-rs, spear), so no live reading changes. - Falsifier: `read_mode_for(concept)` equals today's `classid_read_mode()` for each canon domain, so the move changes no reading. -- [ ] **W3 — D-HPR-3: consumers move.** lance-graph callcenter / deepnsm-v2 / probes, then q2 osint-bake + geo, MedCare cohorts. Each takes its reading from its `Activation`. Then `classid_read_mode` gets `#[deprecated]`. +- [ ] **W3 — D-HPR-3: consumers move.** lance-graph callcenter / deepnsm-v2 / probes, then q2 osint-bake + geo, MedCare cohorts. Each takes its reading from its `Activation`. ⊘ "Then `classid_read_mode` gets `#[deprecated]`" is struck: W4 and rule 5 rule the attribute out (it fails every caller under `-D warnings`). + - **Census 2026-10-11 (synergy ledger):** MedCare has 0 callers. q2's callers are offline bake mints on `CLASSID_FMA_V3`, which can take the reading when next touched. deepnsm-v2 `promote::key_at` is blocked on a concept mint (its corpus has no OGAR concept), not on code. q2 geo (`osm_node` 0x0F01) cannot get a plug reading at all: the reading is gated behind the geo capability table, which expects `osm-soa-bake`. The geo and deepnsm cases need the rule "reading is not a capability" (O3). - [x] **W4 — D-HPR-4: document the fossils as deprecated.** Done in `lance-graph-contract`: the five `CLASSID_*_V3` constants and `classid_read_mode` carry a "Deprecated, kept" doc note. A doc note, not `#[deprecated]`: the attribute would turn every existing caller red under `-D warnings`, which is the forced migration the ruling rules out. OGAR (`ogar-osm` `CLASSVIEW_V3_SUBSTRATE`, ro, dismech, loco) and q2 `geo` get the same note when next touched; existing mints stay. - [ ] **W5 — D-HPR-5: legacy reads stay.** Stored `0x1000` and pre-flip keys keep resolving through `BUILTIN_READ_MODES`; no forced removal. A slab may additionally declare its reading (`SlabDeclaration`), which wins for its own data. Removing a table key is optional and only after nothing reads it. + - Holds today. **Caveat (2026-10-11):** a `SlabDeclaration` overrides `value_schema` and the register reading only, never the key tail (`hotplug.rs:231-257`, `:392`). It cannot protect a V1/V2-tail slab. q2's `osint_scene.soa` is one: V2 tails under a classid whose builtin reading is V1. It is read by its own projection and must not be re-read through the table. - [ ] **W6 — D-HPR-6: V1 cannot be reached by default.** `ReadMode::DEFAULT` stops being the fallback for an unknown classid (it becomes `NoReadingFor`, as on the plug path), and `guid-v3-tail` stops being a feature gate. + - Split (2026-10-11). **W6a**: un-gate `guid-v3-tail`. It is default-on and no fleet consumer disables it, so only `--no-default-features` builds change; there the 5 V3 fossils read `DEFAULT` today (coresearch probe P-X3). **W6b**: an unknown classid errors. This is a behaviour change, and both q2 and MedCare have already hit the V1 default once, so it needs operator approval. ## Open questions (operator) - **O1.** What classview should a NEW mint of a canon domain use instead of `0x1000`: `0x0000` (shared canonical core), or an app-owned value? Not blocking: existing mints keep `0x1000`. - **O2.** Does WoA's `ogit.WorkOrder:TimeSheet` resolve to `0x0103`, with "Stundenzettel" as its label, instead of today's `TimesheetActivity` (plan `cross-glove-business-parity-v1.md` §C.9.5)? Rule 4 settles that the German name is a label; it does not settle which WoA row the label names. +- **O3 (2026-10-11).** Since W2, `concept_override` keys storage readings by **concept** (`0x0101` → `PROJECT_V3`, `0x0202` → `ERP_V3`, `0x0A01` → `FMA_V3`). Those three u16s are also code-minted consumer appid heads (OpenProject, Odoo, q2). So any consumer that plugs `commercial_document` (aliased by the WoA, SMB, Odoo and HubSpo ports) gets the ERP storage reading, not `PLUG_AND_PLAY_V3`. This is latent: no plug names these concepts today. Options: + - (a) key storage readings by a consumer-owned value; + - (b) move the heads off occupied concept slots; + - (c) document that plugging these concepts means that domain's storage model. + + Related: should a plug that asks only for a reading (`covered` empty) succeed for a concept that has a capability table? It would unblock the SAP/Odoo `0x0103` plugs, q2 geo and deepnsm-v2. Record: `entries/2026-10-11-coresearch-labels-address-lifetime.md` (X6), `entries/2026-10-11-synergy-ledger-classid-hotplug.md`. + ## What this plan does not do - It does not re-key stored data. Rule 5 keeps old keys readable.