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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .claude/board/INTEGRATION_PLANS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 2026-10-11 — concept-labels-hotplug-v1 — labels of a concept, pulled through the plug → `.claude/plans/concept-labels-hotplug-v1.md`

**Status:** ACTIVE (D-LBL-0..5). Operator DECISION 2026-10-11: labels are ontology data in `ogar-vocab`, pulled through `hotplug.rs` only for plugged concepts; every language now, a non-breaking per-consumer spec later; customer binaries activate at build time; `0x0103` German preferred "Zeiterfassung".

- Rows `(concept u16, BCP-47 tag, role, text)`, a concept × language `LazyLock` index, `Activation::with_labels` (additive, like `with_register_laws`).
- Carries two corrections: the source-id mapping lives in the consumer's plug, not in OGAR port tables; capabilities carry no consumer list.

## 2026-10-10 (2) — v3-mandatory-hotplug-reading-v1 — the reading comes from the plug, never from the classid value → `.claude/plans/v3-mandatory-hotplug-reading-v1.md`

**Status:** ACTIVE (D-HPR-0..6). Operator DECISION 2026-10-10: V3 mandatory, hotplug.rs + OGAR plug-and-play is the only reading path, lockstep deprecated, concepts are immutable addresses and language names are labels.
Expand Down
17 changes: 16 additions & 1 deletion .claude/board/STATUS_BOARD.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## D-LBL — labels of a concept, pulled through the plug (2026-10-11)

Plan: `.claude/plans/concept-labels-hotplug-v1.md`.

| D-id | Deliverable | Status | Gate |
|---|---|---|---|
| **D-LBL-0** | Decision record, board rows, corrections (mapping in the consumer plug; no executor lists) | In PR | — |
| **D-LBL-1** | `ogar-vocab` label rows + concept × language `LazyLock` index; seed `0x0103` (de pref Zeiterfassung, de alt Stundenzettel) | Queued (OGAR PR) | one preferred per (concept, tag); roles disjoint; concept in `CODEBOOK` |
| **D-LBL-2** | `Activation::with_labels` + `label()` / `alt_labels()`; `OgarAuthority::activate` fills plugged concepts only | Queued | unplugged concept's labels absent; missing language → `None` |
| **D-LBL-3** | Build-time activation for customer binaries (generated constants, labels included) | Queued | the binary links only `lance-graph-contract` |
| **D-LBL-4** | Per-consumer `LabelSpec` + default `activate_with_labels` (non-breaking) | Queued (when a volume problem is measured) | `activate()` output unchanged; spec `["de"]` yields no `en` rows |
| **D-LBL-5** | TTL reader keeps language tags (`ogar-from-schema`) | Queued | a tagged `rdfs:label` reaches the label rows with its tag |

## D-HPR — V3 mandatory; reading from the plug only (2026-10-10)

Plan: `.claude/plans/v3-mandatory-hotplug-reading-v1.md`.
Expand All @@ -10,7 +23,9 @@ Plan: `.claude/plans/v3-mandatory-hotplug-reading-v1.md`.
| **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-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. Decided 2026-10-11: go, staged after 6a, D-HPR-3 and a stored-classid check | unknown classid → `NoReadingFor` |
| **D-HPR-7** | Storage readings leave the concept key: out of `concept_override`, into the slab's `SlabDeclaration` or the owning consumer's plug (O3, decided (a) 2026-10-11) | Queued | a non-Odoo plug of `0x0202` reads `PLUG_AND_PLAY_V3`; Odoo's slab still reads `ERP_V3` |
| **D-HPR-8** | A plug that asks only for a reading succeeds (reading is not a capability; decided 2026-10-11) | Queued | `[0x0103]` with `covered: &[]` → `Ok`, `PLUG_AND_PLAY_V3`; with a covered capability → refused as today |

## D-XGP — Cross-glove business parity: Odoo × SAP over one Quack algebra (2026-10-10)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
**Status:** OPEN — exploration map. It ratifies nothing; the operator chooses.
Plan context: `v3-mandatory-hotplug-reading-v1.md` rules 3–5, O1, O2.

> **⊘ Corrected 2026-10-11 (operator decisions, plan `concept-labels-hotplug-v1.md`).**
> - Shape piece 2 ("`PortSpec` is the mapping set") and the X14 / X17 / X18 verdicts
> "ADOPT in `PortSpec` / OGAR" are superseded. Port alias tables are lockstep tables,
> deprecated and kept. The source-id → concept mapping lives in the consumer's own `HotPlug`.
> - Shape piece 3 and the "Label home" open point are decided. Labels live in `ogar-vocab`.
> A consumer pulls them through `hotplug.rs` only for the concepts it plugs (concept ×
> language `LazyLock` index). Every language comes now; a non-breaking per-consumer spec
> comes later.
> - O2's label half is decided: `0x0103` has German preferred "Zeiterfassung" and German
> alternate "Stundenzettel".

## The question, after the premise audit

