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/AGENT_LOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 2026-07-12 — stockfish-wave3-fleet — chess-signature arc capstone: no-hindsight GREEN, needle 9.70×, personality 98% inter, Turk-Polson substrate in-tree

- **Fleet:** Sonnet workers for D-SF-HINDSIGHT-1, PERSONALITY-1..4, BLITZ-1, SIGNATURE-1, NEEDLE-1 (CHAODA) + temporal-test worker (lance-graph-planner) + this doc applier.
- **Deliverables:** stockfish-rs `79ce78f`/`57ae59f`/`654a605`/`2c54e1a`/`64b8aa3`/`5d74b6c`/`2f73686`/`fa7beff`; lance-graph `505b989e` (`temporal.rs` no-hindsight test).
- **Outcome:** no-hindsight discipline GREEN (0/521k future accesses admitted); delayed-gratification needle rate 9.70× reputation-correct; needle-rate variance decomposition shows personality ~98% opponent-driven (inter) vs ~2% trait (intra); Lyons signature mechanism-confirmed via in-tree `sigker` — see `EPIPHANIES.md` `E-CHESS-SIGNATURE-ARC-1`. PRs pending.
- **Board:** knowledge doc `stockfish-nnue-as-perturbation-cascade.md` § "Wave 3 (final)" appended; EPIPHANIES prepended.

## 2026-07-12 — stockfish-wave2-fleet — D-SF-TRAP-1 GREEN + holes/palette/lichess partials + TemporalPov + lichess-rs scaffold

- **Fleet:** 5 Sonnet grindwork probe/scaffold builders (stockfish-rs trap/holes/piece-palette/lichess-ladder, lichess-rs scaffold) + 1 Sonnet contract worker (`TemporalPov`) + 1 Sonnet doc applier (this repo).
Expand Down
19 changes: 19 additions & 0 deletions .claude/board/EPIPHANIES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
## 2026-07-12 — E-CHESS-SIGNATURE-ARC-1 — personality is the opponent-response function (inter 98% / intra 2%); Turk-Polson substrate already in-tree

