Skip to content

Commit 93c46ee

Browse files
committed
VERDICT on PlasticityEngine: reimagine, do not port — 8 chassis violations + 1 live defect
Answers the operator's question (age + does it need reimagining) and connects the four-philosopher Doppelspalt framing. AGE: 27 days by calendar (2026-07-02 13:47, PR #629), NOT 1-4 months. But the calendar is the wrong clock: 825 commits have landed since, and 2026-07-02 is PRECISELY the V3 flip date — E-V3-FACET-4-PLUS-12 and the classid canon-high flip were both operator-locked that day. So the crate did not arrive before V3; it arrived ON the boundary, inside the v3-substrate-migration-review PR itself, and was never adapted to what that same PR ratified. Every invariant it violates was locked that day or later; the zero-copy law is from today. Generalizable lesson: a migration PR is the easiest place for un-migrated code to enter, because the diff is already enormous and one more crate reads as part of the sweep. One commit ever, 1575 LOC, zero external consumers. The MECHANISM is sound neuroscience — STDP + Hebbian + homeostatic scaling is the right triad and weight_change's exponential windows are reusable as-is. The CHASSIS is pre-V3 on eight counts: (1) HebbianMatrix stores connectivity in a HashMap<(usize,usize), f32> BESIDE EdgeBlock and CausalEdge64 — a second projection of connectivity, which already has a home; (2) hash lookup per pair is pointer CHASING, the exact thing ruled against today, where the substrate's edges are computed displacements; (3) fire(&mut self) mutates while computing, against data-flow's "no &mut self during computation, ever"; (4) raw = write-back instead of gated XOR / BUNDLE; (5) f32 per connection where the LE contract is byte/nibble-quantized; (6) a private timestep counter beside episodic = Lance versions / last_active_cycle; (7) no notion of PlasticityState, whose 3-bit S/P/O hot-frozen gate is exactly this engine's missing input and the measured disconnect; (8) O(n^2) pair space where the substrate's answer is EdgeBlock's bounded degree. LIVE DEFECT (9): depression is computed and DISCARDED. StdpRule::weight_change returns negative dw for LTD, but fire() applies only `if dw > 0.0` under a "TODO: directional hebbian for depression". So `a_minus: 0.012, // Slightly stronger depression (homeostasis)` is an inert doc-comment claim — the homeostasis it documents never happens, the engine can only potentiate, and wiring it as-is produces exactly the unbounded reinforcement runaway that falsifier P2 exists to catch. P0 falsifiability at substrate level: a doc-comment claim is not a behaviour. DOPPELSPALT (operator): the four philosophers are four LENSES over one crystal; interference shows in the projections while the bytes never move. rl_ops.rs already says "STDP for crystal cells" / "crystal lattice" — the right noun with the wrong mechanism, addressing crystal cells as usize hash keys instead of lensing the SoA crystal. Plasticity's job is to modulate WHICH SLIT IS ELECTED — the conductance of the projections — never to accumulate a private matrix beside the crystal. Same statement as violation (1), reached from the physics side rather than the storage side, and it is why P4 requires non-elected stances to stay REACHABLE: closing a slit destroys the interference pattern. Reimagined shape, as a lane and not a port: conductance in an EdgeBlock slot / CausalEdge64 magnitude (bounded degree by construction); update by BUNDLE because conductance is a magnitude and I-SUBSTRATE-MARKOV forbids XOR there; gated by the existing PlasticityState 3-bit S/P/O, which is what consuming that bit means and why it is currently inert; quantized u8/i4; clock = Lance version; no &mut self compute (a pass returns deltas, write-back is a separate gated builder step); and LTD must actually land or be deleted with its homeostasis claim removed — half a mechanism whose disabled half is documented as active is worse than an honest omission. Treat rl_ops.rs as a reference implementation to read, not a dependency to wire. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K3RyLEbuNSHxxB3NTTrGki
1 parent 32077e6 commit 93c46ee

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

‎.claude/plans/epistemic-quadrant-materialization-v1.md‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,79 @@ the same behaviour, because nothing consumes the bit to modulate a path.
9595
That inertness is the first thing to falsify, per the P0 rule: *a knob that
9696
changes nothing is decoration.*
9797

