citations 0.1.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.
- citations-0.1.0/.claude-plugin/marketplace.json +17 -0
- citations-0.1.0/.github/workflows/publish.yml +21 -0
- citations-0.1.0/.gitignore +10 -0
- citations-0.1.0/LICENSE +18 -0
- citations-0.1.0/PKG-INFO +127 -0
- citations-0.1.0/README.md +112 -0
- citations-0.1.0/docs/ALTERNATIVES.md +204 -0
- citations-0.1.0/docs/BEST_PRACTICES.md +181 -0
- citations-0.1.0/docs/PREREG_CONVENTION.md +72 -0
- citations-0.1.0/example/README.md +11 -0
- citations-0.1.0/example/records/arxiv-2211-00593.yaml +14 -0
- citations-0.1.0/plugin/.claude-plugin/plugin.json +9 -0
- citations-0.1.0/plugin/README.md +30 -0
- citations-0.1.0/plugin/skills/citations/SKILL.md +76 -0
- citations-0.1.0/pyproject.toml +23 -0
- citations-0.1.0/src/citations/__init__.py +6 -0
- citations-0.1.0/src/citations/build.py +345 -0
- citations-0.1.0/src/citations/cli.py +178 -0
- citations-0.1.0/src/citations/init.py +101 -0
- citations-0.1.0/src/citations/link_pdfs.py +103 -0
- citations-0.1.0/src/citations/lint.py +140 -0
- citations-0.1.0/src/citations/paths.py +91 -0
- citations-0.1.0/src/citations/resolve.py +306 -0
- citations-0.1.0/src/citations/verify.py +177 -0
- citations-0.1.0/tests/test_cli.py +111 -0
- citations-0.1.0/tests/test_failure_modes.py +214 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "citations",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Elliot Tower"
|
|
5
|
+
},
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Check that quotations resolve in the sources they cite",
|
|
8
|
+
"version": "0.1.0"
|
|
9
|
+
},
|
|
10
|
+
"plugins": [
|
|
11
|
+
{
|
|
12
|
+
"name": "citations",
|
|
13
|
+
"source": "./plugin",
|
|
14
|
+
"strict": false
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
contents: read
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.11"
|
|
19
|
+
- run: pip install hatchling
|
|
20
|
+
- run: python -m hatchling build
|
|
21
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
citations-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elliot Tower
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
6
|
+
and associated documentation files (the "Software"), to deal in the Software without
|
|
7
|
+
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
|
9
|
+
Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
|
12
|
+
substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
15
|
+
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
16
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
17
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
citations-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: citations
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A library of quotations checked against the sources they came from
|
|
5
|
+
Author-email: Elliot Tower <elliot@elliottower.ai>
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: bibliography,bibtex,citations,provenance,reproducibility
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: platformdirs>=3.0
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
12
|
+
Provides-Extra: lint
|
|
13
|
+
Requires-Dist: papis>=0.15; extra == 'lint'
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# citations
|
|
17
|
+
|
|
18
|
+
Check that the passages you quote actually appear in the sources you cite, and keep a library of
|
|
19
|
+
the ones that do.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install citations
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
citations init
|
|
31
|
+
citations verify --claims claims/
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
2,940 quotes
|
|
36
|
+
|
|
37
|
+
found 2,940
|
|
38
|
+
not found 0
|
|
39
|
+
|
|
40
|
+
warnings
|
|
41
|
+
213 short — the source may qualify this in the next clause
|
|
42
|
+
155 normalized — matched after ignoring punctuation and spacing
|
|
43
|
+
|
|
44
|
+
all found.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
| Command | What it does |
|
|
50
|
+
|---------|-------------|
|
|
51
|
+
| `citations init` | Create a library here |
|
|
52
|
+
| `citations verify` | Do the quotations resolve in their sources? |
|
|
53
|
+
| `citations resolve` | Backfill missing DOIs and arXiv ids |
|
|
54
|
+
| `citations build` | Rebuild records from bibliographies |
|
|
55
|
+
| `citations lint` | BibTeX correctness, via papis |
|
|
56
|
+
| `citations link` | Point pdfs/ at the papers' artifacts |
|
|
57
|
+
|
|
58
|
+
## Verify output
|
|
59
|
+
|
|
60
|
+
Three results, and they are exhaustive:
|
|
61
|
+
|
|
62
|
+
| Result | Meaning |
|
|
63
|
+
|--------|---------|
|
|
64
|
+
| `found` | The passage is in the source |
|
|
65
|
+
| `not found` | The source was read and the passage is not in it |
|
|
66
|
+
| `unchecked` | The source could not be read, so no measurement was made |
|
|
67
|
+
|
|
68
|
+
Warnings are separate, because a passage can be found and still worth a second look. A quote
|
|
69
|
+
can be short enough that the next clause changes its meaning — `"We trained 50"` appears
|
|
70
|
+
verbatim in a paper whose sentence continues `"...and 5 refits each for 12 layered"`.
|
|
71
|
+
|
|
72
|
+
`unchecked` is neither a pass nor a failure. Only `not found` fails; `--strict` also fails on
|
|
73
|
+
unchecked, for CI.
|
|
74
|
+
|
|
75
|
+
`not found` means read the source. A mirror-reversed scan or a two-column extraction produces
|
|
76
|
+
the same signal as a passage that was never there.
|
|
77
|
+
|
|
78
|
+
## Where the library lives
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
$CITATIONS_HOME if set
|
|
82
|
+
./.citations/ walking up this project's own, the way git finds .git
|
|
83
|
+
the shared library if you made one with citations init --user
|
|
84
|
+
none of those it tells you to run citations init
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Project-local by default, so running the tool inside a paper works on that paper and there is
|
|
88
|
+
no hidden global state.
|
|
89
|
+
|
|
90
|
+
## What a claim file looks like
|
|
91
|
+
|
|
92
|
+
One file per source, in the paper's `claims/` directory. `citations verify --claims claims`
|
|
93
|
+
reads all of them.
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
source:
|
|
97
|
+
citation: schiffman2026 # the bibkey
|
|
98
|
+
local: reference/schiffman2026.pdf # what gets read
|
|
99
|
+
sha256: 3f9a… # which bytes were read
|
|
100
|
+
extract_cmd: pdftotext
|
|
101
|
+
|
|
102
|
+
claims:
|
|
103
|
+
orthogonal-cores:
|
|
104
|
+
statement: 'Cores meeting equivalent causal criteria sit at principal angles of 75-90 degrees.'
|
|
105
|
+
quotes:
|
|
106
|
+
- exact: 'and principal angles ranged'
|
|
107
|
+
section: 'body'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`statement` is yours; `exact` is theirs. The tool checks the second only, so a `statement` that
|
|
111
|
+
overreaches its quote is for review to catch — the command cannot.
|
|
112
|
+
|
|
113
|
+
## Records are YAML
|
|
114
|
+
|
|
115
|
+
So `git diff` shows what changed. A binary store cannot show you that a year moved from 2021 to
|
|
116
|
+
2022 — a real discrepancy this found between two of one author's own papers.
|
|
117
|
+
|
|
118
|
+
## Claude Code
|
|
119
|
+
|
|
120
|
+
`plugin/` is a Claude Code plugin that tells Claude when to reach for the CLI.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
/plugin marketplace add elliottower/citations
|
|
124
|
+
/plugin install citations@citations
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
MIT licensed. `docs/` has the working practices this came out of.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# citations
|
|
2
|
+
|
|
3
|
+
Check that the passages you quote actually appear in the sources you cite, and keep a library of
|
|
4
|
+
the ones that do.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install citations
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
citations init
|
|
16
|
+
citations verify --claims claims/
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
2,940 quotes
|
|
21
|
+
|
|
22
|
+
found 2,940
|
|
23
|
+
not found 0
|
|
24
|
+
|
|
25
|
+
warnings
|
|
26
|
+
213 short — the source may qualify this in the next clause
|
|
27
|
+
155 normalized — matched after ignoring punctuation and spacing
|
|
28
|
+
|
|
29
|
+
all found.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
| Command | What it does |
|
|
35
|
+
|---------|-------------|
|
|
36
|
+
| `citations init` | Create a library here |
|
|
37
|
+
| `citations verify` | Do the quotations resolve in their sources? |
|
|
38
|
+
| `citations resolve` | Backfill missing DOIs and arXiv ids |
|
|
39
|
+
| `citations build` | Rebuild records from bibliographies |
|
|
40
|
+
| `citations lint` | BibTeX correctness, via papis |
|
|
41
|
+
| `citations link` | Point pdfs/ at the papers' artifacts |
|
|
42
|
+
|
|
43
|
+
## Verify output
|
|
44
|
+
|
|
45
|
+
Three results, and they are exhaustive:
|
|
46
|
+
|
|
47
|
+
| Result | Meaning |
|
|
48
|
+
|--------|---------|
|
|
49
|
+
| `found` | The passage is in the source |
|
|
50
|
+
| `not found` | The source was read and the passage is not in it |
|
|
51
|
+
| `unchecked` | The source could not be read, so no measurement was made |
|
|
52
|
+
|
|
53
|
+
Warnings are separate, because a passage can be found and still worth a second look. A quote
|
|
54
|
+
can be short enough that the next clause changes its meaning — `"We trained 50"` appears
|
|
55
|
+
verbatim in a paper whose sentence continues `"...and 5 refits each for 12 layered"`.
|
|
56
|
+
|
|
57
|
+
`unchecked` is neither a pass nor a failure. Only `not found` fails; `--strict` also fails on
|
|
58
|
+
unchecked, for CI.
|
|
59
|
+
|
|
60
|
+
`not found` means read the source. A mirror-reversed scan or a two-column extraction produces
|
|
61
|
+
the same signal as a passage that was never there.
|
|
62
|
+
|
|
63
|
+
## Where the library lives
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
$CITATIONS_HOME if set
|
|
67
|
+
./.citations/ walking up this project's own, the way git finds .git
|
|
68
|
+
the shared library if you made one with citations init --user
|
|
69
|
+
none of those it tells you to run citations init
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Project-local by default, so running the tool inside a paper works on that paper and there is
|
|
73
|
+
no hidden global state.
|
|
74
|
+
|
|
75
|
+
## What a claim file looks like
|
|
76
|
+
|
|
77
|
+
One file per source, in the paper's `claims/` directory. `citations verify --claims claims`
|
|
78
|
+
reads all of them.
|
|
79
|
+
|
|
80
|
+
```yaml
|
|
81
|
+
source:
|
|
82
|
+
citation: schiffman2026 # the bibkey
|
|
83
|
+
local: reference/schiffman2026.pdf # what gets read
|
|
84
|
+
sha256: 3f9a… # which bytes were read
|
|
85
|
+
extract_cmd: pdftotext
|
|
86
|
+
|
|
87
|
+
claims:
|
|
88
|
+
orthogonal-cores:
|
|
89
|
+
statement: 'Cores meeting equivalent causal criteria sit at principal angles of 75-90 degrees.'
|
|
90
|
+
quotes:
|
|
91
|
+
- exact: 'and principal angles ranged'
|
|
92
|
+
section: 'body'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`statement` is yours; `exact` is theirs. The tool checks the second only, so a `statement` that
|
|
96
|
+
overreaches its quote is for review to catch — the command cannot.
|
|
97
|
+
|
|
98
|
+
## Records are YAML
|
|
99
|
+
|
|
100
|
+
So `git diff` shows what changed. A binary store cannot show you that a year moved from 2021 to
|
|
101
|
+
2022 — a real discrepancy this found between two of one author's own papers.
|
|
102
|
+
|
|
103
|
+
## Claude Code
|
|
104
|
+
|
|
105
|
+
`plugin/` is a Claude Code plugin that tells Claude when to reach for the CLI.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
/plugin marketplace add elliottower/citations
|
|
109
|
+
/plugin install citations@citations
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
MIT licensed. `docs/` has the working practices this came out of.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Why these practices, and what was rejected
|
|
2
|
+
|
|
3
|
+
Companion to `BEST_PRACTICES.md`. Every recommendation there was chosen over something, and
|
|
4
|
+
several were chosen over an earlier version of itself. This records the reasoning so a later
|
|
5
|
+
reader can overturn a decision on its merits rather than rediscovering the argument.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## One file per experiment, not five
|
|
10
|
+
|
|
11
|
+
**Rejected:** `PREREG.md` + `TIMELINE.md` + `AMENDMENTS/` + `DEVIATIONS.md` + `MANIFEST.sha256`,
|
|
12
|
+
with a vocabulary distinguishing amendments from deviations.
|
|
13
|
+
|
|
14
|
+
**Why.** Git already hashes every file, so the manifest restates what `git show <sha>:file`
|
|
15
|
+
proves. The timeline is the log. Amendments and deviations differ only in whether results had
|
|
16
|
+
been seen, and that is one column — so filing them in separate directories records the same fact
|
|
17
|
+
twice and adds a decision the author must get right each time.
|
|
18
|
+
|
|
19
|
+
The deeper problem is that a five-file system has five ways to fall out of sync, and the failure
|
|
20
|
+
is silent. A researcher who forgets to update `TIMELINE.md` has a repository that lies. One
|
|
21
|
+
append-only file has one failure mode: you forgot to append, which is visible as a gap.
|
|
22
|
+
|
|
23
|
+
**The strongest counter.** Separate files are easier to diff and easier for a script to parse.
|
|
24
|
+
True, and it would matter at scale — but a study has perhaps ten log lines, and a human reading
|
|
25
|
+
one file beats a script parsing five.
|
|
26
|
+
|
|
27
|
+
**What survives from the rejected design:** the results-access column. That idea was the good one.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## OSF headings, not a bespoke template
|
|
32
|
+
|
|
33
|
+
**Rejected:** keeping the existing house format, which already covers most of the same ground
|
|
34
|
+
under better-reading names.
|
|
35
|
+
|
|
36
|
+
**Why.** The existing format is genuinely good — the `msms-subspace-collapse` pre-registration
|
|
37
|
+
has an integrity protocol, a frozen threshold, a separated exploratory phase, and an appended
|
|
38
|
+
deviation recording that its own criterion failed. That last item is the behavior no template
|
|
39
|
+
produces and no tooling enforces.
|
|
40
|
+
|
|
41
|
+
But it is bespoke, which means each new document re-decides what to include. Two OSF headings
|
|
42
|
+
are missing from the house format and both map onto errors that actually occurred:
|
|
43
|
+
*Foreknowledge of data or evidence* would have forced a declaration on results that were reused
|
|
44
|
+
as if confirmatory, and *Inference criteria* turns a hoped-for outcome into a committed threshold.
|
|
45
|
+
|
|
46
|
+
Adopting the headings costs nothing and removes the per-document decision.
|
|
47
|
+
|
|
48
|
+
**The strongest counter.** Twenty-seven headings for a small study is heavy, and most will read
|
|
49
|
+
N/A. Fair — but an explicit N/A is information, and a heading you skipped is indistinguishable
|
|
50
|
+
from one you never considered.
|
|
51
|
+
|
|
52
|
+
**Not done:** retrofitting fifty-one existing documents. Converting a year of work to a template
|
|
53
|
+
is the theater this document exists to prevent.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## AsPredicted's eight questions
|
|
58
|
+
|
|
59
|
+
**Rejected as the default, kept as an option.**
|
|
60
|
+
|
|
61
|
+
**Why.** AsPredicted is lighter, widely used, and honest for a small study. It was not chosen as
|
|
62
|
+
the default because it lacks a foreknowledge field, and foreknowledge is the specific thing that
|
|
63
|
+
goes wrong here — exploratory results existing before a plan is written.
|
|
64
|
+
|
|
65
|
+
Use it when a study genuinely has eight questions' worth of content. Do not use the heavier
|
|
66
|
+
template as a way of looking rigorous.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## OSF registration for the plan, not a git tag
|
|
71
|
+
|
|
72
|
+
**Rejected:** signed git tags as the freeze mechanism.
|
|
73
|
+
|
|
74
|
+
**Why.** A signed tag is cryptographically sound and free, and it is the native git answer. It
|
|
75
|
+
fails on the only axis that matters: the author controls the repository. A reviewer discounting
|
|
76
|
+
"you could have rewritten this" is discounting exactly the property a tag cannot supply. The
|
|
77
|
+
value of registration is not cryptographic — it is that someone else holds a dated copy.
|
|
78
|
+
|
|
79
|
+
**Where tags still earn their place:** naming freeze commits so `git show prereg/I3:...` resolves
|
|
80
|
+
by name rather than by remembered hash. Do that, but do not mistake it for attestation.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Not cryptographic timestamping
|
|
85
|
+
|
|
86
|
+
**Rejected:** OpenTimestamps, RFC 3161 timestamp authorities, a continuous stamping tool that
|
|
87
|
+
hashes every script and dataset at creation.
|
|
88
|
+
|
|
89
|
+
**Why.** A timestamp proves a lower bound — this existed by T. It cannot prove an upper bound —
|
|
90
|
+
that the work did not start earlier. The failure mode the field actually names is
|
|
91
|
+
pre-registering after results are known, and that is entirely compatible with a valid timestamp
|
|
92
|
+
on the pre-registration: you run the experiment, see the answer, write the plan, stamp it.
|
|
93
|
+
|
|
94
|
+
Continuous stamping of scripts and data is stronger, because it establishes an ordering — plan,
|
|
95
|
+
then code, then results. But it still cannot exclude an unstamped earlier run. You cannot prove
|
|
96
|
+
a negative about your own private activity, and no anchor changes that.
|
|
97
|
+
|
|
98
|
+
**Worth knowing:** the ML literature names this (*PARKing*, preregistering after results are
|
|
99
|
+
known) and reaches for pre-registration as the remedy rather than cryptography.
|
|
100
|
+
|
|
101
|
+
**The strongest counter, and it holds:** continuous stamping is nearly free and makes fraud more
|
|
102
|
+
expensive. Adopt it if you like. Just never describe it as proof of no peeking, which is the
|
|
103
|
+
claim it invites and cannot support.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Not "because a reviewer will ask"
|
|
108
|
+
|
|
109
|
+
**Rejected reasoning**, not a rejected practice.
|
|
110
|
+
|
|
111
|
+
Pre-registration is close to dead as an ML norm. The workshop series collapsed — seventy-three
|
|
112
|
+
proposals in 2020 to twenty-two in 2021, and results-stage follow-through from twenty-three
|
|
113
|
+
papers to three. `preregister.science` has been untouched since 2022 and no ML venue offers
|
|
114
|
+
Registered Reports. TMLR is the pointed case: pre-registration was pitched to it directly and it
|
|
115
|
+
chose to change acceptance criteria instead.
|
|
116
|
+
|
|
117
|
+
So "a reviewer will ask" is false, and building a practice on it would be building on a norm that
|
|
118
|
+
does not exist.
|
|
119
|
+
|
|
120
|
+
**The reason that survives:** a paper arguing for validity standards that does not meet them has
|
|
121
|
+
a self-consistency problem, and would have one even if nobody ever checked. That reason does not
|
|
122
|
+
depend on anyone asking.
|
|
123
|
+
|
|
124
|
+
**Consequence:** do not advertise it. One sentence in methods. A paper that markets its own rigor
|
|
125
|
+
invites an audit of the rigor instead of the result.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Three platforms, not one
|
|
130
|
+
|
|
131
|
+
**Rejected:** consolidating onto OSF alone, and separately, cutting Zenodo entirely.
|
|
132
|
+
|
|
133
|
+
**Why the plan and the code split.** They want opposite properties. A revisable prediction is not
|
|
134
|
+
a prediction, so the plan must freeze. Code legitimately iterates — bugs, dependency breaks,
|
|
135
|
+
tolerances derived from fixtures — so freezing it once would be absurd. One mechanism for both
|
|
136
|
+
forces a bad choice.
|
|
137
|
+
|
|
138
|
+
**Why not OSF alone.** OSF is file storage, not a git remote; mirroring loses the commit history
|
|
139
|
+
that makes freezes checkable. Its GitHub addon exists because they know this.
|
|
140
|
+
|
|
141
|
+
**Why Zenodo survived a cut.** It was nearly dropped on the grounds that OSF registrations
|
|
142
|
+
already snapshot code and mint a DOI. The argument that kept it: arXiv and bioRxiv are community
|
|
143
|
+
reading lists, and posting imposes a cost on every reader in the field. Zenodo is an archive and
|
|
144
|
+
imposes on nobody. For exploratory or AI-heavy work wanting a citable dated record without
|
|
145
|
+
claiming a field's attention, that distinction is real.
|
|
146
|
+
|
|
147
|
+
**Correction to a claim made in its favour:** a published Zenodo deposit cannot be deleted, and
|
|
148
|
+
files cannot be edited — only superseded, with the old version permanently resolvable. This was
|
|
149
|
+
offered as an advantage and is the opposite. It is also why the tool works: a timestamp you can
|
|
150
|
+
revise establishes nothing.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## The claims/audits split
|
|
155
|
+
|
|
156
|
+
**Rejected:** one record per claim holding both the extraction and the judgment.
|
|
157
|
+
|
|
158
|
+
**Why.** They have different standing. Verbatim quotations with a pinned sha256 are checkable by
|
|
159
|
+
anyone holding the PDF, and reusable by someone who rejects every verdict. Statuses and verdicts
|
|
160
|
+
are contestable and ours. Merged, a reader cannot tell which parts they are being asked to trust.
|
|
161
|
+
|
|
162
|
+
The split was verified lossless before adoption: every key landed on exactly one side, and all
|
|
163
|
+
2,940 quotations still resolved afterwards.
|
|
164
|
+
|
|
165
|
+
**The strongest counter.** Two files per claim is more to maintain. Answered by having the loader
|
|
166
|
+
rejoin them, so every consumer still sees one object.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## The quote gate, and its known hole
|
|
171
|
+
|
|
172
|
+
**Adopted**, with a limitation that must be stated rather than hidden.
|
|
173
|
+
|
|
174
|
+
The gate catches fabrication: quotations that do not exist in the artifact they cite. It cannot
|
|
175
|
+
catch misinterpretation — a real, resolving quotation attached to a claim it does not support.
|
|
176
|
+
|
|
177
|
+
**And it is defeatable by truncation.** A pinned substring ending before a qualifying clause
|
|
178
|
+
verifies a claim its source contradicts. Observed: `"We trained 50"` resolves while the source
|
|
179
|
+
continues `"...each for 2, 4, and 8 layered variants and 5 refits each for 12 layered
|
|
180
|
+
(GPT2-small)"`. The record claimed fifty; the truth was five.
|
|
181
|
+
|
|
182
|
+
This is a measurement-validity failure in the verification apparatus itself, which is why it is
|
|
183
|
+
documented rather than quietly patched.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Things deliberately not built
|
|
188
|
+
|
|
189
|
+
**A provenance timeline of AI contribution.** Conflates two separate questions — were decisions
|
|
190
|
+
fixed before outcomes, and how was AI used. The first is answered by the log; the second by one
|
|
191
|
+
methods sentence.
|
|
192
|
+
|
|
193
|
+
**A Claude Code plugin for timestamping.** Would have wrapped a mechanism that does not support
|
|
194
|
+
the claim it implies. See above.
|
|
195
|
+
|
|
196
|
+
**A central freeze registry across experiments.** Superseded by per-folder freezes plus a
|
|
197
|
+
generated index. A central file must be kept in sync with N folders, and that is a job which will
|
|
198
|
+
eventually not get done.
|
|
199
|
+
|
|
200
|
+
**Migrating research repositories to stripped-down clean copies.** Tried on three, reverted. The
|
|
201
|
+
paper repositories needed it because they were unshippable. Research repositories are different:
|
|
202
|
+
the experiments, data and pre-registrations are the substance, so a copy holding only the paper
|
|
203
|
+
is a different artifact rather than a tidier one — and the copies dropped pre-registrations,
|
|
204
|
+
which is the failure this whole document exists to prevent.
|