Skip to content

Commit dd46ad2

Browse files
committed
Board discipline: hot-plug consumer-migration doc + E-HOTPLUG-MIGRATION-1 ruling
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016b33swuXE23hKtqxsHu9p1
1 parent d72c46f commit dd46ad2

2 files changed

Lines changed: 141 additions & 0 deletions

File tree

.claude/board/EPIPHANIES.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 2026-07-07 — E-HOTPLUG-MIGRATION-1 — the generic hot-plug pattern is the migration target for ALL consumers; migration doc is board discipline
2+
**Status:** RULING (operator, 2026-07-07; shipped OGAR #174/#175 + lance-graph #658 + tesseract-rs #13/#14)
3+
4+
**Every consumer migrates onto the generic hot-plug pattern** — one `HOT_PLUG` const (socket type `lance_graph_contract::hotplug::HotPlug`) + one activation test against `ogar_vocab::capability_registry::resolve_hotplug`; the consumer tells OGAR which classids are hot-plugged and receives BOTH the vocab rows and the action surface. No bespoke per-consumer plug crates, no git pins (sibling path deps only), no ontology payload in lance-graph, contract stays zero-dep (member path deps kill CI workspace load — burned once), classid low u16 = APP prefix, never a shape ordinal.
5+
6+
**Board discipline:** `.claude/knowledge/hotplug-consumer-migration.md` (mirrored in OGAR `.claude/knowledge/`) is MANDATORY READING before (a) migrating any consumer onto the capability surface, (b) adding a new authoritative domain table (thinking-styles next), (c) any cross-repo capability wiring. It carries the 5-step recipe, the 5 drift arms, the burned-once anti-pattern list, and the evaluated ruff synergies (ActionDef lift via `ogar-from-ruff::lift_actions` + a future C++ arm; `walk_enums` param fidelity; ontology plug-and-play over the exports→OGIT→imports tier; thinking-styles as a one-entry `domain_tables()` addition).
7+
18
## 2026-07-07 — E-OCR-FACET-HOME-CORRECTION-1 — operator ruling: domain substrate does NOT live in agnostic lance-graph — textord facets removed; the facet producer is ruff→OGAR
29
**Status:** RULING (operator-corrected same day; code removed in this commit)
310

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Hot-Plug Consumer Migration — the generic plug-and-play pattern
2+
3+
> READ BY: any session migrating a consumer (woa-rs, medcare-rs,
4+
> smb-office-rs, odoo-rs, tesseract-rs, osm-website-rs, …) onto the
5+
> OGAR-authoritative capability surface; any session adding a new
6+
> authoritative domain table (thinking-styles best practices, …);
7+
> integration-lead / baton-handoff-auditor before any cross-repo
8+
> capability wiring.
9+
>
10+
> Shipped 2026-07-07 (operator-ruled same day). Reference PRs:
11+
> OGAR #174 (ocr_actions) + #175 (resolve_hotplug), lance-graph #658
12+
> (hotplug socket + OgarAuthority + CI fuse gate), tesseract-rs #13/#14
13+
> (executor + HOT_PLUG migration — the template consumer).
14+
15+
## The model — three roles, three homes, one binary
16+
17+
Everything links into ONE binary (lance-graph + OGAR + consumer +
18+
ndarray). Nothing serializes; every check is a compile-time const or a
19+
test in the consumer's own suite. "Wenn's knallt, dann einmal — nicht
20+
200 Pins monitoren."
21+
22+
| Role | Home | Surface |
23+
|---|---|---|
24+
| **SOCKET** (agnostic, zero-dep) | `lance_graph_contract::hotplug` | `HotPlug { consumer, classids, covered }`, `Activation`, `ActivationDrift`, trait `CapabilityAuthority` |
25+
| **AUTHORITY** (declares + resolves) | OGAR `ogar_vocab` | domain action tables (e.g. `ocr_actions`) + `capability_registry::{domain_tables, resolve_hotplug, HotplugDrift}` |
26+
| **BRIDGE** (socket ⇄ authority) | `lance-graph-ogar` (workspace-EXCLUDED) | `OgarAuthority: CapabilityAuthority`; also owns COUNT_FUSE + per-entry mirror parity + the roundtrip green light |
27+
| **CONSUMER** | your repo | ONE `HOT_PLUG` const + ONE activation test + your executor |
28+
29+
The classid is the join key on BOTH sides: the consumer says "these
30+
canon-high ids are hot", the authority returns BOTH the vocab rows and
31+
every capability whose subject is one of those ids.
32+
33+
## Migration recipe (per consumer, ~1 hour)
34+
35+
1. **Authority side (OGAR PR #1):** declare your domain's action table
36+
in `ogar-vocab` next to `ocr_actions` — one `ActionDef` per
37+
capability on YOUR already-minted canon-high concepts (mint via the
38+
normal codebook process if missing; hi u16 = concept, lo u16 = APP
39+
render prefix, NEVER a shape ordinal). Export `<DOMAIN>_ACTION_NAMES`
40+
(const fingerprint), `<DOMAIN>_SUBJECT_CLASSIDS`,
41+
`<DOMAIN>_EXPECTED_EXECUTORS = ["<your-crate>"]`. Register ONE entry
42+
in `capability_registry::domain_tables()` mapping
43+
`(capability, subject classid)`. That's the whole authority change.
44+
2. **Consumer side:** add path deps (NO PINS — local siblings):
45+
`ogar-vocab = { path = "<rel>/OGAR/crates/ogar-vocab" }` and
46+
`lance-graph-contract = { path = "<rel>/lance-graph/crates/lance-graph-contract" }`.
47+
3. Declare the plug:
48+
```rust
49+
pub const HOT_PLUG: lance_graph_contract::hotplug::HotPlug =
50+
lance_graph_contract::hotplug::HotPlug {
51+
consumer: "<your-crate>",
52+
classids: ogar_vocab::<domain>_actions::<DOMAIN>_SUBJECT_CLASSIDS,
53+
covered: COVERED_CAPABILITIES, // your executor's arms
54+
};
55+
```
56+
4. Close the loop with ONE test:
57+
```rust
58+
let (concepts, capabilities) = ogar_vocab::capability_registry::resolve_hotplug(
59+
HOT_PLUG.consumer, HOT_PLUG.classids, HOT_PLUG.covered,
60+
).expect("hot-plug drifted from the authoritative OGAR tables");
61+
```
62+
(Or through the socket: `OgarAuthority.activate(&HOT_PLUG)` via
63+
`dyn CapabilityAuthority` when you want authority-agnostic code.)
64+
5. **CI:** your workflows need the sibling checkouts (OGAR +
65+
lance-graph), same as tesseract-rs `rust.yml` / lance-graph
66+
`rust-test.yml`. Sibling layout: check the repo out into a subdir
67+
(`path: <repo>`) so `path: OGAR` lands as a true sibling.
68+
69+
## The drift arms (each one named bang, test-time, in YOUR binary)
70+
71+
| Arm | Meaning |
72+
|---|---|
73+
| `UnknownClassid(id)` | plugged id not minted in the codebook |
74+
| `NoCapabilitiesFor(id)` | id resolves to no capability — the table/ontology was forgotten |
75+
| `UnexpectedConsumer` | you are not in the table's expected-executor list |
76+
| `Uncovered(cap)` | authority declares it, your executor has no arm |
77+
| `Undeclared(cap)` | your executor claims it, authority doesn't declare it |
78+
79+
Plus, CI-side (lance-graph `rust-test.yml`): COUNT_FUSE + per-entry
80+
mirror parity + the roundtrip green light run against the real OGAR
81+
sibling on every push.
82+
83+
## What NOT to do (each burned once, 2026-07-07)
84+
85+
- **No bespoke per-consumer plug crate/mechanism.** The registration
86+
surface is the `HOT_PLUG` const + one test. (tesseract-ogar's first
87+
`CapabilityRegistration` draft was replaced for exactly this.)
88+
- **No path/optional deps on `lance-graph-contract` toward OGAR.** The
89+
contract is a workspace MEMBER; any path dep there (even optional) is
90+
resolved at workspace-load time and kills every CI cargo invocation.
91+
The contract stays zero-dep; armed things live in excluded crates.
92+
- **No shape ordinals in the classid low u16.** Low half = APP render
93+
prefix (`PortSpec::APP_PREFIX`). Distinct shapes are distinct hi-u16
94+
concepts or ClassView payload readings.
95+
- **No ontology payload in lance-graph.** lance-graph carries the wire
96+
mirror + the green light, nothing else. Authority checks live in OGAR.
97+
- **No git deps on OGAR.** git+branch always writes a rev pin into
98+
Cargo.lock. Path deps to the sibling, always.
99+
100+
## Future synergies (evaluated 2026-07-07 — next arcs, not shipped)
101+
102+
1. **ActionDef plug-and-play from ruff (HIGH, near-term).**
103+
`ogar-from-ruff::lift_actions` already lifts ActionDefs from
104+
Rails/Python model graphs — the OCR table is hand-declared only
105+
because tesseract has no AR source. The generic path: ruff harvest
106+
(`ruff_*_spo`) → fuzzy-recipe codebook (`(verb, criteria)` recipes,
107+
ruff `.claude/knowledge/fuzzy-recipe-codebook.md`) → `lift_actions`
108+
the domain table auto-derives instead of being hand-written; a
109+
consumer migration then starts with a harvest, not an authorship
110+
session. Missing piece: a C++ arm for `lift_actions` (ruff_cpp_spo
111+
has walk_tu/walk_free_functions/walk_enums; an action-lift over the
112+
method-body facts is the natural fourth arm) and a
113+
`derive_domain_table!`-style bridge from lifted ActionDefs into
114+
`domain_tables()`.
115+
2. **Param-enum fidelity via `walk_enums` (MEDIUM).** Capability params
116+
that are C/C++ enums (PSM modes, connectivity 4/8, …) can carry
117+
their variants from the ruff enum harvest instead of free-form
118+
names — the same shapes-from-ruff discipline the dawg/dict arc used.
119+
3. **Ontology plug-and-play (MEDIUM, design needed).** Today
120+
`resolve_hotplug` returns vocab rows + capability names. The same
121+
join can return ONTOLOGY fragments per classid: OGAR's
122+
`vocab/exports → OGIT promote → vocab/imports` pipeline already
123+
stages TTL per domain, and `ogar-adapter-ttl` renders it. A
124+
`resolve_hotplug_with_ontology` returning the OGIT NTO fragment
125+
references for the plugged classids would let a consumer pull
126+
concepts + actions + ontology in one activation — still zero
127+
serialization in-binary; the TTL stays an OGAR-internal artifact
128+
(imports/ tier), never hauled through lance-graph. Gate: needs the
129+
imports/ tier populated for the domain (ontologies, not harvests —
130+
harvests stay in the consumer repo).
131+
4. **Thinking-styles best practices (HIGH, planned all along).** One
132+
`domain_tables()` entry + a `<STYLES>_EXPECTED_EXECUTORS` list arms
133+
the thinking-style table for whichever engine executes styles —
134+
same recipe as step 1 above, zero new machinery.

0 commit comments

Comments
 (0)