paperlint 10.2.0 → 10.3.0
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.
- package/dist/adapters/study-registry/index.d.ts +352 -1
- package/dist/adapters/study-registry/index.d.ts.map +1 -1
- package/dist/adapters/study-registry/index.js +171 -8
- package/dist/adapters/study-registry/index.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -4
- package/dist/cli.js.map +1 -1
- package/dist/domain/study-registry.d.ts +201 -5
- package/dist/domain/study-registry.d.ts.map +1 -1
- package/dist/domain/study-registry.js +224 -2
- package/dist/domain/study-registry.js.map +1 -1
- package/dist/ports/study-registry-codec.d.ts +6 -2
- package/dist/ports/study-registry-codec.d.ts.map +1 -1
- package/dist/studies.d.ts.map +1 -1
- package/dist/studies.js +7 -4
- package/dist/studies.js.map +1 -1
- package/dist/study-registry-rule.d.ts +12 -5
- package/dist/study-registry-rule.d.ts.map +1 -1
- package/dist/study-registry-rule.js +67 -37
- package/dist/study-registry-rule.js.map +1 -1
- package/docs/design/study-registry.md +131 -15
- package/docs/layout.md +23 -21
- package/docs/rules/repro/study-plan-name.md +70 -0
- package/docs/rules/repro/study-registered.md +164 -6
- package/docs/rules.md +53 -52
- package/package.json +1 -1
- package/skills/build-benchmark/SKILL.md +24 -12
- package/skills/build-benchmark/SKILL.md.spec.ts +23 -11
- package/skills/build-label-page/SKILL.md +9 -7
- package/skills/build-label-page/SKILL.md.spec.ts +8 -6
- package/skills/run-agent-grid/SKILL.md +10 -5
- package/skills/run-agent-grid/SKILL.md.spec.ts +9 -4
- package/src/adapters/study-registry/index.test.ts +340 -0
- package/src/adapters/study-registry/index.ts +268 -10
- package/src/cli.ts +6 -4
- package/src/domain/study-measurements.test.ts +629 -0
- package/src/domain/study-registry.test.ts +10 -1
- package/src/domain/study-registry.ts +456 -10
- package/src/new-paper.test.ts +1 -0
- package/src/ports/study-registry-codec.ts +6 -2
- package/src/rule-cases.test.ts +27 -0
- package/src/studies-cli.test.ts +2 -2
- package/src/studies.test.ts +6 -0
- package/src/studies.ts +12 -3
- package/src/study-registry-rule.test.ts +140 -1
- package/src/study-registry-rule.ts +106 -39
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `repro/study-registered` — every study folder at the top of a paper's `repro/` has exactly one row in
|
|
3
|
-
* `repro/studies.json`, every row names a folder that exists,
|
|
4
|
-
* one the registry generates.
|
|
3
|
+
* `repro/studies.json`, every row names a folder that exists, a row's measurement and plan hold
|
|
4
|
+
* together, and the index in `repro/README.md` is the one the registry generates. Beside it,
|
|
5
|
+
* `repro/study-plan-name`, a warning: a plan still named `prereg.json`.
|
|
5
6
|
*
|
|
6
7
|
* What is judged, and why, is `src/domain/study-registry.ts` and docs/rules/repro/study-registered.md.
|
|
7
|
-
* This file lists `repro/`, reads the registry, the README
|
|
8
|
+
* This file lists `repro/`, reads the registry, the README, the result files and the plans, and reports.
|
|
8
9
|
*
|
|
9
10
|
* ── WHY A RULE OF ITS OWN, NOT MORE OF `repro/allowed-files-only` ─────────────────────
|
|
10
11
|
* `repro/allowed-files-only` judges what may stand at the top of `repro/`, by name, and accepts the
|
|
@@ -16,10 +17,10 @@
|
|
|
16
17
|
* `PIPELINE-STATUS.md`, first line, like the layout rules: every paper has it, and ESLint lints no
|
|
17
18
|
* file in `repro/`.
|
|
18
19
|
*/
|
|
19
|
-
import { basename, dirname, join } from "node:path";
|
|
20
|
+
import { basename, dirname, join, posix } from "node:path";
|
|
20
21
|
import { callerPath } from "./caller-path.js";
|
|
21
22
|
import { README, REPRO_BYPRODUCTS, REPRO_DIR, REPRO_DIRS, } from "./domain/repro-layout.js";
|
|
22
|
-
import { STUDIES_FILE, judgeStudies, studyMessage, } from "./domain/study-registry.js";
|
|
23
|
+
import { LEGACY_PLAN_FILE, PLAN_NAME_PROBLEMS, STUDIES_FILE, judgeStudies, planKeys, studyMessage, } from "./domain/study-registry.js";
|
|
23
24
|
import { reproEntriesOf } from "./repro-layout-rule.js";
|
|
24
25
|
import { rulePageUrl } from "./venue-rules.js";
|
|
25
26
|
const STATUS_FILE = "PIPELINE-STATUS.md";
|
|
@@ -50,7 +51,23 @@ const existingResults = (dir, r, files) => new Set((r.kind === "read" ? r.regist
|
|
|
50
51
|
// A NUL is no path the disk can hold, and probing one throws: such a row reads as missing.
|
|
51
52
|
.filter((p) => !p.includes("\0") &&
|
|
52
53
|
files.isFile(callerPath(join(dir, REPRO_DIR, p)))));
|
|
53
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* The plan each row of `r` names, read and parsed, by `<folder>/<plan>`; a plan not there is left out.
|
|
56
|
+
* A plan still named `prereg.json` is parsed by the loose schema of its old name.
|
|
57
|
+
*/
|
|
58
|
+
const plansOf = (dir, r, deps) => new Map((r.kind === "read" ? planKeys(r.registry) : [])
|
|
59
|
+
// A NUL is no path the disk can hold, and probing one throws: such a plan reads as missing.
|
|
60
|
+
.filter((key) => !key.includes("\0"))
|
|
61
|
+
.flatMap((key) => {
|
|
62
|
+
const text = textAt(deps.files, join(dir, REPRO_DIR, key));
|
|
63
|
+
if (text === null)
|
|
64
|
+
return [];
|
|
65
|
+
const parse = posix.basename(key) === LEGACY_PLAN_FILE
|
|
66
|
+
? deps.codec.parseLegacyPlan
|
|
67
|
+
: deps.codec.parsePlan;
|
|
68
|
+
return [[key, parse(text)]];
|
|
69
|
+
}));
|
|
70
|
+
/** Every finding of the paper folder `dir`'s study registry — THE function behind both rules. */
|
|
54
71
|
export function studyFindings(dir, deps) {
|
|
55
72
|
const registry = registryOf(dir, deps);
|
|
56
73
|
return judgeStudies({
|
|
@@ -58,9 +75,10 @@ export function studyFindings(dir, deps) {
|
|
|
58
75
|
registry,
|
|
59
76
|
readme: textAt(deps.files, join(dir, REPRO_DIR, README)),
|
|
60
77
|
existingResults: existingResults(dir, registry, deps.files),
|
|
78
|
+
plans: plansOf(dir, registry, deps),
|
|
61
79
|
});
|
|
62
80
|
}
|
|
63
|
-
/** The problems
|
|
81
|
+
/** The problems `repro/study-registered` reports, each its own message id; the text is `studyMessage`. */
|
|
64
82
|
const PROBLEMS = [
|
|
65
83
|
"no-registry",
|
|
66
84
|
"unreadable",
|
|
@@ -75,41 +93,53 @@ const PROBLEMS = [
|
|
|
75
93
|
"result-file",
|
|
76
94
|
"no-successor",
|
|
77
95
|
"stale-index",
|
|
96
|
+
"unknown-measurement",
|
|
97
|
+
"empty-measurement",
|
|
98
|
+
"unknown-requirement",
|
|
99
|
+
"headline-approval",
|
|
100
|
+
"bad-plan",
|
|
101
|
+
"author-check",
|
|
78
102
|
];
|
|
79
|
-
|
|
103
|
+
/** A rule's meta: its page, and a message id per problem, the whole text being `studyMessage`. */
|
|
104
|
+
const metaOf = (name, description, problems) => ({
|
|
80
105
|
type: "suggestion",
|
|
81
|
-
docs: {
|
|
82
|
-
description: "every study folder at the top of a paper's repro/ has exactly one row in repro/studies.json, every row names a folder that exists, and repro/README.md's index is the one the registry generates",
|
|
83
|
-
url: rulePageUrl("repro/study-registered"),
|
|
84
|
-
},
|
|
106
|
+
docs: { description, url: rulePageUrl(name) },
|
|
85
107
|
schema: [],
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
108
|
+
messages: Object.fromEntries(problems.map((p) => [p, "{{text}}"])),
|
|
109
|
+
});
|
|
110
|
+
/** A rule that reports the findings of `problems`, reading the folder through `deps`. */
|
|
111
|
+
const ruleOf = (meta, problems, deps) => ({
|
|
112
|
+
meta,
|
|
113
|
+
create(context) {
|
|
114
|
+
if (basename(context.filename) !== STATUS_FILE)
|
|
115
|
+
return {};
|
|
116
|
+
return {
|
|
117
|
+
root() {
|
|
118
|
+
const at = context.sourceCode.getLocFromIndex(0);
|
|
119
|
+
studyFindings(dirname(context.filename), deps)
|
|
120
|
+
.filter((f) => problems.includes(f.problem))
|
|
121
|
+
.forEach((f) => {
|
|
122
|
+
context.report({
|
|
123
|
+
loc: { start: at, end: at },
|
|
124
|
+
messageId: f.problem,
|
|
125
|
+
data: { text: studyMessage(f) },
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
/**
|
|
133
|
+
* The two rules, reading the folder through `deps`: `study-registered`, the registry's errors, and
|
|
134
|
+
* `study-plan-name`, a warning for a plan still named `prereg.json` — read as the plan, so a paper
|
|
135
|
+
* that wrote one before `plan.json` existed is not broken, and told the name to move to.
|
|
136
|
+
*/
|
|
90
137
|
export function studyRegistryRules(deps) {
|
|
91
138
|
return {
|
|
92
|
-
"study-registered":
|
|
93
|
-
|
|
94
|
-
create(context) {
|
|
95
|
-
if (basename(context.filename) !== STATUS_FILE)
|
|
96
|
-
return {};
|
|
97
|
-
return {
|
|
98
|
-
root() {
|
|
99
|
-
const at = context.sourceCode.getLocFromIndex(0);
|
|
100
|
-
studyFindings(dirname(context.filename), deps).forEach((f) => {
|
|
101
|
-
context.report({
|
|
102
|
-
loc: { start: at, end: at },
|
|
103
|
-
messageId: f.problem,
|
|
104
|
-
data: { text: studyMessage(f) },
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
},
|
|
110
|
-
},
|
|
139
|
+
"study-registered": ruleOf(metaOf("repro/study-registered", "every study folder at the top of a paper's repro/ has exactly one row in repro/studies.json, every row names a folder that exists, its measurement and its plan hold together, and repro/README.md's index is the one the registry generates", PROBLEMS), PROBLEMS, deps),
|
|
140
|
+
"study-plan-name": ruleOf(metaOf("repro/study-plan-name", "a study's plan is named plan.json, not prereg.json", PLAN_NAME_PROBLEMS), PLAN_NAME_PROBLEMS, deps),
|
|
111
141
|
};
|
|
112
142
|
}
|
|
113
|
-
/** The
|
|
114
|
-
export const STUDY_REGISTRY_RULE_LEVELS = { "repro/study-registered": "error" };
|
|
143
|
+
/** The levels they are on at in paperlint's own config, for every paper's `PIPELINE-STATUS.md`. */
|
|
144
|
+
export const STUDY_REGISTRY_RULE_LEVELS = { "repro/study-registered": "error", "repro/study-plan-name": "warn" };
|
|
115
145
|
//# sourceMappingURL=study-registry-rule.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"study-registry-rule.js","sourceRoot":"","sources":["../src/study-registry-rule.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"study-registry-rule.js","sourceRoot":"","sources":["../src/study-registry-rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -47,9 +47,13 @@ two commands that write it.
|
|
|
47
47
|
| `superseded_by` | optional; an id in the registry. Required when `superseded` |
|
|
48
48
|
| `in_paper` | `yes`, `no`, `registry` (listed only in the registry, not in the text) |
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
| `measurement` | optional; the id of the measurement the study belongs to (6) |
|
|
51
|
+
| `plan` | optional; the study's plan, a path inside its folder: `plan.json` (7) |
|
|
52
|
+
|
|
53
|
+
**A row may carry more fields**, and they are kept: a paper merges its own metadata into the rows
|
|
54
|
+
(`frame`, `method`, `outcome`, …). The top level is closed — `prefix`, `studies`, and the optional
|
|
55
|
+
`author`, `requirements` and `measurements` (6) — so a misspelt key is an error, not an ignored
|
|
56
|
+
key.
|
|
53
57
|
|
|
54
58
|
2. **The rule `repro/study-registered`, an error,** reported on the first line of
|
|
55
59
|
`PIPELINE-STATUS.md` like `repro/allowed-files-only`, once per finding:
|
|
@@ -74,8 +78,9 @@ two commands that write it.
|
|
|
74
78
|
3. **Two commands**, in `src/studies.ts`, wired in `src/cli.ts`:
|
|
75
79
|
|
|
76
80
|
- `paperlint studies new <paper-dir> "<title>" [--kind measurement]` takes the next id, creates
|
|
77
|
-
`repro/<id>-<slug>/README.md` (frontmatter `id:` and `title:`)
|
|
78
|
-
`status: designing`, `in_paper: no
|
|
81
|
+
`repro/<id>-<slug>/README.md` (frontmatter `id:` and `title:`) and the plan's template,
|
|
82
|
+
`plan.json` (7), appends the row with `status: designing`, `in_paper: no`, today's date and
|
|
83
|
+
`plan: "plan.json"`, and regenerates the index block. It refuses a
|
|
79
84
|
title over 8 words, a title with no letter or digit to make a slug from, an unknown kind, a folder
|
|
80
85
|
that already exists, and a paper with no `studies.json` (the prefix is the author's choice, so the
|
|
81
86
|
refusal names the file to write and does not guess one).
|
|
@@ -93,19 +98,127 @@ two commands that write it.
|
|
|
93
98
|
`paperlint studies new`, and update its row (status, result, result file, in paper) when it ends,
|
|
94
99
|
then run `paperlint studies index`.
|
|
95
100
|
|
|
101
|
+
6. **Measurements above studies, and the author's requirements.** One measurement (a census, a
|
|
102
|
+
benchmark) spans several study folders: a pilot, the main run, a replication. Before this, a paper
|
|
103
|
+
put the measurement's fields on the row of its first study under prefixed names
|
|
104
|
+
(`measurement_title`, `measurement_status`) and the other rows carried `measurement: <id>`, which
|
|
105
|
+
nothing checked; the author's verbatim requirements went to a separate file nothing read. Now:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"prefix": "P1",
|
|
110
|
+
"author": "A. Author",
|
|
111
|
+
"requirements": [
|
|
112
|
+
{
|
|
113
|
+
"id": "R1",
|
|
114
|
+
"text": "Every sample is a random draw from all rules found.",
|
|
115
|
+
"date": "2026-10-10",
|
|
116
|
+
"source": "chat"
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"measurements": [
|
|
120
|
+
{
|
|
121
|
+
"id": "M1",
|
|
122
|
+
"title": "Rule census",
|
|
123
|
+
"rq": "RQ1",
|
|
124
|
+
"role": "headline",
|
|
125
|
+
"approval": {
|
|
126
|
+
"by": "A. Author",
|
|
127
|
+
"date": "2026-10-12",
|
|
128
|
+
"quote": "This is the one."
|
|
129
|
+
},
|
|
130
|
+
"requirements": ["R1"]
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
"studies": [
|
|
134
|
+
{ "id": "P1-S01", "measurement": "M1", "plan": "plan.json", "…": "…" }
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`role` is `headline` (the paper's claim rests on it) or `baseline`. A measurement keeps extra
|
|
140
|
+
fields like a row; a requirement and an approval are exactly their fields. The rule reports, each
|
|
141
|
+
finding its own message id: a row naming an undeclared measurement (`unknown-measurement`), a
|
|
142
|
+
measurement no row names (`empty-measurement`), a measurement naming an undeclared requirement
|
|
143
|
+
(`unknown-requirement`), and a headline without `approval`, or approved by anyone but `author`
|
|
144
|
+
when the registry names one (`headline-approval`). These cross-references are the rule's, not the
|
|
145
|
+
parser's: one dangling id must not fail the whole parse and hide every other finding. **These checks run only when the registry has
|
|
146
|
+
`measurements`**: a registry written before them, whose rows already carry `measurement` as a field
|
|
147
|
+
of their own, stays valid.
|
|
148
|
+
|
|
149
|
+
7. **The study's plan, `plan.json`.** Each study folder held a hand-written `prereg.json`, its
|
|
150
|
+
fields differing study to study, read only by the experimental `study/declare-sample`. The name
|
|
151
|
+
misled — it is not an outside pre-registration — so the plan is `plan.json`, written as a
|
|
152
|
+
template by `paperlint studies new` beside the README, and named in the row's `plan`:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"question": "",
|
|
157
|
+
"population": {
|
|
158
|
+
"source": "",
|
|
159
|
+
"draw": { "kind": "all", "method": "" }
|
|
160
|
+
},
|
|
161
|
+
"arms": [],
|
|
162
|
+
"primary_outcome": "",
|
|
163
|
+
"author_check": null
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The template's draw is of all the population (`"kind": "all"`, a census); a sampled study changes
|
|
168
|
+
it to `{ "kind": "seeded", "method": "random", "seed": 7 }`. `arms` is empty for a census;
|
|
169
|
+
`author_check` becomes `{ "by", "date", "quote" }` once the author has seen the drawn units.
|
|
170
|
+
**Parse, don't validate:**
|
|
171
|
+
|
|
172
|
+
- **Closed at every level.** A misspelt key is an error; the paper's own keys (hypotheses,
|
|
173
|
+
models, budget) go in the one optional key `extra`, an object of anything.
|
|
174
|
+
- **One spelling of "none".** `author_check` is required, and `null` is "not yet"; an absent key
|
|
175
|
+
is an error, never a second way to say the same.
|
|
176
|
+
- **No contradictory state.** Each of these is a parse error, not a later finding:
|
|
177
|
+
- an `author_check` on a draft — the author approved a plan whose texts are empty;
|
|
178
|
+
- a draw that is not one of two kinds: `seeded`, whose `seed` is required and not null, or
|
|
179
|
+
`all` (a census), which has no seed;
|
|
180
|
+
- two arms of one name;
|
|
181
|
+
- a key of `extra` that is a field of the plan, which would say one thing twice.
|
|
182
|
+
|
|
183
|
+
The population's size is not stored: it is counted from the source, and a stored copy could
|
|
184
|
+
only contradict it. Nothing downstream read it.
|
|
185
|
+
|
|
186
|
+
- **Complete or not is a type.** The parser returns a plan `ready` (every required text filled)
|
|
187
|
+
or a `draft` with the list of its empty texts, or why it is no plan. The rule never looks at a
|
|
188
|
+
text again: a study that has run on a `draft` is `bad-plan`, with the parser's list.
|
|
189
|
+
- **The schemas are the domain's types.** The domain's types are written by hand (the domain
|
|
190
|
+
imports no zod); the adapter holds a compile-time proof that each schema's output — registry,
|
|
191
|
+
study, measurement, requirement, approval, author check, plan, ready-or-draft — and its domain type are the
|
|
192
|
+
same type both ways, so a field added to one alone stops the build.
|
|
193
|
+
|
|
194
|
+
The schemas live beside the registry's, in `src/adapters/study-registry/`. The rule reports a
|
|
195
|
+
`plan` outside the folder, missing, or not of the schema, and — once the study has run (`running`,
|
|
196
|
+
`done`, `stopped`, `superseded`) — a draft (`bad-plan`); a study of a headline measurement
|
|
197
|
+
that has run with no `author_check` in its plan, no plan, or a check by anyone but `author`
|
|
198
|
+
(`author-check`). A `designing` study's template is clean, so `studies new` never leaves the lint
|
|
199
|
+
red.
|
|
200
|
+
|
|
201
|
+
**Compatibility.** A row may name `prereg.json` as its plan: it is parsed by a loose schema of
|
|
202
|
+
its own — keys of its own accepted at every level, those at the top kept in `extra`, a seed makes
|
|
203
|
+
the draw `seeded`, none (or `null`) makes it `all`; a size is not read; an absent check is
|
|
204
|
+
`null` — and judged as the plan, the same contradictions refused; a second rule, `repro/study-plan-name`, warns that it moves to `plan.json` — a warning cannot
|
|
205
|
+
come from an error rule, since ESLint sets the level per rule. A `prereg.json` no row names is not
|
|
206
|
+
read, so no existing paper turns red.
|
|
207
|
+
|
|
96
208
|
## Where each part lives
|
|
97
209
|
|
|
98
|
-
| part
|
|
99
|
-
|
|
|
100
|
-
| the types, the judge, the index, ids
|
|
101
|
-
| the
|
|
102
|
-
|
|
|
103
|
-
| the
|
|
104
|
-
|
|
|
105
|
-
|
|
|
210
|
+
| part | file | layer |
|
|
211
|
+
| -------------------------------------- | ----------------------------------- | ------- |
|
|
212
|
+
| the types, the judge, the index, ids | `src/domain/study-registry.ts` | domain |
|
|
213
|
+
| the plan's type and template | `src/domain/study-registry.ts` | domain |
|
|
214
|
+
| the schemas (zod) of registry and plan | `src/adapters/study-registry/` | adapter |
|
|
215
|
+
| what the app asks of a parser | `src/ports/study-registry-codec.ts` | port |
|
|
216
|
+
| both rules: list, read, report | `src/study-registry-rule.ts` | app |
|
|
217
|
+
| the two commands | `src/studies.ts` | app |
|
|
218
|
+
| wiring, the clock for today's date | `src/cli.ts` | root |
|
|
106
219
|
|
|
107
220
|
The judge is pure: it takes the folder names, the parsed registry (or why it is absent or unreadable),
|
|
108
|
-
the README's text,
|
|
221
|
+
the README's text, which result files exist, and each named plan parsed, and returns findings. The rule and the commands are
|
|
109
222
|
the only places that touch the disk, through the `Files` and `ListDir` ports.
|
|
110
223
|
|
|
111
224
|
## Generated index, and prettier
|
|
@@ -127,4 +240,7 @@ a cell is escaped and a line break becomes a space.
|
|
|
127
240
|
|
|
128
241
|
- Whether the `question` is one sentence, or the `result` one line, beyond their being strings.
|
|
129
242
|
- What a study's `README.md` says, or whether its frontmatter matches the row.
|
|
130
|
-
- Files inside a study folder other than `result_file
|
|
243
|
+
- Files inside a study folder other than `result_file` and the `plan` its row names.
|
|
244
|
+
- `study/declare-sample` still reads only `prereg.json`, and asks for different fields
|
|
245
|
+
(`strata`, `screens`, `coverage`, and an `author_check` of `who`, `when`, `units_seen`,
|
|
246
|
+
`units_drawn`, `verdict`); merging the two shapes is its own decision.
|
package/docs/layout.md
CHANGED
|
@@ -18,8 +18,8 @@ flowchart TB
|
|
|
18
18
|
subgraph S3["3 · study: repro/#lt;id#gt;-#lt;slug#gt;/"]
|
|
19
19
|
direction TB
|
|
20
20
|
D["<b>design</b> · build-benchmark<br/>paperlint studies new<br/>writes: the study's folder, README.md,<br/>its row in repro/studies.json<br/>checked by: repro/allowed-files-only,<br/>repro/study-registered"]
|
|
21
|
-
P["<b>
|
|
22
|
-
A["<b>author check</b> · you see the drawn units<br/>writes: author_check in
|
|
21
|
+
P["<b>plan</b> · build-benchmark<br/>fills: plan.json, before the draw<br/>checked by: repro/study-registered,<br/>once the study runs"]
|
|
22
|
+
A["<b>author check</b> · you see the drawn units<br/>writes: author_check in plan.json<br/>checked by: repro/study-registered,<br/>for a headline measurement"]
|
|
23
23
|
R["<b>run</b> · your scripts<br/>writes: the study folder,<br/>repro/tools/, repro/data/<br/>checked by: repro/allowed-files-only"]
|
|
24
24
|
L["<b>labels</b> · build-label-page<br/>a phone page; the answers go<br/>into the study's data/"]
|
|
25
25
|
Y["<b>analysis</b> · build-benchmark<br/>writes: the numbers, NOTES.md,<br/>the study's row: status, result<br/>then paperlint studies index<br/>checked by: repro/study-registered"]
|
|
@@ -110,7 +110,8 @@ Both are explained in [`venues.md`](venues.md).
|
|
|
110
110
|
| `repro/`, its top | 3 study | `build-benchmark`, your scripts | [`repro/allowed-files-only`](rules/repro/allowed-files-only.md); the hook `paper-folder-layout` refuses a new loose entry |
|
|
111
111
|
| `repro/studies.json` | 3 study | `paperlint studies new` appends a row; you edit a row when its study ends; `paperlint studies index` regenerates the index in `repro/README.md` | [`repro/study-registered`](rules/repro/study-registered.md): a row per study folder, its fields, the index in sync |
|
|
112
112
|
| `repro/<id>-<slug>/` | 3 study | `paperlint studies new` (the folder and its `README.md`), then `build-benchmark` (the design, in its `README.md`) | [`repro/allowed-files-only`](rules/repro/allowed-files-only.md): the name, and a `README.md` in it; [`repro/study-registered`](rules/repro/study-registered.md): its row |
|
|
113
|
-
| `repro/<id>-<slug>/
|
|
113
|
+
| `repro/<id>-<slug>/plan.json` | 3 study | `paperlint studies new` writes the template; `build-benchmark` fills it before the sample is drawn; you add the author's check | [`repro/study-registered`](rules/repro/study-registered.md): its fields, filled once the study runs, and `author_check` in a headline measurement |
|
|
114
|
+
| `repro/<id>-<slug>/prereg.json` | 3 study | the plan's old name, still read when the row names it | [`repro/study-plan-name`](rules/repro/study-plan-name.md) (warning); [`study/declare-sample`](rules/study/declare-sample.md), off by default |
|
|
114
115
|
| `repro/<id>-<slug>/data/` | 3 study | `build-label-page` exports the labels here | nothing |
|
|
115
116
|
| `repro/tools/`, `repro/data/` | 3 study | your scripts; `paperlint build` keeps `repro/data/references-cache.json` | nothing inside them |
|
|
116
117
|
| `NOTES.md` | 3, then 4 | you: each number → the data it comes from; `build-label-page` adds a line per label file | nothing |
|
|
@@ -134,24 +135,25 @@ A check runs at one of four moments:
|
|
|
134
135
|
The lint-only job skips what needs a build (pages, fonts, references).
|
|
135
136
|
- **On demand** — a skill, when you ask for what it does. A skill stops nothing; it writes.
|
|
136
137
|
|
|
137
|
-
| what | kind | when it runs | what it stops
|
|
138
|
-
| ------------------------------------------------------------------------------------------- | ----- | ----------------------------------------------------------- |
|
|
139
|
-
| `paper-folder-layout` | hook | before an agent creates a file (Edit, Write) | a new entry the layout does not allow, at a paper's root or the top of its `repro/`; never an existing file
|
|
140
|
-
| `paper-edit-guard` | hook | before an agent's shell command | a shell command that writes or moves a paper's source, which would skip the hooks that run after an edit
|
|
141
|
-
| `paper-skills-nudge` | hook | after an agent edits a paper's source | nothing: it shows the agent the pre-submit checklist
|
|
142
|
-
| `paper-status-gates` | hook | after an agent edits a paper's source | nothing: it prints the paper's readiness and its unrun gates, for a person reading the transcript
|
|
143
|
-
| [`paper/allowed-files-only`](rules/paper/allowed-files-only.md) | rule | every `paperlint lint`, and CI | a stray file or folder at a paper's root (error)
|
|
144
|
-
| [`repro/allowed-files-only`](rules/repro/allowed-files-only.md) | rule | every `paperlint lint`, and CI | a loose entry at the top of `repro/`, a folder that is not a study's, a study folder without `README.md` (error)
|
|
145
|
-
| [`repro/study-registered`](rules/repro/study-registered.md) | rule | every `paperlint lint`, and CI | a study folder without its row in `repro/studies.json`, a row that does not match, an index out of sync (error)
|
|
146
|
-
| [`study
|
|
147
|
-
| [`
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
|
|
|
151
|
-
| the rules on
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
| `build-
|
|
138
|
+
| what | kind | when it runs | what it stops |
|
|
139
|
+
| ------------------------------------------------------------------------------------------- | ----- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
140
|
+
| `paper-folder-layout` | hook | before an agent creates a file (Edit, Write) | a new entry the layout does not allow, at a paper's root or the top of its `repro/`; never an existing file |
|
|
141
|
+
| `paper-edit-guard` | hook | before an agent's shell command | a shell command that writes or moves a paper's source, which would skip the hooks that run after an edit |
|
|
142
|
+
| `paper-skills-nudge` | hook | after an agent edits a paper's source | nothing: it shows the agent the pre-submit checklist |
|
|
143
|
+
| `paper-status-gates` | hook | after an agent edits a paper's source | nothing: it prints the paper's readiness and its unrun gates, for a person reading the transcript |
|
|
144
|
+
| [`paper/allowed-files-only`](rules/paper/allowed-files-only.md) | rule | every `paperlint lint`, and CI | a stray file or folder at a paper's root (error) |
|
|
145
|
+
| [`repro/allowed-files-only`](rules/repro/allowed-files-only.md) | rule | every `paperlint lint`, and CI | a loose entry at the top of `repro/`, a folder that is not a study's, a study folder without `README.md` (error) |
|
|
146
|
+
| [`repro/study-registered`](rules/repro/study-registered.md) | rule | every `paperlint lint`, and CI | a study folder without its row in `repro/studies.json`, a row that does not match, a measurement or plan that does not hold, an index out of sync (error) |
|
|
147
|
+
| [`repro/study-plan-name`](rules/repro/study-plan-name.md) | rule | every `paperlint lint`, and CI | nothing: it warns when a study's plan is still named `prereg.json` |
|
|
148
|
+
| [`study/declare-sample`](rules/study/declare-sample.md) | rule | every `paperlint lint`, and CI, once a paper turns it on | a study's `prereg.json` without its population, strata, screens, coverage or the author's check (experimental, off by default) |
|
|
149
|
+
| [`paper/folder-venue-leftover`](rules/paper/folder-venue-leftover.md) | rule | every `paperlint lint`, and CI | nothing: it warns when the folder is named after another venue |
|
|
150
|
+
| `review/frontmatter`, `sibling/frontmatter` | rule | every `paperlint lint`, and CI | a review whose findings break the schema (error); a sibling card that does not say how much was read (warning) |
|
|
151
|
+
| `paper/stages`, `paper/source` | rule | every `paperlint lint`, and CI | a stage whose frozen PDF or source is missing or changed (error) |
|
|
152
|
+
| the rules on the source (`tex/*`, `paper/*`, `bib/*`) | rule | every `paperlint lint`, and CI | what each one's [row](rules.md) says |
|
|
153
|
+
| the rules on what `paperlint build` measured (`pdf/*`, `format/page-limit`, the references) | rule | every `paperlint lint` after a build; CI's full job | a PDF over the page limit, in the wrong font or format, or with a bad reference |
|
|
154
|
+
| `study-accepted-papers` | skill | when you ask; stage 2 (modes A, B) and stage 5 (modes C, D) | nothing: it fills the venue's corpus, and writes the strong-accept scorecard in `PIPELINE-STATUS.md` |
|
|
155
|
+
| `build-benchmark` | skill | when you ask; stage 3 | nothing: it registers the study with `paperlint studies new`, writes its design, fills its `plan.json`, and updates its row when it ends |
|
|
156
|
+
| `build-label-page` | skill | when you ask; stage 3 | nothing: it builds the labelling page, and exports the answers into the study's `data/` |
|
|
155
157
|
|
|
156
158
|
The hooks are wired by `paperlint init` ([`install.md`](install.md)). A rule's level and options:
|
|
157
159
|
[`rules.md`](rules.md).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# repro/study-plan-name
|
|
2
|
+
|
|
3
|
+
**Level:** warning · **Reads:** `repro/studies.json` · **Reported on:** the first line of the
|
|
4
|
+
paper's `PIPELINE-STATUS.md`, once per study
|
|
5
|
+
|
|
6
|
+
## What it catches
|
|
7
|
+
|
|
8
|
+
A study whose row in `repro/studies.json` names its plan as `prereg.json` — the name the plan had
|
|
9
|
+
before `paperlint studies new` wrote it as `plan.json`.
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"id": "P1-S01",
|
|
14
|
+
"folder": "P1-S01-rule-census",
|
|
15
|
+
"plan": "prereg.json",
|
|
16
|
+
"…": "…"
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The file is still read as the study's plan — by a loose schema, since it was written by hand before
|
|
21
|
+
the plan had one: keys of its own are accepted, a seed makes its draw `seeded` and none makes it a
|
|
22
|
+
draw of `all`, a size is not read, and an absent check is `null` —
|
|
23
|
+
and [`repro/study-registered`](study-registered.md) judges it like any `plan.json`. This rule only
|
|
24
|
+
asks for the new name. A `prereg.json` moved to `plan.json` is parsed strictly: its own keys go in
|
|
25
|
+
`extra`.
|
|
26
|
+
|
|
27
|
+
## Why
|
|
28
|
+
|
|
29
|
+
A study's plan was once a hand-written `prereg.json`. The name misled: it is not a pre-registration
|
|
30
|
+
with an outside registry, it is the study's own plan, fixed before the runs, with the author's check
|
|
31
|
+
of the drawn units. Papers that wrote one before `plan.json` existed keep working; this warning tells
|
|
32
|
+
them where the file moves, without failing their build.
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
Failing (a warning):
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
papers/example/PIPELINE-STATUS.md
|
|
40
|
+
1:1 warning The plan of `P1-S01` is `prereg.json`, its old name; it is read as the plan. What to
|
|
41
|
+
do: rename it to `plan.json` in the study's folder (`git mv`) and set the row's `plan`
|
|
42
|
+
to `plan.json`.
|
|
43
|
+
Rule repro/study-plan-name: https://github.com/zernie/paperlint/blob/main/docs/rules/repro/study-plan-name.md repro/study-plan-name
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Passing: the row names `"plan": "plan.json"`, as `paperlint studies new` writes it; or the row
|
|
47
|
+
names no plan.
|
|
48
|
+
|
|
49
|
+
## Options / preset fields
|
|
50
|
+
|
|
51
|
+
No rule options.
|
|
52
|
+
|
|
53
|
+
## What it does not check
|
|
54
|
+
|
|
55
|
+
- A `prereg.json` in a study folder whose row names no `plan`: the file is not the study's plan
|
|
56
|
+
until the row says so, and is not read.
|
|
57
|
+
- Anything inside the plan: that is [`repro/study-registered`](study-registered.md).
|
|
58
|
+
|
|
59
|
+
## How to fix
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
git mv papers/example/repro/P1-S01-rule-census/prereg.json papers/example/repro/P1-S01-rule-census/plan.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
then set the row's `"plan": "plan.json"` in `repro/studies.json`. To keep the old name for one
|
|
66
|
+
paper, switch the rule off in its `paperlint.json`:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{ "rules": { "repro/study-plan-name": "off" } }
|
|
70
|
+
```
|