plainproof 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. {plainproof-0.1.0 → plainproof-0.2.0}/.gitignore +1 -0
  2. {plainproof-0.1.0 → plainproof-0.2.0}/CITATION.cff +7 -0
  3. plainproof-0.2.0/PKG-INFO +102 -0
  4. plainproof-0.2.0/README.md +83 -0
  5. {plainproof-0.1.0 → plainproof-0.2.0}/pyproject.toml +1 -1
  6. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/fetch_heldout.sh +3 -2
  7. plainproof-0.2.0/setup.py +31 -0
  8. plainproof-0.2.0/src/plainproof/cli.py +121 -0
  9. plainproof-0.2.0/src/plainproof.egg-info/PKG-INFO +102 -0
  10. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/SOURCES.txt +1 -0
  11. plainproof-0.1.0/PKG-INFO +0 -95
  12. plainproof-0.1.0/README.md +0 -76
  13. plainproof-0.1.0/src/plainproof/cli.py +0 -84
  14. plainproof-0.1.0/src/plainproof.egg-info/PKG-INFO +0 -95
  15. {plainproof-0.1.0 → plainproof-0.2.0}/LICENSE +0 -0
  16. {plainproof-0.1.0 → plainproof-0.2.0}/LICENSE-docs.md +0 -0
  17. {plainproof-0.1.0 → plainproof-0.2.0}/MANIFEST.in +0 -0
  18. {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration-v2.json +0 -0
  19. {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration-v2.receipt.json +0 -0
  20. {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration.json +0 -0
  21. {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration.receipt.json +0 -0
  22. {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/pilot.json +0 -0
  23. {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/tune.json +0 -0
  24. {plainproof-0.1.0 → plainproof-0.2.0}/docs/PREREG_EDM_V2.md +0 -0
  25. {plainproof-0.1.0 → plainproof-0.2.0}/docs/PROTOCOL_E0.md +0 -0
  26. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/error-vs-d.csv +0 -0
  27. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/figures/error-vs-d.png +0 -0
  28. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/freeze.json +0 -0
  29. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/results-numbers.json +0 -0
  30. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/signature-table.md +0 -0
  31. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/figures/probe-auc-vs-d.png +0 -0
  32. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/freeze.json +0 -0
  33. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/numbers.json +0 -0
  34. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/probe-auc-vs-d.csv +0 -0
  35. {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/probe-table.md +0 -0
  36. {plainproof-0.1.0 → plainproof-0.2.0}/reports/receipts/assist2009-dev-2pl.receipt.json +0 -0
  37. {plainproof-0.1.0 → plainproof-0.2.0}/reports/receipts/bobcat-gate.json +0 -0
  38. {plainproof-0.1.0 → plainproof-0.2.0}/reports/receipts/bobcat-run-settings.json +0 -0
  39. {plainproof-0.1.0 → plainproof-0.2.0}/reports/receipts/catirt-install-receipt.txt +0 -0
  40. {plainproof-0.1.0 → plainproof-0.2.0}/requirements.txt +0 -0
  41. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/bobcat/check_checkpoint.py +0 -0
  42. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/bobcat/fetch_bobcat.sh +0 -0
  43. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/bobcat/retrain.py +0 -0
  44. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/bobcat_gate.py +0 -0
  45. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/catirt_sprt_steps.R +0 -0
  46. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/fit_assist2009.py +0 -0
  47. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/heldout.py +0 -0
  48. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/install_catirt.R +0 -0
  49. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/pilot.py +0 -0
  50. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/plot_error_vs_d.R +0 -0
  51. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/r_env.sh +0 -0
  52. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/report.py +0 -0
  53. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/repro_paths.py +0 -0
  54. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/study.py +0 -0
  55. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0b/plot_probe_auc.R +0 -0
  56. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0b/report.py +0 -0
  57. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0b/run.py +0 -0
  58. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/published_cat_reference_v1/bobcat_support.py +0 -0
  59. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/published_cat_reference_v1/compare_selection_v1.py +0 -0
  60. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/rscript.sh +0 -0
  61. {plainproof-0.1.0 → plainproof-0.2.0}/scripts/verify_frozen.py +0 -0
  62. {plainproof-0.1.0 → plainproof-0.2.0}/setup.cfg +0 -0
  63. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/__init__.py +0 -0
  64. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/bank_from_fit.py +0 -0
  65. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/fit.py +0 -0
  66. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/irt.py +0 -0
  67. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/planted.py +0 -0
  68. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/reliability.py +0 -0
  69. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/signature.py +0 -0
  70. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/simulator.py +0 -0
  71. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/sprt.py +0 -0
  72. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/stopping.py +0 -0
  73. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/dependency_links.txt +0 -0
  74. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/entry_points.txt +0 -0
  75. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/requires.txt +0 -0
  76. {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/top_level.txt +0 -0
  77. {plainproof-0.1.0 → plainproof-0.2.0}/substitutions.json +0 -0
  78. {plainproof-0.1.0 → plainproof-0.2.0}/tests/conftest.py +0 -0
  79. {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/bank.csv +0 -0
  80. {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/config.csv +0 -0
  81. {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/resp.csv +0 -0
  82. {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/steps.csv +0 -0
  83. {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/terminal.csv +0 -0
  84. {plainproof-0.1.0 → plainproof-0.2.0}/tests/test_edm_v2_e0.py +0 -0
  85. {plainproof-0.1.0 → plainproof-0.2.0}/tests/test_edm_v2_e0b.py +0 -0
@@ -8,3 +8,4 @@ dist/
8
8
  build/
9
9
  *.egg-info/
10
10
  .venv/
11
+ src/plainproof/payload/
@@ -5,3 +5,10 @@ authors:
5
5
  - family-names: Vettrivel
6
6
  given-names: Vishnu
7
7
  license: MIT
8
+ version: 0.2.0
9
+ doi: 10.5281/zenodo.23647649
10
+ identifiers:
11
+ - type: doi
12
+ value: 10.5281/zenodo.23647650
13
+ description: version 0.1.0
14
+ repository-code: https://github.com/cloudronin/plainproof
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: plainproof
3
+ Version: 0.2.0
4
+ Summary: Reproduction tool for the paper 'How many follow-up questions distinguish genuine understanding from apparent mastery?'. Not a general library. Its sealed checks can stop a run on purpose.
5
+ Author: Vishnu Vettrivel
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: numpy>=2.0
11
+ Requires-Dist: scipy>=1.13
12
+ Provides-Extra: run
13
+ Requires-Dist: scikit-learn>=1.5; extra == "run"
14
+ Requires-Dist: torch>=2.4; extra == "run"
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest>=8; extra == "test"
17
+ Requires-Dist: pytest-xdist>=3.5; extra == "test"
18
+ Dynamic: license-file
19
+
20
+ # plainproof
21
+
22
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23647650.svg)](https://doi.org/10.5281/zenodo.23647650)
23
+
24
+ Archived on Zenodo: version 0.1.0 is DOI [10.5281/zenodo.23647650](https://doi.org/10.5281/zenodo.23647650); all versions are DOI [10.5281/zenodo.23647649](https://doi.org/10.5281/zenodo.23647649). Also on PyPI: `pip install plainproof`.
25
+
26
+ Reproduction package for **"How many follow-up questions distinguish genuine understanding from apparent mastery?"** (EDM 2027 submission, simulation study). It asks how many adaptive follow-up questions a classification test needs to tell genuine understanding from apparent mastery at a calibrated confidence target, and how that changes as a learner outsources a share *d* of the follow-ups to an AI. A second, sealed study (E0b) tests whether planted hard probe items separate outsourcing learners from honest ones.
27
+
28
+ Everything here is CPU-only and needs no paid service. Code: MIT (`LICENSE`). Docs, figures and tables: CC BY 4.0 (`LICENSE-docs.md`).
29
+
30
+ ## From install to the figure (about 10 minutes)
31
+
32
+ ```sh
33
+ pip install 'plainproof[test,run]'
34
+ plainproof init ~/plainproof # writes the working directory: sealed scripts, freezes, receipts, docs, tests
35
+ cd ~/plainproof
36
+ plainproof test # 43 tests: SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, probes
37
+ plainproof verify # every sealed file against both freezes (undoes the documented substitutions, then sha256)
38
+ plainproof fetch heldout # the sealed held-out outputs, hash-checked
39
+ plainproof figures # tables and figures from the held-out summaries (needs R 4.x on PATH; base graphics only)
40
+ ```
41
+
42
+ The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`, byte-identical to the published copies. `plainproof init` writes the files in the exact layout the sealed scripts expect; nothing sealed changes. Every other command runs inside that directory, or takes `--root DIR`. The local path inside the sealed `scripts/edm_v2_e0/r_env.sh` is part of the frozen record; the `scripts/rscript.sh` wrapper, which `plainproof figures` calls, is the one to use.
43
+
44
+ ## Full rerun (about 4 hours of CPU)
45
+
46
+ Only if you want to regenerate everything, including the held-out outputs.
47
+
48
+ ```sh
49
+ plainproof fetch bobcat # BOBCAT (MIT) at its pinned commit, with the preprocessed ASSISTments 2009-2010 file
50
+ plainproof fit # 2PL item fit on the development half of learners; checked against the receipt's hash
51
+ plainproof retrain # BOBCAT checkpoint, about 2 hours (author defaults, fold 1, seed 221), compared with the original run
52
+ plainproof run e0 # E0 held-out run and summary; refuses to overwrite an existing cell
53
+ plainproof run e0b # E0b held-out run and summary
54
+ ```
55
+
56
+ The ASSISTments terms of use forbid passing the data on, so this package never contains it: `fetch bobcat` downloads it from its source, and you accept those terms yourself. Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a different numpy can stop `fit`; and it asserts that the BOBCAT checkpoint's best epoch is 105, so a retrain that is not bit-identical stops `run e0`. In either case, use the published held-out outputs (`plainproof fetch heldout`). The development stages (`scripts/edm_v2_e0/study.py tune|calibrate|calibrate_sprt_full|pilot`) are included for the record; their outputs (synthetic learners only) are in `data/edm-v2-e0/study/`.
57
+
58
+ ## Fingerprints (sha256)
59
+
60
+ | What | sha256 |
61
+ |---|---|
62
+ | E0 sealed freeze `reports/edm-v2-e0/freeze.json` | `a0f8ce404f2b5f7e671e2503a33b4554040e80714f6053553507e0972acdbcdc` |
63
+ | E0b sealed freeze `reports/edm-v2-e0b/freeze.json` | `3fa0b8d457d813f59abd5255f9303e44deb2119ee79d6a9b92439a6c1cbf58ed` |
64
+ | E0 held-out summary (`e0-heldout.tar` → `heldout/summary.json`) | `aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90` |
65
+ | E0b held-out summary (`e0b-heldout.tar` → `heldout/summary.json`) | `617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f` |
66
+ | `e0-heldout.tar` (release asset) | `bd06a11eb7163da102cad6ea0df12ea79e52ff94aab1dc35d28ec3910af2be22` |
67
+ | `e0b-heldout.tar` (release asset) | `68219f228c41da972fe4c8f92c218e01f85f08eed864185f237cecda05314bbf` |
68
+ | ASSISTments 2009 file at BOBCAT e6b6245e | `c07ca9fa0f08207b06488cec527725938fe96e81e3c1762839e1ad0b84f974cc` |
69
+ | 2PL item fit (regenerated in step b) | `12a3b167cd9c9b78b3c3c7faf71b2e464b0943a454f6418faf0f99b1114cb7fc` |
70
+ | catIrt 0.5.1 CRAN binary used for the fixture | `f5418f447e91d184791e668bd2a135ea5da40c981d4a76826018295b6ea9f079` |
71
+
72
+ ## What is in here
73
+
74
+ - `src/plainproof/`: item model, SPRT arm, exact stopping time, simulator (uniform and uncertainty-triggered outsourcing), item fit, signatures, planted probes (with the give-up model), matched-coverage scoring.
75
+ - `src/plainproof/cli.py`: the `plainproof` command. `setup.py` packs the working directory into the wheel for `plainproof init`.
76
+ - `scripts/edm_v2_e0/`, `scripts/edm_v2_e0b/`: the runners, report builders and R plots. `scripts/published_cat_reference_v1/`: the BOBCAT loading code the runners call.
77
+ - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
78
+ - `substitutions.json`: the only differences between this code and the sealed originals (package name, file locations, data paths). `scripts/verify_frozen.py` undoes them and checks every hash. `scripts/edm_v2_e0/r_env.sh` is kept verbatim as the record of the original R runtime; use `scripts/rscript.sh` instead.
79
+
80
+ ## Recorded departures
81
+
82
+ All are in `docs/PREREG_EDM_V2.md`: the SPRT tuning rule was revised after its first development pass (labelled post hoc); SPRT's calibration map was refitted once on full paths before the freeze; the E0 held-out run exceeded its 2 GiB memory cap (no result depends on it; the runner now enforces the cap); E0b was sealed before its pilot table had been reviewed (no result affected).
83
+
84
+ ## Appendix: the raw script calls
85
+
86
+ What each `plainproof` command runs, from the working directory (`REPRO_DATA` defaults to `./data`):
87
+
88
+ ```sh
89
+ python -m pytest -n auto -q tests # plainproof test
90
+ python scripts/verify_frozen.py # plainproof verify
91
+ ZENODO_URL=https://github.com/cloudronin/plainproof/releases/download/v0.1.0 bash scripts/fetch_heldout.sh # plainproof fetch heldout
92
+ python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json # plainproof figures (E0 tables)
93
+ bash scripts/rscript.sh scripts/edm_v2_e0/plot_error_vs_d.R reports/edm-v2-e0/error-vs-d.csv reports/edm-v2-e0/figures/error-vs-d.png <E0 summary sha256>
94
+ python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
95
+ bash scripts/rscript.sh scripts/edm_v2_e0b/plot_probe_auc.R reports/edm-v2-e0b/probe-auc-vs-d.csv reports/edm-v2-e0b/figures/probe-auc-vs-d.png <E0b summary sha256>
96
+ bash scripts/bobcat/fetch_bobcat.sh # plainproof fetch bobcat
97
+ python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit # plainproof fit
98
+ python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py # plainproof retrain
99
+ python scripts/edm_v2_e0/heldout.py run data/edm-v2-e0/heldout && python scripts/edm_v2_e0/heldout.py summarize data/edm-v2-e0/heldout # plainproof run e0
100
+ python scripts/edm_v2_e0b/run.py run data/edm-v2-e0b/heldout && python scripts/edm_v2_e0b/run.py summarize data/edm-v2-e0b/heldout # plainproof run e0b
101
+ scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt # regenerate the catIrt fixture (R with catIrt 0.5.1)
102
+ ```
@@ -0,0 +1,83 @@
1
+ # plainproof
2
+
3
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23647650.svg)](https://doi.org/10.5281/zenodo.23647650)
4
+
5
+ Archived on Zenodo: version 0.1.0 is DOI [10.5281/zenodo.23647650](https://doi.org/10.5281/zenodo.23647650); all versions are DOI [10.5281/zenodo.23647649](https://doi.org/10.5281/zenodo.23647649). Also on PyPI: `pip install plainproof`.
6
+
7
+ Reproduction package for **"How many follow-up questions distinguish genuine understanding from apparent mastery?"** (EDM 2027 submission, simulation study). It asks how many adaptive follow-up questions a classification test needs to tell genuine understanding from apparent mastery at a calibrated confidence target, and how that changes as a learner outsources a share *d* of the follow-ups to an AI. A second, sealed study (E0b) tests whether planted hard probe items separate outsourcing learners from honest ones.
8
+
9
+ Everything here is CPU-only and needs no paid service. Code: MIT (`LICENSE`). Docs, figures and tables: CC BY 4.0 (`LICENSE-docs.md`).
10
+
11
+ ## From install to the figure (about 10 minutes)
12
+
13
+ ```sh
14
+ pip install 'plainproof[test,run]'
15
+ plainproof init ~/plainproof # writes the working directory: sealed scripts, freezes, receipts, docs, tests
16
+ cd ~/plainproof
17
+ plainproof test # 43 tests: SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, probes
18
+ plainproof verify # every sealed file against both freezes (undoes the documented substitutions, then sha256)
19
+ plainproof fetch heldout # the sealed held-out outputs, hash-checked
20
+ plainproof figures # tables and figures from the held-out summaries (needs R 4.x on PATH; base graphics only)
21
+ ```
22
+
23
+ The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`, byte-identical to the published copies. `plainproof init` writes the files in the exact layout the sealed scripts expect; nothing sealed changes. Every other command runs inside that directory, or takes `--root DIR`. The local path inside the sealed `scripts/edm_v2_e0/r_env.sh` is part of the frozen record; the `scripts/rscript.sh` wrapper, which `plainproof figures` calls, is the one to use.
24
+
25
+ ## Full rerun (about 4 hours of CPU)
26
+
27
+ Only if you want to regenerate everything, including the held-out outputs.
28
+
29
+ ```sh
30
+ plainproof fetch bobcat # BOBCAT (MIT) at its pinned commit, with the preprocessed ASSISTments 2009-2010 file
31
+ plainproof fit # 2PL item fit on the development half of learners; checked against the receipt's hash
32
+ plainproof retrain # BOBCAT checkpoint, about 2 hours (author defaults, fold 1, seed 221), compared with the original run
33
+ plainproof run e0 # E0 held-out run and summary; refuses to overwrite an existing cell
34
+ plainproof run e0b # E0b held-out run and summary
35
+ ```
36
+
37
+ The ASSISTments terms of use forbid passing the data on, so this package never contains it: `fetch bobcat` downloads it from its source, and you accept those terms yourself. Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a different numpy can stop `fit`; and it asserts that the BOBCAT checkpoint's best epoch is 105, so a retrain that is not bit-identical stops `run e0`. In either case, use the published held-out outputs (`plainproof fetch heldout`). The development stages (`scripts/edm_v2_e0/study.py tune|calibrate|calibrate_sprt_full|pilot`) are included for the record; their outputs (synthetic learners only) are in `data/edm-v2-e0/study/`.
38
+
39
+ ## Fingerprints (sha256)
40
+
41
+ | What | sha256 |
42
+ |---|---|
43
+ | E0 sealed freeze `reports/edm-v2-e0/freeze.json` | `a0f8ce404f2b5f7e671e2503a33b4554040e80714f6053553507e0972acdbcdc` |
44
+ | E0b sealed freeze `reports/edm-v2-e0b/freeze.json` | `3fa0b8d457d813f59abd5255f9303e44deb2119ee79d6a9b92439a6c1cbf58ed` |
45
+ | E0 held-out summary (`e0-heldout.tar` → `heldout/summary.json`) | `aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90` |
46
+ | E0b held-out summary (`e0b-heldout.tar` → `heldout/summary.json`) | `617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f` |
47
+ | `e0-heldout.tar` (release asset) | `bd06a11eb7163da102cad6ea0df12ea79e52ff94aab1dc35d28ec3910af2be22` |
48
+ | `e0b-heldout.tar` (release asset) | `68219f228c41da972fe4c8f92c218e01f85f08eed864185f237cecda05314bbf` |
49
+ | ASSISTments 2009 file at BOBCAT e6b6245e | `c07ca9fa0f08207b06488cec527725938fe96e81e3c1762839e1ad0b84f974cc` |
50
+ | 2PL item fit (regenerated in step b) | `12a3b167cd9c9b78b3c3c7faf71b2e464b0943a454f6418faf0f99b1114cb7fc` |
51
+ | catIrt 0.5.1 CRAN binary used for the fixture | `f5418f447e91d184791e668bd2a135ea5da40c981d4a76826018295b6ea9f079` |
52
+
53
+ ## What is in here
54
+
55
+ - `src/plainproof/`: item model, SPRT arm, exact stopping time, simulator (uniform and uncertainty-triggered outsourcing), item fit, signatures, planted probes (with the give-up model), matched-coverage scoring.
56
+ - `src/plainproof/cli.py`: the `plainproof` command. `setup.py` packs the working directory into the wheel for `plainproof init`.
57
+ - `scripts/edm_v2_e0/`, `scripts/edm_v2_e0b/`: the runners, report builders and R plots. `scripts/published_cat_reference_v1/`: the BOBCAT loading code the runners call.
58
+ - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
59
+ - `substitutions.json`: the only differences between this code and the sealed originals (package name, file locations, data paths). `scripts/verify_frozen.py` undoes them and checks every hash. `scripts/edm_v2_e0/r_env.sh` is kept verbatim as the record of the original R runtime; use `scripts/rscript.sh` instead.
60
+
61
+ ## Recorded departures
62
+
63
+ All are in `docs/PREREG_EDM_V2.md`: the SPRT tuning rule was revised after its first development pass (labelled post hoc); SPRT's calibration map was refitted once on full paths before the freeze; the E0 held-out run exceeded its 2 GiB memory cap (no result depends on it; the runner now enforces the cap); E0b was sealed before its pilot table had been reviewed (no result affected).
64
+
65
+ ## Appendix: the raw script calls
66
+
67
+ What each `plainproof` command runs, from the working directory (`REPRO_DATA` defaults to `./data`):
68
+
69
+ ```sh
70
+ python -m pytest -n auto -q tests # plainproof test
71
+ python scripts/verify_frozen.py # plainproof verify
72
+ ZENODO_URL=https://github.com/cloudronin/plainproof/releases/download/v0.1.0 bash scripts/fetch_heldout.sh # plainproof fetch heldout
73
+ python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json # plainproof figures (E0 tables)
74
+ bash scripts/rscript.sh scripts/edm_v2_e0/plot_error_vs_d.R reports/edm-v2-e0/error-vs-d.csv reports/edm-v2-e0/figures/error-vs-d.png <E0 summary sha256>
75
+ python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
76
+ bash scripts/rscript.sh scripts/edm_v2_e0b/plot_probe_auc.R reports/edm-v2-e0b/probe-auc-vs-d.csv reports/edm-v2-e0b/figures/probe-auc-vs-d.png <E0b summary sha256>
77
+ bash scripts/bobcat/fetch_bobcat.sh # plainproof fetch bobcat
78
+ python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit # plainproof fit
79
+ python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py # plainproof retrain
80
+ python scripts/edm_v2_e0/heldout.py run data/edm-v2-e0/heldout && python scripts/edm_v2_e0/heldout.py summarize data/edm-v2-e0/heldout # plainproof run e0
81
+ python scripts/edm_v2_e0b/run.py run data/edm-v2-e0b/heldout && python scripts/edm_v2_e0b/run.py summarize data/edm-v2-e0b/heldout # plainproof run e0b
82
+ scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt # regenerate the catIrt fixture (R with catIrt 0.5.1)
83
+ ```
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "plainproof"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "Reproduction tool for the paper 'How many follow-up questions distinguish genuine understanding from apparent mastery?'. Not a general library. Its sealed checks can stop a run on purpose."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,7 +1,8 @@
1
1
  #!/bin/bash
2
- # Download the sealed held-out outputs from Zenodo and check their sha256 before use.
2
+ # Download the sealed held-out outputs and check their sha256 before use. Default source: the v0.1.0 GitHub release assets
3
+ # (cited by DOI 10.5281/zenodo.23647650); set ZENODO_URL (or any mirror base URL) to fetch from elsewhere.
3
4
  set -euo pipefail
4
- DOI_URL=${ZENODO_URL:?set ZENODO_URL to the Zenodo record's file base URL (DOI: to be assigned)}
5
+ DOI_URL=${ZENODO_URL:-https://github.com/cloudronin/plainproof/releases/download/v0.1.0}
5
6
  D=${REPRO_DATA:-data}; mkdir -p "$D/edm-v2-e0" "$D/edm-v2-e0b"
6
7
  for f in e0-heldout.tar e0b-heldout.tar; do curl -fsSL -o "$D/$f" "$DOI_URL/$f"; done
7
8
  cd "$D" && printf '%s %s\n%s %s\n' bd06a11eb7163da102cad6ea0df12ea79e52ff94aab1dc35d28ec3910af2be22 e0-heldout.tar 68219f228c41da972fe4c8f92c218e01f85f08eed864185f237cecda05314bbf e0b-heldout.tar | shasum -a 256 -c
@@ -0,0 +1,31 @@
1
+ """Build hook: copy the reproduction working directory into the package as data, so `plainproof init` can write it
2
+ out after `pip install plainproof` alone. The copied files are the repository's own files, unchanged."""
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+ from setuptools import setup
7
+ from setuptools.command.build_py import build_py
8
+
9
+ PAYLOAD = ['scripts', 'reports', 'docs', 'tests', 'data/edm-v2-e0/study', 'substitutions.json', 'README.md', 'LICENSE',
10
+ 'LICENSE-docs.md', 'CITATION.cff', 'requirements.txt']
11
+
12
+
13
+ class with_payload(build_py):
14
+ def run(self):
15
+ super().run()
16
+ here = Path(__file__).resolve().parent
17
+ dest = Path(self.build_lib) / 'plainproof' / 'payload'
18
+ if dest.exists():
19
+ shutil.rmtree(dest)
20
+ for item in PAYLOAD:
21
+ src = here / item
22
+ if not src.exists():
23
+ raise SystemExit(f'payload item missing from the source tree: {item}')
24
+ if src.is_dir():
25
+ shutil.copytree(src, dest / item, ignore=shutil.ignore_patterns('__pycache__', '*.pyc'))
26
+ else:
27
+ (dest / item).parent.mkdir(parents=True, exist_ok=True)
28
+ shutil.copy2(src, dest / item)
29
+
30
+
31
+ setup(cmdclass={'build_py': with_payload})
@@ -0,0 +1,121 @@
1
+ """plainproof: the command-line front end of this reproduction package.
2
+
3
+ `plainproof init DIR` writes a working directory from the package (sealed scripts, both freezes, receipts,
4
+ substitutions.json, R scripts, docs, tests) in the exact layout the sealed scripts expect; nothing sealed changes.
5
+ Every other command runs inside that directory, or takes --root DIR.
6
+
7
+ plainproof init DIR write the working directory (refuses a non-empty DIR)
8
+ plainproof test the 43 offline tests
9
+ plainproof verify check every sealed file against both freezes
10
+ plainproof fetch heldout|bobcat|all the sealed held-out outputs, and/or BOBCAT + the ASSISTments file (hash-checked)
11
+ plainproof figures rebuild tables and figures from the held-out summaries (needs R for the plots)
12
+ plainproof fit refit the 2PL item parameters on ASSISTments development learners
13
+ plainproof retrain retrain the BOBCAT checkpoint, then compare it with the original run
14
+ plainproof run e0|e0b held-out run and summary (refuses to overwrite an existing cell)
15
+ """
16
+ import argparse
17
+ import hashlib
18
+ import os
19
+ import shutil
20
+ import subprocess
21
+ import sys
22
+ from pathlib import Path
23
+
24
+ # The sealed held-out outputs. Their sha256 values are checked by scripts/fetch_heldout.sh before use.
25
+ HELDOUT_BASE_URL = 'https://github.com/cloudronin/plainproof/releases/download/v0.1.0'
26
+ PAYLOAD = Path(__file__).resolve().parent / 'payload'
27
+
28
+
29
+ def find_root(given):
30
+ root = Path(given or os.getcwd()).resolve()
31
+ if not (root / 'substitutions.json').exists() or not (root / 'reports' / 'edm-v2-e0' / 'freeze.json').exists():
32
+ raise SystemExit(f'{root} is not a plainproof working directory; run `plainproof init DIR` and cd there, or pass --root')
33
+ return root
34
+
35
+
36
+ def sh(root, *cmd, env_extra=None):
37
+ env = dict(os.environ)
38
+ env.setdefault('REPRO_DATA', str(root / 'data'))
39
+ env.update(env_extra or {})
40
+ print('+', ' '.join(str(c) for c in cmd), flush=True)
41
+ r = subprocess.run([str(c) for c in cmd], cwd=root, env=env)
42
+ if r.returncode:
43
+ raise SystemExit(r.returncode)
44
+
45
+
46
+ def sha(p):
47
+ return hashlib.sha256(Path(p).read_bytes()).hexdigest()
48
+
49
+
50
+ def init(target):
51
+ target = Path(target).expanduser().resolve()
52
+ if target.exists() and any(target.iterdir()):
53
+ raise SystemExit(f'{target} is not empty; choose a new directory')
54
+ if not PAYLOAD.exists():
55
+ raise SystemExit('this installation has no payload; reinstall plainproof from the wheel or sdist')
56
+ shutil.copytree(PAYLOAD, target, dirs_exist_ok=True)
57
+ # The sealed scripts import the package from <root>/src and hash its modules there, so the package is written
58
+ # out too, byte for byte from this installation.
59
+ pkg = target / 'src' / 'plainproof'
60
+ pkg.mkdir(parents=True)
61
+ for f in Path(__file__).resolve().parent.glob('*.py'):
62
+ shutil.copy2(f, pkg / f.name)
63
+ for d in ('data/edm-v2-e0', 'data/edm-v2-e0b'):
64
+ (target / d).mkdir(parents=True, exist_ok=True)
65
+ for f in target.rglob('*.sh'):
66
+ f.chmod(0o755)
67
+ print(f'wrote {target}\nnext: cd {target} && plainproof test && plainproof verify && plainproof fetch heldout && plainproof figures')
68
+
69
+
70
+ def main(argv=None):
71
+ ap = argparse.ArgumentParser(prog='plainproof', description=__doc__.split('\n\n')[0])
72
+ ap.add_argument('--root', help='working directory (default: current directory)')
73
+ sub = ap.add_subparsers(dest='cmd', required=True)
74
+ sub.add_parser('init').add_argument('dir')
75
+ sub.add_parser('test')
76
+ sub.add_parser('verify')
77
+ sub.add_parser('fetch').add_argument('what', choices=('heldout', 'bobcat', 'all'))
78
+ sub.add_parser('figures')
79
+ sub.add_parser('fit')
80
+ sub.add_parser('retrain')
81
+ sub.add_parser('run').add_argument('study', choices=('e0', 'e0b'))
82
+ a = ap.parse_args(argv)
83
+ if a.cmd == 'init':
84
+ return init(a.dir)
85
+ root = find_root(a.root)
86
+ py = sys.executable
87
+ data = Path(os.environ.get('REPRO_DATA', root / 'data'))
88
+ if a.cmd == 'test':
89
+ sh(root, py, '-m', 'pytest', '-n', 'auto', '-q', '-p', 'no:cacheprovider', 'tests')
90
+ elif a.cmd == 'verify':
91
+ sh(root, py, 'scripts/verify_frozen.py')
92
+ elif a.cmd == 'fetch':
93
+ if a.what in ('heldout', 'all'):
94
+ sh(root, 'bash', 'scripts/fetch_heldout.sh', env_extra={'ZENODO_URL': os.environ.get('ZENODO_URL', HELDOUT_BASE_URL)})
95
+ if a.what in ('bobcat', 'all'):
96
+ sh(root, 'bash', 'scripts/bobcat/fetch_bobcat.sh')
97
+ elif a.cmd == 'figures':
98
+ s0, s1 = data / 'edm-v2-e0' / 'heldout' / 'summary.json', data / 'edm-v2-e0b' / 'heldout' / 'summary.json'
99
+ for s in (s0, s1):
100
+ if not s.exists():
101
+ raise SystemExit(f'{s} missing; run `plainproof fetch heldout` first')
102
+ sh(root, py, 'scripts/edm_v2_e0/report.py', s0)
103
+ sh(root, 'bash', 'scripts/rscript.sh', 'scripts/edm_v2_e0/plot_error_vs_d.R', 'reports/edm-v2-e0/error-vs-d.csv',
104
+ 'reports/edm-v2-e0/figures/error-vs-d.png', sha(s0))
105
+ sh(root, py, 'scripts/edm_v2_e0b/report.py', s1)
106
+ sh(root, 'bash', 'scripts/rscript.sh', 'scripts/edm_v2_e0b/plot_probe_auc.R', 'reports/edm-v2-e0b/probe-auc-vs-d.csv',
107
+ 'reports/edm-v2-e0b/figures/probe-auc-vs-d.png', sha(s1))
108
+ elif a.cmd == 'fit':
109
+ sh(root, py, 'scripts/edm_v2_e0/fit_assist2009.py', data / 'edm-v2-e0' / 'item-fit')
110
+ elif a.cmd == 'retrain':
111
+ sh(root, py, 'scripts/bobcat/retrain.py')
112
+ sh(root, py, 'scripts/bobcat/check_checkpoint.py')
113
+ elif a.cmd == 'run':
114
+ out = data / a.study.replace('e0', 'edm-v2-e0', 1) / 'heldout'
115
+ script = 'scripts/edm_v2_e0/heldout.py' if a.study == 'e0' else 'scripts/edm_v2_e0b/run.py'
116
+ sh(root, py, script, 'run', out)
117
+ sh(root, py, script, 'summarize', out)
118
+
119
+
120
+ if __name__ == '__main__':
121
+ main()
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: plainproof
3
+ Version: 0.2.0
4
+ Summary: Reproduction tool for the paper 'How many follow-up questions distinguish genuine understanding from apparent mastery?'. Not a general library. Its sealed checks can stop a run on purpose.
5
+ Author: Vishnu Vettrivel
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: numpy>=2.0
11
+ Requires-Dist: scipy>=1.13
12
+ Provides-Extra: run
13
+ Requires-Dist: scikit-learn>=1.5; extra == "run"
14
+ Requires-Dist: torch>=2.4; extra == "run"
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest>=8; extra == "test"
17
+ Requires-Dist: pytest-xdist>=3.5; extra == "test"
18
+ Dynamic: license-file
19
+
20
+ # plainproof
21
+
22
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23647650.svg)](https://doi.org/10.5281/zenodo.23647650)
23
+
24
+ Archived on Zenodo: version 0.1.0 is DOI [10.5281/zenodo.23647650](https://doi.org/10.5281/zenodo.23647650); all versions are DOI [10.5281/zenodo.23647649](https://doi.org/10.5281/zenodo.23647649). Also on PyPI: `pip install plainproof`.
25
+
26
+ Reproduction package for **"How many follow-up questions distinguish genuine understanding from apparent mastery?"** (EDM 2027 submission, simulation study). It asks how many adaptive follow-up questions a classification test needs to tell genuine understanding from apparent mastery at a calibrated confidence target, and how that changes as a learner outsources a share *d* of the follow-ups to an AI. A second, sealed study (E0b) tests whether planted hard probe items separate outsourcing learners from honest ones.
27
+
28
+ Everything here is CPU-only and needs no paid service. Code: MIT (`LICENSE`). Docs, figures and tables: CC BY 4.0 (`LICENSE-docs.md`).
29
+
30
+ ## From install to the figure (about 10 minutes)
31
+
32
+ ```sh
33
+ pip install 'plainproof[test,run]'
34
+ plainproof init ~/plainproof # writes the working directory: sealed scripts, freezes, receipts, docs, tests
35
+ cd ~/plainproof
36
+ plainproof test # 43 tests: SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, probes
37
+ plainproof verify # every sealed file against both freezes (undoes the documented substitutions, then sha256)
38
+ plainproof fetch heldout # the sealed held-out outputs, hash-checked
39
+ plainproof figures # tables and figures from the held-out summaries (needs R 4.x on PATH; base graphics only)
40
+ ```
41
+
42
+ The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`, byte-identical to the published copies. `plainproof init` writes the files in the exact layout the sealed scripts expect; nothing sealed changes. Every other command runs inside that directory, or takes `--root DIR`. The local path inside the sealed `scripts/edm_v2_e0/r_env.sh` is part of the frozen record; the `scripts/rscript.sh` wrapper, which `plainproof figures` calls, is the one to use.
43
+
44
+ ## Full rerun (about 4 hours of CPU)
45
+
46
+ Only if you want to regenerate everything, including the held-out outputs.
47
+
48
+ ```sh
49
+ plainproof fetch bobcat # BOBCAT (MIT) at its pinned commit, with the preprocessed ASSISTments 2009-2010 file
50
+ plainproof fit # 2PL item fit on the development half of learners; checked against the receipt's hash
51
+ plainproof retrain # BOBCAT checkpoint, about 2 hours (author defaults, fold 1, seed 221), compared with the original run
52
+ plainproof run e0 # E0 held-out run and summary; refuses to overwrite an existing cell
53
+ plainproof run e0b # E0b held-out run and summary
54
+ ```
55
+
56
+ The ASSISTments terms of use forbid passing the data on, so this package never contains it: `fetch bobcat` downloads it from its source, and you accept those terms yourself. Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a different numpy can stop `fit`; and it asserts that the BOBCAT checkpoint's best epoch is 105, so a retrain that is not bit-identical stops `run e0`. In either case, use the published held-out outputs (`plainproof fetch heldout`). The development stages (`scripts/edm_v2_e0/study.py tune|calibrate|calibrate_sprt_full|pilot`) are included for the record; their outputs (synthetic learners only) are in `data/edm-v2-e0/study/`.
57
+
58
+ ## Fingerprints (sha256)
59
+
60
+ | What | sha256 |
61
+ |---|---|
62
+ | E0 sealed freeze `reports/edm-v2-e0/freeze.json` | `a0f8ce404f2b5f7e671e2503a33b4554040e80714f6053553507e0972acdbcdc` |
63
+ | E0b sealed freeze `reports/edm-v2-e0b/freeze.json` | `3fa0b8d457d813f59abd5255f9303e44deb2119ee79d6a9b92439a6c1cbf58ed` |
64
+ | E0 held-out summary (`e0-heldout.tar` → `heldout/summary.json`) | `aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90` |
65
+ | E0b held-out summary (`e0b-heldout.tar` → `heldout/summary.json`) | `617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f` |
66
+ | `e0-heldout.tar` (release asset) | `bd06a11eb7163da102cad6ea0df12ea79e52ff94aab1dc35d28ec3910af2be22` |
67
+ | `e0b-heldout.tar` (release asset) | `68219f228c41da972fe4c8f92c218e01f85f08eed864185f237cecda05314bbf` |
68
+ | ASSISTments 2009 file at BOBCAT e6b6245e | `c07ca9fa0f08207b06488cec527725938fe96e81e3c1762839e1ad0b84f974cc` |
69
+ | 2PL item fit (regenerated in step b) | `12a3b167cd9c9b78b3c3c7faf71b2e464b0943a454f6418faf0f99b1114cb7fc` |
70
+ | catIrt 0.5.1 CRAN binary used for the fixture | `f5418f447e91d184791e668bd2a135ea5da40c981d4a76826018295b6ea9f079` |
71
+
72
+ ## What is in here
73
+
74
+ - `src/plainproof/`: item model, SPRT arm, exact stopping time, simulator (uniform and uncertainty-triggered outsourcing), item fit, signatures, planted probes (with the give-up model), matched-coverage scoring.
75
+ - `src/plainproof/cli.py`: the `plainproof` command. `setup.py` packs the working directory into the wheel for `plainproof init`.
76
+ - `scripts/edm_v2_e0/`, `scripts/edm_v2_e0b/`: the runners, report builders and R plots. `scripts/published_cat_reference_v1/`: the BOBCAT loading code the runners call.
77
+ - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
78
+ - `substitutions.json`: the only differences between this code and the sealed originals (package name, file locations, data paths). `scripts/verify_frozen.py` undoes them and checks every hash. `scripts/edm_v2_e0/r_env.sh` is kept verbatim as the record of the original R runtime; use `scripts/rscript.sh` instead.
79
+
80
+ ## Recorded departures
81
+
82
+ All are in `docs/PREREG_EDM_V2.md`: the SPRT tuning rule was revised after its first development pass (labelled post hoc); SPRT's calibration map was refitted once on full paths before the freeze; the E0 held-out run exceeded its 2 GiB memory cap (no result depends on it; the runner now enforces the cap); E0b was sealed before its pilot table had been reviewed (no result affected).
83
+
84
+ ## Appendix: the raw script calls
85
+
86
+ What each `plainproof` command runs, from the working directory (`REPRO_DATA` defaults to `./data`):
87
+
88
+ ```sh
89
+ python -m pytest -n auto -q tests # plainproof test
90
+ python scripts/verify_frozen.py # plainproof verify
91
+ ZENODO_URL=https://github.com/cloudronin/plainproof/releases/download/v0.1.0 bash scripts/fetch_heldout.sh # plainproof fetch heldout
92
+ python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json # plainproof figures (E0 tables)
93
+ bash scripts/rscript.sh scripts/edm_v2_e0/plot_error_vs_d.R reports/edm-v2-e0/error-vs-d.csv reports/edm-v2-e0/figures/error-vs-d.png <E0 summary sha256>
94
+ python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
95
+ bash scripts/rscript.sh scripts/edm_v2_e0b/plot_probe_auc.R reports/edm-v2-e0b/probe-auc-vs-d.csv reports/edm-v2-e0b/figures/probe-auc-vs-d.png <E0b summary sha256>
96
+ bash scripts/bobcat/fetch_bobcat.sh # plainproof fetch bobcat
97
+ python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit # plainproof fit
98
+ python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py # plainproof retrain
99
+ python scripts/edm_v2_e0/heldout.py run data/edm-v2-e0/heldout && python scripts/edm_v2_e0/heldout.py summarize data/edm-v2-e0/heldout # plainproof run e0
100
+ python scripts/edm_v2_e0b/run.py run data/edm-v2-e0b/heldout && python scripts/edm_v2_e0b/run.py summarize data/edm-v2-e0b/heldout # plainproof run e0b
101
+ scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt # regenerate the catIrt fixture (R with catIrt 0.5.1)
102
+ ```
@@ -6,6 +6,7 @@ MANIFEST.in
6
6
  README.md
7
7
  pyproject.toml
8
8
  requirements.txt
9
+ setup.py
9
10
  substitutions.json
10
11
  data/edm-v2-e0/study/calibration-v2.json
11
12
  data/edm-v2-e0/study/calibration-v2.receipt.json
plainproof-0.1.0/PKG-INFO DELETED
@@ -1,95 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: plainproof
3
- Version: 0.1.0
4
- Summary: Reproduction tool for the paper 'How many follow-up questions distinguish genuine understanding from apparent mastery?'. Not a general library. Its sealed checks can stop a run on purpose.
5
- Author: Vishnu Vettrivel
6
- License-Expression: MIT
7
- Requires-Python: >=3.11
8
- Description-Content-Type: text/markdown
9
- License-File: LICENSE
10
- Requires-Dist: numpy>=2.0
11
- Requires-Dist: scipy>=1.13
12
- Provides-Extra: run
13
- Requires-Dist: scikit-learn>=1.5; extra == "run"
14
- Requires-Dist: torch>=2.4; extra == "run"
15
- Provides-Extra: test
16
- Requires-Dist: pytest>=8; extra == "test"
17
- Requires-Dist: pytest-xdist>=3.5; extra == "test"
18
- Dynamic: license-file
19
-
20
- # plainproof
21
-
22
- Reproduction package for **"How many follow-up questions distinguish genuine understanding from apparent mastery?"** (EDM 2027 submission, simulation study). It asks how many adaptive follow-up questions a classification test needs to tell genuine understanding from apparent mastery at a calibrated confidence target, and how that changes as a learner outsources a share *d* of the follow-ups to an AI. A second, sealed study (E0b) tests whether planted hard probe items separate outsourcing learners from honest ones.
23
-
24
- Everything here is CPU-only and needs no paid service. Code: MIT (`LICENSE`). Docs, figures and tables: CC BY 4.0 (`LICENSE-docs.md`).
25
-
26
- ## From clone to the figure (about 10 minutes)
27
-
28
- The `plainproof` command runs each step (`plainproof --help`); the raw script calls below are what it runs. The local path inside the sealed `scripts/edm_v2_e0/r_env.sh` is part of the frozen record; use the `scripts/rscript.sh` wrapper, which `plainproof figures` calls.
29
-
30
- ```sh
31
- git clone <this repository> && cd plainproof
32
- python3.11 -m venv .venv && . .venv/bin/activate && pip install -e '.[test,run]' # or: pip install -r requirements.txt
33
-
34
- # 1. Tests (43): SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, planted probes
35
- python -m pytest -n auto -q tests
36
-
37
- # 2. Check that the code here is the sealed code (undoes the documented path substitutions, then compares sha256)
38
- plainproof verify
39
-
40
- # 3. Fetch the sealed held-out outputs from Zenodo (DOI: to be assigned) and check their hashes
41
- ZENODO_URL=<record file URL> plainproof fetch heldout
42
-
43
- # 4. Rebuild the tables and figures from the held-out summaries (needs R 4.x for the plots; base graphics only)
44
- python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json
45
- scripts/rscript.sh scripts/edm_v2_e0/plot_error_vs_d.R reports/edm-v2-e0/error-vs-d.csv reports/edm-v2-e0/figures/error-vs-d.png aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90
46
- python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
47
- scripts/rscript.sh scripts/edm_v2_e0b/plot_probe_auc.R reports/edm-v2-e0b/probe-auc-vs-d.csv reports/edm-v2-e0b/figures/probe-auc-vs-d.png 617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f
48
- ```
49
-
50
- The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`; the committed copies are the same files.
51
-
52
- ## Full rerun (about 4 hours of CPU)
53
-
54
- Only if you want to regenerate everything, including the held-out outputs.
55
-
56
- ```sh
57
- # a. BOBCAT (MIT) at the pinned commit, with the preprocessed ASSISTments 2009-2010 file; the data's own terms forbid
58
- # passing it on, so you fetch it from its source and accept them yourself
59
- scripts/bobcat/fetch_bobcat.sh
60
- # b. Item fit on the development half of ASSISTments learners (the output is checked against the receipt's hash)
61
- python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit
62
- # c. Retrain the BOBCAT checkpoint (about 2 hours; author defaults, fold 1, seed 221), then compare it with the original
63
- python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py
64
- # d. catIrt fixture, development stages, held-out runs (each refuses to overwrite an existing cell)
65
- scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt
66
- python scripts/edm_v2_e0/heldout.py run data/edm-v2-e0/heldout && python scripts/edm_v2_e0/heldout.py summarize data/edm-v2-e0/heldout
67
- python scripts/edm_v2_e0b/run.py run data/edm-v2-e0b/heldout && python scripts/edm_v2_e0b/run.py summarize data/edm-v2-e0b/heldout
68
- ```
69
-
70
- Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a different numpy can stop step b; and it asserts that the BOBCAT checkpoint's best epoch is 105, so a retrain that is not bit-identical can stop step d. In either case, use the Zenodo outputs. The development stages (`study.py tune|calibrate|calibrate_sprt_full|pilot`) are included for the record; their outputs (synthetic learners only) are in `data/edm-v2-e0/study/`.
71
-
72
- ## Fingerprints (sha256)
73
-
74
- | What | sha256 |
75
- |---|---|
76
- | E0 sealed freeze `reports/edm-v2-e0/freeze.json` | `a0f8ce404f2b5f7e671e2503a33b4554040e80714f6053553507e0972acdbcdc` |
77
- | E0b sealed freeze `reports/edm-v2-e0b/freeze.json` | `3fa0b8d457d813f59abd5255f9303e44deb2119ee79d6a9b92439a6c1cbf58ed` |
78
- | E0 held-out summary (Zenodo, `e0-heldout.tar` → `heldout/summary.json`) | `aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90` |
79
- | E0b held-out summary (Zenodo, `e0b-heldout.tar` → `heldout/summary.json`) | `617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f` |
80
- | Zenodo `e0-heldout.tar` | `bd06a11eb7163da102cad6ea0df12ea79e52ff94aab1dc35d28ec3910af2be22` |
81
- | Zenodo `e0b-heldout.tar` | `68219f228c41da972fe4c8f92c218e01f85f08eed864185f237cecda05314bbf` |
82
- | ASSISTments 2009 file at BOBCAT e6b6245e | `c07ca9fa0f08207b06488cec527725938fe96e81e3c1762839e1ad0b84f974cc` |
83
- | 2PL item fit (regenerated in step b) | `12a3b167cd9c9b78b3c3c7faf71b2e464b0943a454f6418faf0f99b1114cb7fc` |
84
- | catIrt 0.5.1 CRAN binary used for the fixture | `f5418f447e91d184791e668bd2a135ea5da40c981d4a76826018295b6ea9f079` |
85
-
86
- ## What is in here
87
-
88
- - `src/plainproof/`: item model, SPRT arm, exact stopping time, simulator (uniform and uncertainty-triggered outsourcing), item fit, signatures, planted probes (with the give-up model), matched-coverage scoring.
89
- - `scripts/edm_v2_e0/`, `scripts/edm_v2_e0b/`: the runners, report builders and R plots. `scripts/published_cat_reference_v1/`: the BOBCAT loading code the runners call.
90
- - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
91
- - `substitutions.json`: the only differences between this code and the sealed originals (package name, file locations, data paths). `scripts/verify_frozen.py` undoes them and checks every hash. `scripts/edm_v2_e0/r_env.sh` is kept verbatim as the record of the original R runtime; use `scripts/rscript.sh` instead.
92
-
93
- ## Recorded departures
94
-
95
- All are in `docs/PREREG_EDM_V2.md`: the SPRT tuning rule was revised after its first development pass (labelled post hoc); SPRT's calibration map was refitted once on full paths before the freeze; the E0 held-out run exceeded its 2 GiB memory cap (no result depends on it; the runner now enforces the cap); E0b was sealed before its pilot table had been reviewed (no result affected).
@@ -1,76 +0,0 @@
1
- # plainproof
2
-
3
- Reproduction package for **"How many follow-up questions distinguish genuine understanding from apparent mastery?"** (EDM 2027 submission, simulation study). It asks how many adaptive follow-up questions a classification test needs to tell genuine understanding from apparent mastery at a calibrated confidence target, and how that changes as a learner outsources a share *d* of the follow-ups to an AI. A second, sealed study (E0b) tests whether planted hard probe items separate outsourcing learners from honest ones.
4
-
5
- Everything here is CPU-only and needs no paid service. Code: MIT (`LICENSE`). Docs, figures and tables: CC BY 4.0 (`LICENSE-docs.md`).
6
-
7
- ## From clone to the figure (about 10 minutes)
8
-
9
- The `plainproof` command runs each step (`plainproof --help`); the raw script calls below are what it runs. The local path inside the sealed `scripts/edm_v2_e0/r_env.sh` is part of the frozen record; use the `scripts/rscript.sh` wrapper, which `plainproof figures` calls.
10
-
11
- ```sh
12
- git clone <this repository> && cd plainproof
13
- python3.11 -m venv .venv && . .venv/bin/activate && pip install -e '.[test,run]' # or: pip install -r requirements.txt
14
-
15
- # 1. Tests (43): SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, planted probes
16
- python -m pytest -n auto -q tests
17
-
18
- # 2. Check that the code here is the sealed code (undoes the documented path substitutions, then compares sha256)
19
- plainproof verify
20
-
21
- # 3. Fetch the sealed held-out outputs from Zenodo (DOI: to be assigned) and check their hashes
22
- ZENODO_URL=<record file URL> plainproof fetch heldout
23
-
24
- # 4. Rebuild the tables and figures from the held-out summaries (needs R 4.x for the plots; base graphics only)
25
- python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json
26
- scripts/rscript.sh scripts/edm_v2_e0/plot_error_vs_d.R reports/edm-v2-e0/error-vs-d.csv reports/edm-v2-e0/figures/error-vs-d.png aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90
27
- python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
28
- scripts/rscript.sh scripts/edm_v2_e0b/plot_probe_auc.R reports/edm-v2-e0b/probe-auc-vs-d.csv reports/edm-v2-e0b/figures/probe-auc-vs-d.png 617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f
29
- ```
30
-
31
- The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`; the committed copies are the same files.
32
-
33
- ## Full rerun (about 4 hours of CPU)
34
-
35
- Only if you want to regenerate everything, including the held-out outputs.
36
-
37
- ```sh
38
- # a. BOBCAT (MIT) at the pinned commit, with the preprocessed ASSISTments 2009-2010 file; the data's own terms forbid
39
- # passing it on, so you fetch it from its source and accept them yourself
40
- scripts/bobcat/fetch_bobcat.sh
41
- # b. Item fit on the development half of ASSISTments learners (the output is checked against the receipt's hash)
42
- python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit
43
- # c. Retrain the BOBCAT checkpoint (about 2 hours; author defaults, fold 1, seed 221), then compare it with the original
44
- python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py
45
- # d. catIrt fixture, development stages, held-out runs (each refuses to overwrite an existing cell)
46
- scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt
47
- python scripts/edm_v2_e0/heldout.py run data/edm-v2-e0/heldout && python scripts/edm_v2_e0/heldout.py summarize data/edm-v2-e0/heldout
48
- python scripts/edm_v2_e0b/run.py run data/edm-v2-e0b/heldout && python scripts/edm_v2_e0b/run.py summarize data/edm-v2-e0b/heldout
49
- ```
50
-
51
- Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a different numpy can stop step b; and it asserts that the BOBCAT checkpoint's best epoch is 105, so a retrain that is not bit-identical can stop step d. In either case, use the Zenodo outputs. The development stages (`study.py tune|calibrate|calibrate_sprt_full|pilot`) are included for the record; their outputs (synthetic learners only) are in `data/edm-v2-e0/study/`.
52
-
53
- ## Fingerprints (sha256)
54
-
55
- | What | sha256 |
56
- |---|---|
57
- | E0 sealed freeze `reports/edm-v2-e0/freeze.json` | `a0f8ce404f2b5f7e671e2503a33b4554040e80714f6053553507e0972acdbcdc` |
58
- | E0b sealed freeze `reports/edm-v2-e0b/freeze.json` | `3fa0b8d457d813f59abd5255f9303e44deb2119ee79d6a9b92439a6c1cbf58ed` |
59
- | E0 held-out summary (Zenodo, `e0-heldout.tar` → `heldout/summary.json`) | `aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90` |
60
- | E0b held-out summary (Zenodo, `e0b-heldout.tar` → `heldout/summary.json`) | `617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f` |
61
- | Zenodo `e0-heldout.tar` | `bd06a11eb7163da102cad6ea0df12ea79e52ff94aab1dc35d28ec3910af2be22` |
62
- | Zenodo `e0b-heldout.tar` | `68219f228c41da972fe4c8f92c218e01f85f08eed864185f237cecda05314bbf` |
63
- | ASSISTments 2009 file at BOBCAT e6b6245e | `c07ca9fa0f08207b06488cec527725938fe96e81e3c1762839e1ad0b84f974cc` |
64
- | 2PL item fit (regenerated in step b) | `12a3b167cd9c9b78b3c3c7faf71b2e464b0943a454f6418faf0f99b1114cb7fc` |
65
- | catIrt 0.5.1 CRAN binary used for the fixture | `f5418f447e91d184791e668bd2a135ea5da40c981d4a76826018295b6ea9f079` |
66
-
67
- ## What is in here
68
-
69
- - `src/plainproof/`: item model, SPRT arm, exact stopping time, simulator (uniform and uncertainty-triggered outsourcing), item fit, signatures, planted probes (with the give-up model), matched-coverage scoring.
70
- - `scripts/edm_v2_e0/`, `scripts/edm_v2_e0b/`: the runners, report builders and R plots. `scripts/published_cat_reference_v1/`: the BOBCAT loading code the runners call.
71
- - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
72
- - `substitutions.json`: the only differences between this code and the sealed originals (package name, file locations, data paths). `scripts/verify_frozen.py` undoes them and checks every hash. `scripts/edm_v2_e0/r_env.sh` is kept verbatim as the record of the original R runtime; use `scripts/rscript.sh` instead.
73
-
74
- ## Recorded departures
75
-
76
- All are in `docs/PREREG_EDM_V2.md`: the SPRT tuning rule was revised after its first development pass (labelled post hoc); SPRT's calibration map was refitted once on full paths before the freeze; the E0 held-out run exceeded its 2 GiB memory cap (no result depends on it; the runner now enforces the cap); E0b was sealed before its pilot table had been reviewed (no result affected).
@@ -1,84 +0,0 @@
1
- """plainproof: the command-line front end of this reproduction package.
2
-
3
- It runs the repository's own scripts, so it needs a checkout or the unpacked sdist (the sealed scripts locate the
4
- repository by its layout). Pass --root, or run it from the repository root.
5
-
6
- plainproof fetch [bobcat|heldout|all] fetch BOBCAT + the ASSISTments file (hash-checked), and/or the Zenodo outputs
7
- plainproof fit refit the 2PL item parameters on ASSISTments development learners
8
- plainproof run e0|e0b held-out run and summary (refuses to overwrite an existing cell)
9
- plainproof figures rebuild tables and figures from the held-out summaries (needs R for the plots)
10
- plainproof verify check every sealed file against both freezes
11
- """
12
- import argparse
13
- import hashlib
14
- import os
15
- import subprocess
16
- import sys
17
- from pathlib import Path
18
-
19
-
20
- def find_root(given):
21
- root = Path(given or os.getcwd()).resolve()
22
- if not (root / 'substitutions.json').exists() or not (root / 'reports' / 'edm-v2-e0' / 'freeze.json').exists():
23
- raise SystemExit(f'{root} is not a plainproof checkout (no substitutions.json or reports/); use --root')
24
- return root
25
-
26
-
27
- def sh(root, *cmd):
28
- env = dict(os.environ)
29
- env.setdefault('REPRO_DATA', str(root / 'data'))
30
- print('+', ' '.join(str(c) for c in cmd), flush=True)
31
- r = subprocess.run([str(c) for c in cmd], cwd=root, env=env)
32
- if r.returncode:
33
- raise SystemExit(r.returncode)
34
-
35
-
36
- def sha(p):
37
- return hashlib.sha256(Path(p).read_bytes()).hexdigest()
38
-
39
-
40
- def main(argv=None):
41
- ap = argparse.ArgumentParser(prog='plainproof', description=__doc__.split('\n\n')[0])
42
- ap.add_argument('--root', help='repository root (default: current directory)')
43
- sub = ap.add_subparsers(dest='cmd', required=True)
44
- f = sub.add_parser('fetch'); f.add_argument('what', nargs='?', default='all', choices=('bobcat', 'heldout', 'all'))
45
- sub.add_parser('fit')
46
- r = sub.add_parser('run'); r.add_argument('study', choices=('e0', 'e0b'))
47
- sub.add_parser('figures')
48
- sub.add_parser('verify')
49
- a = ap.parse_args(argv)
50
- root = find_root(a.root)
51
- py = sys.executable
52
- data = Path(os.environ.get('REPRO_DATA', root / 'data'))
53
- if a.cmd == 'fetch':
54
- if a.what in ('bobcat', 'all'):
55
- sh(root, 'bash', 'scripts/bobcat/fetch_bobcat.sh')
56
- if a.what in ('heldout', 'all'):
57
- if not os.environ.get('ZENODO_URL'):
58
- raise SystemExit('set ZENODO_URL to the Zenodo record file URL to fetch the held-out outputs')
59
- sh(root, 'bash', 'scripts/fetch_heldout.sh')
60
- elif a.cmd == 'fit':
61
- sh(root, py, 'scripts/edm_v2_e0/fit_assist2009.py', data / 'edm-v2-e0' / 'item-fit')
62
- elif a.cmd == 'run':
63
- if a.study == 'e0':
64
- out = data / 'edm-v2-e0' / 'heldout'
65
- sh(root, py, 'scripts/edm_v2_e0/heldout.py', 'run', out)
66
- sh(root, py, 'scripts/edm_v2_e0/heldout.py', 'summarize', out)
67
- else:
68
- out = data / 'edm-v2-e0b' / 'heldout'
69
- sh(root, py, 'scripts/edm_v2_e0b/run.py', 'run', out)
70
- sh(root, py, 'scripts/edm_v2_e0b/run.py', 'summarize', out)
71
- elif a.cmd == 'figures':
72
- s0, s1 = data / 'edm-v2-e0' / 'heldout' / 'summary.json', data / 'edm-v2-e0b' / 'heldout' / 'summary.json'
73
- sh(root, py, 'scripts/edm_v2_e0/report.py', s0)
74
- sh(root, 'bash', 'scripts/rscript.sh', 'scripts/edm_v2_e0/plot_error_vs_d.R', 'reports/edm-v2-e0/error-vs-d.csv',
75
- 'reports/edm-v2-e0/figures/error-vs-d.png', sha(s0))
76
- sh(root, py, 'scripts/edm_v2_e0b/report.py', s1)
77
- sh(root, 'bash', 'scripts/rscript.sh', 'scripts/edm_v2_e0b/plot_probe_auc.R', 'reports/edm-v2-e0b/probe-auc-vs-d.csv',
78
- 'reports/edm-v2-e0b/figures/probe-auc-vs-d.png', sha(s1))
79
- elif a.cmd == 'verify':
80
- sh(root, py, 'scripts/verify_frozen.py')
81
-
82
-
83
- if __name__ == '__main__':
84
- main()
@@ -1,95 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: plainproof
3
- Version: 0.1.0
4
- Summary: Reproduction tool for the paper 'How many follow-up questions distinguish genuine understanding from apparent mastery?'. Not a general library. Its sealed checks can stop a run on purpose.
5
- Author: Vishnu Vettrivel
6
- License-Expression: MIT
7
- Requires-Python: >=3.11
8
- Description-Content-Type: text/markdown
9
- License-File: LICENSE
10
- Requires-Dist: numpy>=2.0
11
- Requires-Dist: scipy>=1.13
12
- Provides-Extra: run
13
- Requires-Dist: scikit-learn>=1.5; extra == "run"
14
- Requires-Dist: torch>=2.4; extra == "run"
15
- Provides-Extra: test
16
- Requires-Dist: pytest>=8; extra == "test"
17
- Requires-Dist: pytest-xdist>=3.5; extra == "test"
18
- Dynamic: license-file
19
-
20
- # plainproof
21
-
22
- Reproduction package for **"How many follow-up questions distinguish genuine understanding from apparent mastery?"** (EDM 2027 submission, simulation study). It asks how many adaptive follow-up questions a classification test needs to tell genuine understanding from apparent mastery at a calibrated confidence target, and how that changes as a learner outsources a share *d* of the follow-ups to an AI. A second, sealed study (E0b) tests whether planted hard probe items separate outsourcing learners from honest ones.
23
-
24
- Everything here is CPU-only and needs no paid service. Code: MIT (`LICENSE`). Docs, figures and tables: CC BY 4.0 (`LICENSE-docs.md`).
25
-
26
- ## From clone to the figure (about 10 minutes)
27
-
28
- The `plainproof` command runs each step (`plainproof --help`); the raw script calls below are what it runs. The local path inside the sealed `scripts/edm_v2_e0/r_env.sh` is part of the frozen record; use the `scripts/rscript.sh` wrapper, which `plainproof figures` calls.
29
-
30
- ```sh
31
- git clone <this repository> && cd plainproof
32
- python3.11 -m venv .venv && . .venv/bin/activate && pip install -e '.[test,run]' # or: pip install -r requirements.txt
33
-
34
- # 1. Tests (43): SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, planted probes
35
- python -m pytest -n auto -q tests
36
-
37
- # 2. Check that the code here is the sealed code (undoes the documented path substitutions, then compares sha256)
38
- plainproof verify
39
-
40
- # 3. Fetch the sealed held-out outputs from Zenodo (DOI: to be assigned) and check their hashes
41
- ZENODO_URL=<record file URL> plainproof fetch heldout
42
-
43
- # 4. Rebuild the tables and figures from the held-out summaries (needs R 4.x for the plots; base graphics only)
44
- python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json
45
- scripts/rscript.sh scripts/edm_v2_e0/plot_error_vs_d.R reports/edm-v2-e0/error-vs-d.csv reports/edm-v2-e0/figures/error-vs-d.png aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90
46
- python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
47
- scripts/rscript.sh scripts/edm_v2_e0b/plot_probe_auc.R reports/edm-v2-e0b/probe-auc-vs-d.csv reports/edm-v2-e0b/figures/probe-auc-vs-d.png 617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f
48
- ```
49
-
50
- The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`; the committed copies are the same files.
51
-
52
- ## Full rerun (about 4 hours of CPU)
53
-
54
- Only if you want to regenerate everything, including the held-out outputs.
55
-
56
- ```sh
57
- # a. BOBCAT (MIT) at the pinned commit, with the preprocessed ASSISTments 2009-2010 file; the data's own terms forbid
58
- # passing it on, so you fetch it from its source and accept them yourself
59
- scripts/bobcat/fetch_bobcat.sh
60
- # b. Item fit on the development half of ASSISTments learners (the output is checked against the receipt's hash)
61
- python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit
62
- # c. Retrain the BOBCAT checkpoint (about 2 hours; author defaults, fold 1, seed 221), then compare it with the original
63
- python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py
64
- # d. catIrt fixture, development stages, held-out runs (each refuses to overwrite an existing cell)
65
- scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt
66
- python scripts/edm_v2_e0/heldout.py run data/edm-v2-e0/heldout && python scripts/edm_v2_e0/heldout.py summarize data/edm-v2-e0/heldout
67
- python scripts/edm_v2_e0b/run.py run data/edm-v2-e0b/heldout && python scripts/edm_v2_e0b/run.py summarize data/edm-v2-e0b/heldout
68
- ```
69
-
70
- Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a different numpy can stop step b; and it asserts that the BOBCAT checkpoint's best epoch is 105, so a retrain that is not bit-identical can stop step d. In either case, use the Zenodo outputs. The development stages (`study.py tune|calibrate|calibrate_sprt_full|pilot`) are included for the record; their outputs (synthetic learners only) are in `data/edm-v2-e0/study/`.
71
-
72
- ## Fingerprints (sha256)
73
-
74
- | What | sha256 |
75
- |---|---|
76
- | E0 sealed freeze `reports/edm-v2-e0/freeze.json` | `a0f8ce404f2b5f7e671e2503a33b4554040e80714f6053553507e0972acdbcdc` |
77
- | E0b sealed freeze `reports/edm-v2-e0b/freeze.json` | `3fa0b8d457d813f59abd5255f9303e44deb2119ee79d6a9b92439a6c1cbf58ed` |
78
- | E0 held-out summary (Zenodo, `e0-heldout.tar` → `heldout/summary.json`) | `aff9a8c49d48821c0e9343cd058c4e0e2f1659ffabcaa719824412f3b14abc90` |
79
- | E0b held-out summary (Zenodo, `e0b-heldout.tar` → `heldout/summary.json`) | `617be427feac24df2e342da00d34e91c78d5de91592cee390ef3516ae9e2ff3f` |
80
- | Zenodo `e0-heldout.tar` | `bd06a11eb7163da102cad6ea0df12ea79e52ff94aab1dc35d28ec3910af2be22` |
81
- | Zenodo `e0b-heldout.tar` | `68219f228c41da972fe4c8f92c218e01f85f08eed864185f237cecda05314bbf` |
82
- | ASSISTments 2009 file at BOBCAT e6b6245e | `c07ca9fa0f08207b06488cec527725938fe96e81e3c1762839e1ad0b84f974cc` |
83
- | 2PL item fit (regenerated in step b) | `12a3b167cd9c9b78b3c3c7faf71b2e464b0943a454f6418faf0f99b1114cb7fc` |
84
- | catIrt 0.5.1 CRAN binary used for the fixture | `f5418f447e91d184791e668bd2a135ea5da40c981d4a76826018295b6ea9f079` |
85
-
86
- ## What is in here
87
-
88
- - `src/plainproof/`: item model, SPRT arm, exact stopping time, simulator (uniform and uncertainty-triggered outsourcing), item fit, signatures, planted probes (with the give-up model), matched-coverage scoring.
89
- - `scripts/edm_v2_e0/`, `scripts/edm_v2_e0b/`: the runners, report builders and R plots. `scripts/published_cat_reference_v1/`: the BOBCAT loading code the runners call.
90
- - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
91
- - `substitutions.json`: the only differences between this code and the sealed originals (package name, file locations, data paths). `scripts/verify_frozen.py` undoes them and checks every hash. `scripts/edm_v2_e0/r_env.sh` is kept verbatim as the record of the original R runtime; use `scripts/rscript.sh` instead.
92
-
93
- ## Recorded departures
94
-
95
- All are in `docs/PREREG_EDM_V2.md`: the SPRT tuning rule was revised after its first development pass (labelled post hoc); SPRT's calibration map was refitted once on full paths before the freeze; the E0 held-out run exceeded its 2 GiB memory cap (no result depends on it; the runner now enforces the cap); E0b was sealed before its pilot table had been reviewed (no result affected).
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes