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
71 changes: 71 additions & 0 deletions .claude/board/EPIPHANIES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,74 @@
## 2026-09-07 — E-PLUG-AND-PLAY-IS-THE-DECLARATION-NOT-A-TABLE-1 — my fix rebuilt the lockstep it was closing

**Status:** FINDING, measured. Fixed in this PR (7 tests, both guards disable-verified).
**Confidence:** High — the failure mode is demonstrated by a test that goes red when the scoping is restored.

**Operator ruling (2026-09-07):** *"plug and play already has all the domains,
you could simply make the global schema for all appids already in plug-and-play
pattern activate V3 and be silent about all others… local quad usage must mint
any V3 settings in plug and play, regardless of the settings here… otherwise I
will spend weeks until I remember that we changed it here wondering why quad
4x24 stopped working."*

**The finding, and it is about my own two prior fixes.**
`D-BLOCKS-HOTPLUG-1` retired a central `BUILTIN_READ_MODES` row per consumer
because adding a frontend must not mean editing the substrate. The seam I built
to replace it held **`const LOCO_READ_MODES` — one hard-coded row per consumer
seat** (`0x1717` alone), answered only when the plug covered every declared
seat, and returned `&[]` otherwise. **That is the same central table, relocated
one level up.** Adding a frontend meant adding a row; every consumer outside
`0x17XX` got no reading at all.

**Why that is worse than it sounds.** Both failures are silent AND remote. A
missing row does not break a build — it surfaces much later as a V1 tail where
V3 was expected. The quad (`LegacyOutlier::WideTriple`, G2 `4 × u24`) is a
carving of the 12-byte content-blind payload, which exists as such only under a
V3 tail; so "somebody scoped the reading in lance-graph" and "quad 4×24 stopped
working in medcare-rs" are the same event, weeks and one repo apart, with no
mechanical link between them.

**The `&'static` decision was the root cause, and it was mine.** I typed
`Activation::read_modes` as `&'static` and argued it as "plug-and-play at
COMPILE time: a reading is looked up, not computed". The consequence I did not
weigh: a `&'static` table cannot be built per plug, so the authority can only
return a table it holds ALL of — which forces all-or-nothing, which forces a
per-seat table. **An aesthetic constraint on a type silently dictated the
architecture underneath it.** Now owned (`Vec`), so the authority answers for
exactly the ids a plug declared.

**The rule now: being plugged in IS the declaration.** Every classid in a plug
gets [`ReadMode::PLUG_AND_PLAY_V3`] (V3 tail; `DEFAULT` stays V1 as the canon
zero-fallback for classes nobody plugged, and is unreachable from a hot-plug
lookup). `concept_override` remains for genuine per-class deviations — blockly's
seat reads `Bootstrap` because it stores an `ogar-loco` body, not cognitive
tenants — and it is *a short list of exceptions, not a roster of participants*:
a consumer absent from it is not absent from plug-and-play. The asymmetry is
the point — a forgotten entry means "no override", never "no reading".

**The ownership guard survived the rewrite, but only because it was checked.**
Deriving readings from the plug initially dropped the consumer check codex
flagged on #1207, so an impostor could have activated blockly's seat. Restored
as `palette_seat_owner`: a CLAIMED seat is its owner's; an UNCLAIMED one is
plug-and-play for whoever plugs it. A new frontend at `0x1718` activates and
reads V3 with no edit here — which is the ruling — while `0x1717` stays
blockly's.

**Falsifiers, both disable-verified.** Restoring the palette-only scoping turns
`a_capability_consumer_outside_the_loco_domain_also_reads_v3` (a MedCare-shaped
plug of `0x0901`/`0x0902`) red; dropping the impersonation guard turns
`another_consumer_cannot_activate_a_claimed_seat` red. The silence twin,
`an_unplugged_concept_is_silent_not_v3`, holds the other end: "V3 for all
plugged appids" must not become "V3 for everything".

**Process note worth more than the fix.** The first run of disable 1 PASSED and
I nearly recorded the guard as non-load-bearing. `cargo fmt` had reflowed the
closure I was patching, so my `replace()` matched nothing and the disable was a
no-op — the code under test never changed. The re-run asserts the anchor exists
before writing. **A disable that does not apply is indistinguishable from a
guard that does not matter**, and this is the second time this session that a
disable silently failed to disable (the first: zeroing a constant whose guarded
quantity could go negative).

## 2026-09-07 — E-A-DOC-COMMENT-IS-NOT-A-FAIL-CLOSED-MECHANISM-1 — hotplug could still land on V1 with a one-liner

**Status:** FINDING, measured. Fixed in this PR (2 tests, disable-verified).
Expand Down
28 changes: 28 additions & 0 deletions crates/lance-graph-contract/src/canonical_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,34 @@ impl ReadMode {
edge_codec: EdgeCodecFlavor::CoarseOnly,
};

/// The **plug-and-play** reading: what any hot-plugged appid reads as,
/// unless its authority declares an override.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
///
/// Operator, 2026-09-07: *"plug and play already has all the domains, you
/// could simply make the global schema for all appids already in
/// plug-and-play pattern activate V3 and be silent about all others"* —
/// and *"local quad usage must mint any V3 settings in plug and play,
/// regardless of the settings here."*
///
/// **V3 is the answer for being plugged in at all, not for being listed
/// somewhere.** The alternative — a per-seat table in the authority with
/// one row per consumer — is the central lockstep `D-BLOCKS-HOTPLUG-1`
/// retired, rebuilt one level up: adding a frontend would again mean
/// editing a shared table, and a consumer whose row was missing would
/// silently lose its V3 tail *at a distance*, weeks from the edit that
/// caused it. That is the footgun this constant exists to remove.
///
/// Differs from [`DEFAULT`](ReadMode::DEFAULT) in exactly one field —
/// the tail — because that is the field the ruling is about. `DEFAULT`
/// stays V1: it is the canon zero-fallback for a class nobody plugged,
/// and it is NOT reachable from a hot-plug lookup (an unplugged concept
/// yields `NoReadingFor`, never a defaulted reading).
pub const PLUG_AND_PLAY_V3: ReadMode = ReadMode {
tail_variant: TailVariant::V3,
value_schema: ValueSchema::Full,
edge_codec: EdgeCodecFlavor::CoarseOnly,
};

/// The **OSINT / Palantir-Gotham** read-mode ([`NodeGuid::CLASSID_OSINT`]):
/// a *hot* entity graph — [`ValueSchema::Cognitive`] (Meta + Qualia +
/// Fingerprint + Energy + Plasticity + EntityType, for live NARS reasoning)
Expand Down
40 changes: 22 additions & 18 deletions crates/lance-graph-contract/src/hotplug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,22 @@ pub struct Activation {
/// authority handed it — never by asking the canon registry about a class
/// the canon does not own.
///
/// **`&'static` on purpose — this is plug-and-play at COMPILE time.** The
/// socket half is already const ([`HotPlug`] is one `const` per consumer,
/// `&'static [u16]` + `&'static [&'static str]`), and activation is by
/// Cargo presence: a build graph that pulls the authority crate gets the
/// real tables, one that does not cannot call [`CapabilityAuthority`] at
/// all. So the reading is a STATIC DESCRIPTOR the authority hands back —
/// a `const` table, no allocation, nothing resolved at runtime that was
/// not already decided by which crates are in the graph. `concepts` /
/// `capabilities` stay owned because they are derived (joined, sorted,
/// deduped); a reading is looked up, not computed.
/// **Owned, and per-plug — corrected 2026-09-07.** This was `&'static`,
/// argued as "plug-and-play at COMPILE time: a reading is looked up, not
/// computed". That argument had a consequence I did not weigh: a
/// `&'static` table cannot be built per plug, so the authority could only
/// hand back a table it already held ALL of, which forced an
/// all-or-nothing guard and, behind it, one hard-coded row per consumer
/// seat. That is the central lockstep `D-BLOCKS-HOTPLUG-1` retired,
/// rebuilt one level up — and its failure mode is the worst kind: a
/// consumer missing from the table keeps compiling and silently loses its
/// V3 tail, discoverable only weeks later and nowhere near the edit.
///
/// Owned lets the authority answer for exactly the ids a plug declared,
/// derived from the plug rather than looked up in a shared list. Being
/// plugged in IS the declaration
/// ([`ReadMode::PLUG_AND_PLAY_V3`](crate::canonical_node::ReadMode::PLUG_AND_PLAY_V3)),
/// and an authority may still override any single concept.
///
/// **Fails closed by MECHANISM, not by prose** (operator, 2026-09-07:
/// *"don't silently enforce V1 fallback in hotplug, that's
Expand All @@ -95,7 +101,7 @@ pub struct Activation {
/// executor that mints no keys) has no reading to declare. What the type
/// now guarantees is that *asking* for an absent one bangs instead of
/// quietly yielding a V1 tail.
read_modes: &'static [(u16, crate::canonical_node::ReadMode)],
read_modes: Vec<(u16, crate::canonical_node::ReadMode)>,
}

impl Activation {
Expand All @@ -106,7 +112,7 @@ impl Activation {
pub fn new(
concepts: Vec<(String, u16)>,
capabilities: Vec<String>,
read_modes: &'static [(u16, crate::canonical_node::ReadMode)],
read_modes: Vec<(u16, crate::canonical_node::ReadMode)>,
) -> Self {
Self {
concepts,
Expand Down Expand Up @@ -148,8 +154,8 @@ impl Activation {
/// slice, so scanning it and defaulting is once again expressible, and
/// that is exactly what the lookup exists to avoid.
#[must_use]
pub fn declared_readings(&self) -> &'static [(u16, crate::canonical_node::ReadMode)] {
self.read_modes
pub fn declared_readings(&self) -> &[(u16, crate::canonical_node::ReadMode)] {
&self.read_modes
}
}

Expand Down Expand Up @@ -290,7 +296,7 @@ mod tests {
plug.covered.iter().map(|s| (*s).to_string()).collect(),
// This toy authority declares no reading — an authority that
// has none says so, and asking it for one bangs.
&[],
Vec::new(),
))
}
}
Expand Down Expand Up @@ -337,9 +343,7 @@ mod tests {
value_schema: ValueSchema::Bootstrap,
edge_codec: EdgeCodecFlavor::CoarseOnly,
};
const TABLE: &[(u16, ReadMode)] = &[(0x1717, V3_SEAT)];

let act = Activation::new(Vec::new(), Vec::new(), TABLE);
let act = Activation::new(Vec::new(), Vec::new(), vec![(0x1717, V3_SEAT)]);

// Can-fire on the happy half: a declared seat resolves to its own
// reading, not to some other row of the table.
Expand Down
Loading
Loading