plainproof 0.1.1__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 (82) hide show
  1. {plainproof-0.1.1 → plainproof-0.2.0}/.gitignore +1 -0
  2. {plainproof-0.1.1 → plainproof-0.2.0}/CITATION.cff +1 -1
  3. {plainproof-0.1.1 → plainproof-0.2.0}/PKG-INFO +37 -34
  4. {plainproof-0.1.1 → plainproof-0.2.0}/README.md +36 -33
  5. {plainproof-0.1.1 → plainproof-0.2.0}/pyproject.toml +1 -1
  6. plainproof-0.2.0/setup.py +31 -0
  7. plainproof-0.2.0/src/plainproof/cli.py +121 -0
  8. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof.egg-info/PKG-INFO +37 -34
  9. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof.egg-info/SOURCES.txt +1 -0
  10. plainproof-0.1.1/src/plainproof/cli.py +0 -82
  11. {plainproof-0.1.1 → plainproof-0.2.0}/LICENSE +0 -0
  12. {plainproof-0.1.1 → plainproof-0.2.0}/LICENSE-docs.md +0 -0
  13. {plainproof-0.1.1 → plainproof-0.2.0}/MANIFEST.in +0 -0
  14. {plainproof-0.1.1 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration-v2.json +0 -0
  15. {plainproof-0.1.1 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration-v2.receipt.json +0 -0
  16. {plainproof-0.1.1 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration.json +0 -0
  17. {plainproof-0.1.1 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration.receipt.json +0 -0
  18. {plainproof-0.1.1 → plainproof-0.2.0}/data/edm-v2-e0/study/pilot.json +0 -0
  19. {plainproof-0.1.1 → plainproof-0.2.0}/data/edm-v2-e0/study/tune.json +0 -0
  20. {plainproof-0.1.1 → plainproof-0.2.0}/docs/PREREG_EDM_V2.md +0 -0
  21. {plainproof-0.1.1 → plainproof-0.2.0}/docs/PROTOCOL_E0.md +0 -0
  22. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0/error-vs-d.csv +0 -0
  23. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0/figures/error-vs-d.png +0 -0
  24. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0/freeze.json +0 -0
  25. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0/results-numbers.json +0 -0
  26. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0/signature-table.md +0 -0
  27. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0b/figures/probe-auc-vs-d.png +0 -0
  28. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0b/freeze.json +0 -0
  29. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0b/numbers.json +0 -0
  30. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0b/probe-auc-vs-d.csv +0 -0
  31. {plainproof-0.1.1 → plainproof-0.2.0}/reports/edm-v2-e0b/probe-table.md +0 -0
  32. {plainproof-0.1.1 → plainproof-0.2.0}/reports/receipts/assist2009-dev-2pl.receipt.json +0 -0
  33. {plainproof-0.1.1 → plainproof-0.2.0}/reports/receipts/bobcat-gate.json +0 -0
  34. {plainproof-0.1.1 → plainproof-0.2.0}/reports/receipts/bobcat-run-settings.json +0 -0
  35. {plainproof-0.1.1 → plainproof-0.2.0}/reports/receipts/catirt-install-receipt.txt +0 -0
  36. {plainproof-0.1.1 → plainproof-0.2.0}/requirements.txt +0 -0
  37. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/bobcat/check_checkpoint.py +0 -0
  38. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/bobcat/fetch_bobcat.sh +0 -0
  39. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/bobcat/retrain.py +0 -0
  40. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/bobcat_gate.py +0 -0
  41. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/catirt_sprt_steps.R +0 -0
  42. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/fit_assist2009.py +0 -0
  43. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/heldout.py +0 -0
  44. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/install_catirt.R +0 -0
  45. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/pilot.py +0 -0
  46. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/plot_error_vs_d.R +0 -0
  47. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/r_env.sh +0 -0
  48. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/report.py +0 -0
  49. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/repro_paths.py +0 -0
  50. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0/study.py +0 -0
  51. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0b/plot_probe_auc.R +0 -0
  52. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0b/report.py +0 -0
  53. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/edm_v2_e0b/run.py +0 -0
  54. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/fetch_heldout.sh +0 -0
  55. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/published_cat_reference_v1/bobcat_support.py +0 -0
  56. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/published_cat_reference_v1/compare_selection_v1.py +0 -0
  57. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/rscript.sh +0 -0
  58. {plainproof-0.1.1 → plainproof-0.2.0}/scripts/verify_frozen.py +0 -0
  59. {plainproof-0.1.1 → plainproof-0.2.0}/setup.cfg +0 -0
  60. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/__init__.py +0 -0
  61. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/bank_from_fit.py +0 -0
  62. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/fit.py +0 -0
  63. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/irt.py +0 -0
  64. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/planted.py +0 -0
  65. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/reliability.py +0 -0
  66. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/signature.py +0 -0
  67. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/simulator.py +0 -0
  68. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/sprt.py +0 -0
  69. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof/stopping.py +0 -0
  70. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof.egg-info/dependency_links.txt +0 -0
  71. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof.egg-info/entry_points.txt +0 -0
  72. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof.egg-info/requires.txt +0 -0
  73. {plainproof-0.1.1 → plainproof-0.2.0}/src/plainproof.egg-info/top_level.txt +0 -0
  74. {plainproof-0.1.1 → plainproof-0.2.0}/substitutions.json +0 -0
  75. {plainproof-0.1.1 → plainproof-0.2.0}/tests/conftest.py +0 -0
  76. {plainproof-0.1.1 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/bank.csv +0 -0
  77. {plainproof-0.1.1 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/config.csv +0 -0
  78. {plainproof-0.1.1 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/resp.csv +0 -0
  79. {plainproof-0.1.1 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/steps.csv +0 -0
  80. {plainproof-0.1.1 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/terminal.csv +0 -0
  81. {plainproof-0.1.1 → plainproof-0.2.0}/tests/test_edm_v2_e0.py +0 -0
  82. {plainproof-0.1.1 → 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,7 +5,7 @@ authors:
5
5
  - family-names: Vettrivel
6
6
  given-names: Vishnu
7
7
  license: MIT
8
- version: 0.1.1
8
+ version: 0.2.0
9
9
  doi: 10.5281/zenodo.23647649
10
10
  identifiers:
11
11
  - type: doi
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plainproof
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
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
5
  Author: Vishnu Vettrivel
6
6
  License-Expression: MIT
@@ -27,51 +27,33 @@ Reproduction package for **"How many follow-up questions distinguish genuine und
27
27
 
28
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
29
 
30
- ## From clone to the figure (about 10 minutes)
31
-
32
- 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.
30
+ ## From install to the figure (about 10 minutes)
33
31
 
34
32
  ```sh
35
- git clone <this repository> && cd plainproof
36
- python3.11 -m venv .venv && . .venv/bin/activate && pip install -e '.[test,run]' # or: pip install -r requirements.txt
37
-
38
- # 1. Tests (43): SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, planted probes
39
- python -m pytest -n auto -q tests
40
-
41
- # 2. Check that the code here is the sealed code (undoes the documented path substitutions, then compares sha256)
42
- plainproof verify
43
-
44
- # 3. Fetch the sealed held-out outputs (from the v0.1.0 release assets) and check their hashes
45
- plainproof fetch heldout
46
-
47
- # 4. Rebuild the tables and figures from the held-out summaries (needs R 4.x for the plots; base graphics only)
48
- python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json
49
- 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
50
- python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
51
- 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
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)
52
40
  ```
53
41
 
54
- The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`; the committed copies are the same files.
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.
55
43
 
56
44
  ## Full rerun (about 4 hours of CPU)
57
45
 
58
46
  Only if you want to regenerate everything, including the held-out outputs.
59
47
 
60
48
  ```sh
61
- # a. BOBCAT (MIT) at the pinned commit, with the preprocessed ASSISTments 2009-2010 file; the data's own terms forbid
62
- # passing it on, so you fetch it from its source and accept them yourself
63
- scripts/bobcat/fetch_bobcat.sh
64
- # b. Item fit on the development half of ASSISTments learners (the output is checked against the receipt's hash)
65
- python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit
66
- # c. Retrain the BOBCAT checkpoint (about 2 hours; author defaults, fold 1, seed 221), then compare it with the original
67
- python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py
68
- # d. catIrt fixture, development stages, held-out runs (each refuses to overwrite an existing cell)
69
- scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt
70
- 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
71
- 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
+ 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
72
54
  ```
73
55
 
74
- 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 published held-out outputs (`plainproof fetch heldout`). 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/`.
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/`.
75
57
 
76
58
  ## Fingerprints (sha256)
77
59
 
@@ -90,6 +72,7 @@ Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a
90
72
  ## What is in here
91
73
 
92
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`.
93
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.
94
77
  - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
95
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.
@@ -97,3 +80,23 @@ Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a
97
80
  ## Recorded departures
98
81
 
99
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
+ ```
@@ -8,51 +8,33 @@ Reproduction package for **"How many follow-up questions distinguish genuine und
8
8
 
9
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
10
 
11
- ## From clone to the figure (about 10 minutes)
12
-
13
- 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.
11
+ ## From install to the figure (about 10 minutes)
14
12
 
15
13
  ```sh
16
- git clone <this repository> && cd plainproof
17
- python3.11 -m venv .venv && . .venv/bin/activate && pip install -e '.[test,run]' # or: pip install -r requirements.txt
18
-
19
- # 1. Tests (43): SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, planted probes
20
- python -m pytest -n auto -q tests
21
-
22
- # 2. Check that the code here is the sealed code (undoes the documented path substitutions, then compares sha256)
23
- plainproof verify
24
-
25
- # 3. Fetch the sealed held-out outputs (from the v0.1.0 release assets) and check their hashes
26
- plainproof fetch heldout
27
-
28
- # 4. Rebuild the tables and figures from the held-out summaries (needs R 4.x for the plots; base graphics only)
29
- python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json
30
- 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
31
- python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
32
- 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
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)
33
21
  ```
34
22
 
35
- The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`; the committed copies are the same files.
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.
36
24
 
37
25
  ## Full rerun (about 4 hours of CPU)
38
26
 
39
27
  Only if you want to regenerate everything, including the held-out outputs.
40
28
 
41
29
  ```sh
42
- # a. BOBCAT (MIT) at the pinned commit, with the preprocessed ASSISTments 2009-2010 file; the data's own terms forbid
43
- # passing it on, so you fetch it from its source and accept them yourself
44
- scripts/bobcat/fetch_bobcat.sh
45
- # b. Item fit on the development half of ASSISTments learners (the output is checked against the receipt's hash)
46
- python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit
47
- # c. Retrain the BOBCAT checkpoint (about 2 hours; author defaults, fold 1, seed 221), then compare it with the original
48
- python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py
49
- # d. catIrt fixture, development stages, held-out runs (each refuses to overwrite an existing cell)
50
- scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt
51
- 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
52
- 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
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
53
35
  ```
54
36
 
55
- 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 published held-out outputs (`plainproof fetch heldout`). 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/`.
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/`.
56
38
 
57
39
  ## Fingerprints (sha256)
58
40
 
@@ -71,6 +53,7 @@ Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a
71
53
  ## What is in here
72
54
 
73
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`.
74
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.
75
58
  - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
76
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.
@@ -78,3 +61,23 @@ Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a
78
61
  ## Recorded departures
79
62
 
80
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.1"
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"
@@ -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()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plainproof
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
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
5
  Author: Vishnu Vettrivel
6
6
  License-Expression: MIT
@@ -27,51 +27,33 @@ Reproduction package for **"How many follow-up questions distinguish genuine und
27
27
 
28
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
29
 
30
- ## From clone to the figure (about 10 minutes)
31
-
32
- 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.
30
+ ## From install to the figure (about 10 minutes)
33
31
 
34
32
  ```sh
35
- git clone <this repository> && cd plainproof
36
- python3.11 -m venv .venv && . .venv/bin/activate && pip install -e '.[test,run]' # or: pip install -r requirements.txt
37
-
38
- # 1. Tests (43): SPRT against catIrt 0.5.1's saved steps, exact stopping time, simulator, signatures, planted probes
39
- python -m pytest -n auto -q tests
40
-
41
- # 2. Check that the code here is the sealed code (undoes the documented path substitutions, then compares sha256)
42
- plainproof verify
43
-
44
- # 3. Fetch the sealed held-out outputs (from the v0.1.0 release assets) and check their hashes
45
- plainproof fetch heldout
46
-
47
- # 4. Rebuild the tables and figures from the held-out summaries (needs R 4.x for the plots; base graphics only)
48
- python scripts/edm_v2_e0/report.py data/edm-v2-e0/heldout/summary.json
49
- 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
50
- python scripts/edm_v2_e0b/report.py data/edm-v2-e0b/heldout/summary.json
51
- 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
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)
52
40
  ```
53
41
 
54
- The figures land in `reports/edm-v2-e0/figures/` and `reports/edm-v2-e0b/figures/`; the committed copies are the same files.
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.
55
43
 
56
44
  ## Full rerun (about 4 hours of CPU)
57
45
 
58
46
  Only if you want to regenerate everything, including the held-out outputs.
59
47
 
60
48
  ```sh
61
- # a. BOBCAT (MIT) at the pinned commit, with the preprocessed ASSISTments 2009-2010 file; the data's own terms forbid
62
- # passing it on, so you fetch it from its source and accept them yourself
63
- scripts/bobcat/fetch_bobcat.sh
64
- # b. Item fit on the development half of ASSISTments learners (the output is checked against the receipt's hash)
65
- python scripts/edm_v2_e0/fit_assist2009.py data/edm-v2-e0/item-fit
66
- # c. Retrain the BOBCAT checkpoint (about 2 hours; author defaults, fold 1, seed 221), then compare it with the original
67
- python scripts/bobcat/retrain.py && python scripts/bobcat/check_checkpoint.py
68
- # d. catIrt fixture, development stages, held-out runs (each refuses to overwrite an existing cell)
69
- scripts/rscript.sh scripts/edm_v2_e0/catirt_sprt_steps.R tests/fixtures/edm_v2_catirt_sprt
70
- 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
71
- 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
+ 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
72
54
  ```
73
55
 
74
- 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 published held-out outputs (`plainproof fetch heldout`). 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/`.
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/`.
75
57
 
76
58
  ## Fingerprints (sha256)
77
59
 
@@ -90,6 +72,7 @@ Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a
90
72
  ## What is in here
91
73
 
92
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`.
93
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.
94
77
  - `reports/`: both sealed freezes, receipts, figures and tables. `docs/`: the E0 protocol and the pre-registration log (verbatim extract).
95
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.
@@ -97,3 +80,23 @@ Two caveats, stated plainly. The sealed code checks the item fit's sha256, so a
97
80
  ## Recorded departures
98
81
 
99
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
@@ -1,82 +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, and/or the held-out outputs (all hash-checked)
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
- sh(root, 'bash', 'scripts/fetch_heldout.sh')
58
- elif a.cmd == 'fit':
59
- sh(root, py, 'scripts/edm_v2_e0/fit_assist2009.py', data / 'edm-v2-e0' / 'item-fit')
60
- elif a.cmd == 'run':
61
- if a.study == 'e0':
62
- out = data / 'edm-v2-e0' / 'heldout'
63
- sh(root, py, 'scripts/edm_v2_e0/heldout.py', 'run', out)
64
- sh(root, py, 'scripts/edm_v2_e0/heldout.py', 'summarize', out)
65
- else:
66
- out = data / 'edm-v2-e0b' / 'heldout'
67
- sh(root, py, 'scripts/edm_v2_e0b/run.py', 'run', out)
68
- sh(root, py, 'scripts/edm_v2_e0b/run.py', 'summarize', out)
69
- elif a.cmd == 'figures':
70
- s0, s1 = data / 'edm-v2-e0' / 'heldout' / 'summary.json', data / 'edm-v2-e0b' / 'heldout' / 'summary.json'
71
- sh(root, py, 'scripts/edm_v2_e0/report.py', s0)
72
- sh(root, 'bash', 'scripts/rscript.sh', 'scripts/edm_v2_e0/plot_error_vs_d.R', 'reports/edm-v2-e0/error-vs-d.csv',
73
- 'reports/edm-v2-e0/figures/error-vs-d.png', sha(s0))
74
- sh(root, py, 'scripts/edm_v2_e0b/report.py', s1)
75
- sh(root, 'bash', 'scripts/rscript.sh', 'scripts/edm_v2_e0b/plot_probe_auc.R', 'reports/edm-v2-e0b/probe-auc-vs-d.csv',
76
- 'reports/edm-v2-e0b/figures/probe-auc-vs-d.png', sha(s1))
77
- elif a.cmd == 'verify':
78
- sh(root, py, 'scripts/verify_frozen.py')
79
-
80
-
81
- if __name__ == '__main__':
82
- main()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes