Skip to content

RFC 0002 wave 1b: surprise, pace, dispositions (0.10.0) - #40

Merged
BitmapAsset merged 19 commits into
mainfrom
rfc2-wave1b-surprise-pace-dispositions
Oct 17, 2026
Merged

BitmapAsset merged 19 commits into
mainfrom
rfc2-wave1b-surprise-pace-dispositions

Conversation

@BitmapAsset

@BitmapAsset BitmapAsset commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Wave 1b of RFC 0002 (docs/rfcs/0002-neuromodulators-and-body.md, Designs B, C and D), stacked on #39 (wave 1a): the surprise, pace and dispositions blocks.

  1. PR RFC 0002 wave 1b: surprise, pace, dispositions (0.10.0) #40 (draft) this PR, head 509c8d04260c8563652cfbf655712b668cc73342 on rfc2-wave1b-surprise-pace-dispositions, base rfc2-wave1a-needs @ 8e2600c (stacked; rfc2-wave0-freeze 889a993, main 164bd3b); CI on the full head sha: ci run 38887899248 success, check run 38887899289 success. Never marked ready, merged, tagged, released or posted.
  2. Tests: new unit, live, monitor and golden tests all pass (9 unit tests covering every closed form of Designs B-D, the α⁻ seam, 30 refusal cases for V-R1, V-R2, P-R1-P-R3, D-R1, D-R2, 18 state refusals, surfaces, prove boxes, the refusal property); the whole suite cargo +stable test --workspace --locked --no-fail-fast locally: 32 targets, 404 passed, 3 failed, 1 ignored, the 3 being the wall-clock tests (acc1_tv_le_001_within_10ms, sample_on_budget_is_a_deadline_at_many_chains, decide_fallback_enumerates_a_program_no_chain_can_start) that fail on the base's release build at the same moments too and pass in CI; MSRV 1.78 exit 0 with Cargo.lock unchanged; P0 653 outputs, 0 differ, 8/8 strands.
  3. Bench (bars v2, the frozen release binary of the head, PROBBIT_THREADS=1; nulls.py 51 rows, 0 pass): s1 pass (ratios 0.5-0.6667); s2 pass (1.0343-1.0719); s3 pass (1800/1800, error 0.0); s4 pass (1800 strands 0 diff); s5 pass (P0); p1a pass (error 0.0, 0 changed); p1b pass (0 changes, control 0.0); p1c pass (Spearman 0.8414); p6 pass (transients within 1.1e-5, pins, burst exact); o1 pass (pooled -0.001417, gaps 0.0); o2 pass (100/100, 0.0); o3 pass (distance 0.002753, 18/20); o4 pass (0 breaks); o5 pass (4/4); wave 1a's bars re-measured on this build: n1, n2, n3, n4, n5, n6, n7, n8, n9, v1, v2, v3, om1 pass; n10, n11 fail as in wave 1a (the design findings it recorded; bars unchanged).
  4. Changes after the freeze: scripts 0, fixtures 0, MANIFEST unchanged, bars.md / bars.json / bars-v1.md byte-identical; RFC text: item 5 of the dated note (P-R3 also refuses a habit condition on pace_up / pace_down, and an event that sends either is refused at inputs.<id>; the stance's surprise map is {} once every gate is closed; precision reads each sense's variance after the event's sense step; the pace clause prints R̄ to 2 decimals). No pass value moved.
  5. Risk: a new learner's gate starts open: g = (r_ref + 1) / 2 = 2.5 at the defaults, so every new individual takes steps up to 2.5x the fixed rate's on its earliest feedback and its why says learning fast: feedback changed before any feedback has changed; the bars measure what the gate buys on a reversal (s1) and what it costs on a stable phase (s2: 1.03-1.07x), not how a host reads the clause on a brand-new individual. Wave 2 needs: load_level is an engine-owned number input like pace_up / pace_down: reuse build_body's lowering (reserved only with the block, refused when sent, left out of inputs, boxed by prove); the load step goes right after pace_step in prep; a rest line must say what it does to each learned trait's gate (v, r̂, g, counts sit next to Δ and the RFC is silent); load.from.expired will read credit expiries, which the patience gene now scales.

Bench (bench/body, bars v2, the release build of the head)

python3 bench/body/nulls.py: 51 competent nulls over 40 bars, 0 pass (exit 0). Then the parts of run.py --only needs,gate,pace,dispositions,valence,replay,habits,p0, with PROBBIT_THREADS=1 (outputs are byte-identical at any thread count); the gate part's nine (T, noise) cells ran in parallel through the part's own functions and were combined by its own gate_cells.

bar measured bar value result
s1 flip re-learning gated / fixed median turns per (T, noise): T100 n0.00 0.625, T100 n0.10 0.5, T100 n0.20 0.5769, T40 n0.00 0.625, T40 n0.10 0.5556, T40 n0.20 0.6667, T60 n0.00 0.625, T60 n0.10 0.5, T60 n0.20 0.625; every same-budget constant gain re-learns strictly slower (gated50 medians 5.0, 5.0, 7.0, 5.0, 6.0, 8.0, 5.0, 5.0, 7.0) ≤ 0.75 in every cell; constant gains within the gate's movement strictly slower pass
s2 stable-phase movement gated / fixed phase-A movement: T100 n0.00 1.0502, T100 n0.10 1.0343, T100 n0.20 1.0719, T40 n0.00 1.0502, T40 n0.10 1.0415, T40 n0.20 1.0613, T60 n0.00 1.0502, T60 n0.10 1.0383, T60 n0.20 1.0626; mid on top at the end of phase A in 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000; re-learned before T in 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000 ≤ 1.5; ≥ 0.9 and ≥ 0.9 pass
s3 caps and the opening step 1800/1800 lives within g_max × step_cap and ±total_cap; opening step max error 0.0 100 %; within 1e-5 pass
p1a pace reads the past max R̄ − recomputed 0.0 over 2,000 events; 0 earlier stances changed by a perturbed future (4 cuts)
p1b offered stakes do nothing 0 pace changes over 10 fuzzed streams; the accepted-win control moves R̄ by 1 − 0.5^(1/6) within 0.0 0; within 2e-6 pass
p1c pace tracks the reward rate Spearman 0.8414 on blocks; bursts: mean steady 0.499996, bursty 0.5, bursty range 0.401242, spaced last 0.558741 vs 0.558743 ≥ 0.7; within 0.02; ≤ 1.0; within 1e-4 pass
p6 loop gain G 0.24: 1.263152 vs 1.263158; G 0.6: 1.499989 vs 1.5; G 0.84: 2.249084 vs 2.249084; pinned G 1.08 a_cap 12: 3.599996 (max 3.599996); G 1.08 a_cap 20: 3.999996 (max 3.999996); G 1.2 a_cap 12: 3.599996 (max 3.599996); G 1.2 a_cap 20: 3.999996 (max 3.999996); burst: max 4, 4 from the 10th win, recovery error 0.0 within 1e-4; at the binding cap, never above 4; exact recovery within 2e-6 pass
o1 E settles at the expectile pooled sign-aligned error -0.001417 over individuals 0-4 (o: -0.2877, 0.2429, -0.1708, 0.1468, 0.2556); gaps stream max error 0.0 ·
o2 the gene's sign is readable 100/100 individuals; trajectory max error 0.0 100/100; within 1e-5 pass
o3 twin distance rises with outcomes mean distance 0.002753 at spread 0.3 (0.0 at spread 0); 0.0 up to the earliest win; pursue differs in 18/20 pairs ≥ 0.001; 0 before; ≥ 10 of 20 pass
n5 0 habit breaks {"n5": {"bound": 12600, "breaks": 0, "habit_free_twin_breaks": 1317}} 0; ≥ 50 bound pass
o4 0 habit breaks {"o4": {"bound": 2390, "breaks": 0, "habit_free_twin_breaks": 1709}} 0; ≥ 50 bound pass
n4 replay 112 strands: 0 verify failures, 0 third-copy and 0 split-copy differences; planted changes refused: {'changed': True, 'removed': True, 'swapped': True} 0 differing bytes; nulls refused pass
s4 replay 1800 strands: 0 verify failures, 0 third-copy and 0 split-copy differences; planted changes refused: {'changed': True, 'removed': True, 'swapped': True} 0 differing bytes; nulls refused pass
n6 / s5 P0 corpus exit 0: {"outputs": 653, "differ": 0, "identical": 629, "stderr_warnings_only": 24, "strands_verified": 8, "verify_failed": [], "seconds": 1753.2} byte-identical pass (n6 pass)
o5 P0 4/4 pairs identical without digests; a planted change detected: True spread 0 = today's bytes pass

Measured tables: BENCHMARKS.md §12 at the head.

Changes after the freeze

  • Scripts, fixtures and MANIFEST: none; bars.md, bars.json and bars-v1.md byte-identical to the base.
  • RFC text: item 5 of the dated note (P-R3 also refuses a habit condition on pace_up or pace_down, and an event that sends either; the stance's surprise map is {} once every gate is closed; precision reads each sense's variance after the event's sense step; the pace clause prints R̄ to 2 decimals). No pass value moved.

Draft: never marked ready, never merged.

…asurement

docs/rfcs/0002-neuromodulators-and-body.md: the RFC 0002 draft (needs and the omission let-down, surprise, pace,
dispositions, valence; part 2 rest and load) in RFC 0001's shape, references by author and year.

bench/body/: the benchmark that defines "done" for it, frozen: 9 fixture personas and 13 derived twins, 11 seeded streams
and their generator (fixtures/gen.py --verify regenerates them byte for byte), the bars (README tables, bars.md, bars.json),
run.py and the per-part scripts, and fixtures/MANIFEST (50 sha256 entries, manifest_check.py). arith_0002.py: 40 checks,
0 mismatches. No engine has the blocks yet: every part reports "setup error: this engine does not support <block>" and
run.py exits 2. No engine change; every bar unmeasured by design.
An independent review graded the 40 bench/body bars (12 sound, 10 weak, 18 vacuous) by naming a degenerate
policy or null that passes each. No engine with an RFC 0002 block has produced a number for any of them, so
they are repaired under the freeze rule (a bar is never edited after a number is seen). No pass value relaxed.

- Two-sided correctness and coverage: exact wins on a 15-cell needs1 grid (n1, n2); success-weighted order,
  odds magnitudes and released goals on a second probe (n3); contact ceiling also while the principal is away
  and every answered report paying (n8); non-positive wins, coverage and a deficit bound (n9); a positive
  baseline and recomputed deficits (n10); contact before the absence and after the return (n11); learning
  that must happen (s2) and an exact opening step (s3); E trajectories exact at every event (o1, o2); residual
  at lags 1-5 (v3); exact contraction plus a below-threshold control (r0); the lesson kept after the gap
  (r1); a non-saturated lineage probe with a 20 % reduction (r2); conflicts that bind (r4); each load
  channel's amplitude and time course (l1-l3).
- Nulls that fail inside their own fixture: the env control through the refused sources' transports (n7),
  an admissible burst above the pace cap (p6), constant-gain engine twins at the gate's movement budget (s1),
  planted corruptions for the replay bars, habit-free twins gated.
- Effects on decisions: released odds for v1/v2, changed pursue goals for o3, P(careful) for l1.
- nulls.py: a competent plain-Python null for every bar, judged by the parts' own gate functions; run.py
  stops with exit 2 when one passes. 51 null rows over 40 bars, 0 pass. The RFC's own rules run as
  non-gating references: they pass every bar they cover except n10 and n11 (kept as frozen; flagged).
- New streams return, bursts, burst, two-point-gaps; variants needs2-s02, gate-g1.25..3.0, load-effects;
  every v1 stream and variant regenerates byte for byte. bars.json/bars.md at version 2; v1 kept verbatim as
  bars-v1.json/bars-v1.md; MANIFEST regenerated (64 entries). arith_0002.py: 66 checks, 0 mismatches.
- run.py on an engine without the blocks still exits 2, one setup line per part.
At 1 h the deficit is 0.1 and the amount 0.2 overshoots it back to 0.1, so a correct engine shows no change and would
fail n7. Found by a dry run of needs.py against a Python model of RFC 0002 A.3-A.4 (not the engine), before any engine
measurement; pass value and bar text unchanged; logged under 'Changes after the freeze'.
…, v2's null within rounding

Found by dry runs of every part against Python models of RFC 0002 (not the engine), before any engine measurement:
- r1 is measured on the reversal draws without the lock turns: with them the stand-in learner re-learns in 6 turns
  after rest instead of 5 (6/11 = 0.545 against 0.5) because r4's lock habit shares the stream (rule 2); without them
  5/11 = 0.4545, the number the bar's reachability check cites. The locked ratio is reported.
- s3 checks the cap where the RFC puts it, on the step before recentring: the recentred changes come from a step
  within +-g_max x step_cap exactly when their range is <= 2 x g_max x step_cap (v1's script compared each recentred
  change with the cap, which a correct step exceeds in 968 of 1,800 lives of the dry run).
- v2's no-block twin moves by rounding residue (1e-6), so its move is gated at <= 2e-6, not == 0.
Pass values and bar text unchanged; logged under 'Changes after the freeze'.
…d events, v1's and v2's mood odds)

Verdicts unchanged (51 null rows, 0 pass a v2 bar); the rows printed illustrative numbers where the null's outcome follows
from its definition, and now print the computed ones.
… windows, prove boxes, verify needs summary, monitor, MCP refusal) and unit tests
…cs (persona.md 2.9/2.12, cheatsheet, man page), CHANGELOG, RFC changes after the freeze, BENCHMARKS 12, bench n7 MCP shape fix
…ields, surfaces), pacer example with golden, live tests
…heet, man page, changelog), RFC changes after the freeze item 5, monitor PACE and GAIN rows
@BitmapAsset BitmapAsset mentioned this pull request Oct 17, 2026
BitmapAsset added a commit that referenced this pull request Oct 17, 2026
…ows needs, #40 knows state.pace)