The draft asked where "Stundenzettel / TimeSheet / Zeiterfassung" live as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ adversarial re-reader per scout checked every item against its cited lines:
completeness critic was not run (stopped to save tokens), so the ranking below
is the main thread's.

> **⊘ Corrected 2026-10-11 (operator, plan `concept-labels-hotplug-v1.md`):** capabilities on a
> concept carry no list of consumers. Each consumer's plug declares what it covers, and the
> expected-executors check in OGAR's `resolve_hotplug` is a lockstep residue to deprecate.
> The executor-list framing of `ogar-p18-capability-table-0x0103` and
> `odoo-capability-0x0103-consumer-tension` is superseded.

## Leverage ranking (open items)

**Low fruit (hours, no operator needed):**
Expand Down
105 changes: 105 additions & 0 deletions .claude/plans/concept-labels-hotplug-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# concept-labels-hotplug-v1 — labels of a concept, pulled through the plug

**Status:** ACTIVE (D-LBL-0..5). DECISION by the operator, 2026-10-11. W0 (this record) lands first; W1 onward are code.

## The decisions (operator, 2026-10-11, verbatim)

> "Labels live in ogar-vocab pulled via hotplug.rs from the consumers. No need to keep labels for hundreds of consumers hot when it's separation of concerns that the plug and play pattern enables the consumers to activate the label distribution via ogar-vocab"

> "lean (a) now, with (b) when a real volume problem shows up. if you can make multilingual no breaking plan option per consumer in the board. Consumers mint the specs and Concept x language lazylock would make it cheap"

> Customer binaries activate at "build time". The German preferred label of `0x0103` is "Zeiterfassung".

What it means, in rules:

1. **Labels are ontology data in `ogar-vocab`.** OGAR is the only writer. No consumer is ever listed in the label data, so it is not a lockstep table.
2. **A consumer gets labels only for the concepts it plugs**, through `hotplug.rs`, the same way it gets readings. Nothing keeps every label hot for every consumer.
3. **Now:** an activation carries every language of each plugged concept. `HotPlug` does not change.
4. **Later (when a volume problem is measured):** a consumer selects languages through a spec it mints itself. This must not break any existing consumer (D-LBL-4).
5. **Customer binaries activate at build time.** The build emits a static activation, labels included. No OGAR link at runtime (BBB barrier).
6. **`0x0103`:** German preferred "Zeiterfassung", German alternate "Stundenzettel".

## Shape

**Rows (`ogar-vocab`).** One row per label: `(concept u16, BCP-47 tag, role, text)`, role ∈ {preferred, alternate, hidden}. Invariants, each a test:

- at most one preferred row per (concept, tag);
- the three roles are disjoint per (concept, tag);
- every concept exists in `CODEBOOK`;
- an absent language has no row. A lookup never copies another language into it.

**Index.** `static LABELS: LazyLock<HashMap<(u16, LangTag), LabelSet>>` is built once from the rows: concept × language. Filling an activation costs one lookup per plugged concept and language, independent of how many labels exist in total.

**Activation (contract, additive).** `Activation` is built only through `Activation::new(..)`. No sibling repo constructs it, and `with_register_laws(..)` already shows the additive builder pattern. Labels follow that pattern:

- `Activation::with_labels(..)` builder; `OgarAuthority::activate` fills it for `plug.classids`;
- `Activation::label(concept, &["de-AT", "de", "en"]) -> Option<&str>` returns the preferred label;
- `Activation::alt_labels(concept, lang)` returns the alternates;
- the caller passes its own language priority. The lookup walks it and returns `None` when no requested language exists, never another language.

**App-specific and private labels** stay in the consumer's own ClassView or overlay, never in `ogar-vocab`. A private repository's wording never reaches a public crate.

## D-LBL-4 — per-consumer languages, non-breaking

The consumer mints its spec beside its `HOT_PLUG`, in its own crate:

```rust
pub const LABEL_SPEC: LabelSpec = LabelSpec {
consumer: "<crate>", // must equal HOT_PLUG.consumer
languages: &["de", "en"], // BCP-47 tags
roles: LabelRoles::PREFERRED_AND_ALTERNATE,
};
```

The authority gains a **default** trait method, so every existing authority keeps compiling:

```rust
fn activate_with_labels(&self, plug: &HotPlug, spec: &LabelSpec)
-> Result<Activation, ActivationDrift>
{
// default: activate(plug), then keep only spec.languages × spec.roles
}
```

- `activate(&HOT_PLUG)` keeps returning every language, so no existing caller changes behaviour.
- Filtering reads the concept × language index directly: one lookup per plugged concept and requested language.
- A tag with no rows is not an error; it yields no labels for that tag.
- `spec.consumer` must equal `plug.consumer`.
- Nothing in `ogar-vocab` lists consumers or specs. The spec lives in the consumer.

## Build-time activation (D-LBL-3)

