paperlint 9.0.0 → 10.0.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/.github/CLAUDE.md +22 -0
- package/.github/CLAUDE.md.spec.ts +20 -0
- package/CLAUDE.md +59 -515
- package/CONTRIBUTING.md +2 -2
- package/README.md +68 -128
- package/dist/CLAUDE.md.spec.d.ts +3 -0
- package/dist/CLAUDE.md.spec.d.ts.map +1 -0
- package/dist/CLAUDE.md.spec.js +62 -0
- package/dist/CLAUDE.md.spec.js.map +1 -0
- package/dist/build.d.ts +1 -1
- package/dist/build.js +2 -2
- package/dist/cli.d.ts +5 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +52 -6
- package/dist/cli.js.map +1 -1
- package/dist/domain/layout-tree.d.ts +19 -0
- package/dist/domain/layout-tree.d.ts.map +1 -0
- package/dist/domain/layout-tree.js +32 -0
- package/dist/domain/layout-tree.js.map +1 -0
- package/dist/domain/lookup-cache.d.ts +2 -2
- package/dist/domain/lookup-cache.js +2 -2
- package/dist/domain/paper-layout.d.ts +81 -0
- package/dist/domain/paper-layout.d.ts.map +1 -0
- package/dist/domain/paper-layout.js +259 -0
- package/dist/domain/paper-layout.js.map +1 -0
- package/dist/domain/repro-layout.d.ts +80 -0
- package/dist/domain/repro-layout.d.ts.map +1 -0
- package/dist/domain/repro-layout.js +247 -0
- package/dist/domain/repro-layout.js.map +1 -0
- package/dist/domain/scaffold-layout.d.ts +28 -0
- package/dist/domain/scaffold-layout.d.ts.map +1 -0
- package/dist/domain/scaffold-layout.js +81 -0
- package/dist/domain/scaffold-layout.js.map +1 -0
- package/dist/eslint-rules/CLAUDE.md.spec.d.ts +3 -0
- package/dist/eslint-rules/CLAUDE.md.spec.d.ts.map +1 -0
- package/dist/eslint-rules/CLAUDE.md.spec.js +39 -0
- package/dist/eslint-rules/CLAUDE.md.spec.js.map +1 -0
- package/dist/eslint-rules/install-path-literals.d.ts +1 -1
- package/dist/eslint-rules/install-path-literals.js +4 -4
- package/dist/eslint-rules/install-path-literals.js.map +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.js +1 -1
- package/dist/eslint-rules/prereg-coverage.d.ts +98 -0
- package/dist/eslint-rules/prereg-coverage.d.ts.map +1 -0
- package/dist/eslint-rules/prereg-coverage.js +274 -0
- package/dist/eslint-rules/prereg-coverage.js.map +1 -0
- package/dist/folder-layout-hook.d.ts +21 -0
- package/dist/folder-layout-hook.d.ts.map +1 -0
- package/dist/folder-layout-hook.js +117 -0
- package/dist/folder-layout-hook.js.map +1 -0
- package/dist/folder-layout-rule.d.ts +22 -0
- package/dist/folder-layout-rule.d.ts.map +1 -0
- package/dist/folder-layout-rule.js +107 -0
- package/dist/folder-layout-rule.js.map +1 -0
- package/dist/init.js +1 -1
- package/dist/init.js.map +1 -1
- package/dist/lib/agent-cli-version.js +1 -1
- package/dist/lib/agent-cli-version.js.map +1 -1
- package/dist/new-paper.d.ts +4 -1
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +40 -6
- package/dist/new-paper.js.map +1 -1
- package/dist/references.d.ts +1 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +2 -2
- package/dist/references.js.map +1 -1
- package/dist/repro-layout-rule.d.ts +16 -0
- package/dist/repro-layout-rule.d.ts.map +1 -0
- package/dist/repro-layout-rule.js +81 -0
- package/dist/repro-layout-rule.js.map +1 -0
- package/dist/tex-requirements.js +1 -1
- package/dist/toolchain.js +1 -1
- package/docs/ci.md +60 -0
- package/docs/configuration.md +2 -0
- package/docs/e2e.md +3 -3
- package/docs/incidents.md +5 -5
- package/docs/install.md +20 -16
- package/docs/layout.md +154 -0
- package/docs/optional-rules.md +5 -4
- package/docs/references.md +5 -2
- package/docs/rules/paper/allowed-files-only.md +192 -0
- package/docs/rules/repro/allowed-files-only.md +128 -0
- package/docs/rules/study/declare-sample.md +146 -0
- package/docs/rules.md +53 -50
- package/docs/skills.md +6 -3
- package/docs/venues.md +94 -0
- package/eslint-rules/CLAUDE.md +44 -0
- package/eslint-rules/CLAUDE.md.spec.ts +43 -0
- package/eslint-rules/install-path-literals.harness.mjs +1 -1
- package/eslint-rules/install-path-literals.ts +4 -4
- package/eslint-rules/pdf-last-page-balance.ts +1 -1
- package/eslint-rules/prereg-coverage.test.ts +448 -0
- package/eslint-rules/prereg-coverage.ts +419 -0
- package/eslint.config.mjs +6 -3
- package/hooks/CLAUDE.md +34 -0
- package/hooks/CLAUDE.md.spec.ts +30 -0
- package/lib/agent-cli-version.ts +1 -1
- package/lib/skill-trigger-cases.harness.mjs +51 -5
- package/lib/skill-trigger-cases.mjs +53 -15
- package/package.json +2 -2
- package/plugin/CLAUDE.md +22 -0
- package/plugin/CLAUDE.md.spec.ts +22 -0
- package/plugin/hooks/hooks.json +9 -0
- package/scripts/coverage-config.test.ts +2 -1
- package/skills/CLAUDE.md +19 -0
- package/skills/CLAUDE.md.spec.ts +18 -0
- package/skills/analyze-sibling-paper/SKILL.md +2 -2
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +1 -1
- package/skills/build-benchmark/SKILL.md +14 -1
- package/skills/build-benchmark/SKILL.md.spec.ts +13 -0
- package/skills/build-label-page/SKILL.md +118 -0
- package/skills/build-label-page/SKILL.md.spec.ts +129 -0
- package/skills/build-label-page/build-label-page.eval.mjs +15 -0
- package/skills/build-label-page/build-label-page.test.ts +959 -0
- package/skills/build-label-page/references/checklist.md +148 -0
- package/skills/build-label-page/references/example-generator.py +803 -0
- package/skills/find-venue/SKILL.md +5 -3
- package/skills/find-venue/SKILL.md.spec.ts +4 -2
- package/skills/grade-paper-writing/SKILL.md +7 -7
- package/skills/grade-paper-writing/SKILL.md.spec.ts +6 -6
- package/skills/map-prior-work/SKILL.md +2 -2
- package/skills/map-prior-work/SKILL.md.spec.ts +1 -1
- package/skills/paper-pipeline/SKILL.md +8 -6
- package/skills/paper-pipeline/SKILL.md.spec.ts +7 -5
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +19 -9
- package/skills/paper-pipeline/references/acceptance-gate.md +19 -19
- package/skills/paper-pipeline/references/artifact-checklist.md +5 -0
- package/skills/paper-pipeline/references/pipeline-status-template.md +30 -1
- package/skills/paper-pipeline/repro/2026-08-07-fork-check.log +1 -1
- package/skills/paper-pipeline/repro/2026-08-07-fork-check2.log +1 -1
- package/skills/paper-pipeline/repro/2026-08-07-language-eval-pilot.log +1 -1
- package/skills/paper-pipeline/repro/2026-08-07-language-eval-raw.log +1 -1
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.log +48 -48
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-oracle.log +8 -8
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.log +48 -48
- package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.log +2 -2
- package/skills/paper-pipeline/repro/2026-08-08-parent-replication.mjs +3 -3
- package/skills/paper-pipeline/repro/2026-10-13-grade-paper-writing-ablation-preflight-after.log +81 -0
- package/skills/paper-pipeline/repro/2026-10-13-grade-paper-writing-ablation-preflight-before.log +81 -0
- package/skills/paper-pipeline/repro/2026-10-13-grade-paper-writing-ablation-setupdiff.log +59 -0
- package/skills/paper-pipeline/repro/2026-10-13-grade-paper-writing-trigger.jsonl +1 -0
- package/skills/paper-pipeline/repro/2026-10-13-grade-paper-writing-trigger.log +22 -0
- package/skills/paper-pipeline/repro/README.md +4 -0
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +2 -2
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +2 -2
- package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +4 -2
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +7 -2
- package/skills/paper-pipeline/scripts/generated-code.mjs +8 -4
- package/skills/paper-pipeline/scripts/generated-code.test.ts +15 -1
- package/skills/paper-status/SKILL.md +2 -2
- package/skills/paper-status/SKILL.md.spec.ts +1 -1
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +21 -102
- package/skills/study-accepted-papers/SKILL.md +163 -161
- package/skills/study-accepted-papers/SKILL.md.spec.ts +167 -165
- package/skills/study-accepted-papers/references/base-rates.md +69 -0
- package/skills/study-accepted-papers/references/mechanisms.md +181 -0
- package/skills/verify-citations/SKILL.md +2 -2
- package/skills/verify-citations/SKILL.md.spec.ts +1 -1
- package/src/CLAUDE.md +23 -1
- package/src/CLAUDE.md.spec.ts +72 -0
- package/src/build.ts +2 -2
- package/src/cli.harness.mjs +42 -0
- package/src/cli.test.ts +90 -6
- package/src/cli.ts +78 -5
- package/src/domain/layout-tree.test.ts +32 -0
- package/src/domain/layout-tree.ts +47 -0
- package/src/domain/lookup-cache.ts +2 -2
- package/src/domain/paper-layout.test.ts +264 -0
- package/src/domain/paper-layout.ts +336 -0
- package/src/domain/repro-layout.test.ts +222 -0
- package/src/domain/repro-layout.ts +311 -0
- package/src/domain/scaffold-layout.ts +104 -0
- package/src/folder-layout-hook.test.ts +214 -0
- package/src/folder-layout-hook.ts +141 -0
- package/src/folder-layout-rule.test.ts +235 -0
- package/src/folder-layout-rule.ts +151 -0
- package/src/hooks-settings.harness.ts +9 -8
- package/src/init.ts +1 -1
- package/src/layout-docs.test.ts +52 -0
- package/src/new-paper.harness.mjs +23 -1
- package/src/new-paper.test.ts +299 -6
- package/src/new-paper.ts +51 -5
- package/src/paper-files.test.ts +9 -6
- package/src/references.test.ts +5 -5
- package/src/references.ts +2 -2
- package/src/repro-layout-rule.test.ts +114 -0
- package/src/repro-layout-rule.ts +121 -0
- package/src/rule-cases.test.ts +98 -0
- package/src/tex-requirements.ts +1 -1
- package/src/toolchain.ts +1 -1
- package/templates/paper/PIPELINE-STATUS.md +41 -7
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
*
|
|
13
13
|
* skill the skill under test
|
|
14
14
|
* why the territory it owns, in one line — the thing a sibling must NOT take
|
|
15
|
-
* prompts should-fire. FOUR
|
|
15
|
+
* prompts should-fire. At least FOUR, deliberately mixed (below)
|
|
16
16
|
* collides siblings whose own should-fire prompts become this case's
|
|
17
|
-
* irrelevantPrompts
|
|
18
|
-
*
|
|
19
|
-
* from both directions.
|
|
17
|
+
* irrelevantPrompts — at least one from EVERY collider. That is how
|
|
18
|
+
* "the WRONG skill must not fire" is asserted, and it is symmetric:
|
|
19
|
+
* each side of a collision is measured from both directions.
|
|
20
20
|
*
|
|
21
21
|
* 🔴 THE PROMPTS ARE MIXED ON PURPOSE, AND THE MIX DECIDES THE NUMBER.
|
|
22
22
|
* `framing-vs-vocabulary.eval.mjs` measured the same skills two ways: prompts that
|
|
@@ -55,13 +55,36 @@ const PACKAGE_CASES = [
|
|
|
55
55
|
{
|
|
56
56
|
skill: "grade-paper-writing",
|
|
57
57
|
why: "prose craft — the sentence is the unit, NOT the section",
|
|
58
|
+
// The first four are HARVESTED and measured; they stay first and unchanged, so the rate on
|
|
59
|
+
// them stays comparable with pipeline-firing.eval.mjs and the siblings that collide with this
|
|
60
|
+
// case keep receiving the same irrelevant prompts. The last four were added 2026-10-13 with
|
|
61
|
+
// the rewritten description and have never been run — rates UNKNOWN. Eight, not four, because
|
|
62
|
+
// this skill's firing was measured at 12%, then 50–54%, on the same prompts: four prompts
|
|
63
|
+
// cannot tell those apart.
|
|
58
64
|
prompts: [
|
|
59
65
|
"оцени как написано — читается как стена жаргона",
|
|
60
66
|
"is the writing any good or does it read like shit",
|
|
61
67
|
"abstract звучит криво хотя по смыслу всё на месте, дай оценку прозе",
|
|
62
68
|
"grade the craft: title, abstract, sentence clarity, hedge stacking",
|
|
69
|
+
"прочитай черновик и скажи честно, нормально ли он читается",
|
|
70
|
+
"the reviewer says our paper reads like a blog post — is he right about the prose",
|
|
71
|
+
"каждое предложение по отдельности понятно, а абзацы всё равно сливаются в сплошную простыню",
|
|
72
|
+
"grade the prose in section 3 and give me the sentences to rewrite",
|
|
73
|
+
],
|
|
74
|
+
// Every sibling the description sends a request to. Each is a different wrong answer to "is
|
|
75
|
+
// this paper any good?": cut it, re-read one edit, attack the science, predict the committee,
|
|
76
|
+
// gate the submission, study the venue. Of the five added 2026-10-13, only cold-read-diff
|
|
77
|
+
// already named this case; the other four do not name it back, because that would change the
|
|
78
|
+
// irrelevant sets their own rates are measured on.
|
|
79
|
+
collides: [
|
|
80
|
+
"tighten-paper",
|
|
81
|
+
"argument-arc",
|
|
82
|
+
"cold-read-diff",
|
|
83
|
+
"paper-adversarial-review",
|
|
84
|
+
"pc-panel-review",
|
|
85
|
+
"harden-paper",
|
|
86
|
+
"study-accepted-papers",
|
|
63
87
|
],
|
|
64
|
-
collides: ["tighten-paper", "argument-arc"],
|
|
65
88
|
},
|
|
66
89
|
{
|
|
67
90
|
skill: "argument-arc",
|
|
@@ -153,6 +176,17 @@ const PACKAGE_CASES = [
|
|
|
153
176
|
],
|
|
154
177
|
collides: ["research-ideate", "draft-paper"],
|
|
155
178
|
},
|
|
179
|
+
{
|
|
180
|
+
skill: "build-label-page",
|
|
181
|
+
why: "a PERSON labels items on a phone page with a shared store, and the answers are exported into the study",
|
|
182
|
+
prompts: [
|
|
183
|
+
"сделай мне страницу, где я разметил бы эти примеры с телефона",
|
|
184
|
+
"build a gold-labelling page for these 40 items so I can answer on my phone",
|
|
185
|
+
"нужна слепая страница для ревью ответов модели, чтобы я не видел, какой из них чей",
|
|
186
|
+
"make me a page to label these, and put the answers back into the study folder",
|
|
187
|
+
],
|
|
188
|
+
collides: ["build-benchmark", "draft-paper"],
|
|
189
|
+
},
|
|
156
190
|
{
|
|
157
191
|
skill: "camera-ready",
|
|
158
192
|
why: "AFTER accept — de-anonymize, archive, disclose",
|
|
@@ -248,7 +282,7 @@ const PACKAGE_CASES = [
|
|
|
248
282
|
"посмотри что принимали на этой площадке и чем те статьи сильны",
|
|
249
283
|
"хочу дотянуть с accept до strong accept — что для этого нужно именно там",
|
|
250
284
|
"read a dozen accepted papers from this venue and diff our draft against them",
|
|
251
|
-
"
|
|
285
|
+
"before we design the study: what does this venue actually reward? look at its award winners",
|
|
252
286
|
],
|
|
253
287
|
collides: ["find-venue", "harden-paper"],
|
|
254
288
|
},
|
|
@@ -436,14 +470,18 @@ export function irrelevantFor(skill, want = 4) {
|
|
|
436
470
|
// verify-citations — seven of twenty-one, exactly the set with `collides.length
|
|
437
471
|
// === 1`. Two-collider cases are unaffected (ceil(4/2) === 2), so numbers
|
|
438
472
|
// measured before the fix stay comparable.
|
|
473
|
+
//
|
|
474
|
+
// `want` is a FLOOR, not a cap (2026-10-13). The set used to be cut at `want`,
|
|
475
|
+
// so a case with more than four colliders silently dropped the rest: the table
|
|
476
|
+
// said "must not take X's requests" and no request of X's was ever sent. Cases
|
|
477
|
+
// with one or two colliders get exactly what they got before (4); a case with
|
|
478
|
+
// three gets 6, with seven gets 7 — one from each.
|
|
439
479
|
const per = Math.ceil(want / c.collides.length);
|
|
440
|
-
return c.collides
|
|
441
|
-
.
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
})
|
|
448
|
-
.slice(0, want);
|
|
480
|
+
return c.collides.flatMap((sib, i) => {
|
|
481
|
+
const s = BY_SKILL.get(sib);
|
|
482
|
+
if (!s) throw new Error(`${skill} collides with unknown skill "${sib}"`);
|
|
483
|
+
// Rotate by the collider's index so two cases sharing a collider do not
|
|
484
|
+
// receive byte-identical irrelevant sets.
|
|
485
|
+
return [...s.prompts.slice(i), ...s.prompts.slice(0, i)].slice(0, per);
|
|
486
|
+
});
|
|
449
487
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paperlint",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
4
|
"description": "A linter for scientific papers written in LaTeX: catches mistakes before you submit to a conference or journal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"ts-essentials": "^10.2.1",
|
|
35
35
|
"typescript": "^6.0.3",
|
|
36
36
|
"unpdf": "^1.8.1",
|
|
37
|
-
"vigiles": "^
|
|
37
|
+
"vigiles": "^38.2.0",
|
|
38
38
|
"zod": "^4.6.5"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
package/plugin/CLAUDE.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!-- vigiles:sha256:6312a3b8f9804eba compiled from plugin/CLAUDE.md.spec.ts -->
|
|
2
|
+
|
|
3
|
+
# CLAUDE.md
|
|
4
|
+
|
|
5
|
+
## `plugin/`
|
|
6
|
+
|
|
7
|
+
Not a plugin any more. `plugin/hooks/hooks.json` is the hook wiring that `paperlint init` merges
|
|
8
|
+
into the consumer's `.claude/settings.json`, and it is the only source of that wiring.
|
|
9
|
+
|
|
10
|
+
## Why there is no Claude Code plugin
|
|
11
|
+
|
|
12
|
+
There is no Claude Code plugin or marketplace entry; it was removed in the release after 1.0.0
|
|
13
|
+
(#82). Do not bring it back without answering each of these, measured (`docs/install.md`,
|
|
14
|
+
"Why it is shaped this way"):
|
|
15
|
+
|
|
16
|
+
- **A plugin cannot carry the code.** Claude Code installs a plugin's dependencies with a 60-second
|
|
17
|
+
timeout, and a failed install never blocks the plugin: the hooks load and fail with
|
|
18
|
+
`cannot find module vigiles`, silently.
|
|
19
|
+
- **The skills need the npm package anyway.** 23 of 24 skills ran scripts that resolve only through
|
|
20
|
+
`node_modules/paperlint/`.
|
|
21
|
+
- **Its manifests carried versions nothing updated**, and Claude Code decides plugin updates from
|
|
22
|
+
that number.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Compiled to plugin/CLAUDE.md by `npx vigiles compile`. Edit THIS file, never the markdown.
|
|
2
|
+
import { file, instructionFile, prose } from "vigiles/spec";
|
|
3
|
+
|
|
4
|
+
export default instructionFile({
|
|
5
|
+
sections: {
|
|
6
|
+
"`plugin/`": prose`Not a plugin any more. ${file("plugin/hooks/hooks.json")} is the hook wiring that \`paperlint init\` merges
|
|
7
|
+
into the consumer's \`.claude/settings.json\`, and it is the only source of that wiring.`,
|
|
8
|
+
|
|
9
|
+
"Why there is no Claude Code plugin": prose`There is no Claude Code plugin or marketplace entry; it was removed in the release after 1.0.0
|
|
10
|
+
(#82). Do not bring it back without answering each of these, measured (${file("docs/install.md")},
|
|
11
|
+
"Why it is shaped this way"):
|
|
12
|
+
|
|
13
|
+
- **A plugin cannot carry the code.** Claude Code installs a plugin's dependencies with a 60-second
|
|
14
|
+
timeout, and a failed install never blocks the plugin: the hooks load and fail with
|
|
15
|
+
\`cannot find module vigiles\`, silently.
|
|
16
|
+
- **The skills need the npm package anyway.** 23 of 24 skills ran scripts that resolve only through
|
|
17
|
+
\`node_modules/paperlint/\`.
|
|
18
|
+
- **Its manifests carried versions nothing updated**, and Claude Code decides plugin updates from
|
|
19
|
+
that number.`,
|
|
20
|
+
},
|
|
21
|
+
rules: {},
|
|
22
|
+
});
|
package/plugin/hooks/hooks.json
CHANGED
|
@@ -9,6 +9,15 @@
|
|
|
9
9
|
"command": "node \"${CLAUDE_PROJECT_DIR}/node_modules/paperlint/bin/paperlint.mjs\" hook paper-edit-guard"
|
|
10
10
|
}
|
|
11
11
|
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
15
|
+
"hooks": [
|
|
16
|
+
{
|
|
17
|
+
"type": "command",
|
|
18
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/node_modules/paperlint/bin/paperlint.mjs\" hook paper-folder-layout"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
12
21
|
}
|
|
13
22
|
],
|
|
14
23
|
"PostToolUse": [
|
|
@@ -400,8 +400,9 @@ test("the exclude list is exactly the justified set", () => {
|
|
|
400
400
|
"**/*.test.*",
|
|
401
401
|
// PAID LLM evaluations, never run by `npm test`
|
|
402
402
|
"**/*.eval.mjs",
|
|
403
|
-
// skill sources vigiles compiles
|
|
403
|
+
// skill and CLAUDE.md sources vigiles compiles; a glob's `**` skips a dot directory
|
|
404
404
|
"**/*.spec.ts",
|
|
405
|
+
".github/*.spec.ts",
|
|
405
406
|
// type declarations
|
|
406
407
|
"**/*.d.ts",
|
|
407
408
|
"**/*.d.mts",
|
package/skills/CLAUDE.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- vigiles:sha256:e0aa2cec8926b04f compiled from skills/CLAUDE.md.spec.ts -->
|
|
2
|
+
|
|
3
|
+
# CLAUDE.md
|
|
4
|
+
|
|
5
|
+
## `skills/`
|
|
6
|
+
|
|
7
|
+
The skills this package ships. Loaded when working under `skills/`. The consumer's root and the
|
|
8
|
+
package's location come from `skills/paper-pipeline/scripts/consumer.mjs`; the links are made by
|
|
9
|
+
`src/link-skills.ts`; install-specific paths are flagged by `eslint-rules/install-path-literals.ts`.
|
|
10
|
+
|
|
11
|
+
## Rules
|
|
12
|
+
|
|
13
|
+
### Skills Ship In Skills
|
|
14
|
+
|
|
15
|
+
**Guidance only** — Skills ship in `skills/`, never `.claude/skills/`. `paperlint init` symlinks each one into the consumer's `.claude/skills/<name>`; the link's directory name is the skill's name. `skills/` is the npm layout: of 855 packages scanned, 336 shipped `skills/` against 15 `.claude/skills/`. Rejected: leaving the skills for Claude Code to find inside `node_modules` (`docs/install.md`); a symlink loads at startup, deterministically.
|
|
16
|
+
|
|
17
|
+
### A Criterion That Judges Prose
|
|
18
|
+
|
|
19
|
+
**Guidance only** — It follows the five principles in `eslint-rules/CLAUDE.md` ("A rule that judges prose"). A skill does not grep prose for what a rule can count.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Compiled to skills/CLAUDE.md by `npx vigiles compile`. Edit THIS file, never the markdown.
|
|
2
|
+
import { file, guidance, instructionFile, prose } from "vigiles/spec";
|
|
3
|
+
|
|
4
|
+
export default instructionFile({
|
|
5
|
+
sections: {
|
|
6
|
+
"`skills/`": prose`The skills this package ships. Loaded when working under \`skills/\`. The consumer's root and the
|
|
7
|
+
package's location come from ${file("skills/paper-pipeline/scripts/consumer.mjs")}; the links are made by
|
|
8
|
+
${file("src/link-skills.ts")}; install-specific paths are flagged by ${file("eslint-rules/install-path-literals.ts")}.`,
|
|
9
|
+
},
|
|
10
|
+
rules: {
|
|
11
|
+
"skills-ship-in-skills": guidance(
|
|
12
|
+
"Skills ship in `skills/`, never `.claude/skills/`. `paperlint init` symlinks each one into the consumer's `.claude/skills/<name>`; the link's directory name is the skill's name. `skills/` is the npm layout: of 855 packages scanned, 336 shipped `skills/` against 15 `.claude/skills/`. Rejected: leaving the skills for Claude Code to find inside `node_modules` (`docs/install.md`); a symlink loads at startup, deterministically.",
|
|
13
|
+
),
|
|
14
|
+
"a-criterion-that-judges-prose": guidance(
|
|
15
|
+
'It follows the five principles in `eslint-rules/CLAUDE.md` ("A rule that judges prose"). A skill does not grep prose for what a rule can count.',
|
|
16
|
+
),
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -5,7 +5,7 @@ context: fork
|
|
|
5
5
|
allowed-tools: [WebSearch, WebFetch, Read, Write, Grep, Glob, Bash, Agent]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
<!-- vigiles:sha256:
|
|
8
|
+
<!-- vigiles:sha256:834f128ace92288a compiled from skills/analyze-sibling-paper/SKILL.md.spec.ts -->
|
|
9
9
|
|
|
10
10
|
# analyze-sibling-paper — settle "isn't this just X?" before a reviewer does
|
|
11
11
|
|
|
@@ -115,7 +115,7 @@ again at rebuttal. **A close sibling with no file in `<paper-dir>/siblings/` is
|
|
|
115
115
|
## Compose with
|
|
116
116
|
- `verify-citations` — surfaces the nearest-neighbor works; hand each genuine sibling to this skill.
|
|
117
117
|
- `harden-paper` — its nearest-neighbor-scoop axis (axis 3) calls this for each close competitor.
|
|
118
|
-
- `study-accepted-papers` — venue-corpus levers (different axis: the venue
|
|
118
|
+
- `study-accepted-papers` — venue-corpus levers (different axis: what the venue rewards, not a specific rival).
|
|
119
119
|
- `extend-paper` — a scooped angle, or the un-scooped remainder, can become the next paper's pivot.
|
|
120
120
|
|
|
121
121
|
## Provenance
|
|
@@ -130,7 +130,7 @@ again at rebuttal. **A close sibling with no file in \`<paper-dir>/siblings/\` i
|
|
|
130
130
|
## Compose with
|
|
131
131
|
- \`verify-citations\` — surfaces the nearest-neighbor works; hand each genuine sibling to this skill.
|
|
132
132
|
- \`harden-paper\` — its nearest-neighbor-scoop axis (axis 3) calls this for each close competitor.
|
|
133
|
-
- \`study-accepted-papers\` — venue-corpus levers (different axis: the venue
|
|
133
|
+
- \`study-accepted-papers\` — venue-corpus levers (different axis: what the venue rewards, not a specific rival).
|
|
134
134
|
- \`extend-paper\` — a scooped angle, or the un-scooped remainder, can become the next paper's pivot.
|
|
135
135
|
|
|
136
136
|
## Provenance
|
|
@@ -5,7 +5,7 @@ context: fork
|
|
|
5
5
|
allowed-tools: [Read, Write, Edit, Grep, Glob, Bash, Agent]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
<!-- vigiles:sha256:
|
|
8
|
+
<!-- vigiles:sha256:5eb2ba9561e082d9 compiled from skills/build-benchmark/SKILL.md.spec.ts -->
|
|
9
9
|
|
|
10
10
|
# build-benchmark — the study + the artifact reviewers can run
|
|
11
11
|
|
|
@@ -51,6 +51,17 @@ is the *inverse* of the flaw:
|
|
|
51
51
|
|
|
52
52
|
Write the design as the answer to "what would make the critiqued pitfall impossible here?"
|
|
53
53
|
|
|
54
|
+
**Declare the population, the screens and the coverage before freezing the sample.** Each screen
|
|
55
|
+
between the population and the sample (fits one excerpt, one classifier lane, a model-picked item)
|
|
56
|
+
changes what the sample can say, not only its size; screens that are reasonable one by one can leave a
|
|
57
|
+
sample nobody meets in practice. So, before the draw is frozen, the study's `prereg.json` says what
|
|
58
|
+
the claim is about, what each screen removed per stratum and what share the sample can represent; then
|
|
59
|
+
show the author the drawn **units** (the rules or cases, not the items made from them) and ask: *is
|
|
60
|
+
this what you meet in practice?* The fields are the experimental rule
|
|
61
|
+
`study/declare-sample` (`docs/rules/study/declare-sample.md`), off by default: do this step either way,
|
|
62
|
+
and turn the check on with `"rules": { "study/declare-sample": "error" }` in the paper's `paperlint.json`
|
|
63
|
+
for `paperlint lint` to fail until they are there.
|
|
64
|
+
|
|
54
65
|
## 2. Honest statistics — the part reviewers attack first
|
|
55
66
|
|
|
56
67
|
- **Paired where the design is paired; Welch where variances differ.** Use a **paired-t** when the same
|
|
@@ -156,6 +167,8 @@ Before submitting, verify the artifact you built with the reviewer-side reproduc
|
|
|
156
167
|
- **argument-arc (frame mode)** — 🔴 **hard input.** Owns row `frame`, the stated claim. No `frame`, no study.
|
|
157
168
|
- **research-ideate** (upstream) — supplies the contribution and the pitfall to invert; this skill turns
|
|
158
169
|
it into evidence.
|
|
170
|
+
- **build-label-page** — when the study needs a person to label items (gold labels, a blind review of
|
|
171
|
+
outputs): it builds the page, publishes it and exports the answers into the study's `data/`.
|
|
159
172
|
- **draft-paper** — the study's stats, bound, and artifact-number table feed Methods/Results/Availability.
|
|
160
173
|
- **pc-panel-review** — its artifact-runner reviewer `cd`s in and re-executes every harness; build so
|
|
161
174
|
that pass is deterministic.
|
|
@@ -57,6 +57,17 @@ is the *inverse* of the flaw:
|
|
|
57
57
|
|
|
58
58
|
Write the design as the answer to "what would make the critiqued pitfall impossible here?"
|
|
59
59
|
|
|
60
|
+
**Declare the population, the screens and the coverage before freezing the sample.** Each screen
|
|
61
|
+
between the population and the sample (fits one excerpt, one classifier lane, a model-picked item)
|
|
62
|
+
changes what the sample can say, not only its size; screens that are reasonable one by one can leave a
|
|
63
|
+
sample nobody meets in practice. So, before the draw is frozen, the study's \`prereg.json\` says what
|
|
64
|
+
the claim is about, what each screen removed per stratum and what share the sample can represent; then
|
|
65
|
+
show the author the drawn **units** (the rules or cases, not the items made from them) and ask: *is
|
|
66
|
+
this what you meet in practice?* The fields are the experimental rule
|
|
67
|
+
\`study/declare-sample\` (\`docs/rules/study/declare-sample.md\`), off by default: do this step either way,
|
|
68
|
+
and turn the check on with \`"rules": { "study/declare-sample": "error" }\` in the paper's \`paperlint.json\`
|
|
69
|
+
for \`paperlint lint\` to fail until they are there.
|
|
70
|
+
|
|
60
71
|
## 2. Honest statistics — the part reviewers attack first
|
|
61
72
|
|
|
62
73
|
- **Paired where the design is paired; Welch where variances differ.** Use a **paired-t** when the same
|
|
@@ -162,6 +173,8 @@ Before submitting, verify the artifact you built with the reviewer-side reproduc
|
|
|
162
173
|
- **argument-arc (frame mode)** — 🔴 **hard input.** Owns row \`frame\`, the stated claim. No \`frame\`, no study.
|
|
163
174
|
- **research-ideate** (upstream) — supplies the contribution and the pitfall to invert; this skill turns
|
|
164
175
|
it into evidence.
|
|
176
|
+
- **build-label-page** — when the study needs a person to label items (gold labels, a blind review of
|
|
177
|
+
outputs): it builds the page, publishes it and exports the answers into the study's \`data/\`.
|
|
165
178
|
- **draft-paper** — the study's stats, bound, and artifact-number table feed Methods/Results/Availability.
|
|
166
179
|
- **pc-panel-review** — its artifact-runner reviewer \`cd\`s in and re-executes every harness; build so
|
|
167
180
|
that pass is deterministic.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-label-page
|
|
3
|
+
description: Build a phone labelling page published as a claude.ai Artifact with a shared answer store, and export the answers into the paper's study folder. Use when a study needs a person to label items (gold labels, a blind review of model outputs, "is this a real boundary case"), or on "a page to label these", "a gold-labelling page", "a blind review page". Carries the seven rules that keep such a page honest. Composes with build-benchmark and draft-paper.
|
|
4
|
+
allowed-tools: [Read, Write, Edit, Grep, Glob, Bash, Artifact, ArtifactData]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- vigiles:sha256:894d8a2df3f5c319 compiled from skills/build-label-page/SKILL.md.spec.ts -->
|
|
8
|
+
|
|
9
|
+
# build-label-page — a page the person labels on a phone, and the labels back in the repo
|
|
10
|
+
|
|
11
|
+
When a study needs a person to decide something about each of many items, a chat thread is the wrong
|
|
12
|
+
tool: it loses answers, shows the model's own output next to the question and gives no count of what
|
|
13
|
+
is left. Build a page instead. The agent generates it from the items, publishes it as an Artifact with
|
|
14
|
+
a shared answer store (the `db` capability), the person answers on a phone, and the agent exports the
|
|
15
|
+
answers into the study's `data/` folder. The labels are data the paper's numbers trace to, so they are
|
|
16
|
+
committed, not left in the store.
|
|
17
|
+
|
|
18
|
+
**Not for** an LLM judge (no person answers), a questionnaire about the person, or a form that collects
|
|
19
|
+
anything but labels.
|
|
20
|
+
|
|
21
|
+
## The seven rules
|
|
22
|
+
|
|
23
|
+
The full text, each with its reason and its check, is
|
|
24
|
+
[`references/checklist.md`](references/checklist.md). Read it before building. In one line each:
|
|
25
|
+
|
|
26
|
+
1. **Test it in the claude.ai phone viewer before sending the link.** The viewer can size the frame to
|
|
27
|
+
the page, so the page cannot scroll itself and a fixed toast may be off-screen. A plain browser
|
|
28
|
+
passing proves nothing about this.
|
|
29
|
+
2. **Navigation never relies on in-page scrolling or toasts.** "Next unanswered" is a filter: it hides
|
|
30
|
+
every finished item and group, and a note at the top lists what is left and what each still needs.
|
|
31
|
+
3. **An item is done only when every question on it is answered.** The card names the missing
|
|
32
|
+
question; the progress counter counts complete items only.
|
|
33
|
+
4. **Blind.** Neutral ids (`G001`…), order shuffled with a fixed seed, no model answers, verdicts or
|
|
34
|
+
source labels on the page. The generator refuses to build when an item carries a field outside an
|
|
35
|
+
allow-list; new question wording is added to the allow-list on purpose.
|
|
36
|
+
5. **Ask only what the labeller can answer.** Only the languages and tools they know; one "how well do
|
|
37
|
+
you know it" question per group, used later as an analysis filter; "clear-cut or real boundary"
|
|
38
|
+
is the labeller's judgement, not the designer's.
|
|
39
|
+
6. **Export into the repository right away**, one JSON per page into the study's `data/` with the
|
|
40
|
+
export date, commit it, and record answers given in chat with `source: "chat"`. If the page fails,
|
|
41
|
+
take the last answers in chat; patch the page blind at most once.
|
|
42
|
+
7. **Save on click**, no submit button; "Saved <time>" on every card; survive a reload; render
|
|
43
|
+
readable, with a banner, when the store is unavailable.
|
|
44
|
+
|
|
45
|
+
## Procedure
|
|
46
|
+
|
|
47
|
+
1. **Decide the labelling.** What exactly does the labeller decide per item (the questions, each with
|
|
48
|
+
a closed set of answers)? Which groups (languages, tools) does the labeller know? How many items
|
|
49
|
+
fit the time they have on a phone? Who is the labeller: a page with a store opens only for people
|
|
50
|
+
with access to the artifact, so the labeller is the owner or has been shared as a Contributor.
|
|
51
|
+
If the study design is not written yet, `build-benchmark` comes first.
|
|
52
|
+
If the items come from a drawn sample, the study's `prereg.json` declares the population, the
|
|
53
|
+
screens and the coverage before the sample is frozen (the experimental rule `study/declare-sample` checks it, off by default), and the
|
|
54
|
+
author has been shown the drawn **units** (the rules or cases, not the items) with "is this what
|
|
55
|
+
you meet in practice?". The labelling page is not that check: items made from easy units each look
|
|
56
|
+
fine on their own.
|
|
57
|
+
2. **Copy the generator into the study and write the items.** The study folder is
|
|
58
|
+
`<paper-dir>/repro/<slug>-YYYY-MM-DD/` (`gold-labels-2026-10-12`; `repro/allowed-files-only` wants the
|
|
59
|
+
date, a `README.md` in it saying what the study asks, and a line in `repro/README.md`; where this
|
|
60
|
+
sits in stage 3, and what checks each place: `docs/layout.md` in the paperlint package).
|
|
61
|
+
`items.json` follows the header of the generator. Source ids in `items.json` are the study's own;
|
|
62
|
+
the page never shows them.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cp ${CLAUDE_SKILL_DIR}/references/example-generator.py <study-dir>/make_label_page.py
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The generator is a template: change the questions and keep the guards (allow-list, neutral ids,
|
|
69
|
+
store-unavailable banner, filter instead of scrolling). Do not loosen the allow-list to make a
|
|
70
|
+
build pass; take the field out of the item.
|
|
71
|
+
3. **Build and read it as the labeller.** From the study folder (`<study-dir>`):
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python3 make_label_page.py build items.json label-page
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
This writes `label-page/page.html` and `label-page/key.json` (the only link from `G001` to the
|
|
78
|
+
source id; it never goes on the page). Rebuilding with the same seed keeps every id, and a new item
|
|
79
|
+
gets the next one. Read the page text once as a person who knows nothing about the source: if
|
|
80
|
+
anything on it tells the answer, take it out of the item.
|
|
81
|
+
4. **Publish.** Load `artifact-design` and `artifact-capabilities`, then publish `page.html` with
|
|
82
|
+
`capabilities: {db: {}}`. Use a title of two to four words. Do not ask the page for `user` or
|
|
83
|
+
anything else it does not use.
|
|
84
|
+
5. **Test in the viewer (rule 1)** and list the store once with `ArtifactData` (`list` of
|
|
85
|
+
`answers`) to confirm the test answer arrived. `ArtifactData` can be a deferred tool: load it with
|
|
86
|
+
`ToolSearch` first. Then delete the test answer's document, or tell the person which one it is
|
|
87
|
+
and keep it out of the export.
|
|
88
|
+
6. **Send the link** with one line on how it works: tap an answer, it saves; "Next unanswered" shows
|
|
89
|
+
what is left. Say what you tested and what you could not.
|
|
90
|
+
7. **Export when the person is done, or stops** (rule 6). Save the store's two collections, `answers`
|
|
91
|
+
and `groups`, as `dump.json` in the shape the generator's header gives (answers given in chat go
|
|
92
|
+
in with `"source": "chat"`), then:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
python3 make_label_page.py export dump.json label-page/key.json data
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
It writes `data/<study>-labels-<date>.json` and prints every incomplete item, every answer or
|
|
99
|
+
familiarity value that is not one of the offered options (not counted, same rule as on the page;
|
|
100
|
+
correct it in the dump and export again) and every group with no familiarity answer. Commit the file in the same pass, and add the line "labels →
|
|
101
|
+
`data/<study>-labels-<date>.json`" to the paper's `NOTES.md` for the numbers that use them.
|
|
102
|
+
|
|
103
|
+
## When the page misbehaves
|
|
104
|
+
|
|
105
|
+
Look at what the store holds (`ArtifactData` `list`) before changing anything: the page may be fine
|
|
106
|
+
and the person may have opened it without access. One fix to the page is allowed. If it fails again,
|
|
107
|
+
ask for the remaining answers in chat, write them into the dump with `"source": "chat"`, and export.
|
|
108
|
+
Do not iterate on a page you cannot see.
|
|
109
|
+
|
|
110
|
+
## Compose with
|
|
111
|
+
|
|
112
|
+
- **build-benchmark** — owns the study design and the inter-rater rule: agreement with the person who
|
|
113
|
+
wrote the codebook measures trainability, not reliability, so the labeller for gold labels is
|
|
114
|
+
someone who did not write the scheme.
|
|
115
|
+
- **draft-paper** — the exported labels, the familiarity filter and the complete-item count feed the
|
|
116
|
+
Methods and the threats.
|
|
117
|
+
- **submit-paper** — a published artifact page is not anonymous. Do not link it from an anonymized
|
|
118
|
+
submission; the exported JSON is what goes into the reproduction artifact.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Compiled to SKILL.md by `vigiles compile`. Edit THIS file, never the markdown.
|
|
2
|
+
import { experimental_skill } from "vigiles/spec";
|
|
3
|
+
|
|
4
|
+
export default experimental_skill({
|
|
5
|
+
name: "build-label-page",
|
|
6
|
+
description:
|
|
7
|
+
'Build a phone labelling page published as a claude.ai Artifact with a shared answer store, and export the answers into the paper\'s study folder. Use when a study needs a person to label items (gold labels, a blind review of model outputs, "is this a real boundary case"), or on "a page to label these", "a gold-labelling page", "a blind review page". Carries the seven rules that keep such a page honest. Composes with build-benchmark and draft-paper.',
|
|
8
|
+
tools: [
|
|
9
|
+
"Read",
|
|
10
|
+
"Write",
|
|
11
|
+
"Edit",
|
|
12
|
+
"Grep",
|
|
13
|
+
"Glob",
|
|
14
|
+
"Bash",
|
|
15
|
+
"Artifact",
|
|
16
|
+
"ArtifactData",
|
|
17
|
+
],
|
|
18
|
+
body: `
|
|
19
|
+
# build-label-page — a page the person labels on a phone, and the labels back in the repo
|
|
20
|
+
|
|
21
|
+
When a study needs a person to decide something about each of many items, a chat thread is the wrong
|
|
22
|
+
tool: it loses answers, shows the model's own output next to the question and gives no count of what
|
|
23
|
+
is left. Build a page instead. The agent generates it from the items, publishes it as an Artifact with
|
|
24
|
+
a shared answer store (the \`db\` capability), the person answers on a phone, and the agent exports the
|
|
25
|
+
answers into the study's \`data/\` folder. The labels are data the paper's numbers trace to, so they are
|
|
26
|
+
committed, not left in the store.
|
|
27
|
+
|
|
28
|
+
**Not for** an LLM judge (no person answers), a questionnaire about the person, or a form that collects
|
|
29
|
+
anything but labels.
|
|
30
|
+
|
|
31
|
+
## The seven rules
|
|
32
|
+
|
|
33
|
+
The full text, each with its reason and its check, is
|
|
34
|
+
[\`references/checklist.md\`](references/checklist.md). Read it before building. In one line each:
|
|
35
|
+
|
|
36
|
+
1. **Test it in the claude.ai phone viewer before sending the link.** The viewer can size the frame to
|
|
37
|
+
the page, so the page cannot scroll itself and a fixed toast may be off-screen. A plain browser
|
|
38
|
+
passing proves nothing about this.
|
|
39
|
+
2. **Navigation never relies on in-page scrolling or toasts.** "Next unanswered" is a filter: it hides
|
|
40
|
+
every finished item and group, and a note at the top lists what is left and what each still needs.
|
|
41
|
+
3. **An item is done only when every question on it is answered.** The card names the missing
|
|
42
|
+
question; the progress counter counts complete items only.
|
|
43
|
+
4. **Blind.** Neutral ids (\`G001\`…), order shuffled with a fixed seed, no model answers, verdicts or
|
|
44
|
+
source labels on the page. The generator refuses to build when an item carries a field outside an
|
|
45
|
+
allow-list; new question wording is added to the allow-list on purpose.
|
|
46
|
+
5. **Ask only what the labeller can answer.** Only the languages and tools they know; one "how well do
|
|
47
|
+
you know it" question per group, used later as an analysis filter; "clear-cut or real boundary"
|
|
48
|
+
is the labeller's judgement, not the designer's.
|
|
49
|
+
6. **Export into the repository right away**, one JSON per page into the study's \`data/\` with the
|
|
50
|
+
export date, commit it, and record answers given in chat with \`source: "chat"\`. If the page fails,
|
|
51
|
+
take the last answers in chat; patch the page blind at most once.
|
|
52
|
+
7. **Save on click**, no submit button; "Saved <time>" on every card; survive a reload; render
|
|
53
|
+
readable, with a banner, when the store is unavailable.
|
|
54
|
+
|
|
55
|
+
## Procedure
|
|
56
|
+
|
|
57
|
+
1. **Decide the labelling.** What exactly does the labeller decide per item (the questions, each with
|
|
58
|
+
a closed set of answers)? Which groups (languages, tools) does the labeller know? How many items
|
|
59
|
+
fit the time they have on a phone? Who is the labeller: a page with a store opens only for people
|
|
60
|
+
with access to the artifact, so the labeller is the owner or has been shared as a Contributor.
|
|
61
|
+
If the study design is not written yet, \`build-benchmark\` comes first.
|
|
62
|
+
If the items come from a drawn sample, the study's \`prereg.json\` declares the population, the
|
|
63
|
+
screens and the coverage before the sample is frozen (the experimental rule \`study/declare-sample\` checks it, off by default), and the
|
|
64
|
+
author has been shown the drawn **units** (the rules or cases, not the items) with "is this what
|
|
65
|
+
you meet in practice?". The labelling page is not that check: items made from easy units each look
|
|
66
|
+
fine on their own.
|
|
67
|
+
2. **Copy the generator into the study and write the items.** The study folder is
|
|
68
|
+
\`<paper-dir>/repro/<slug>-YYYY-MM-DD/\` (\`gold-labels-2026-10-12\`; \`repro/allowed-files-only\` wants the
|
|
69
|
+
date, a \`README.md\` in it saying what the study asks, and a line in \`repro/README.md\`; where this
|
|
70
|
+
sits in stage 3, and what checks each place: \`docs/layout.md\` in the paperlint package).
|
|
71
|
+
\`items.json\` follows the header of the generator. Source ids in \`items.json\` are the study's own;
|
|
72
|
+
the page never shows them.
|
|
73
|
+
|
|
74
|
+
\`\`\`bash
|
|
75
|
+
cp \${CLAUDE_SKILL_DIR}/references/example-generator.py <study-dir>/make_label_page.py
|
|
76
|
+
\`\`\`
|
|
77
|
+
|
|
78
|
+
The generator is a template: change the questions and keep the guards (allow-list, neutral ids,
|
|
79
|
+
store-unavailable banner, filter instead of scrolling). Do not loosen the allow-list to make a
|
|
80
|
+
build pass; take the field out of the item.
|
|
81
|
+
3. **Build and read it as the labeller.** From the study folder (\`<study-dir>\`):
|
|
82
|
+
|
|
83
|
+
\`\`\`bash
|
|
84
|
+
python3 make_label_page.py build items.json label-page
|
|
85
|
+
\`\`\`
|
|
86
|
+
|
|
87
|
+
This writes \`label-page/page.html\` and \`label-page/key.json\` (the only link from \`G001\` to the
|
|
88
|
+
source id; it never goes on the page). Rebuilding with the same seed keeps every id, and a new item
|
|
89
|
+
gets the next one. Read the page text once as a person who knows nothing about the source: if
|
|
90
|
+
anything on it tells the answer, take it out of the item.
|
|
91
|
+
4. **Publish.** Load \`artifact-design\` and \`artifact-capabilities\`, then publish \`page.html\` with
|
|
92
|
+
\`capabilities: {db: {}}\`. Use a title of two to four words. Do not ask the page for \`user\` or
|
|
93
|
+
anything else it does not use.
|
|
94
|
+
5. **Test in the viewer (rule 1)** and list the store once with \`ArtifactData\` (\`list\` of
|
|
95
|
+
\`answers\`) to confirm the test answer arrived. \`ArtifactData\` can be a deferred tool: load it with
|
|
96
|
+
\`ToolSearch\` first. Then delete the test answer's document, or tell the person which one it is
|
|
97
|
+
and keep it out of the export.
|
|
98
|
+
6. **Send the link** with one line on how it works: tap an answer, it saves; "Next unanswered" shows
|
|
99
|
+
what is left. Say what you tested and what you could not.
|
|
100
|
+
7. **Export when the person is done, or stops** (rule 6). Save the store's two collections, \`answers\`
|
|
101
|
+
and \`groups\`, as \`dump.json\` in the shape the generator's header gives (answers given in chat go
|
|
102
|
+
in with \`"source": "chat"\`), then:
|
|
103
|
+
|
|
104
|
+
\`\`\`bash
|
|
105
|
+
python3 make_label_page.py export dump.json label-page/key.json data
|
|
106
|
+
\`\`\`
|
|
107
|
+
|
|
108
|
+
It writes \`data/<study>-labels-<date>.json\` and prints every incomplete item, every answer or
|
|
109
|
+
familiarity value that is not one of the offered options (not counted, same rule as on the page;
|
|
110
|
+
correct it in the dump and export again) and every group with no familiarity answer. Commit the file in the same pass, and add the line "labels →
|
|
111
|
+
\`data/<study>-labels-<date>.json\`" to the paper's \`NOTES.md\` for the numbers that use them.
|
|
112
|
+
|
|
113
|
+
## When the page misbehaves
|
|
114
|
+
|
|
115
|
+
Look at what the store holds (\`ArtifactData\` \`list\`) before changing anything: the page may be fine
|
|
116
|
+
and the person may have opened it without access. One fix to the page is allowed. If it fails again,
|
|
117
|
+
ask for the remaining answers in chat, write them into the dump with \`"source": "chat"\`, and export.
|
|
118
|
+
Do not iterate on a page you cannot see.
|
|
119
|
+
|
|
120
|
+
## Compose with
|
|
121
|
+
|
|
122
|
+
- **build-benchmark** — owns the study design and the inter-rater rule: agreement with the person who
|
|
123
|
+
wrote the codebook measures trainability, not reliability, so the labeller for gold labels is
|
|
124
|
+
someone who did not write the scheme.
|
|
125
|
+
- **draft-paper** — the exported labels, the familiarity filter and the complete-item count feed the
|
|
126
|
+
Methods and the threats.
|
|
127
|
+
- **submit-paper** — a published artifact page is not anonymous. Do not link it from an anonymized
|
|
128
|
+
submission; the exported JSON is what goes into the reproduction artifact.`,
|
|
129
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* build-label-page — the PAID tier: does this skill's description actually fire?
|
|
3
|
+
*
|
|
4
|
+
* The prompts live in `lib/skill-trigger-cases.mjs` beside every other skill's, so collisions with
|
|
5
|
+
* `build-benchmark` and `draft-paper` are visible in one table. Measures recall on its own
|
|
6
|
+
* territory and precision against those siblings, against the real harness.
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ NEVER RUN. Written 2026-10-12 with the skill; its rate is UNKNOWN, not assumed good.
|
|
9
|
+
*
|
|
10
|
+
* Costs money; not CI.
|
|
11
|
+
* node skills/build-label-page/build-label-page.eval.mjs [trials]
|
|
12
|
+
*/
|
|
13
|
+
import { runSkillTriggerEval } from "../../lib/skill-eval-kit.mjs";
|
|
14
|
+
|
|
15
|
+
await runSkillTriggerEval("build-label-page");
|