R117 semantic-conflict fix. #38's tests use RFC 0002's needs block (next-needs.strand; the unit test's header case) and a state.pace field as what this engine does not know. Since #39 the engine knows needs (the strand's header is refused at line 1: a needs block needs a drives block) and since #40 a pace state field (this persona has no pace block): divergences, not unsupported. next-load.strand is derived the same way (R111's make_next_fixtures.py helpers) with the load block of docs/rfcs/0002 Part 2, which no engine has yet; the unit test uses a load block and state.load; docs/persona.md 5.7 names load. Tests, fixtures and one docs sentence only; no engine code, no bar.
BitmapAsset added a commit that referenced this pull request Oct 17, 2026
* WIP RFC 0002 wave 1a: needs step, omission windows, valence and liking in the engine (compiles; no tests yet)

* WIP RFC 0002 wave 1a: surface (describe, lint notes, fuzz amounts and windows, prove boxes, verify needs summary, monitor, MCP refusal) and unit tests

* WIP RFC 0002 wave 1a: body example and golden, live and MCP tests, docs (persona.md 2.9/2.12, cheatsheet, man page), CHANGELOG, RFC changes after the freeze, BENCHMARKS 12, bench n7 MCP shape fix

* WIP RFC 0002 wave 1a: privacy and law gate fixes

