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.
- {plainproof-0.1.0 → plainproof-0.2.0}/.gitignore +1 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/CITATION.cff +7 -0
- plainproof-0.2.0/PKG-INFO +102 -0
- plainproof-0.2.0/README.md +83 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/pyproject.toml +1 -1
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/fetch_heldout.sh +3 -2
- plainproof-0.2.0/setup.py +31 -0
- plainproof-0.2.0/src/plainproof/cli.py +121 -0
- plainproof-0.2.0/src/plainproof.egg-info/PKG-INFO +102 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/SOURCES.txt +1 -0
- plainproof-0.1.0/PKG-INFO +0 -95
- plainproof-0.1.0/README.md +0 -76
- plainproof-0.1.0/src/plainproof/cli.py +0 -84
- plainproof-0.1.0/src/plainproof.egg-info/PKG-INFO +0 -95
- {plainproof-0.1.0 → plainproof-0.2.0}/LICENSE +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/LICENSE-docs.md +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/MANIFEST.in +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration-v2.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration-v2.receipt.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/calibration.receipt.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/pilot.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/data/edm-v2-e0/study/tune.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/docs/PREREG_EDM_V2.md +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/docs/PROTOCOL_E0.md +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/error-vs-d.csv +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/figures/error-vs-d.png +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/freeze.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/results-numbers.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0/signature-table.md +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/figures/probe-auc-vs-d.png +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/freeze.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/numbers.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/probe-auc-vs-d.csv +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/edm-v2-e0b/probe-table.md +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/receipts/assist2009-dev-2pl.receipt.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/receipts/bobcat-gate.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/receipts/bobcat-run-settings.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/reports/receipts/catirt-install-receipt.txt +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/requirements.txt +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/bobcat/check_checkpoint.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/bobcat/fetch_bobcat.sh +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/bobcat/retrain.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/bobcat_gate.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/catirt_sprt_steps.R +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/fit_assist2009.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/heldout.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/install_catirt.R +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/pilot.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/plot_error_vs_d.R +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/r_env.sh +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/report.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/repro_paths.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0/study.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0b/plot_probe_auc.R +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0b/report.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/edm_v2_e0b/run.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/published_cat_reference_v1/bobcat_support.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/published_cat_reference_v1/compare_selection_v1.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/rscript.sh +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/scripts/verify_frozen.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/setup.cfg +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/__init__.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/bank_from_fit.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/fit.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/irt.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/planted.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/reliability.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/signature.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/simulator.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/sprt.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof/stopping.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/dependency_links.txt +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/entry_points.txt +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/requires.txt +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/src/plainproof.egg-info/top_level.txt +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/substitutions.json +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/tests/conftest.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/bank.csv +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/config.csv +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/resp.csv +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/steps.csv +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/tests/fixtures/edm_v2_catirt_sprt/terminal.csv +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/tests/test_edm_v2_e0.py +0 -0
- {plainproof-0.1.0 → plainproof-0.2.0}/tests/test_edm_v2_e0b.py +0 -0
|
@@ -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
|
+
[](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
|
+
[](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.
|
|
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
|
|
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
|
|
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
|
+
[](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
|
+
```
|
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).
|
plainproof-0.1.0/README.md
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plainproof-0.1.0 → plainproof-0.2.0}/scripts/published_cat_reference_v1/compare_selection_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|