**Status:** MEASURED (stockfish-rs `79ce78f`/`57ae59f`/`654a605`/`2c54e1a`/`64b8aa3`/`5d74b6c`/`2f73686`/`fa7beff`; lance-graph `505b989e`).
**Arc:** reconstructed Turk & Polson "Chess Signatures of Play" (arXiv 2606.18544, June 2026) from first principles, then found its full math substrate already in-tree.
**Capstone finding (D-SF-NEEDLE-1):** needle-rate variance decomposition — between-player (trait) 0.021 vs player×opponent (adaptation) 0.979 → personality is **~98% INTER (adaptive), not INTRA (trait)**. Karpov-Kasparov head-to-head (66 mutual games, opponent fixed): +1.26 needles/100 — a modest trait residual survives. Unifies the personality arc with the opponent-modeling arc (D-SF-OPPONENT-1/2/3): same object.
**Why every averaged probe failed (~1.1-1.3×):** (a) needle-in-haystack SNR (a ~1% signature can't be lifted by a mean at ~5k moves/player); (b) trait-model misspecification on a 98%-adaptive process.
**The one positive:** delayed-gratification (Belohnungsaufschub) sacrifice RATE 9.70× reputation-correct — a NAMED rare event, whereas CHAODA generic anomaly over the same features stayed at chance (1.19×). Style is in the specific tail event, not statistical outliers, not the mean.
**Signature (D-SF-SIGNATURE-1):** consumed in-tree `sigker`; signature > aggregate and Lévy-interaction > level (both directions per the paper); magnitude ~1.3-1.4× (gap = missing clock channel / deep-search accuracy / depth).
**No-hindsight (GREEN):** D-SF-HINDSIGHT-1 fixed RUNG-1 via `TemporalPov` Strict-gating (0/521k future accesses) + real-Result oracle; convergence 0.631→0.818.
**Impulsivity refuted:** D-SF-BLITZ-1 — classical most identifiable (length/strength-confounded).
**Meta:** `sigker` (Chen-Lyons signature + kernel), `jc/hambly_lyons` (uniqueness certificate), `temporal.rs` (stream), CLAM/CHAODA (anomaly) = Turk-Polson's pipeline, composable from in-tree parts. Use `signature_kernel` not `signature_kernel_pde` (jc-flagged bug).
**Cross-ref:** knowledge doc § "Wave 3 (final)"; E-SF-AWARENESS-OPPONENT-ARC-1, E-SF-TRAP-LURE-GREEN-1, E-TEMPORAL-NO-HINDSIGHT-1.

## 2026-07-12 — E-TEMPORAL-NO-HINDSIGHT-1 — temporal.rs's Spoiler/Anachronistic classification IS the no-hindsight gate, demonstrated on a streamed known-game version series

**Status:** MEASURED (test, `crates/lance-graph-planner/src/temporal.rs::tests::no_hindsight_streamed_known_game`, 16/16 green in `temporal::tests`).
A short known game modelled as N plies -> N rows (`lance_version == ply`, `knowable_from = 0`); a `Strict` reader (`QueryReference::at(v, 0)`) pinned at ply `v` sees every future row classify `Anachronistic` (NOT `Spoiler`) and `EpistemicMode::Strict::admits` refuses it, so `deinterlace`'s projection is exactly plies `0..=v` — the future is structurally excluded, not silently readable. **Surprise vs. the brief's assumption:** `Spoiler` is what `Retro` mode (rung 9+) produces on an *intentional* peek past the horizon, not what `Strict` produces on an ordinary future row — the no-hindsight gate a default present-reader hits is `Anachronistic`-refused, and `Spoiler`-admitted is its deliberate opt-in contrast (both asserted in the same test).
**Cross-ref:** `AdaWorldAPI/stockfish-rs` `examples/hindsight_stream.rs` (`D-SF-HINDSIGHT-1`) consumes the zero-dep `TemporalPov` contract mirror of this machinery to re-run the rung/ladder reads under `Strict` discipline over real lichess games, fixing D-SF-RUNG-1's leaked-outcome oracle with real game `Result`s.

## 2026-07-12 — E-SF-TRAP-LURE-GREEN-1 — opponent-aware lure synthesis works; opponent-model inference is the bottleneck (wave-2 arc: 4 probes + contract type + lichess-rs scaffold)

**Status:** MEASURED (stockfish-rs `4c47ce1`/`eaa902b`/`f028442`/`1c9418f`, PR #10; lance-graph `0ed93b59`; lichess-rs `ce44ada`).
Expand Down
81 changes: 81 additions & 0 deletions .claude/knowledge/stockfish-nnue-as-perturbation-cascade.md
Original file line number Diff line number Diff line change
Expand Up @@ -560,3 +560,84 @@ wide-angle (perturbation-field read) and temporal tele (k-ply rollout read), swi
on the contact/wedge signal, gated on beating both pure reads at predicting strong
play. Plus the lichess iteration knobs above, the piece-palette + edges follow-up,
and traps-on-INFERRED-models (chains behind a working style inference).

## Wave 3 (final): the chess-signature arc — Turk-Polson convergence, intra vs inter, the needle

Closing wave of the chess-as-substrate program. Operator-steered from first principles to
a formal result: **Turk & Polson, "Chess Signatures of Play" (arXiv 2606.18544, June 2026)** —
game-as-multivariate-path, the Lyons signature transform, style identifiable from the expected
signature up to tree-like equivalence (Hambly-Lyons 2010), discriminating info in the Lévy
areas (accuracy×complexity interaction), cheating detection as an anytime-valid signature-kernel
conformance test. All probes: stockfish-rs examples, net/data-gated, deterministic, exit-0.

**The no-hindsight discipline (GREEN).** D-SF-HINDSIGHT-1 (stockfish `79ce78f`) streams real
decisive lichess games as a version series and reads them under `TemporalPov::at(v, Strict)` —
0/521,630 future-ply accesses admitted (causal window enforced by `VersionRange::contains`, not
discipline). It FIXES D-SF-RUNG-1's leaked-outcome oracle (real game Result replaces NNUE-final-eval):
present-rung agreement rises monotonically toward the settled result (far 0.631 → end 0.818), the
honest convergence RUNG-1 could not produce. Companion: lance-graph-planner `temporal.rs`
no-hindsight test (`505b989e`, `E-TEMPORAL-NO-HINDSIGHT-1`) — a Strict reader classifies future
plies `Anachronistic` and refuses them (Spoiler is reserved for a Retro reader's deliberate peek).

**The personality question — six probes, one honest answer.** "Can we measure a player's style
(Carlsen/Karpov/Kasparov/Tal, 120 games/player, pgnmentor)?" Every AVERAGED measure converged at
~1.1-1.3× chance:

| probe | measure | result |
|---|---|---|
| D-SF-PERSONALITY-1 (`57ae59f`) | mean move-delta vs 1-ply rational | 1.18× |
| D-SF-PERSONALITY-2 (`654a605`) | anomaly-corrected delta, ICC(1) | 1.17× (0/3 gates) |
| D-SF-PERSONALITY-3 (`2c54e1a`) | intrinsic NNUE-fingerprint readout | 1.28× (no confound) |
| D-SF-PERSONALITY-4 Arm A (`64b8aa3`) | comfort-zone situation MEAN | 1.1× |
| D-SF-NEEDLE-1 CHAODA (`fa7beff`) | manifold-anomaly over deviation feats | 1.19× |
| D-SF-SIGNATURE-1 (`2f73686`) | Lyons path-signature (Turk-Polson) | 1.31× / 1.39× kernel-MMD |

Two compounding reasons, BOTH measured: (a) **needle-in-haystack SNR** — a signature move is ~1%
of decisions; a mean estimator's SNR is bounded by the signature rate, so at ~5k moves/player the
needle sits inside the noise band (would need ~100× the games to lift it out). (b) **trait-vs-adaptive
misspecification** — see intra/inter below.

**The one POSITIVE — the needle is a NAMED event, not a statistical outlier.** D-SF-PERSONALITY-4
Arm B: the **delayed-gratification (Belohnungsaufschub) sacrifice rate** separated players **9.70×**,
reputation-correct (Tal 1.197/100dec ≫ Karpov 0.123), on events that are 0.12-1.20% of decisions —
material given for LONG-term positional comp, which engines rarely do (maximally diagnostic). CRUCIAL
contrast: CHAODA generic anomaly detection over the SAME deviation features stayed at chance (1.19×) —
so the signal is NOT "statistically anomalous move," it is a **specific, domain-meaningful rare event**.
Reputation shows up in the tail, not the mean.

**INTRA vs INTER — the capstone finding.** D-SF-NEEDLE-1 variance decomposition on needle rate over
258 player×opponent cells (900-game corpus): SSB (between-player, TRAIT) = **0.021**, SSW
(player×opponent, ADAPTATION) = **0.979**, ratio 0.021 — needle rate is **~98% opponent-driven**.
Personality is overwhelmingly INTER (adaptive), not INTRA (a fixed trait). Karpov-Kasparov head-to-head
control (66 mutual games, opponent+era fixed): Karpov 5.55 vs Kasparov 4.29 needles/100 (+1.26) — a
real but modest trait signal survives once the opponent is held constant, exactly as an inter-dominant
world predicts. **This unifies the two halves of the program: personality IS the opponent-response
function — the personality arc and the opponent-modeling arc (D-SF-OPPONENT-1/2/3) are the same object.**

**Impulsivity refuted.** D-SF-BLITZ-1 (`5d74b6c`, 115k lichess games): classical is the MOST
identifiable time control (3.43×/3.85×), not the least — opposite to "faster play reveals the habitual
self." Confounded by game-length (longer games → tighter fingerprint) and rating heterogeneity
(strength, not style); an honest refutation of the specific gradient, not a clean disproof. The
signature (reparametrization/length-invariant) is the tool that sidesteps this confound.

**Signature: mechanism-confirmed, magnitude-honest.** D-SF-SIGNATURE-1 consumed the workspace's OWN
certified `sigker` (not a hand-roll): `signature_truncated(path, 2)` + `signature_kernel_normalized`
(MMD). All signature readouts (1.11-1.44×) BEAT the aggregate baselines, and Lévy-areas-only (1.25×)
beat level-1-only (1.11×) — both DIRECTIONS as Turk-Polson predict. Absolute magnitude stayed ~1.3-1.4×
because our setup lacks the paper's ingredients: no clock channel (OTB PGN), 1-ply-NNUE accuracy (not
deep-search), depth-2, 4 players. Mechanism validated; magnitude gap fully attributable to listable
missing ingredients.

**The meta-finding.** The workspace already contained Turk-Polson's entire mathematical substrate,
built independently: **`sigker`** (Chen-Lyons `signature_truncated` / `log_signature_truncated` /
`signature_kernel[_normalized]`, zero-dep), **`jc/hambly_lyons.rs`** (pillar #11 — the tree-like-
equivalence uniqueness certificate the paper's identifiability rests on), **`temporal.rs`** (the stream),
**ndarray CLAM/CHAODA** (the anomaly layer). The paper's pipeline (path → signature → kernel two-sample /
conformance) is composable from in-tree parts today. Caveat: use `signature_kernel` (tensor-algebra,
correct), NOT `signature_kernel_pde` (documented divergence from the true I₀ kernel; jc flags it).

**Net honest verdict of the arc:** style at the statistical-mass level is (1) a ~1% needle averaging
cannot see, (2) a specific named rare event (delayed-grat sacrifice) when detected directly, and (3)
~98% adaptive (opponent-driven), not a fixed trait — with a modest trait residual surviving under
opponent control. The Lyons signature is the right featurization (mechanism confirmed) and its
substrate already lives in-tree.
117 changes: 117 additions & 0 deletions crates/lance-graph-planner/src/temporal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,4 +543,121 @@ mod tests {
"legacy row must sort by its lance_version, not 0"
);
}

/// No-hindsight guarantee, demonstrated on a streamed known game.
///
/// A known game is modelled as a Lance version stream: N plies, one row
/// per ply, `lance_version == ply index`. The game's *class* (that a
/// game is being observed at all) was knowable from the start
/// (`knowable_from = 0`) — only the individual ply rows arrive later, one
/// per streamed version, exactly as `temporal.rs`'s doc comment describes
/// four independently-clocked producers merge-sorting onto one timeline.
///
/// A `Strict`-mode reader (rung 0) pinned at ply `v` — the "present" —
/// must be structurally unable to see the game's outcome or any future
/// ply: [`classify`] marks every row with `row_version > v` as
/// [`TemporalStatus::Anachronistic`], and [`EpistemicMode::Strict`]
/// refuses (`admits` returns `false`) to dispatch on that status. The
/// hindsight leak `temporal.rs` refuses is therefore `Anachronistic`
/// under `Strict`, not silently-readable — so [`deinterlace`]'s
/// dispatchable projection for a `Strict` reader excludes every future
/// ply outright, by construction, not by convention.
///
/// **Surprise vs. the naive expectation going in:** the "hindsight leak"
/// `Strict` refuses is [`TemporalStatus::Anachronistic`], **not**
/// [`TemporalStatus::Spoiler`]. Per [`classify`], `Spoiler` only ever
/// appears when the reader's own `mode` is already `Retro` — it is the
/// label for an *intentional* peek past one's own horizon, not the
/// default label a `Strict` reader sees on a future row. This test
/// demonstrates both: a `Strict` present-reader's future rows classify
/// `Anachronistic` and are refused; a contrasting `Retro` reader (rung
/// 9+) at the *same* `v_ref` sees the identical future row classify
/// `Spoiler` and admits it — the difference between structural
/// blindness (default) and a deliberate, opted-in horizon break, never
/// an accidental leak.
///
/// Cross-ref: `AdaWorldAPI/stockfish-rs` `examples/hindsight_stream.rs`
/// (`D-SF-HINDSIGHT-1`) consumes the zero-dep `TemporalPov` mirror of
/// this exact machinery to re-run the rung/ladder reads under `Strict`
/// discipline over real lichess games.
#[test]
fn no_hindsight_streamed_known_game() {
// A tiny synthetic move-label sequence — illustrative only. Row's
// fixed `subj` field carries no move text; the semantics under test
// are purely temporal (version-indexed), so the labels are not
// stored, only used to anchor "known game" in the reader's mind.
const MOVES: [&str; 10] = [
"e4", "e5", "Nf3", "Nc6", "Bb5", "a6", "Ba4", "Nf6", "O-O", "Be7",
];
let rows: Vec<Row> = (0..MOVES.len() as u64)
.map(|ply| Row::new(ply, 0, None))
.collect();

// Representative "present" readers: early, mid, near-end.
for &v in &[2u64, 5, 8] {
let strict = QueryReference::at(v, 0); // rung 0 -> Strict
assert_eq!(strict.mode, EpistemicMode::Strict);

for (ply, row) in rows.iter().enumerate() {
let ply = ply as u64;
let status = classify(row.lance_version(), row.knowable_from(), &strict);
if ply <= v {
assert_eq!(
status,
TemporalStatus::Contemporary,
"ply {ply} must be Contemporary for a present-reader at v_ref {v}"
);
} else {
// The future is structurally flagged...
assert_eq!(
status,
TemporalStatus::Anachronistic,
"ply {ply} (future of v_ref {v}) must classify Anachronistic under Strict"
);
// ...and refused, not silently readable, under Strict.
assert!(
!strict.mode.admits(status),
"ply {ply} must NOT be admitted under Strict at v_ref {v} — this is the no-hindsight gate"
);
}
}

// The hindsight-free projection: deinterlace's dispatchable view
// excludes every future ply outright — not merely flags it.
let visible = deinterlace(&rows, &strict, &NoDeps);
let visible_versions: Vec<u64> = visible.iter().map(|r| r.lance_version()).collect();
let expected: Vec<u64> = (0..=v).collect();
assert_eq!(
visible_versions, expected,
"Strict projection at v_ref {v} must be exactly plies 0..={v}, no future ply visible"
);

// Contrast: an intentional Retro peek (rung 9+) at the SAME
// v_ref sees the future too — Spoiler, admitted — showing the
// difference between structural blindness (Strict, above) and a
// deliberate horizon break (Retro), never an accidental leak.
if (v as usize) + 1 < MOVES.len() {
let retro = QueryReference::at(v, 9);
assert_eq!(retro.mode, EpistemicMode::Retro);

let future_ply = v + 1;
let future_row = &rows[future_ply as usize];
let retro_status = classify(
future_row.lance_version(),
future_row.knowable_from(),
&retro,
);
assert_eq!(retro_status, TemporalStatus::Spoiler);
assert!(retro.mode.admits(retro_status));

let retro_visible = deinterlace(&rows, &retro, &NoDeps);
assert!(
retro_visible
.iter()
.any(|r| r.lance_version() == future_ply),
"Retro must be able to see future ply {future_ply} when explicitly requested"
);
}
}
}
}
Loading