Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Hebbian / anti-Hebbian plasticity as a separate overlay, not codebook retraining

Status: **lab-only**. The Google-search formula `Δz = η pre post (1 − tanh(|z|))` is a local update proposal. It is neither canonical NARS revision nor a Bayesian posterior.

Existing owner: `.claude/knowledge/reference-frame-vs-motion.md`: immutable calibrated reference versus dynamic motion/alpha/thought. Keep the Fisher-Z pairwise LUT unchanged and version the update overlay independently.

Probe claims ONLY:
- bounded finite latent and bounded tanh readout on tested activations;
- independent source gating prevents immediate evidence echo;
- negative coactivation can decrease the plastic overlay;
- codebook address never changes.

Refusals/next experiments: dependent sources sharing ancestry, adversarial wrong associations, negative saturation recovery, catastrophic reinforcement, forgetting/decay, convergence, calibration vs a held-out event oracle. The toy 64-bit witness cannot replace full provenance handling.

Run: `cargo test --manifest-path crates/causal-edge/Cargo.toml --test palette256_hebbian_overlay_probe`.
3 changes: 2 additions & 1 deletion .claude/board/entries/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ 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.

434 entries, 2026-08-06 .. 2026-10-22.
436 entries, 2026-08-06 .. 2026-10-22.

| date | entry id | finding | file |
|---|---|---|---|
| 2026-10-22 | `pal256-salience-mp3-probe` | | [2026-10-22-pal256-salience-mp3-probe.md](2026-10-22-pal256-salience-mp3-probe.md) |
| 2026-10-22 | `pal256-immutable-needle-distribution-probe` | | [2026-10-22-pal256-immutable-needle-distribution-probe.md](2026-10-22-pal256-immutable-needle-distribution-probe.md) |
| 2026-10-22 | `pal256-hebbian-overlay-plasticity` | | [2026-10-22-pal256-hebbian-overlay-plasticity.md](2026-10-22-pal256-hebbian-overlay-plasticity.md) |
| 2026-10-22 | `pal256-argextrema-margins` | | [2026-10-22-pal256-argextrema-margins.md](2026-10-22-pal256-argextrema-margins.md) |
| 2026-10-22 | `pal256-3sigma-statistical-gate` | | [2026-10-22-pal256-3sigma-statistical-gate.md](2026-10-22-pal256-3sigma-statistical-gate.md) |
| 2026-10-22 | `math-compiler-stage-b-e1` | | [2026-10-22-math-compiler-stage-b-e1.md](2026-10-22-math-compiler-stage-b-e1.md) |
Expand Down
62 changes: 62 additions & 0 deletions crates/causal-edge/tests/palette256_hebbian_overlay_probe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//! Local associative learning belongs to a versioned overlay, not to the
//! immutable Palette256 codebook or its family-calibrated pairwise LUT.
#[derive(Default)]
struct Overlay {
latent: f64,
seen_sources: u64,
}
impl Overlay {
fn apply(
&mut self,
source_id: u8,
pre: f64,
post: f64,
eta: f64,
) -> Result<bool, &'static str> {
if source_id >= 64
|| !pre.is_finite()
|| !post.is_finite()
|| !eta.is_finite()
|| !(0.0..=1.0).contains(&eta)
{
return Err("invalid update contract");
}
let source = 1_u64 << source_id;
if self.seen_sources & source != 0 {
return Ok(false);
}
// Hypothesis under test, NOT NARS revision or a proven Bayesian update.
let damping = 1.0 - self.latent.abs().tanh();
self.latent = (self.latent + eta * pre * post * damping).clamp(-8.0, 8.0);
self.seen_sources |= source;
Ok(true)
}
fn bounded_readout(&self) -> f64 {
self.latent.tanh()
}
}
#[test]
fn repeated_eligible_updates_remain_bounded_and_do_not_move_reference() {
let frozen_reference: [u8; 4] = [13, 42, 99, 241];
let reference_before = frozen_reference;
let mut synapse = Overlay::default();
for source in 0..64_u8 {
assert!(synapse.apply(source, 0.8, 0.9, 0.15).unwrap());
}
assert!(synapse.latent.is_finite());
assert!(synapse.bounded_readout() > 0.0 && synapse.bounded_readout() < 1.0);
assert_eq!(frozen_reference, reference_before);
}
#[test]
fn a_duplicate_root_does_not_reinforce_the_synapse_again() {
let mut synapse = Overlay::default();
assert!(synapse.apply(4, 0.8, 0.9, 0.1).unwrap());
let first = synapse.latent;
assert!(!synapse.apply(4, 0.8, 0.9, 0.1).unwrap());
assert_eq!(synapse.latent, first);
assert!(synapse.apply(5, -0.8, 0.9, 0.1).unwrap());
assert!(
synapse.latent < first,
"anticorrelated activation must decrease the overlay"
);
}
Loading