|
Download docs/analysis_plan.md from NicolasT08/formal-mas: direct link, hf CLI and curl.
- Browser
- Download file 22.8 kB
-
https://huggingface.co/NicolasT08/formal-mas/resolve/main/docs/analysis_plan.md
- Command line
-
hf download hf://NicolasT08/formal-mas/docs/analysis_plan.md
-
curl -L -o analysis_plan.md https://huggingface.co/NicolasT08/formal-mas/resolve/main/docs/analysis_plan.md
22.8 kB
| # Analysis plan (pre-registered before any run on `test`) | |
| Written 2026-11-03, during Phase 8 Part A, **before any configuration was run on the `test` | |
| split**. It fixes the metrics, tests and handling rules so that the analysis does not depend on | |
| the results. Any later change must be recorded at the end of this file with its date and reason, | |
| and reported in the paper as a deviation. | |
| Notation and equations refer to the report (`docs/report/Proyecto_Inteligencia.pdf`, Section IV-A). | |
| ## 1. Data and design | |
| - **Problems:** `data/eval.jsonl`, split `test`: 30 problems, stratified on the 3 × 3 grid | |
| (difficulty easy/medium/hard × area algebra/number theory/combinatorics, with the documented | |
| reallocation of Phase 7). The split was fixed with seed 2026 before any prompt tuning. | |
| - **Configurations:** C1–C5 (Section IV-A8), all on the same LangGraph graph, profile | |
| `experiment` (`deepseek-flash`, `config/models.yaml`), seed 2026, with the configuration frozen | |
| by the team's commit at the end of Part A (its hash is recorded in each `run_config.json`). | |
| - **Run order on `test`:** C5, C3, C4, C2, C1 (team decision 2026-10-31). | |
| - **One run per (configuration, problem).** No configuration is re-run on `test` to obtain a | |
| better result. The only exception is the `provider_error` rule of Section 5. | |
| - **Paired design:** every configuration sees the same 30 problems, so comparisons between | |
| configurations are paired by problem. | |
| - The LLM response cache stays on. Identical requests across configurations (e.g. the first | |
| attempt of C4 and C5) are answered from the cache; this keeps the paired comparison tighter and is | |
| stated in the paper. Costs are compared with the **nominal** cost (`cost_usd_nominal`: cache | |
| hits priced as fresh calls) so that run order does not favour later configurations. | |
| ## 2. Primary outcome | |
| - **Verified success** of configuration *m* on problem *x*: Acc(φ_x, c*_x) of Eq. 2 for the final | |
| assembled proof (status `solved` in `results.jsonl`). Only the Lean kernel decides (RNF-1). | |
| - **Success rate:** SR_m = (number solved) / 30, with a **Wilson 95 % interval**. | |
| - Since each problem is run once, pass@k of Eq. 15 is estimated only for k = 1 (= SR_m). This is | |
| stated as a limitation; no repeated sampling is run. | |
| ## 3. Planned comparisons (confirmatory) | |
| Three comparisons, decided now, each a **two-sided exact McNemar test** on the paired outcomes | |
| (binomial test on the discordant pairs b, c with p = 1/2), **Bonferroni-corrected** for 3 tests | |
| (reject at p < 0.05 / 3 ≈ 0.0167; adjusted p-values = min(1, 3p) are also reported): | |
| | ID | Comparison | Question | | |
| |---|---|---| | |
| | H1 | C5 vs C1 | Does the multi-agent pipeline beat direct proof prompting (at equal mean measured computation, `b_max` of C1 fixed in Part A)? | | |
| | H2 | C5 vs C3 | RAG contribution, Δ_RAG = SR_C5 − SR_C3 (Section IV-A9e). | | |
| | H3 | C5 vs C4 | Contribution of the Critic loop (retries and replanning). | | |
| For each one we report: b and c (discordant counts), ΔSR, a 95 % **paired bootstrap** interval for | |
| ΔSR (10 000 resamples of problems, seed 2026, percentile method), the exact p-value and the | |
| Bonferroni-adjusted p-value. With n = 30 the power is low; a non-significant result is reported as | |
| "no evidence of a difference", never as "no difference". | |
| **Exploratory only** (no correction, labelled exploratory, no claims): C3 vs C4, C1 vs C3, C1 vs C4, | |
| and any per-difficulty or per-area comparison. | |
| C2 is **not** compared with McNemar on verified success: its success is self-assessed, not verified. | |
| ## 4. Secondary outcomes | |
| 1. **Per cell of the 3 × 3 grid:** for each configuration, solved / n of each (difficulty, area) | |
| cell, with the cell's n shown. Descriptive only: no tests and no intervals per cell (n ≤ 5). | |
| Margins by difficulty and by area are reported with Wilson intervals. Empty cells (no easy | |
| combinatorics) are shown as "—". | |
| 2. **Baseline B (Eq. 16):** claimed rate |B⁺| / 30 (Wilson), and FPR_B = |{x ∈ B⁺ : ¬Acc}| / |B⁺| | |
| (Wilson), where every self-assessed proof is passed to the Autoformalizer–Verifier loop with the | |
| same budget (`run_baseline_b.py --check`, to be built before the C2 run on `test`). FPR_B is an | |
| upper bound on the true false-positive rate; a manual review of the B⁺ problems that fail | |
| formalization (all of them if ≤ 10, otherwise 10 drawn with seed 2026) separates wrong informal | |
| proofs from formalization failures. | |
| 3. **Efficiency (Section IV-A9c, RNF-3):** per configuration, C̄_solved = Σ_x C(x) / #solved | |
| (failed problems' calls included in the numerator), and the same ratio for tokens, nominal USD | |
| cost and wall-clock time; also the means per problem. 95 % bootstrap intervals (resampling | |
| problems). RNF-3 (C̄_solved ≤ 20) is checked for C5 and reported as met or not; it is not tuned. | |
| 4. **Refinement robustness (Eqs. 14, IV-A9d):** SR(k) for k = 1, 2, 3, where a C5 problem counts | |
| as solved at k if its accepted proof used at most k attempts on every subgoal (read from | |
| `trace.jsonl`); k = 1 is also reported from C4. Δ̂(k) = SR(k) − SR(k−1) is plotted against the | |
| independence curve of Eq. 14 with p_i estimated from first-attempt subgoal success in C5. The | |
| paper states that k = 1 from C4 has no retries or advice while k = 2, 3 come from C5. | |
| 5. **Error taxonomy (Section IV-A9f):** relative frequency of each κ class of Eq. 11 over **all | |
| failed attempts**, per configuration and per area; separately, the final failure reason per | |
| problem (`stage` and final status). C1 attempts are classified with the same κ. | |
| ## 5. Status handling | |
| | Status in `results.jsonl` | Meaning | Primary analysis | | |
| |---|---|---| | |
| | `solved` | Acc holds on the assembled proof | success | | |
| | `failed` (any `stage`) | the method did not find an accepted proof | failure | | |
| | `budget_exhausted` | `b_max` LLM calls reached | failure (the budget is part of the method) | | |
| | `timeout` / memory limit | Lean verification limits | failure | | |
| | `error` / `node_error` / `invalid_statement` | a bug in the system or the statement | failure; counted and listed | | |
| | `provider_error` | the API refused or failed after all transport retries | see below | | |
| | `budget_stop` | the project or run spend cap stopped the run | see below | | |
| | run status `lean_unavailable`; row with `lean_down: true` | Lean could not load Mathlib (start-up probes) | as `provider_error`: infrastructure; re-run once, see below | | |
| - **`provider_error`** is an infrastructure failure, not a decision of the model. After a run, the | |
| problems with `provider_error` are re-run **once**, in a new run folder with the same | |
| configuration and cache (the original run is kept untouched). The re-run's result replaces the | |
| provider error in the analysis. If it is again `provider_error`, it counts as a **failure** in the | |
| primary analysis, and a sensitivity analysis excludes those problems from that configuration | |
| (and, for McNemar, the pairs where either side is excluded). Counts are reported per configuration. | |
| - **`budget_stop`**: the problem and the rest of the run were not attempted. The team decides | |
| whether to raise the spend cap; if raised, only the problems not attempted are run with the same | |
| frozen configuration and merged. If not, that configuration is reported as **incomplete**: SR on | |
| the attempted problems (with n stated), a conservative SR counting not-attempted problems as | |
| failures, and McNemar only on the problems attempted by both configurations. | |
| - **Lean unavailable**: a run that stops with `lean_unavailable` made no LLM call for the problems | |
| not run; those problems, and a row marked `lean_down: true` (Lean was lost during it, so its | |
| failure may be Lean's), are re-run once with the same configuration, exactly like | |
| `provider_error`. A success in a `lean_down` row stands (the kernel accepted it). | |
| - Runs marked `degraded` (Lean file back-end used) are valid and are flagged in the tables. | |
| ## 6. Fidelity notes (manual check before reporting success) | |
| `data/curation/fidelity_review.yaml` lists, under `notes`, problems whose formal statement differs | |
| from the informal text in a way judged harmless at curation time. Every problem **solved on `test` | |
| by any configuration** that has a note is reviewed by hand before it is counted as a success in the | |
| paper (PLAN.md, Phase 9). The review records whether the accepted proof establishes what the | |
| informal problem asks. The verified SR (Section 2) is never changed by this review: the kernel's | |
| verdict is what it is. If a review concludes that the formal statement does not capture the | |
| informal problem, the paper reports it next to the table (problem, configuration, reason) and gives | |
| the SR both with and without that problem. | |
| ## 7. What is reported, in order | |
| 1. Table: SR with Wilson 95 % CI for C1, C3, C4, C5; claimed rate and FPR_B for C2. | |
| 2. Table: H1–H3 with b, c, ΔSR, bootstrap CI, exact p and Bonferroni-adjusted p. | |
| 3. Table: per-cell solved/n for each configuration, with difficulty and area margins. | |
| 4. Table: efficiency (calls, tokens, nominal cost, time per problem and per solved problem). | |
| 5. Figure: SR(k), k = 1…3, vs the independence curve of Eq. 14. | |
| 6. Figure or table: κ taxonomy per configuration and area. | |
| 7. Counts of `provider_error`, `budget_stop`, `error`, degraded runs and the fidelity reviews. | |
| Analysis code (`src/formal_mas/analysis/stats.py`, `scripts/compare.py`) is written in Phase 9 to | |
| implement exactly this plan; it is tested on `dev` runs before it reads any `test` result. | |
| ## Exploratory analysis (post hoc, decided 2026-11-08) | |
| Decided after all confirmatory `test` runs and their analysis were finished. It is exploratory | |
| and changes no result, test or conclusion of §2–§7. | |
| - **Motivation.** The hard problems look limited by the model rather than by the method: C1 and | |
| C5 solve the same 4 of the 10 hard `test` problems (`imo_1964_p1_2`, `imo_1965_p2`, | |
| `putnam_1964_b2`, `putnam_1965_b2`), so the agents add nothing on that stratum with | |
| DeepSeek-Flash. | |
| - **Run.** C5 exactly as frozen for the main runs (same graph, prompts, `pipeline.yaml` method | |
| settings, seed, `B_max`/`b_max`), with model profile `experiment_pro`: identical to | |
| `experiment` except that every role uses `deepseek-v4-pro` instead of `deepseek-flash` | |
| (`config/models.yaml`). Input: the 10 hard `test` problems, all of them (not only those C5-Flash | |
| failed), as a file with exactly those lines of `data/eval.jsonl` in dataset order; its sha256 and | |
| id list go in `run_config.json`. One run, `--run-usd 5.00`; if it ends in `budget_stop` it is not | |
| resumed and the problems without a complete row are reported as not attempted. | |
| - **Reported.** A descriptive paired table, problem by problem, C5-Flash (the kept rows of the | |
| main C5 `test` result, §Deviations) vs C5-Pro on the same 10 problems: solved, LLM calls, | |
| cost (real and nominal), wall time in minutes; plus totals. The 2×2 table of solved/not solved | |
| may be shown as counts. | |
| - **Not done.** No hypothesis test, CI or p-value; nothing is added to the Bonferroni family; no | |
| claim about Pro beyond these 10 problems. Pro's results never replace C5's in any main table. | |
| - **Fidelity.** Any new success gets the same manual fidelity check as §6 before it is reported. | |
| ## Deviations | |
| No deviation from the analysis itself. Infrastructure incidents during the `test` runs: | |
| - **2026-11-03, C5 on `test` interrupted by low memory.** Run `20261103T174646Z_C5_experiment` | |
| (commit `ad70ec2`, clean tree) was killed at about 19:16 UTC by the host (Claude Code stops | |
| background jobs when the machine runs critically low on memory; the Lean REPL, ~3.5 GB, was | |
| sharing RAM with an idle Lean language server, ~2.7 GB). It is an infrastructure failure, not a | |
| decision of the method. 23 of 30 problems had finished and are kept unchanged; the 24th | |
| (`imo_1987_p6`) was cut mid-problem and left no row in `results.jsonl`. No row was `lean_down`, | |
| and there was no `provider_error` or `budget_stop`. | |
| The 7 problems without a row were completed in two resume runs. Both used the same frozen | |
| configuration (the analysis is the same at either commit), the same seed and cache, and the | |
| language server was stopped first. The input of each is a file holding exactly the needed lines of | |
| `data/eval.jsonl`, unchanged and in the original order. Its sha256 and the id list are in that | |
| run's `run_config.json`, and a copy is kept as `test_remaining.jsonl` in that run's folder. | |
| 1. `20261103T212359Z_C5_experiment_resume` (commit `ad70ec2`, clean tree; input sha256 | |
| `53284f8f…086fc4`) ran all 7 from scratch: `imo_1987_p6`, `imo_1979_p1`, `imo_1984_p6`, | |
| `imo_1964_p1_2`, `putnam_1964_b2`, `putnam_1995_b1`, `putnam_1965_b2`. It reached its spend | |
| cap (`--run-usd 0.50`) during the third problem. `imo_1987_p6` and `imo_1979_p1` finished | |
| (both `failed`). `imo_1984_p6` got a `budget_stop` row after 19 calls, and the last 4 were | |
| not attempted. | |
| 2. `20261103T225140Z_C5_experiment_resume2` (commit `93bc701`, which changes only this file; clean | |
| tree; input sha256 `f3da0f6d…6d77f91`) ran `imo_1984_p6` from scratch, | |
| plus the 4 problems not attempted, with `--run-usd 1.00` (the cap raised by team decision, §5). | |
| The requests that `imo_1984_p6` repeats from step 1 are answered from the cache. | |
| **Merge:** the C5 result on `test` has one row per problem (30 in all), taken from the run where | |
| the problem finished: | |
| - 23 rows from the first run; | |
| - `imo_1987_p6` and `imo_1979_p1` from resume 1; | |
| - `imo_1984_p6` and the other 4 from resume 2. | |
| The `budget_stop` row of `imo_1984_p6` in resume 1 is discarded; only its complete row counts. The | |
| spend of the discarded attempts (`imo_1987_p6` in the first run and `imo_1984_p6` in resume 1) | |
| counts towards the project's real cost. It is not in any kept row, so each problem's efficiency | |
| figures come from its kept row only. Cache hits lower the real cost of the resume runs but not | |
| their nominal cost, and nominal cost is the figure compared (§1). | |
| - **2026-11-03, run order C4 before C3.** C4 was run right after C5, and C3 moved to the next | |
| off-peak morning, so the order is C5, C4, C3, C2, C1 instead of C5, C3, C4, C2, C1 (§1). The | |
| reason is schedule and cost only. C3 takes about 3 h and would have run into the provider's peak | |
| window (01:00 UTC), while C4 is short and is answered mostly from the cache of C5. This has no | |
| effect on the analysis. Each configuration is still run once on the same 30 problems with the | |
| same frozen configuration, and the comparisons are paired by problem. C4 shares its cached | |
| requests with C5, not with C3, so its cache hits are the same in either order. Costs are compared | |
| at nominal prices (§1), so run order does not favour either configuration. | |
| - **2026-11-04, per-run spend cap raised from 1.0 to 2.0 USD before C3 on `test`.** Team decision. | |
| Only `config/pipeline.yaml → spend.run_usd` changed (1.0 → 2.0); `run_eval.py --run-usd` can only | |
| lower that cap, so C3 (about 3 h, no cache shared with C5 because its prompts carry no lemmas; | |
| C5 on `test` cost 1.36 USD real in total) would otherwise very likely end in `budget_stop` | |
| before the 30th problem. This is a spend-control change, not a method change: the cap is | |
| checked before each paid request and only decides whether the request is sent, so it does not | |
| change any prompt, model, budget `B_max`/`b_max`, policy or result of a request that is sent. The | |
| project cap `spend.total_usd` stays at 9.0 USD. C5 and C4 ran under the 1.0 USD cap (or a lower | |
| `--run-usd`); C3 runs with `--run-usd 2.00`. The offline test that pins the configured caps | |
| (`tests/test_spend.py::test_real_pipeline_yaml_has_the_caps`) was updated to the new value. | |
| - **2026-11-05, per-run spend cap raised from 2.0 to 3.5 USD before C1 on `test`.** Team decision. | |
| Only `config/pipeline.yaml → spend.run_usd` changed (2.0 → 3.5). C1 costs more per call than C5 | |
| (the cost run `20261103T161957Z_C1_experiment_c1_cost` spent 0.21 USD real on 3 `dev` problems, | |
| about 0.07 USD per problem), so 30 problems would likely end in `budget_stop` under 2.0 USD. As | |
| before, this is a spend-control change, not a method change: the cap is checked before each paid | |
| request and only decides whether the request is sent, so it does not change any prompt, model, | |
| budget `B_max`/`b_max`, policy or result of a request that is sent. The project cap | |
| `spend.total_usd` stays at 9.0 USD. C1 runs with `--run-usd 3.50`. The offline test that pins | |
| the configured caps was updated to the new value. | |
| - **2026-11-05, C1 on `test` stopped by the team.** Run `20261105T131443Z_C1_experiment` (commit | |
| `5ed7507`, clean tree, `--run-usd 3.50`) was stopped on purpose at about 17:43 UTC, together with | |
| its whole process tree (REPL, `lake`), to free the machine for other work. It is an operational | |
| incident, not a decision of the method: no code, prompt, model or configuration changed. 23 of 30 | |
| problems had finished and are kept unchanged; the 24th (`imo_1987_p6`) was cut mid-problem | |
| (after 10 calls, 0.10 USD real) and left no row in `results.jsonl`. There was no `provider_error` | |
| or `budget_stop`. The 7 problems without a row will be completed in a resume run, following the | |
| same procedure as for C5 (same frozen configuration, seed and cache; input file with exactly the | |
| needed lines of `data/eval.jsonl`; `imo_1987_p6` run from scratch, its earlier spend counted in the | |
| project's real cost but in no kept row). | |
| The resume run is `20261107T200233Z_C1_experiment_resume` (commit `2c8eae5`, clean tree; input | |
| sha256 `009bece56dc0fdde3c814c9e81aeda6ee7bd8dd677d0fa29bab5dd723c907b8b`, the 7 problems in | |
| dataset order; `--run-usd 1.65` = 3.50 minus the 1.8407 USD C1 had spent, rounded down, so that | |
| C1 as a whole stays under 3.50). | |
| - **2026-11-07, `dirty: true` in four `run_config.json` files (recording artefact, found in the | |
| analysis).** `run_eval.py` rewrites `run_config.json` when a run ends, and the git state (and | |
| `created_utc`) were read again at that moment instead of at launch. In | |
| `20261103T212359Z_C5_experiment_resume`, `20261103T225140Z_C5_experiment_resume2`, | |
| `20261103T235556Z_C4_experiment` and `20261107T200233Z_C1_experiment_resume` the only changed file | |
| is `docs/analysis_plan.md`, edited while the run was going to log these very incidents; every | |
| tree was clean at launch (checked before each run, as the Phase 8 rules require). No code, | |
| prompt, configuration or data file changed, so the method is not affected. In those files | |
| `created_utc` is also the end time; the start is the timestamp in the run name and the | |
| `run_start` event of `trace.jsonl`. The two interrupted runs (`20261103T174646Z_C5_experiment`, | |
| `20261105T131443Z_C1_experiment`) never reached the final rewrite and show their launch state. | |
| Fixed after all `test` runs (`run_config.run_start_info`): `git` and `created_utc` now describe | |
| the launch, and the state when the file is written goes to `git_end` and `written_utc`. Runs | |
| already made are not rewritten. | |
| - **2026-11-08, spend caps raised for the exploratory C5-Pro run (spend control).** Team decision, | |
| after all confirmatory `test` runs. Only `config/pipeline.yaml → spend` changed: `total_usd` | |
| 9.0 → 12.5 and `run_usd` 3.5 → 5.0. The ledger stood at 7.36 USD; re-pricing C5-Flash's tokens on | |
| the 10 hard `test` problems at Pro prices gives about 3.75 USD off-peak (7.49 USD at peak), so the | |
| old caps would stop the run. As before, the caps are checked before each paid request and only | |
| decide whether it is sent; no prompt, model of the main profiles, budget `B_max`/`b_max`, policy | |
| or result changes, and no confirmatory run is repeated. The run uses `--run-usd 5.00`. The | |
| offline test that pins the configured caps | |
| (`tests/test_spend.py::test_real_pipeline_yaml_has_the_caps`) was updated to the new values. | |
| - **2026-11-08, exploratory C5-Pro run stopped by the team (operational incident).** Run | |
| `20261108T130803Z_C5_experiment_pro_pro_hard` (commit `8f72b02`, clean tree, profile | |
| `experiment_pro`, `--run-usd 5.00`; input sha256 `acfd3825…26cf7a66`, the 10 hard `test` | |
| problems in dataset order) was stopped on purpose at about 17:23 UTC, together with its whole | |
| process tree (REPL, `lake`), because the team had to leave. No code, prompt, model or | |
| configuration changed; all calls were off-peak. 5 of 10 problems finished and are kept | |
| unchanged: `imo_1965_p2`, `imo_1993_p5`, `imo_1979_p1` (`failed`), `imo_1987_p6` | |
| (`budget_exhausted`) and `imo_1978_p5` (`provider_error`: the Autoformalizer request on subgoal 1, | |
| the problem's 30th call, got `APIConnectionError: Connection error.` with no HTTP response on all | |
| 5 transport attempts, 15:34:50–15:37:28 UTC). The 6th (`imo_1984_p6`) was cut mid-problem after 4 | |
| calls and left no row. The last 4 (`imo_1964_p1_2`, `putnam_1964_b2`, `putnam_1995_b1`, | |
| `putnam_1965_b2`) were not attempted. The run is **not resumed** and the `provider_error` is | |
| **not re-run**: the exploratory table reports the 5 finished rows, the cut problem and the 4 | |
| not attempted as such. Real cost 1.9407 USD (151 paid calls; 0.1725 USD of it on the cut | |
| problem, in no kept row); ledger total after the run 9.3003 USD. `run_config.json` still shows | |
| `status: running` because the run never reached its final rewrite. | |
| Clarifications written before any run on `test`: | |
| - **2026-11-03, FPR_B check (§4.2), how "the Autoformalizer–Verifier loop with the same budget" is | |
| implemented** (`scripts/run_baseline_b.py --check`, `baselines/baseline_b.check_claim`): each claimed | |
| proof (B⁺) is the sketch of the Autoformalizer on the trivial plan (the whole theorem as the only | |
| subgoal), with the Retriever's lemmas as in C5; up to `critic.k_max` = 3 attempts, each failure | |
| classified by κ and followed by the Critic's deterministic feedback (no LLM advice, no Planner, no | |
| Generator, no automation pre-pass, so no fixed tactic can stand in for the claimed proof); its own | |
| budget of `B_max` = 40 calls, counted apart from C2's own calls (C2's efficiency figures exclude the | |
| check; in practice the check makes at most k_max × 2 = 6 calls: one Autoformalizer call and at most | |
| one JSON repair per attempt). Acc is Eq. 2 on the assembled theorem. FPR_B = not_verified / | |
| (verified + not_verified), where `budget_exhausted` counts as not_verified (the budget is part of the | |
| method). A check that ended in `provider_error`, `budget_stop` or `error`, or a row marked `lean_down`, | |
| is left out of FPR_B, counted apart and re-run once like a `provider_error` (§5); if it fails again | |
| the same way it is reported as not checked. Problems C2 did not claim are not checked. | |