paperlint 13.0.3 → 13.2.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.
Files changed (114) hide show
  1. package/CLAUDE.md +9 -1
  2. package/dist/adapters/git/index.d.ts.map +1 -1
  3. package/dist/adapters/git/index.js +13 -0
  4. package/dist/adapters/git/index.js.map +1 -1
  5. package/dist/adapters/study-registry/index.d.ts +142 -1
  6. package/dist/adapters/study-registry/index.d.ts.map +1 -1
  7. package/dist/adapters/study-registry/index.js +160 -1
  8. package/dist/adapters/study-registry/index.js.map +1 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +3 -0
  11. package/dist/cli.js.map +1 -1
  12. package/dist/domain/decide-first.d.ts +43 -0
  13. package/dist/domain/decide-first.d.ts.map +1 -1
  14. package/dist/domain/decide-first.js +45 -2
  15. package/dist/domain/decide-first.js.map +1 -1
  16. package/dist/domain/study-gates.d.ts +96 -0
  17. package/dist/domain/study-gates.d.ts.map +1 -0
  18. package/dist/domain/study-gates.js +56 -0
  19. package/dist/domain/study-gates.js.map +1 -0
  20. package/dist/domain/study-mode.d.ts +6 -0
  21. package/dist/domain/study-mode.d.ts.map +1 -1
  22. package/dist/domain/study-mode.js.map +1 -1
  23. package/dist/domain/study-registry.d.ts +24 -4
  24. package/dist/domain/study-registry.d.ts.map +1 -1
  25. package/dist/domain/study-registry.js +39 -2
  26. package/dist/domain/study-registry.js.map +1 -1
  27. package/dist/domain/study-result.d.ts +151 -0
  28. package/dist/domain/study-result.d.ts.map +1 -0
  29. package/dist/domain/study-result.js +175 -0
  30. package/dist/domain/study-result.js.map +1 -0
  31. package/dist/outputs-before-decision-rule.d.ts.map +1 -1
  32. package/dist/outputs-before-decision-rule.js +37 -3
  33. package/dist/outputs-before-decision-rule.js.map +1 -1
  34. package/dist/ports/git-history.d.ts +12 -0
  35. package/dist/ports/git-history.d.ts.map +1 -1
  36. package/dist/ports/study-registry-codec.d.ts +3 -0
  37. package/dist/ports/study-registry-codec.d.ts.map +1 -1
  38. package/dist/skills/build-label-page/scripts/label-page-cli.d.ts +6 -0
  39. package/dist/skills/build-label-page/scripts/label-page-commands.d.ts +14 -0
  40. package/dist/skills/build-label-page/scripts/label-page-core.d.ts +149 -0
  41. package/dist/skills/build-label-page/scripts/label-page-html.d.ts +5 -0
  42. package/dist/skills/build-label-page/scripts/label-page.d.ts +2 -0
  43. package/dist/study-modes.d.ts +3 -0
  44. package/dist/study-modes.d.ts.map +1 -1
  45. package/dist/study-modes.js +8 -1
  46. package/dist/study-modes.js.map +1 -1
  47. package/dist/study-registry-rule.d.ts.map +1 -1
  48. package/dist/study-registry-rule.js +1 -0
  49. package/dist/study-registry-rule.js.map +1 -1
  50. package/dist/study-result-rule.d.ts +12 -0
  51. package/dist/study-result-rule.d.ts.map +1 -0
  52. package/dist/study-result-rule.js +87 -0
  53. package/dist/study-result-rule.js.map +1 -0
  54. package/docs/design/study-gates.md +208 -0
  55. package/docs/rules/repro/outputs-before-decision.md +8 -0
  56. package/docs/rules/repro/study-registered.md +38 -15
  57. package/docs/rules/repro/study-result.md +100 -0
  58. package/docs/rules.md +1 -0
  59. package/eslint.config.mjs +1 -1
  60. package/hooks/hooks.harness.ts +51 -13
  61. package/hooks/paper-skills-nudge.hook.d.mts +22 -0
  62. package/hooks/paper-skills-nudge.hook.mjs +85 -23
  63. package/hooks/paper-skills-nudge.test.ts +82 -4
  64. package/package.json +2 -1
  65. package/plugin/hooks/hooks.json +7 -2
  66. package/schemas/plan.v2.schema.json +341 -0
  67. package/skills/argument-arc/SKILL.md.spec.ts +1 -1
  68. package/skills/build-label-page/SKILL.md +85 -54
  69. package/skills/build-label-page/SKILL.md.spec.ts +85 -53
  70. package/skills/build-label-page/build-label-page.test.ts +10 -941
  71. package/skills/build-label-page/references/checklist.md +45 -3
  72. package/skills/build-label-page/references/closed-choice-generator.md +88 -0
  73. package/skills/build-label-page/scripts/label-page-cli.js +72 -0
  74. package/skills/build-label-page/scripts/label-page-cli.ts +85 -0
  75. package/skills/build-label-page/scripts/label-page-commands.js +14 -0
  76. package/skills/build-label-page/scripts/label-page-commands.ts +14 -0
  77. package/skills/build-label-page/scripts/label-page-core.js +850 -0
  78. package/skills/build-label-page/scripts/label-page-core.test.ts +1164 -0
  79. package/skills/build-label-page/scripts/label-page-core.ts +1210 -0
  80. package/skills/build-label-page/scripts/label-page-html.js +33 -0
  81. package/skills/build-label-page/scripts/label-page-html.test.ts +413 -0
  82. package/skills/build-label-page/scripts/label-page-html.ts +43 -0
  83. package/skills/build-label-page/scripts/label-page.js +70 -0
  84. package/skills/build-label-page/scripts/label-page.test.ts +71 -0
  85. package/skills/build-label-page/scripts/label-page.ts +71 -0
  86. package/skills/build-label-page/scripts/page-template.html +513 -0
  87. package/skills/find-venue/SKILL.md.spec.ts +1 -1
  88. package/skills/paper-status/SKILL.md.spec.ts +1 -1
  89. package/skills/render-paper/SKILL.md.spec.ts +1 -1
  90. package/src/adapters/git/index.test.ts +33 -0
  91. package/src/adapters/git/index.ts +19 -0
  92. package/src/adapters/study-registry/gates.test.ts +181 -0
  93. package/src/adapters/study-registry/index.ts +219 -1
  94. package/src/adapters/study-registry/mode.test.ts +6 -0
  95. package/src/cli.ts +3 -0
  96. package/src/domain/decide-first.test.ts +131 -0
  97. package/src/domain/decide-first.ts +92 -2
  98. package/src/domain/study-gates.ts +125 -0
  99. package/src/domain/study-measurements.test.ts +71 -0
  100. package/src/domain/study-mode.ts +6 -0
  101. package/src/domain/study-registry.ts +64 -2
  102. package/src/domain/study-result.test.ts +300 -0
  103. package/src/domain/study-result.ts +358 -0
  104. package/src/outputs-before-decision-rule.test.ts +115 -2
  105. package/src/outputs-before-decision-rule.ts +50 -2
  106. package/src/ports/git-history.ts +12 -0
  107. package/src/ports/study-registry-codec.ts +3 -0
  108. package/src/rule-cases.test.ts +74 -0
  109. package/src/studies.test.ts +3 -0
  110. package/src/study-modes.ts +10 -1
  111. package/src/study-registry-rule.ts +1 -0
  112. package/src/study-result-rule.test.ts +281 -0
  113. package/src/study-result-rule.ts +123 -0
  114. package/skills/build-label-page/references/example-generator.py +0 -803
@@ -1,10 +1,11 @@
1
1
  // Compiled to SKILL.md by `vigiles compile`. Edit THIS file, never the markdown.
2
2
  import { experimental_skill } from "vigiles/spec";
3
+ import { COMMANDS } from "./scripts/label-page-commands.ts";
3
4
 
4
5
  export default experimental_skill({
5
6
  name: "build-label-page",
6
7
  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
+ '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 eight rules that keep such a page honest, the last one a check that the labeller understands each question before the real items. Composes with build-benchmark and draft-paper.',
8
9
  tools: [
9
10
  "Read",
10
11
  "Write",
@@ -28,10 +29,39 @@ committed, not left in the store.
28
29
  **Not for** an LLM judge (no person answers), a questionnaire about the person, or a form that collects
29
30
  anything but labels.
30
31
 
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:
32
+ ## Which page you need
33
+
34
+ | the labeller… | page |
35
+ | --- | --- |
36
+ | looks at one item and picks from a closed list: gold labels, a blind review of model outputs, fits / text silent / contradicts, an approval (keep / drop, and why), with an optional reason box and code blocks | **the generator** of this skill |
37
+ | compares two outputs side by side, ranks several items, marks parts (spans) of a text — a recall audit, reading a whole file and marking every rule in it —, gives a number on a slider, or writes free text | **written by the agent** |
38
+
39
+ - **The generator** is \`scripts/label-page.js\`, run from the skill (commands in the procedure):
40
+ a core with no page layout (\`label-page-core.ts\`: the \`items.json\` checks, the leak guard, the
41
+ neutral ids, the key, the export) and the one closed-choice page built from the core's payload
42
+ (\`label-page-html.ts\`). How to write its \`items.json\` — examples, practice, \`ask_why\`, the
43
+ approval page — is
44
+ [\`references/closed-choice-generator.md\`](references/closed-choice-generator.md).
45
+ - **A page written by the agent** meets the same eight rules, and each rule's **Check** line in
46
+ [\`references/checklist.md\`](references/checklist.md) is its acceptance list: every one verified,
47
+ and stated in the hand-over, before the link is sent. It also looks the way the generator's pages
48
+ look: one dark palette, one column, answer buttons as full-width rows with space between them,
49
+ icons rather than coloured side stripes, code shown as code with its whitespace visible, built for
50
+ a phone first, and screenshotted at 400px and 1280px wide and looked at before publishing.
51
+ It can still take its blindness and its export from the core: \`prepareBuild\` checks
52
+ \`items.json\`, gives the items their neutral ids, writes \`key.json\` and returns the blind
53
+ payload to lay out, and \`export\` reads any store that keeps the generator's collections.
54
+ - A second generator, for another page shape, is added only after that shape has been built by
55
+ hand, following the eight rules, twice without its fields changing. Until then the agent writes
56
+ such a page itself.
57
+ - The other ways to build pages that were considered (a JS kit plus an automatic page check; rules
58
+ only; one growing generator), and when to switch: #335.
59
+
60
+ ## The eight rules
61
+
62
+ They hold for every labelling page, generated or written by hand. The full text, each with its
63
+ reason and its check, is [\`references/checklist.md\`](references/checklist.md). Read it before
64
+ building. In one line each:
35
65
 
36
66
  1. **Test it in the claude.ai phone viewer before sending the link.** The viewer can size the frame to
37
67
  the page, so the page cannot scroll itself and a fixed toast may be off-screen. A plain browser
@@ -42,7 +72,7 @@ The full text, each with its reason and its check, is
42
72
  question; the progress counter counts complete items only.
43
73
  4. **Blind.** Neutral ids (\`G001\`…), order shuffled with a fixed seed, no model answers, verdicts or
44
74
  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.
75
+ allow-list; a page written by hand checks its items against the same list.
46
76
  5. **Ask only what the labeller can answer.** Only the languages and tools they know; one "how well do
47
77
  you know it" question per group, used later as an analysis filter; "clear-cut or real boundary"
48
78
  is the labeller's judgement, not the designer's.
@@ -51,69 +81,71 @@ The full text, each with its reason and its check, is
51
81
  take the last answers in chat; patch the page blind at most once.
52
82
  7. **Save on click**, no submit button; "Saved <time>" on every card; survive a reload; render
53
83
  readable, with a banner, when the store is unavailable.
84
+ 8. **The labeller understands each question first.** Every answer option carries one real example,
85
+ shown on the first screen; 3 or more practice items with known answers come before the real
86
+ items, and the page shows the expected answer after each; one question per screen. A practice
87
+ miss means the question is reworded and the practice taken again; practice answers never reach
88
+ the labels.
54
89
 
55
90
  ## Procedure
56
91
 
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 \`plan.json\` (written by
63
- \`paperlint studies new\`) declares the population and its draw before the sample is frozen, and its
64
- \`author_check\` records that the author has been shown the drawn **units** (the rules or cases, not
65
- the items) with "is this what you meet in practice?". The labelling page is not that check: items
66
- made from easy units each look fine on their own.
67
- 2. **Copy the generator into the study and write the items.** The study folder is
68
- \`<paper-dir>/repro/<id>-<slug>/\`, made by \`npx paperlint studies new <paper-dir> "Gold labels"
69
- --kind data\` when the labelling is a study of its own (\`P1-S04-gold-labels\`): the command writes
70
- its \`README.md\`, its \`plan.json\` and its row in \`repro/studies.json\`, and \`repro/study-registered\`
71
- checks them; fill the plan (what is labelled, the items' source, \`arms: []\`, the primary outcome)
72
- before the first label. When
73
- the labels are in, update the row (\`status\`, \`result\`, \`result_file\`) and run
74
- \`npx paperlint studies index <paper-dir>\`. Where this sits in stage 3, and what checks each place:
75
- \`docs/layout.md\` in the paperlint package.
76
- \`items.json\` follows the header of the generator. Source ids in \`items.json\` are the study's own;
77
- the page never shows them.
78
-
79
- \`\`\`bash
80
- cp \${CLAUDE_SKILL_DIR}/references/example-generator.py <study-dir>/make_label_page.py
81
- \`\`\`
82
-
83
- The generator is a template: change the questions and keep the guards (allow-list, neutral ids,
84
- store-unavailable banner, filter instead of scrolling). Do not loosen the allow-list to make a
85
- build pass; take the field out of the item.
86
- 3. **Build and read it as the labeller.** From the study folder (\`<study-dir>\`):
92
+ 1. **Decide the labelling and the page.** What exactly does the labeller decide per item (the
93
+ questions, each with its answers)? Which page that takes (the table above)? Which groups
94
+ (languages, tools) does the labeller know? How many items fit the time they have on a phone? Who
95
+ is the labeller: a page with a store opens only for people with access to the artifact, so the
96
+ labeller is the owner or has been shared as a Contributor. If the study design is not written
97
+ yet, \`build-benchmark\` comes first. If the items come from a drawn sample, the study's
98
+ \`plan.json\` declares the population and its draw before the sample is frozen, and its
99
+ \`author_check\` records that the author has been shown the drawn **units** (the rules or cases,
100
+ not the items) — on an approval page, not on the labelling page, where items made from easy units
101
+ each look fine on their own.
102
+ 2. **Make the study folder.** \`<paper-dir>/repro/<id>-<slug>/\`, made by \`npx paperlint studies new
103
+ <paper-dir> "Gold labels" --kind data\` when the labelling is a study of its own: the command
104
+ writes its \`README.md\`, its \`plan.json\` and its row in \`repro/studies.json\`, and
105
+ \`repro/study-registered\` checks them; fill the plan before the first label. When the labels are
106
+ in, update the row (\`status\`, \`result\`, \`result_file\`) and run \`npx paperlint studies index
107
+ <paper-dir>\`. Where this sits in stage 3: \`docs/layout.md\` in the paperlint package.
108
+ 3. **Build the page.** With the generator, write \`items.json\`
109
+ ([\`references/closed-choice-generator.md\`](references/closed-choice-generator.md)) and, from the
110
+ study folder:
87
111
 
88
112
  \`\`\`bash
89
- python3 make_label_page.py build items.json label-page
113
+ node \${CLAUDE_SKILL_DIR}/scripts/label-page.js ${COMMANDS.build} items.json label-page
90
114
  \`\`\`
91
115
 
92
- This writes \`label-page/page.html\` and \`label-page/key.json\` (the only link from \`G001\` to the
93
- source id; it never goes on the page). Rebuilding with the same seed keeps every id, and a new item
94
- gets the next one. Read the page text once as a person who knows nothing about the source: if
95
- anything on it tells the answer, take it out of the item.
96
- 4. **Publish.** Load \`artifact-design\` and \`artifact-capabilities\`, then publish \`page.html\` with
116
+ It writes \`label-page/page.html\` and \`label-page/key.json\` (the only link from \`G001\` to the
117
+ source id; it never goes on the page). Written by hand, the page meets the requirements above.
118
+ 4. **Read it as the labeller, then look at it.** Read the page text once as a person who knows
119
+ nothing about the source: if anything on it tells the answer, take it out. Read each question as
120
+ someone who did not design the study: can they tell what each answer means from the question, its
121
+ examples and nothing else? If not, reword. Then screenshot it at 400px and at 1280px wide with the
122
+ pre-installed Chromium (Playwright), once before any answer and once after the practice, open both
123
+ images, and fix what they show. A page that only passed its tests has not been seen.
124
+ 5. **Publish.** Load \`artifact-design\` and \`artifact-capabilities\`, then publish \`page.html\` with
97
125
  \`capabilities: {db: {}}\`. Use a title of two to four words. Do not ask the page for \`user\` or
98
126
  anything else it does not use.
99
- 5. **Test in the viewer (rule 1)** and list the store once with \`ArtifactData\` (\`list\` of
127
+ 6. **Test in the viewer (rule 1)** and list the store once with \`ArtifactData\` (\`list\` of
100
128
  \`answers\`) to confirm the test answer arrived. \`ArtifactData\` can be a deferred tool: load it with
101
129
  \`ToolSearch\` first. Then delete the test answer's document, or tell the person which one it is
102
130
  and keep it out of the export.
103
- 6. **Send the link** with one line on how it works: tap an answer, it saves; "Next unanswered" shows
104
- what is left. Say what you tested and what you could not.
105
- 7. **Export when the person is done, or stops** (rule 6). Save the store's two collections, \`answers\`
106
- and \`groups\`, as \`dump.json\` in the shape the generator's header gives (answers given in chat go
107
- in with \`"source": "chat"\`), then:
131
+ 7. **Send the link** with one line on how it works: start with the practice; tap an answer, it saves;
132
+ "Next unanswered" shows what is left. Say what you tested and what you could not. **Check the
133
+ practice before the real answers count** (rule 8): list the store's \`practice\` collection. A
134
+ miss means a question was unclear: ask the labeller which one and why, reword it and its
135
+ examples, rebuild, republish, and have them take the practice again. Write one line per round in
136
+ the study's README: what was reworded and why.
137
+ 8. **Export when the person is done, or stops** (rule 6). Save the store's collections as
138
+ \`dump.json\` (answers given in chat go in with \`"source": "chat"\`). With the generator:
108
139
 
109
140
  \`\`\`bash
110
- python3 make_label_page.py export dump.json label-page/key.json data
141
+ node \${CLAUDE_SKILL_DIR}/scripts/label-page.js ${COMMANDS.export} dump.json label-page/key.json data
111
142
  \`\`\`
112
143
 
113
- It writes \`data/<study>-labels-<date>.json\` and prints every incomplete item, every answer or
114
- familiarity value that is not one of the offered options (not counted, same rule as on the page;
115
- 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 →
116
- \`data/<study>-labels-<date>.json\`" to the paper's \`NOTES.md\` for the numbers that use them.
144
+ It writes \`data/<study>-labels-<date>.json\`, scores the practice into
145
+ \`data/<study>-practice-r<round>-<date>.json\` beside it, and prints every item it could not count. A page
146
+ written by hand exports to the same two files, practice kept out of the labels. Commit both in the
147
+ same pass, and add the line "labels → \`data/<study>-labels-<date>.json\`" to the paper's
148
+ \`NOTES.md\` for the numbers that use them.
117
149
 
118
150
  ## When the page misbehaves
119
151