- A customer binary's build step calls the authority and emits the activation as generated Rust constants: concepts, capabilities, readings and labels.
- The binary links only `lance-graph-contract`. Spine and test binaries may still activate at runtime.
- The generated constants also record which label set shipped.

## Waves

- [ ] **W0 — D-LBL-0: record.** This plan, `INTEGRATION_PLANS.md`, `STATUS_BOARD.md`, and the corrections below.
- [ ] **W1 — D-LBL-1: label rows + index in `ogar-vocab`** (OGAR PR). Seed `0x0103`: de preferred "Zeiterfassung", de alternate "Stundenzettel"; en preferred from the canonical name. Then the other German words the 2026-10-11 census found (`0x0202`, `0x0203`, `0x0204`, `0x0205`). Invariant tests above.
- [ ] **W2 — D-LBL-2: `Activation::with_labels` + `label()`;** `OgarAuthority::activate` fills labels for plugged concepts.
- [ ] **W3 — D-LBL-3: build-time activation** for customer binaries.
- [ ] **W4 — D-LBL-4: `LabelSpec` + default `activate_with_labels`,** when a volume problem is measured.
- [ ] **W5 — D-LBL-5: the TTL reader keeps language tags** (`ogar-from-schema` keeps only the first `rdfs:label` and drops the tag today). This feeds W1 from OGIT once OGIT carries tagged labels.

## Falsifiers

- **It fires:** a plug of `[0x0103]` gives `label(0x0103, &["de"]) == Some("Zeiterfassung")`, and the German alternates contain "Stundenzettel".
- **It stays silent:**
- an unplugged concept's labels (`0x0202`) are absent from that activation;
- `label(c, &["fr"])` is `None` when no French row exists, never the English one.
- **Invariants:** two preferred rows for one (concept, tag) turn the test red; a row naming a concept absent from `CODEBOOK` turns it red.
- **D-LBL-4:** a spec of `["de"]` yields no English rows; `activate()` without a spec returns exactly what it returned before the change.

## Corrections carried by this record (operator, 2026-10-11)

> "'WoA's port row' suggests that deprecated lockstep instead of hotplug.rs is used"

- **The mapping lives in the consumer's plug, not in OGAR's port tables.** WoA's `HotPlug` declares `0x0103` for its `TimeSheet` (a close match, owned by WoA). `WOA_ALIASES` and the other `PortSpec` alias tables are lockstep tables: deprecated, kept. This supersedes, in `entries/2026-10-11-coresearch-labels-address-lifetime.md`, shape piece 2 ("`PortSpec` is the mapping set") and the X14 / X17 / X18 verdicts "ADOPT in `PortSpec` / OGAR".
- **Capabilities.** The concept declares its capabilities; each consumer's plug declares which it covers. No list of consumers exists. The expected-executors check in OGAR's `resolve_hotplug` (`UnexpectedConsumer`) is a lockstep residue to deprecate. This supersedes the executor-list framing of `ogar-p18-capability-table-0x0103` in `entries/2026-10-11-synergy-ledger-classid-hotplug.md`.

## Decided with this record (operator, 2026-10-11: "Recommended accepted")

- The three colliding u16s: storage readings leave the concept key (`v3-mandatory-hotplug-reading-v1` W7, D-HPR-7).
- A plug that asks only for a reading succeeds; reading is not a capability (W8, D-HPR-8).
- D-HPR-6b goes ahead, staged after W6a, W3 and a stored-classid check.
7 changes: 5 additions & 2 deletions .claude/plans/v3-mandatory-hotplug-reading-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,21 @@ What it means, in rules:
- 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.
- **Decided (operator, 2026-10-11: "Recommended accepted"): go, staged.** 1. W6a. 2. W3 moves the remaining mint paths onto plug readings. 3. A check that every stored artifact's classid resolves. 4. Only then W6b.
- [ ] **W7 — D-HPR-7: storage readings leave the concept key** (O3, decided (a)). The five domain storage readings move out of `concept_override` (keyed by concept) into the slab's `SlabDeclaration` or the owning consumer's plug. A consumer plugging a shared concept then reads `PLUG_AND_PLAY_V3`. Falsifier: a plug of `0x0202` by a non-Odoo consumer reads `PLUG_AND_PLAY_V3`, and Odoo's own slab still reads `ERP_V3`.
- [ ] **W8 — D-HPR-8: a plug that asks only for a reading succeeds** (decided). Reading is not a capability. A plug with `covered` empty gets readings only, also for a concept that has a capability table. A plug that names a capability still needs the table. Falsifier: `[0x0103]` with `covered: &[]` → `Ok` and `read_mode_for(0x0103) == PLUG_AND_PLAY_V3`; with `covered: &["anything"]` → refused as today.

## 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:
- **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. **Decided 2026-10-11: (a)** → W7 (D-HPR-7). Options were:
- (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`.
Related, **decided 2026-10-11: yes** → W8 (D-HPR-8). The question was: 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

Expand Down
Loading