* WIP RFC 0002 wave 1a: strict-field test string, monitor needs rows test

* Merge branch 'main' into rfc2-wave1a-needs

* tests: the newer-engine fixtures carry RFC 0002 part 2's load (#39 knows needs, #40 knows state.pace)

R117 semantic-conflict fix. #38's tests use RFC 0002's needs block (next-needs.strand; the unit test's header case) and a state.pace field as what this engine does not know. Since #39 the engine knows needs (the strand's header is refused at line 1: a needs block needs a drives block) and since #40 a pace state field (this persona has no pace block): divergences, not unsupported. next-load.strand is derived the same way (R111's make_next_fixtures.py helpers) with the load block of docs/rfcs/0002 Part 2, which no engine has yet; the unit test uses a load block and state.load; docs/persona.md 5.7 names load. Tests, fixtures and one docs sentence only; no engine code, no bar.

* Version 0.10.0-dev on main; the next-* fixtures re-derived at probbit 0.11.0-dev

0.9.0 is released, so main moves to 0.10.0-dev: Cargo.toml, the internal path dependencies, Cargo.lock (cargo update
--workspace --offline) and docs/probbit.1 (regenerated with probbit man); one CHANGELOG line under 0.10.0. The derived
newer-engine strands stay one version up: next-load.strand and next-rest.strand re-derived at probbit 0.11.0-dev with the
same derivation (it reproduces the 0.10.0-dev files byte for byte), and the five test strings in tests/live.rs and the two
Python tests that pin their engine follow. No engine code.
Base automatically changed from rfc2-wave1a-needs to main October 17, 2026 08:26
One line under the "What's new in 0.9.0" block: what main carries after #39 and #40 (opt-in, measured in
BENCHMARKS.md section 12) and that it ships as 0.10.0 after the fix wave.
The README's rule-lock example is re-measured with the released 0.9.0 binary (the same verdicts, broken seeds and exit
codes, and the nine seeds checked alone are unproven, exit 3); the cheat sheet's check heading and the action's error
message for a release without the check command name 0.9.0, the version that ships it.
@BitmapAsset
BitmapAsset marked this pull request as ready for review October 17, 2026 08:27
@BitmapAsset
BitmapAsset merged commit 4d5075d into main Oct 17, 2026
16 checks passed
@BitmapAsset
BitmapAsset deleted the rfc2-wave1b-surprise-pace-dispositions branch October 17, 2026 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant