Skip to content

Commit b637ce5

Browse files
authored
Record sealed ECP-7 learning rate decay batch (#15)
Add the learning-rate schedule, preregister and record sealed Batch 14, and update the evidence-backed fresh-agent handoff. The confirmatory ECP-7 test remains sealed.
1 parent 1b42db8 commit b637ce5

12 files changed

Lines changed: 286 additions & 16 deletions

File tree

‎README.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ The protocol uses no words or alphabet, but four meaning-free local symbols. For
2626
See [`docs/results-ecp6.md`](docs/results-ecp6.md) for the conclusion, [`docs/protocol-specification-ecp6.md`](docs/protocol-specification-ecp6.md) for the wire format and [`evidence/ecp6/report.md`](evidence/ecp6/report.md) for the compact confirmatory evidence.
2727

2828
ECP-7 development now tests how much of that result depends on the explicit
29-
one-factor-per-slot architecture. Its first thirteen sealed batches are valid
29+
one-factor-per-slot architecture. Its first fourteen sealed batches are valid
3030
development results but none passes the full gate. Batch 10 remains strongest,
3131
extending the position-aware design to 15,000 optimization steps. It reaches
3232
82.08% train exactness, 72.98% validation and 75.15% translator validation while
3333
using 12,358–12,906 hard messages per sender. The translator threshold now passes,
3434
but the registered train, validation and injectivity thresholds do not. Batch
3535
11's utilization-weight decay regressed all principal measures, and Batch 12's
3636
deeper decoder regressed further. Batch 13's deeper sender collapsed almost
37-
completely. The ECP-6 positive controls remain perfect and the ECP-7
38-
confirmatory test remains sealed. See
37+
completely, and Batch 14's late learning-rate decay also regressed. The ECP-6
38+
positive controls remain perfect and the ECP-7 confirmatory test remains sealed. See
3939
[`docs/development-log-ecp7.md`](docs/development-log-ecp7.md).
4040

4141
## Build on this work
@@ -89,6 +89,7 @@ Do not translate those artifacts in place. New experiment configurations and all
8989
- [`config/ecp7-b11-development.yaml`](config/ecp7-b11-development.yaml) — late utilization-weight decay on the Batch 10 base.
9090
- [`config/ecp7-b12-development.yaml`](config/ecp7-b12-development.yaml) — one additional generic shared decoder layer on the Batch 10 base.
9191
- [`config/ecp7-b13-development.yaml`](config/ecp7-b13-development.yaml) — one additional generic shared sender layer on the Batch 10 base.
92+
- [`config/ecp7-b14-development.yaml`](config/ecp7-b14-development.yaml) — late learning-rate decay on the Batch 10 base.
9293
- [`config/ecp7-positive-control-development.yaml`](config/ecp7-positive-control-development.yaml) — ECP-6 positive control on the ECP-7 split.
9394
- [`config/ecp0.yaml`](config/ecp0.yaml) — machine-readable configuration from step 1.
9495
- [`config/ecp1.yaml`](config/ecp1.yaml) — frozen configuration of the population trial.

‎config/ecp7-b14-development.yaml‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
extends: ecp7-b10-development.yaml
2+
3+
experiment:
4+
title: ECP-7 extended optimization with late learning-rate decay
5+
arm: extended_optimization_learning_rate_decay
6+
objective: >-
7+
Test whether reducing optimizer step size after the original 5,000-step
8+
horizon stabilizes refinement of the strongest weak-structure protocol
9+
without changing its architecture, losses, or temperature schedule.
10+
11+
training:
12+
learning_rate_decay:
13+
enabled: true
14+
start_step: 5000
15+
end_step: 15000
16+
final_learning_rate: 0.0001

‎docs/AI_AGENT_START.md‎

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ python3.12 -m venv .venv
4141
.venv/bin/ecp6 --config config/ecp6.yaml validate
4242
```
4343

44-
Expected baseline: 85 passing tests and split sizes `14336/1024/1024`.
44+
Expected baseline: 88 passing tests and split sizes `14336/1024/1024`.
4545

4646
## 4. Reproduce ECP-6
4747

@@ -71,7 +71,7 @@ This reruns a known experiment. It must not be presented as a new independent co
7171

7272
## 5. Continue ECP-7 scientifically
7373

74-
Do not modify ECP-0 through ECP-6 or the completed ECP-7 Batch 1 through Batch 13
74+
Do not modify ECP-0 through ECP-6 or the completed ECP-7 Batch 1 through Batch 14
7575
configs. ECP7-B1-I collapsed to 130–139 hard messages. ECP7-B2-I improved its
7676
soft objective but collapsed further to 85–104 hard messages. ECP7-B3-I applied
7777
that loss to straight-through hard messages and improved to 585–972 messages,
@@ -99,12 +99,14 @@ the strongest base. ECP7-B12-I added one shared decoder layer and regressed
9999
further to 71.53% train, 47.98% validation and 63.04% translator validation.
100100
ECP7-B13-I added the symmetric sender layer and collapsed to 1.32% train, 0.32%
101101
validation and 0.61% translator validation. The confirmatory ECP-7 test is still
102-
sealed.
102+
sealed. ECP7-B14-I decayed late learning rate and regressed to 79.13% train,
103+
65.49% validation and 71.02% translator validation. B10 remains the strongest
104+
base.
103105

104106
Continue with this sequence:
105107

106108
1. Read `docs/research-design-ecp7.md` and `docs/development-log-ecp7.md`.
107-
2. Define exactly one ECP7-B14 intervention and its failure criterion.
109+
2. Define exactly one ECP7-B15 intervention and its failure criterion.
108110
3. Register the variant and immutable configuration hashes before training.
109111
4. Add tests for every new invariant.
110112
5. Use only `smoke` and `develop`; keep the ECP-7 test split sealed.
@@ -119,21 +121,23 @@ Continue with this sequence:
119121

120122
Batch 10 is the strongest weak-structure result. Batch 11 ruled out reduced late
121123
utilization pressure, while Batches 12 and 13 ruled out extra generic decoder
122-
and sender depth. B10 improved late but fluctuated around its validation plateau
123-
at the unchanged learning rate `0.001`. The most informative next step is one
124-
optimization-stability schedule. A clean ECP7-B14 progression is:
124+
and sender depth. Batch 14 showed that reducing late learning rate is also
125+
harmful, while B10 selected its final 15,000-step checkpoint. The most
126+
informative next step is one final duration-only extension. A clean ECP7-B15
127+
progression is:
125128

126129
- keep the same world and bit budget;
127130
- return to the complete B10 training and loss schedule;
128-
- keep learning rate `0.001` through step 5,000;
129-
- decay only that rate linearly to `0.0001` at step 15,000;
131+
- keep constant learning rate `0.001` and the temperature endpoint `0.8`;
132+
- extend only maximum population steps to 30,000, minimum selection to 15,000
133+
and patience to 5,000;
130134
- measure injectivity, validation composition and new-reader induction;
131135
- rerun the ECP-6 architecture as the frozen positive control.
132136

133-
Do not change architecture, loss weights, optimizer type, data, temperature,
134-
duration, validation cadence or development thresholds, and do not combine the
135-
learning-rate schedule with variable-length messages or negotiation. That would
136-
make its effect uninterpretable.
137+
Do not change architecture, loss weights, optimizer, data, temperature,
138+
validation cadence or development thresholds, and do not combine the longer
139+
horizon with variable-length messages or negotiation. That would make its
140+
effect uninterpretable.
137141

138142
## 7. Definition of done for any contribution
139143

‎docs/development-log-ecp7.md‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,3 +924,71 @@ validation plateau at the unchanged learning rate `0.001`. A future ECP7-B14 may
924924
keep the complete B10 design and learning rate through step 5,000, then decay
925925
only that rate linearly to `0.0001` at step 15,000. Temperature, utilization,
926926
architecture, duration, data, translator and thresholds must remain unchanged.
927+
928+
## Batch 14 preregistration
929+
930+
Date: July 18, 2026<br>
931+
Seed: `11`<br>
932+
Maximum population steps: `15,000`<br>
933+
Temperature schedule steps: `5,000`, then hold at `0.8`<br>
934+
Learning rate: `0.001` through step `5,000`, then linear to `0.0001` at step `15,000`<br>
935+
Split-SHA-256: `4947058c75ab07cb43a87eb82776b12cb2a7e2eeba7114de110d3b852cbc64cd`<br>
936+
Test unsealed: **no**
937+
938+
ECP7-B14-I keeps every Batch 10 model, loss and training setting except the late
939+
learning-rate schedule. The optimizer rate remains identical through the
940+
original 5,000-step horizon, then decays tenfold. The unchanged positive control
941+
is rerun, and no alternative schedule or accompanying intervention is admitted
942+
into this batch.
943+
944+
## Batch 14 results
945+
946+
Positive-control run: `runs/ecp7-batch14-control-development/20260718T132929Z-ecp7-development`<br>
947+
Intervention run: `runs/ecp7-batch14-intervention-development/20260718T132929Z-ecp7-development`<br>
948+
Test unsealed: **no**
949+
950+
| Metric | Positive control | ECP7-B14-I |
951+
|---|---:|---:|
952+
| Population train, mean | 100% | 79.1321% |
953+
| Population train, worst link | 100% | 77.7902% |
954+
| Population validation, mean | 100% | 65.4907% |
955+
| Population validation, worst link | 100% | 63.1836% |
956+
| Universal translator, validation | 100% | 71.0205% |
957+
| Exact sender-message agreement | 100% | 89.04% |
958+
| Unique messages per sender | 15,360 | 11,961–12,280 |
959+
| Collision meanings per sender | 0 | 3,080–3,399 |
960+
| Message entropy | 13.91 bits | 13.43–13.48 bits |
961+
| Development gate | pass | **fail** |
962+
963+
The positive control passed every gate at 100%. ECP7-B14-I retained a passing
964+
translator score, but failed train, validation and injectivity. It does not
965+
authorize confirmatory access.
966+
967+
Relative to B10, late learning-rate decay reduced train exactness from 82.0836%
968+
to 79.1321%, validation from 72.9797% to 65.4907%, and translator validation from
969+
75.1465% to 71.0205%. Sender agreement and code use also fell. Smaller late
970+
updates therefore did not stabilize the B10 refinement trajectory.
971+
972+
Population validation factor accuracies were
973+
`[87.10%, 91.46%, 98.44%, 86.36%]`; universal-translator factor accuracies were
974+
`[87.21%, 98.34%, 98.44%, 85.35%]`.
975+
976+
The selected checkpoint was step 14,800, where learning rate had decayed to
977+
`0.000118`. Task loss was `0.0868` and utilization loss was `-0.7330`. The final
978+
step at learning rate `0.0001` was slightly worse on validation.
979+
980+
Both sealed analyses report 65 matching artifact hashes, 16,384 validation-only
981+
episodes, no confirmatory-test keys, valid local alphabets, and exactly 14
982+
declared bits for every logged message.
983+
984+
## Batch 14 decision
985+
986+
ECP7-B14-I is rejected. Constant late learning rate is beneficial relative to
987+
decay, and Batch 10 remains the strongest weak-structure base. The confirmatory
988+
split remains sealed.
989+
990+
B10 selected its final 15,000-step checkpoint and B14 shows that shrinking late
991+
updates is harmful. A future ECP7-B15 may therefore keep the exact B10
992+
architecture, losses, constant learning rate and temperature endpoint, then
993+
extend only the maximum population horizon to 30,000 steps with minimum
994+
selection step 15,000 and patience 5,000. No other setting may change.

‎docs/research-design-ecp7.md‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,3 +591,38 @@ All existing validity and development gates remain unchanged. Failure is
591591
recorded without confirmatory test access. No alternative sender depth,
592592
activation, width, residual connection, decoder, loss, duration, optimizer or
593593
seed may be tried inside Batch 13.
594+
595+
## Batch 14 preregistration — Late learning-rate decay
596+
597+
Status: **preregistered for sealed development**<br>
598+
Preregistered: July 18, 2026<br>
599+
Configuration: `config/ecp7-b14-development.yaml`<br>
600+
Raw configuration SHA-256: `867e42a0a8c530a4bd1d42be68f2846b66ce368644e993be67f82b39c8caec04`<br>
601+
Effective configuration SHA-256: `f44a36695c59bd532d7372c6cb3fb5b6eeed06b5bc10f04e96603926f7a9f37e`
602+
603+
Batches 12 and 13 rejected additional generic decoder and sender depth. Batch
604+
11 rejected reducing late utilization pressure. Batch 10 remains the base: it
605+
continued to improve late, but its validation score fluctuated around a plateau
606+
while AdamW retained learning rate `0.001` through step 15,000.
607+
608+
Batch 14 tests one optimization-stability hypothesis: smaller late parameter
609+
updates can refine the established high-entropy code without changing its
610+
architecture, temperature or objective balance.
611+
612+
ECP7-B14-I keeps the complete B10 model, losses, optimizer type, data,
613+
temperature schedule, duration, selection window and translator. Learning rate
614+
remains exactly `0.001` through step 5,000, then decays linearly to `0.0001` at
615+
step 15,000. No other AdamW or training setting changes.
616+
617+
This reproduces the full B9 trajectory before the learning-rate schedules
618+
diverge. Smoke runs are mechanical only and may not authorize tuning.
619+
620+
The batch contains exactly two seed-11 runs:
621+
622+
1. the unchanged ECP-6 positive control;
623+
2. ECP7-B14-I with late learning-rate decay on the B10 base.
624+
625+
All existing validity and development gates remain unchanged. Failure is
626+
recorded without confirmatory test access. No alternative final rate, decay
627+
shape, decay boundary, architecture, loss, duration, optimizer or seed may be
628+
tried inside Batch 14.

‎evidence/ecp7-development/README.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ exactness, 0.32% validation, 0.61% translator validation and only 694–831
7373
messages. Sender depth is therefore also rejected. Exact identities and hashes
7474
are in `batch13-manifest.json`.
7575

76+
Batch 14 decayed learning rate after step 5,000. It regressed to 79.13% train
77+
exactness, 65.49% validation and 71.02% translator validation. Constant late
78+
learning rate is therefore retained. Exact identities and hashes are in
79+
`batch14-manifest.json`.
80+
7681
Reproduce the development arms with:
7782

7883
```bash
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"batch": "ECP7-B14",
3+
"confirmatory_test_unsealed": false,
4+
"control": {
5+
"artifact_hashes": {
6+
"effective_config.yaml": "4bfb976293f117d3ae35f790e4fd6371628be95d91febb334bc275dc5d6b66d4",
7+
"posthoc-analysis.json": "a7bccd464704ce71e3e8baa7508883f2512c0dd202d5a0f735ca1b5d9011f7ae",
8+
"seed-11/metrics.json": "96bbb66b3561ad9f051a8ff6680ef1950488c6ba59aa755365e8e94be8468e01",
9+
"summary.json": "69f46e4b77edadb7186f2dba02283945bae97e6f66aff80b39d1f868496c3737"
10+
},
11+
"development_gate_passed": true,
12+
"population_train_mean_exact_match": 1.0,
13+
"population_validation_mean_exact_match": 1.0,
14+
"run_id": "20260718T132929Z-ecp7-development",
15+
"universal_translator_validation_exact_match": 1.0,
16+
"unique_messages_per_sender": [15360, 15360, 15360, 15360]
17+
},
18+
"intervention": {
19+
"artifact_hashes": {
20+
"effective_config.yaml": "c6f581a77ca83bea6b0703ef6a58fc9081dfcbaf4c2af5e1cd94fbb85eff2185",
21+
"posthoc-analysis.json": "1b7010c1487517868fb782cec2eb42dcb39adef33e8ceb005ac467982a0dd852",
22+
"seed-11/metrics.json": "31383793df7c77b6fa85f8d7a7748c6a4d88d7d42690f329eed6e35b9a5913a3",
23+
"summary.json": "e63674150ff7fd0503460b7e018357e9e2f5478ead2db4a8a896fdde379854ab"
24+
},
25+
"best_code_utilization_loss": -0.733005940914154,
26+
"best_learning_rate": 0.00011800000000000005,
27+
"best_step": 14800,
28+
"collision_meanings_per_sender": [3080, 3081, 3399, 3297],
29+
"development_gate_passed": false,
30+
"exact_sender_message_agreement": 0.890407986111111,
31+
"message_entropy_bits_per_sender": [13.479958807644351, 13.479892430690663, 13.425251135080563, 13.449829537426103],
32+
"population_train_mean_exact_match": 0.79132080078125,
33+
"population_train_worst_link_exact_match": 0.7779017857142857,
34+
"population_validation_factor_accuracy": [0.87103271484375, 0.91461181640625, 0.984375, 0.8636474609375],
35+
"population_validation_mean_exact_match": 0.6549072265625,
36+
"population_validation_worst_link_exact_match": 0.6318359375,
37+
"run_id": "20260718T132929Z-ecp7-development",
38+
"universal_translator_validation_exact_match": 0.710205078125,
39+
"unique_messages_per_sender": [12280, 12279, 11961, 12063]
40+
},
41+
"seed": 11,
42+
"split_artifact_sha256": "676195997ee0c77d5c9565bae045dbb938b432a2e4e74b666233b0a41f924718",
43+
"split_sha256": "4947058c75ab07cb43a87eb82776b12cb2a7e2eeba7114de110d3b852cbc64cd"
44+
}

