From bb92fa7c3cb6775d3ecf8612191d4dcc81b49a57 Mon Sep 17 00:00:00 2001 From: FatosLocos Date: Sat, 18 Jul 2026 20:25:38 +0200 Subject: [PATCH] Add ECP-7 Batch 27 collision pulse study --- README.md | 8 +- config/ecp7-b27-development.yaml | 24 ++++ docs/AI_AGENT_START.md | 40 ++++--- docs/development-log-ecp7.md | 104 ++++++++++++++++++ docs/research-design-ecp7.md | 58 ++++++++++ evidence/ecp7-development/README.md | 7 ++ .../ecp7-development/batch27-manifest.json | 55 +++++++++ tests/conftest.py | 5 + tests/test_config.py | 27 +++++ tests/test_training.py | 13 +++ 10 files changed, 322 insertions(+), 19 deletions(-) create mode 100644 config/ecp7-b27-development.yaml create mode 100644 evidence/ecp7-development/batch27-manifest.json diff --git a/README.md b/README.md index 8ceebbd..3b48069 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,11 @@ now nearly reaches the mathematical ceiling of the non-injective sender codebooks, so another horizon-only extension is not justified. Batch 26 added one sender/receiver route cycle and reached 85.38% validation, but did not add a single net unique code: shared errors became link-specific errors instead. -The replay-routing family is therefore closed; future work must target sender -capacity directly. See +Batch 27 directly penalized globally mined sender collisions after step 30,000. +It reduced collision multiplicity and reached 85.38% validation, but unique +code counts again remained unchanged and worst-link validation regressed to +82.13%. Both replay routing and the existing collision-loss schedule are now +closed; future work must change sender representation or code occupancy. See [`docs/development-log-ecp7.md`](docs/development-log-ecp7.md). ## Build on this work @@ -126,6 +129,7 @@ Do not translate those artifacts in place. New experiment configurations and all - [`config/ecp7-b24-development.yaml`](config/ecp7-b24-development.yaml) — Batch 23 routing with sender messages detached for receiver-only replay after step 20,000. - [`config/ecp7-b25-development.yaml`](config/ecp7-b25-development.yaml) — Batch 24 receiver-only catch-up with an isolated 45,000-step maximum horizon. - [`config/ecp7-b26-development.yaml`](config/ecp7-b26-development.yaml) — Batch 25 with one preregistered sender/receiver replay-route cycle. +- [`config/ecp7-b27-development.yaml`](config/ecp7-b27-development.yaml) — Batch 25 plus one late bounded direct sender-collision pulse. - [`config/ecp7-positive-control-development.yaml`](config/ecp7-positive-control-development.yaml) — ECP-6 positive control on the ECP-7 split. - [`config/ecp0.yaml`](config/ecp0.yaml) — machine-readable configuration from step 1. - [`config/ecp1.yaml`](config/ecp1.yaml) — frozen configuration of the population trial. diff --git a/config/ecp7-b27-development.yaml b/config/ecp7-b27-development.yaml new file mode 100644 index 0000000..b0b42d5 --- /dev/null +++ b/config/ecp7-b27-development.yaml @@ -0,0 +1,24 @@ +extends: ecp7-b25-development.yaml + +experiment: + title: ECP-7 late bounded sender-collision pulse + arm: late_bounded_sender_collision_pulse + objective: >- + Test whether a direct bounded separation pulse on globally mined sender + collisions can increase codebook capacity after receivers have saturated, + without sacrificing the established weak-structure reconstruction result. + +training: + global_collision_replay: + enabled: true + weight: 0.1 + start_step: 30000 + warmup_steps: 5000 + pair_batch_size: 32 + refresh_interval: 200 + relaxed_temperature: 1.0 + weight_decay: + enabled: true + start_step: 35000 + end_step: 40000 + final_weight: 0.0 diff --git a/docs/AI_AGENT_START.md b/docs/AI_AGENT_START.md index a3fd820..f0a2d26 100644 --- a/docs/AI_AGENT_START.md +++ b/docs/AI_AGENT_START.md @@ -41,7 +41,7 @@ python3.12 -m venv .venv .venv/bin/ecp6 --config config/ecp6.yaml validate ``` -Expected baseline: 125 passing tests and split sizes `14336/1024/1024`. +Expected baseline: 127 passing tests and split sizes `14336/1024/1024`. ## 4. Reproduce ECP-6 @@ -71,7 +71,7 @@ This reruns a known experiment. It must not be presented as a new independent co ## 5. Continue ECP-7 scientifically -Do not modify ECP-0 through ECP-6 or the completed ECP-7 Batch 1 through Batch 26 +Do not modify ECP-0 through ECP-6 or the completed ECP-7 Batch 1 through Batch 27 configs. ECP7-B1-I collapsed to 130–139 hard messages. ECP7-B2-I improved its soft objective but collapsed further to 85–104 hard messages. ECP7-B3-I applied that loss to straight-through hard messages and improved to 585–972 messages, @@ -155,11 +155,17 @@ and translator validation, but its unique-message counts were effectively unchanged. Shared failures fell while any-link failures rose, closing the replay-routing family as an error-redistribution mechanism rather than an injectivity solution. The confirmatory ECP-7 test remains sealed. +ECP7-B27-I added a late bounded direct collision-pair penalty. It reached +85.38% mean validation and reduced collision-pair multiplicity, but produced +exactly the same 13,440, 12,960, 12,720 and 13,440 unique-message counts as +Batch 25. Worst-link validation regressed to 82.13%, so the existing collision +loss is also closed as a capacity solution. The confirmatory test remains +sealed. Continue with this sequence: 1. Read `docs/research-design-ecp7.md` and `docs/development-log-ecp7.md`. -2. Define exactly one ECP7-B27 direct sender-capacity intervention and its +2. Define exactly one ECP7-B28 sender-representation or occupancy intervention and its failure criterion. 3. Register the variant and immutable configuration hashes before training. 4. Add tests for every new invariant. @@ -173,20 +179,20 @@ Continue with this sequence: ## 6. Recommended next experiment -Batch 26 shows that another one-sided replay cycle cannot increase sender code -capacity. Receiver-only phases fit the existing codebook ceiling; sender-only -ordinary-task replay converts shared errors into link-specific errors. Do not -try another route boundary, route cycle or horizon extension. - -For ECP7-B27, preregister exactly one direct sender-capacity intervention on the -strongest stable base. A defensible candidate is a late, bounded pulse that -explicitly separates globally mined hard-message collisions while preserving -the ordinary reconstruction task. Reuse an already tested loss and coefficient -where possible, activate it only after a shared unchanged trajectory, and -define success primarily as a reproducible increase in unique messages without -loss of worst-link validation. Do not combine this with a new architecture, -new predicate, optimizer change, factor-specific supervision, variable-length -messages or negotiation in the same batch. +Batch 27 shows that the existing relaxed collision-pair loss can reduce +collision multiplicity but cannot create newly occupied hard codes. Do not try +another coefficient, pulse boundary, route cycle or horizon extension. + +For ECP7-B28, preregister exactly one factor-agnostic sender representation or +genuinely different occupancy-creation intervention. A defensible +representation candidate is an identity-preserving residual interaction block +on the successful bounded-parallel sender: retain the complete shallow joint +context and slot heads, add one shared nonlinear residual branch initialized to +zero output, and change no receiver, loss, data or training schedule. This +isolates whether missing joint-context interaction capacity caused the stable +code ceiling while avoiding Batch 13's replacement of the successful shallow +path. Do not combine it with collision replay, a new coefficient, factor-slot +bindings, optimizer changes, variable-length messages or negotiation. ## 7. Definition of done for any contribution diff --git a/docs/development-log-ecp7.md b/docs/development-log-ecp7.md index f7c9bf5..f23dc03 100644 --- a/docs/development-log-ecp7.md +++ b/docs/development-log-ecp7.md @@ -34,6 +34,7 @@ this log. | ECP7-B24-I | Intervention | B23 sender-only warmup followed by receiver-only replay catch-up | Position-aware MLP | valid negative; new-best means but link-specific errors and injectivity fail | | ECP7-B25-I | Intervention | B24 receiver-only catch-up with a 45,000-step maximum horizon | Position-aware MLP | valid negative; new-best means reach the non-injective code-cap | | ECP7-B26-I | Intervention | B25 with a second sender-only pulse and final receiver-only catch-up | Position-aware MLP | valid negative; route cycle changes error sharing but not code capacity | +| ECP7-B27-I | Intervention | B25 plus one late bounded direct sender-collision pulse | Position-aware MLP | valid negative; collision multiplicity falls but unique-code capacity is unchanged | ## Batch 1 preregistration @@ -2184,3 +2185,106 @@ sender-only training reduces shared errors by fragmenting them across links. The ECP-7 confirmatory split remains sealed. Any future batch must change the sender collision objective or sender representation directly, rather than add another route phase, route boundary or horizon extension. + +## Batch 27 preregistration + +Preregistered: July 18, 2026 at 18:05:30 UTC
+Seed: `11`
+Maximum population steps: `45,000`
+Minimum selection steps: `15,000`
+Early-stopping patience: `5,000` steps
+Base hard-meaning replay: unchanged B25 sender-only warmup, then receiver-only catch-up
+Direct sender-collision pulse start: step `30,000`, weight `0`
+Direct sender-collision pulse peak: step `35,000`, weight `0.1`
+Direct sender-collision pulse end: step `40,000`, weight `0`
+Collision pairs: globally mined hard-message collisions per sender on training meanings only
+Collision pair batch: `32` pairs per sender, uniform with replacement
+Collision refresh interval: `200` steps
+Relaxed replay temperature: `1.0`
+Raw configuration SHA-256: `d44df83436f5ca81a2a51229b8ffe1a6fd6832d28dff4c7ab2ead3ace8efc9bd`
+Effective configuration SHA-256: `649ddca4a285fbbb00b29c1cab82678e42ab8d6810f89f2131766cd82496c463`
+Split-SHA-256: `4947058c75ab07cb43a87eb82776b12cb2a7e2eeba7114de110d3b852cbc64cd`
+Test unsealed: **no** + +ECP7-B27-I inherits Batch 25 and adds only one bounded direct sender-collision +loss after the unchanged trajectory through step 30,000. It reuses Batch 18's +task-scale `0.1` coefficient and Batch 19's registered 5,000-step rise and +5,000-step decay. The existing shared-hard-meaning replay remains receiver-only +after step 20,000, so readers continue fitting while the new branch acts only +on sender code separation. A final 5,000-step zero-collision-loss phase permits +unperturbed receiver catch-up. + +The positive control is rerun. All existing validity and development gates +remain unchanged. The direct-capacity hypothesis also requires a selected +minimum sender codebook larger than Batch 25's 12,720-message minimum without a +lower worst-link validation score. No alternative coefficient, pulse boundary, +pair sampler, replay route, predicate, architecture, optimizer, horizon, data, +translator or seed may be tried inside Batch 27. Failure is recorded without +confirmatory test access. + +## Batch 27 results + +Positive-control run: `runs/ecp7-batch27-control-development/20260718T180724Z-ecp7-development`
+Intervention run: `runs/ecp7-batch27-intervention-development/20260718T180838Z-ecp7-development`
+Test unsealed: **no** + +| Metric | Positive control | ECP7-B27-I | +|---|---:|---:| +| Population train, mean | 100% | **85.3760%** | +| Population train, worst link | 100% | 82.1498% | +| Population validation, mean | 100% | **85.3760%** | +| Population validation, worst link | 100% | 82.1289% | +| Universal translator, validation | 100% | **85.3516%** | +| Exact sender-message agreement | 100% | 92.36% | +| Unique messages per sender | 15,360 | 12,720–13,440 | +| Collision meanings per sender | 0 | 1,920–2,640 | +| Message entropy | 13.91 bits | 13.56–13.66 bits | +| Development gate | pass | **fail** | + +The positive control passed every gate at 100%. ECP7-B27-I modestly exceeds +Batch 25's mean train, mean validation and translator scores, but fails both +train thresholds, sender injectivity and the preregistered direct-capacity +criterion. Worst-link validation falls from Batch 25's 82.7148% to 82.1289%. +The joint gate fails and confirmatory access remains unauthorized. + +All 151 optimization records through step 30,000 match Batch 25 exactly after +excluding the new zero-weight collision diagnostics. The first mining boundary +finds 2,429, 2,578, 2,912 and 2,128 unordered collision pairs. At the pulse +peak on step 35,000, the pair banks contain 1,792, 2,605, 2,480 and 2,128 +pairs. Once the pulse reaches zero at step 40,000 they stabilize at 1,792, +2,240, 2,464 and 1,792 pairs through the selected step 43,800 and final step +45,000. + +For comparison, Batch 25's selected hard codebooks contain 2,128, 2,576, +2,912 and 2,128 unordered collision pairs. B27 therefore reduces collision +pair multiplicity substantially. It nevertheless produces exactly the same +unique-message counts as B25: 13,440, 12,960, 12,720 and 13,440. Collision +meaning counts are likewise unchanged at 1,920, 2,400, 2,640 and 1,920. The +higher 13.56–13.66-bit entropies show that the loss redistributes multiplicity +among already occupied codes instead of creating new occupied codes. + +The selected diagnostic finds 1,792 meanings failed by all links and 2,812 +failed by at least one link, with 11.93 mean failed links per erroneous +meaning. Relative to Batch 25, any-link failures fall by 155 while shared +failures rise by 115. The direct pulse therefore produces a different +error-sharing tradeoff from route cycling, but still cannot raise the minimum +sender code capacity above 12,720. + +Population validation factor accuracies were +`[100%, 100%, 98.44%, 86.94%]`; universal-translator factor accuracies were +`[100%, 100%, 98.44%, 86.91%]`. Both sealed analyses report 65 matching +artifact hashes, 16,384 validation-only episodes, no confirmatory-test keys, +valid local alphabets, and exactly 14 declared bits for every logged message. + +## Batch 27 decision + +ECP7-B27-I is a valid negative result. Direct relaxed collision-pair pressure +can reduce high-multiplicity hard collisions while preserving mean accuracy, +but it does not occupy additional codes and it weakens the worst population +link. Repeating this loss with another late coefficient or pulse boundary is +not justified. + +The ECP-7 confirmatory split remains sealed. A future batch must change the +factor-agnostic sender representation or introduce a genuinely different +occupancy-creation mechanism; it may not combine that change with another +replay-route or collision-coefficient search. diff --git a/docs/research-design-ecp7.md b/docs/research-design-ecp7.md index a4f2f4b..1217686 100644 --- a/docs/research-design-ecp7.md +++ b/docs/research-design-ecp7.md @@ -1147,3 +1147,61 @@ train and injectivity gates without accessing the confirmatory split. This completes the registered replay-routing family. Further route cycling or horizon extension is disallowed as an unsupported repetition; any later development batch must preregister a direct sender-capacity intervention. + +## Batch 27 preregistration — Late bounded sender-collision pulse + +Status: **completed sealed development; valid negative**
+Preregistered: July 18, 2026 at 18:05:30 UTC
+Configuration: `config/ecp7-b27-development.yaml`
+Raw configuration SHA-256: `d44df83436f5ca81a2a51229b8ffe1a6fd6832d28dff4c7ab2ead3ace8efc9bd`
+Effective configuration SHA-256: `649ddca4a285fbbb00b29c1cab82678e42ab8d6810f89f2131766cd82496c463` + +Batch 25 establishes the strongest stable receiver-saturated base. Batch 26 +shows that ordinary-task route cycling cannot add sender code capacity. Batch +27 therefore changes the objective rather than the route: it directly +penalizes each sender's globally mined hard-message collisions only after the +complete Batch 25 trajectory through step 30,000. + +ECP7-B27-I inherits the full Batch 25 configuration and implementation. The +sole addition is the existing factor-agnostic global collision-pair mechanism +with this fixed schedule: + +1. weight zero through step 30,000; +2. linear warmup to `0.1` at step 35,000; +3. linear decay to zero at step 40,000; +4. weight zero through the 45,000-step ceiling. + +Pairs are mined independently for every sender from hard messages over training +meanings only, refreshed every 200 steps and sampled as 32 pairs per sender +with replacement. Their relaxed full-message collision probability is measured +at temperature `1.0`. The coefficient is reused from Batch 18; the 5,000-step +rise and decay durations are reused from Batch 19. The unchanged hard-meaning +replay branch stays receiver-only after step 20,000, and the ordinary task +continues to update both sides. + +The batch contains exactly two seed-11 runs: + +1. the unchanged ECP-6 positive control; +2. ECP7-B27-I with the late bounded sender-collision pulse. + +All existing validity and development gates remain unchanged. Additionally, +the direct-capacity claim requires the selected minimum unique-message count to +exceed Batch 25's 12,720 while worst-link validation is at least Batch 25's +82.7148%. No alternative coefficient, pulse boundary, pair sampler, replay +route, hard-meaning predicate, architecture, base loss, optimizer, horizon, +data, translator or seed may be tried inside Batch 27. Failure is recorded +without confirmatory test access. + +### Batch 27 outcome + +The registered seed-11 intervention reached 85.38% mean train and validation, +82.15% worst-link train, 82.13% worst-link validation and 85.35% universal- +translator validation. Its global collision-pair banks became substantially +smaller and message entropy increased, but sender codebooks still contained +exactly 13,440, 12,960, 12,720 and 13,440 unique messages—the same capacities +as Batch 25. It failed the unchanged train and injectivity gates and the added +minimum-capacity/worst-link criterion without accessing the confirmatory split. + +This closes coefficient and timing development for the existing relaxed +collision-pair loss. Any later batch must preregister a distinct sender +representation or occupancy-creation mechanism. diff --git a/evidence/ecp7-development/README.md b/evidence/ecp7-development/README.md index 94f2a7f..deed4b3 100644 --- a/evidence/ecp7-development/README.md +++ b/evidence/ecp7-development/README.md @@ -151,6 +151,13 @@ rose from 2,967 to 3,262, confirming that route cycling redistributes errors without fixing sender collisions. Exact identities and hashes are in `batch26-manifest.json`. +Batch 27 added a late bounded direct penalty on globally mined sender +collisions. It reduced unordered collision-pair multiplicity and increased +message entropy, but produced exactly the same unique-message counts as Batch +25 while worst-link validation fell to 82.13%. The existing collision loss +therefore reshapes occupied codes without creating new ones. Exact identities +and hashes are in `batch27-manifest.json`. + Reproduce the development arms with: ```bash diff --git a/evidence/ecp7-development/batch27-manifest.json b/evidence/ecp7-development/batch27-manifest.json new file mode 100644 index 0000000..3cea7d0 --- /dev/null +++ b/evidence/ecp7-development/batch27-manifest.json @@ -0,0 +1,55 @@ +{ + "batch": "ECP7-B27", + "confirmatory_test_unsealed": false, + "config_effective_sha256": "649ddca4a285fbbb00b29c1cab82678e42ab8d6810f89f2131766cd82496c463", + "config_raw_sha256": "d44df83436f5ca81a2a51229b8ffe1a6fd6832d28dff4c7ab2ead3ace8efc9bd", + "control": { + "artifact_hashes": { + "effective_config.yaml": "4bfb976293f117d3ae35f790e4fd6371628be95d91febb334bc275dc5d6b66d4", + "posthoc-analysis.json": "c52382de54ed1ae11716256fa3c9a48f9e61cd6ef39d927ef4fba93548938d0b", + "seed-11/metrics.json": "d772d990448d4f2450cf2b2fed901ab45acec4f74d6b24a9c060e5c0748c48fc", + "summary.json": "0b4f13ef92858adf9113a022fe0d65679f95dfa0d55d959d2b366c9910f19efe" + }, + "development_gate_passed": true, + "population_train_mean_exact_match": 1.0, + "population_validation_mean_exact_match": 1.0, + "run_id": "20260718T180724Z-ecp7-development", + "universal_translator_validation_exact_match": 1.0, + "unique_messages_per_sender": [15360, 15360, 15360, 15360] + }, + "intervention": { + "artifact_hashes": { + "effective_config.yaml": "87db10e18624e99741de1063cbbc0198ef88aed76472ddbfcbdf0843f90f7a48", + "posthoc-analysis.json": "79146dee4f0b1c41c64553fb4c5eddd832726e8946b30ff6375db810f7285ce7", + "seed-11/metrics.json": "97f600d564f387425027151cfe4b534260819975e54920676a00177e48dc8200", + "summary.json": "967378da477f8537b84a5ec23c590c961145f2d464776d8ac54abd57c78fa406" + }, + "batch25_collision_pairs_per_sender": [2128, 2576, 2912, 2128], + "best_step": 43800, + "collision_meanings_per_sender": [1920, 2400, 2640, 1920], + "collision_pairs_per_sender": [1792, 2240, 2464, 1792], + "development_gate_passed": false, + "exact_sender_message_agreement": 0.9236002604166668, + "final_hard_meaning_replay_pool_size": 1792, + "final_step": 45000, + "initial_hard_meaning_replay_pool_size": 1745, + "message_entropy_bits_per_sender": [13.656890595608516, 13.594390595608516, 13.563140595608516, 13.656890595608516], + "minimum_hard_meaning_replay_pool_size": 1414, + "minimum_hard_meaning_replay_pool_step": 18200, + "population_train_mean_exact_match": 0.853759765625, + "population_train_worst_link_exact_match": 0.8214983258928571, + "population_validation_factor_accuracy": [1.0, 1.0, 0.984375, 0.869384765625], + "population_validation_mean_exact_match": 0.853759765625, + "population_validation_worst_link_exact_match": 0.8212890625, + "run_id": "20260718T180838Z-ecp7-development", + "selected_all_links_wrong_meaning_count": 1792, + "selected_any_link_wrong_meaning_count": 2812, + "selected_mean_incorrect_links_per_hard_meaning": 11.928875923156738, + "universal_translator_validation_exact_match": 0.853515625, + "unique_message_capacity_mean": 0.85546875, + "unique_messages_per_sender": [13440, 12960, 12720, 13440] + }, + "seed": 11, + "split_artifact_sha256": "676195997ee0c77d5c9565bae045dbb938b432a2e4e74b666233b0a41f924718", + "split_sha256": "4947058c75ab07cb43a87eb82776b12cb2a7e2eeba7114de110d3b852cbc64cd" +} diff --git a/tests/conftest.py b/tests/conftest.py index efceb99..b319e22 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -173,3 +173,8 @@ def ecp7_b25_config(): @pytest.fixture(scope="session") def ecp7_b26_config(): return load_config(PROJECT_ROOT / "config" / "ecp7-b26-development.yaml") + + +@pytest.fixture(scope="session") +def ecp7_b27_config(): + return load_config(PROJECT_ROOT / "config" / "ecp7-b27-development.yaml") diff --git a/tests/test_config.py b/tests/test_config.py index 854b7f3..47bfb1f 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -943,3 +943,30 @@ def test_hard_replay_gradient_route_phases_are_bounded_and_one_sided( ][-1]["end_step"] = 44800 with pytest.raises(ConfigError, match="must cover max_steps"): validate_config(invalid_final) + + +def test_ecp7_b27_adds_only_a_late_bounded_collision_pulse( + ecp7_b25_config, ecp7_b27_config +): + assert ecp7_b27_config["world"] == ecp7_b25_config["world"] + assert ecp7_b27_config["dataset"] == ecp7_b25_config["dataset"] + assert ecp7_b27_config["channel"] == ecp7_b25_config["channel"] + assert ecp7_b27_config["agents"] == ecp7_b25_config["agents"] + b25_training = deepcopy(ecp7_b25_config["training"]) + b27_training = deepcopy(ecp7_b27_config["training"]) + assert b27_training.pop("global_collision_replay") == { + "enabled": True, + "weight": 0.1, + "start_step": 30000, + "warmup_steps": 5000, + "pair_batch_size": 32, + "refresh_interval": 200, + "relaxed_temperature": 1.0, + "weight_decay": { + "enabled": True, + "start_step": 35000, + "end_step": 40000, + "final_weight": 0.0, + }, + } + assert b27_training == b25_training diff --git a/tests/test_training.py b/tests/test_training.py index 37602f3..cca1e34 100644 --- a/tests/test_training.py +++ b/tests/test_training.py @@ -731,6 +731,19 @@ def test_hard_replay_coordinate_route_follows_registered_phases( ) +def test_late_sender_collision_pulse_preserves_the_first_30000_steps( + ecp7_b27_config, +): + schedule = ecp7_b27_config["training"]["global_collision_replay"] + + assert _scheduled_collision_replay_weight(schedule, 30000) == 0.0 + assert _scheduled_collision_replay_weight(schedule, 32500) == 0.05 + assert _scheduled_collision_replay_weight(schedule, 35000) == 0.1 + assert _scheduled_collision_replay_weight(schedule, 37500) == 0.05 + assert _scheduled_collision_replay_weight(schedule, 40000) == 0.0 + assert _scheduled_collision_replay_weight(schedule, 45000) == 0.0 + + def test_receiver_binding_calibration_recovers_exact_permutation(ecp4_config): receiver = FactorizedPermutationSlotReceiver(ModelSpec.from_config(ecp4_config)) meanings = torch.tensor(