98+
## 4a. VERDICT on `PlasticityEngine`: reimagine, do not port
99+
100+
**Age: 27 days by calendar, one full generation by substrate.** `git log` shows
101+
exactly ONE commit touching `holograph/src/rl_ops.rs` — `28f17cd`, 2026-07-02
102+
13:47, the squashed `v3-substrate-migration-review` merge (#629) that landed the
103+
whole crate at once. Nothing has touched it since. 1575 LOC, zero external
104+
consumers.
105+
106+
Measure it in commits rather than days and the picture inverts: **825 commits
107+
have landed since**, and 2026-07-02 is *precisely* the V3 flip date — both
108+
`E-V3-FACET-4-PLUS-12` (content-blind 4+12 facet) and the classid canon-high
109+
flip were operator-locked that day. So the crate did not arrive "before V3": it
110+
arrived **on the boundary, inside the V3 migration PR itself, and was never
111+
adapted to what that same PR ratified.** Every invariant it violates was locked
112+
either that day or later — the zero-copy law is from today.
113+
114+
The lesson generalizes past this crate: *a migration PR is the easiest place for
115+
un-migrated code to enter*, because the diff is already enormous and one more
116+
crate reads as part of the sweep.
117+
118+
The mechanism is sound neuroscience (STDP + Hebbian + homeostatic scaling is the
119+
right triad). The **chassis is pre-V3** and violates current invariants:
120+
121+
| # | violation | the rule it breaks |
122+
|---|---|---|
123+
| 1 | `HebbianMatrix { weights: HashMap<(usize,usize), f32> }` — connectivity stored **beside** `EdgeBlock` (12 in-family + 4 out-of-family) and `CausalEdge64` | **SECOND-PROJECTION.** Connectivity already has a home; this is a second reading of it |
124+
| 2 | HashMap lookup per pair — data-dependent addresses | **pointer CHASING**, the exact thing ruled against 2026-07-29; the substrate's edges are computed displacements |
125+
| 3 | `fire(&mut self, cell)` mutates while computing | `.claude/rules/data-flow.md`: *"No `&mut self` during computation. Ever."* |
126+
| 4 | `*scale *= 0.99; *scale += …` | borrow-strategy: gated XOR (single writer) or BUNDLE (multi); **never raw `=`** on shared state |
127+
| 5 | `f32` per connection | LE contract is byte/nibble-quantized (i4 loci, u8 palette); f32-per-pair has no lane shape |
128+
| 6 | private `timestep: u32` | a second clock beside episodic = Lance versions / `last_active_cycle` |
129+
| 7 | no notion of `PlasticityState` | the 3-bit S/P/O hot-frozen gate is **exactly** this engine's missing input — the measured disconnect in §4 |
130+
| 8 | O(n²) pair space | at 32k rows ≈ 10⁹ pairs; the substrate's answer is EdgeBlock's **bounded degree**, not a growing map |
131+
132+
**And a live defect, not merely a mismatch — #9: depression is computed and
133+
discarded.** `StdpRule::weight_change` returns negative `dw` for LTD, but
134+
`PlasticityEngine::fire` applies only `if dw > 0.0`, carrying
135+
`// TODO: directional hebbian (asymmetric matrix) for depression`. So
136+
`a_minus: 0.012, // Slightly stronger depression (homeostasis)` is an **inert
137+
doc-comment claim**: the homeostasis it documents never happens. The engine can
138+
only potentiate — i.e. wiring it as-is produces exactly the unbounded
139+
reinforcement runaway that falsifier P2 exists to catch. This is the P0
140+
falsifiability rule at substrate level: *a doc-comment claim is not a behaviour.*
141+
142+
**Reimagined shape (a lane, not a port):**
143+
144+
- **Conductance lives in the edge** — an `EdgeBlock` slot / `CausalEdge64`
145+
magnitude, never a side map. Bounded degree by construction.
146+
- **Update is BUNDLE**, because conductance is a magnitude — `I-SUBSTRATE-MARKOV`
147+
forbids `MergeMode::Xor` on magnitudes (it breaks Chapman-Kolmogorov).
148+
- **Gated by the existing `PlasticityState`** 3-bit S/P/O. That bit is *for*
149+
this; consuming it is what makes it stop being inert (§4, falsifier P1).
150+
- **Quantized** (u8 / i4), not f32. Same reason every other lane is.
151+
- **Clock = Lance version / `last_active_cycle`**, not a private counter.
152+
- **No `&mut self` compute:** a pass *returns* deltas; write-back is a separate
153+
gated builder step (engines return results, they do not mutate while computing).
154+
- **LTD must actually land**, or be deleted and the homeostasis claim removed.
155+
Half a mechanism whose disabled half is documented as active is worse than an
156+
honest omission.
157+
158+
**Doppelspalt framing (operator, 2026-07-28→29):** the four philosophers are four
159+
**lenses over one crystal**; interference is visible in the projections while the
160+
bytes never move (CLAUDE.md § I-SUBSTRATE-MARKOV consequence). Plasticity's job
161+
is therefore to modulate **which slit is elected** — the conductance of the
162+
projections — never to accumulate a private matrix beside the crystal. That is
163+
the same statement as row 1 of the table above, arrived at from the physics side
164+
rather than the storage side, which is why P4 requires the non-elected stances to
165+
stay *reachable*: closing a slit destroys the interference pattern.
166+
167+
**Verdict: REIMAGINE.** Keep the triad's math (`weight_change`'s exponential
168+
windows are reusable as-is); discard the chassis. Treat `rl_ops.rs` as a
169+
reference implementation to read, not a dependency to wire.
170+
98171
## 5. Falsifiers — required before any wiring lands
99172

100173
- **P1 — the hot/frozen bit must be INERTNESS-TESTABLE.** Flipping

0 commit comments

Comments
 (0)