‎src/ai_taal/config.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,29 @@ def validate_config(config: dict[str, Any]) -> None:
139139
if temperature_schedule_steps > training["max_steps"]:
140140
raise ConfigError("Temperature schedule steps cannot exceed max_steps.")
141141

142+
learning_rate_decay = training.get("learning_rate_decay", {})
143+
if learning_rate_decay.get("enabled", False):
144+
start_step = learning_rate_decay.get("start_step", 0)
145+
end_step = learning_rate_decay.get("end_step", 0)
146+
final_learning_rate = learning_rate_decay.get("final_learning_rate", 0)
147+
if not isinstance(start_step, int) or isinstance(start_step, bool):
148+
raise ConfigError("Learning-rate decay start must be an integer.")
149+
if not isinstance(end_step, int) or isinstance(end_step, bool):
150+
raise ConfigError("Learning-rate decay end must be an integer.")
151+
if start_step < 1:
152+
raise ConfigError("Learning-rate decay start must be positive.")
153+
if end_step <= start_step or end_step > training["max_steps"]:
154+
raise ConfigError(
155+
"Learning-rate decay end must follow its start and fit max_steps."
156+
)
157+
if (
158+
final_learning_rate <= 0
159+
or final_learning_rate >= training["learning_rate"]
160+
):
161+
raise ConfigError(
162+
"Final learning rate must be positive and below its initial value."
163+
)
164+
142165
utilization = training.get("code_utilization", {})
143166
if utilization.get("enabled", False):
144167
if utilization.get("weight", -1) < 0:

‎src/ai_taal/training.py‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ def train_communication_system(
9393

9494
for step in range(1, max_steps + 1):
9595
system.train()
96+
learning_rate = _scheduled_learning_rate(training, step)
97+
for parameter_group in optimizer.param_groups:
98+
parameter_group["lr"] = learning_rate
9699
indices = torch.randint(
97100
len(train_values), (batch_size,), generator=generator, device="cpu"
98101
).to(device)
@@ -113,6 +116,7 @@ def train_communication_system(
113116
record: dict[str, float | int] = {
114117
"step": step,
115118
"loss": float(loss.detach().cpu()),
119+
"learning_rate": float(learning_rate),
116120
"temperature": float(temperature),
117121
"train_exact": train_metrics["exact_match"],
118122
"validation_exact": validation_metrics["exact_match"],
@@ -246,6 +250,9 @@ def train_population_system(
246250

247251
for step in range(1, max_steps + 1):
248252
population.train()
253+
learning_rate = _scheduled_learning_rate(training, step)
254+
for parameter_group in optimizer.param_groups:
255+
parameter_group["lr"] = learning_rate
249256
indices = torch.randint(
250257
len(train_values),
251258
(training["batch_size"],),
@@ -443,6 +450,7 @@ def train_population_system(
443450
"sender_message_consensus_weight": float(
444451
sender_consensus_weight
445452
),
453+
"learning_rate": float(learning_rate),
446454
"temperature": float(temperature),
447455
"train_mean_exact": train_metrics["mean_exact_match"],
448456
"train_worst_pair_exact": train_metrics["worst_pair_exact_match"],
@@ -1023,6 +1031,25 @@ def _scheduled_temperature(
10231031
)
10241032

10251033

1034+
def _scheduled_learning_rate(training: dict[str, Any], step: int) -> float:
1035+
initial_learning_rate = float(training["learning_rate"])
1036+
decay = training.get("learning_rate_decay", {})
1037+
if not decay.get("enabled", False):
1038+
return initial_learning_rate
1039+
1040+
start_step = int(decay["start_step"])
1041+
if step <= start_step:
1042+
return initial_learning_rate
1043+
end_step = int(decay["end_step"])
1044+
final_learning_rate = float(decay["final_learning_rate"])
1045+
if step >= end_step:
1046+
return final_learning_rate
1047+
progress = (step - start_step) / (end_step - start_step)
1048+
return initial_learning_rate + (
1049+
final_learning_rate - initial_learning_rate
1050+
) * progress
1051+
1052+
10261053
def _scheduled_code_utilization_weight(
10271054
utilization_config: dict[str, Any], step: int
10281055
) -> float:

‎tests/conftest.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,8 @@ def ecp7_b12_config():
108108
@pytest.fixture(scope="session")
109109
def ecp7_b13_config():
110110
return load_config(PROJECT_ROOT / "config" / "ecp7-b13-development.yaml")
111+
112+
113+
@pytest.fixture(scope="session")
114+
def ecp7_b14_config():
115+
return load_config(PROJECT_ROOT / "config" / "ecp7-b14-development.yaml")

0 commit comments

Comments
 (0)