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
package/skills/paper-pipeline/repro/2026-10-13-grade-paper-writing-ablation-preflight-before.log
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
|
|
2
|
+
26 skills installed → 25 competitors per run
|
|
3
|
+
|
|
4
|
+
ARMS — description length, word-set delta vs A0, mean prompt overlap
|
|
5
|
+
arm label chars words − + ovAH ovSH
|
|
6
|
+
A0 baseline (verbatim) 1371 103 0 0 0.85 0.78
|
|
7
|
+
A1 short (sentences 1-2 only) 618 51 52 0 0.71 0.78
|
|
8
|
+
A2 no-subordination 1189 94 9 0 0.85 0.78
|
|
9
|
+
A3 no-negation 1141 92 11 0 0.85 0.78
|
|
10
|
+
A4 no-machinery 670 45 58 0 0.44 0.35
|
|
11
|
+
A5 renamed (description identical) 1371 103 0 0 0.85 0.78
|
|
12
|
+
A6 persona-only (A1's mirror) 298 28 75 0 0.23 0.42
|
|
13
|
+
|
|
14
|
+
⚠ ovAH/ovSH FALL AS TEXT IS DELETED — caveat 2 in the header, quantified. The deletion arms carry
|
|
15
|
+
a vocabulary handicap against the parent's dominant factor. A rising deletion arm rose DESPITE it;
|
|
16
|
+
a flat one may be a real gain cancelled by it, and this design cannot tell. A5 is the only arm
|
|
17
|
+
with zero handicap (identical word set).
|
|
18
|
+
|
|
19
|
+
WORD-SET DELTAS (stemmed content words removed from A0 — none may be added)
|
|
20
|
+
|
|
21
|
+
A0 baseline (verbatim)
|
|
22
|
+
removed (0): —
|
|
23
|
+
added (0): —
|
|
24
|
+
|
|
25
|
+
A1 short (sentences 1-2 only)
|
|
26
|
+
removed (52): run cold stall pas committ persona non academic engineer per section workshop reviewer skimm introduction conclusion inventory rubric number readability gate skill consume panel review adversarial harden default blind multi grader mandate claim preservation diff row content defect structural cut plan tighten first bloat strength reward study compose call generative counterpart render
|
|
27
|
+
added (0): —
|
|
28
|
+
|
|
29
|
+
A2 no-subordination
|
|
30
|
+
removed (9): inventory rubric number readability gate skill consume harden call
|
|
31
|
+
added (0): —
|
|
32
|
+
|
|
33
|
+
A3 no-negation
|
|
34
|
+
removed (11): content defect structural cut plan tighten first bloat strength reward study
|
|
35
|
+
added (0): —
|
|
36
|
+
|
|
37
|
+
A4 no-machinery
|
|
38
|
+
removed (58): title abstract intro architecture structure prose clarity discipline land point figure economy honesty without hedge stack register distance peyton jone mcenerney gopen swan exemplar trust carlini greshake cold stall pas committ persona non academic engineer per section workshop reviewer skimm introduction conclusion inventory rubric number readability gate skill consume default blind multi grader mandate claim preservation diff row
|
|
39
|
+
added (0): —
|
|
40
|
+
|
|
41
|
+
A5 renamed (description identical)
|
|
42
|
+
removed (0): —
|
|
43
|
+
added (0): —
|
|
44
|
+
|
|
45
|
+
A6 persona-only (A1's mirror)
|
|
46
|
+
removed (75): grade craft ten dimension title intro architecture structure prose clarity discipline land point figure economy honesty without hedge stack register distance target venue best written peyton jone mcenerney gopen swan exemplar trust carlini greshake accept nam offend sentence fix inventory rubric number readability gate skill consume panel review adversarial harden default blind multi grader mandate claim preservation diff row content defect structural cut plan tighten first bloat strength reward study compose call generative counterpart render
|
|
47
|
+
added (0): —
|
|
48
|
+
|
|
49
|
+
RESULTING DESCRIPTIONS
|
|
50
|
+
|
|
51
|
+
── A0 (grade-paper-writing, 1371 chars)
|
|
52
|
+
Use when asking "does this paper read well?" / "is the writing any good?" / "it reads like a wall of text and jargon" / "grade the writing" on a draft. Grades WRITING CRAFT only — ten dimensions 1–5 (Title, Abstract, Intro architecture, Structure, Prose clarity, Jargon discipline, Landing-the-point, Figure economy, Honesty-without-hedge-stacking, Register distance to the target venue) against how the best-written papers read (Peyton Jones, McEnerney, Gopen & Swan; exemplars Trusting Trust, Carlini, Greshake) AND against 2–3 accepted papers of the target venue, naming the offending sentence and the fix for each. Runs the cold-read stall pass with TWO committed personas (a non-academic engineer per section, and a workshop reviewer skimming abstract, introduction and conclusion) whose stall inventory — not the rubric number — is the readability gate other skills consume (pc-panel-review, paper-adversarial-review, harden-paper). Defaults to a blind multi-grader panel; after fixes, mandates the claims-preservation diff (row `claims`). NOT a content/defect review (paper-adversarial-review / pc-panel-review), NOT a structural cut plan (tighten-paper — run that first on a bloated draft), NOT content strength against what the venue rewards (study-accepted-papers). Compose with harden-paper (which calls it), draft-paper (generative counterpart), render-paper.
|
|
53
|
+
|
|
54
|
+
── A1 (grade-paper-writing, 618 chars)
|
|
55
|
+
Use when asking "does this paper read well?" / "is the writing any good?" / "it reads like a wall of text and jargon" / "grade the writing" on a draft. Grades WRITING CRAFT only — ten dimensions 1–5 (Title, Abstract, Intro architecture, Structure, Prose clarity, Jargon discipline, Landing-the-point, Figure economy, Honesty-without-hedge-stacking, Register distance to the target venue) against how the best-written papers read (Peyton Jones, McEnerney, Gopen & Swan; exemplars Trusting Trust, Carlini, Greshake) AND against 2–3 accepted papers of the target venue, naming the offending sentence and the fix for each.
|
|
56
|
+
|
|
57
|
+
── A2 (grade-paper-writing, 1189 chars)
|
|
58
|
+
Use when asking "does this paper read well?" / "is the writing any good?" / "it reads like a wall of text and jargon" / "grade the writing" on a draft. Grades WRITING CRAFT only — ten dimensions 1–5 (Title, Abstract, Intro architecture, Structure, Prose clarity, Jargon discipline, Landing-the-point, Figure economy, Honesty-without-hedge-stacking, Register distance to the target venue) against how the best-written papers read (Peyton Jones, McEnerney, Gopen & Swan; exemplars Trusting Trust, Carlini, Greshake) AND against 2–3 accepted papers of the target venue, naming the offending sentence and the fix for each. Runs the cold-read stall pass with TWO committed personas (a non-academic engineer per section, and a workshop reviewer skimming abstract, introduction and conclusion). Defaults to a blind multi-grader panel; after fixes, mandates the claims-preservation diff (row `claims`). NOT a content/defect review (paper-adversarial-review / pc-panel-review), NOT a structural cut plan (tighten-paper — run that first on a bloated draft), NOT content strength against what the venue rewards (study-accepted-papers). Compose with draft-paper (generative counterpart), render-paper.
|
|
59
|
+
|
|
60
|
+
── A3 (grade-paper-writing, 1141 chars)
|
|
61
|
+
Use when asking "does this paper read well?" / "is the writing any good?" / "it reads like a wall of text and jargon" / "grade the writing" on a draft. Grades WRITING CRAFT only — ten dimensions 1–5 (Title, Abstract, Intro architecture, Structure, Prose clarity, Jargon discipline, Landing-the-point, Figure economy, Honesty-without-hedge-stacking, Register distance to the target venue) against how the best-written papers read (Peyton Jones, McEnerney, Gopen & Swan; exemplars Trusting Trust, Carlini, Greshake) AND against 2–3 accepted papers of the target venue, naming the offending sentence and the fix for each. Runs the cold-read stall pass with TWO committed personas (a non-academic engineer per section, and a workshop reviewer skimming abstract, introduction and conclusion) whose stall inventory — not the rubric number — is the readability gate other skills consume (pc-panel-review, paper-adversarial-review, harden-paper). Defaults to a blind multi-grader panel; after fixes, mandates the claims-preservation diff (row `claims`). Compose with harden-paper (which calls it), draft-paper (generative counterpart), render-paper.
|
|
62
|
+
|
|
63
|
+
── A4 (grade-paper-writing, 670 chars)
|
|
64
|
+
Use when asking "does this paper read well?" / "is the writing any good?" / "it reads like a wall of text and jargon" / "grade the writing" on a draft. Grades WRITING CRAFT only — ten dimensions 1–5 against how the best-written papers read AND against 2–3 accepted papers of the target venue, naming the offending sentence and the fix for each. NOT a content/defect review (paper-adversarial-review / pc-panel-review), NOT a structural cut plan (tighten-paper — run that first on a bloated draft), NOT content strength against what the venue rewards (study-accepted-papers). Compose with harden-paper (which calls it), draft-paper (generative counterpart), render-paper.
|
|
65
|
+
|
|
66
|
+
── A5 (paper-readability-review, 1371 chars)
|
|
67
|
+
Use when asking "does this paper read well?" / "is the writing any good?" / "it reads like a wall of text and jargon" / "grade the writing" on a draft. Grades WRITING CRAFT only — ten dimensions 1–5 (Title, Abstract, Intro architecture, Structure, Prose clarity, Jargon discipline, Landing-the-point, Figure economy, Honesty-without-hedge-stacking, Register distance to the target venue) against how the best-written papers read (Peyton Jones, McEnerney, Gopen & Swan; exemplars Trusting Trust, Carlini, Greshake) AND against 2–3 accepted papers of the target venue, naming the offending sentence and the fix for each. Runs the cold-read stall pass with TWO committed personas (a non-academic engineer per section, and a workshop reviewer skimming abstract, introduction and conclusion) whose stall inventory — not the rubric number — is the readability gate other skills consume (pc-panel-review, paper-adversarial-review, harden-paper). Defaults to a blind multi-grader panel; after fixes, mandates the claims-preservation diff (row `claims`). NOT a content/defect review (paper-adversarial-review / pc-panel-review), NOT a structural cut plan (tighten-paper — run that first on a bloated draft), NOT content strength against what the venue rewards (study-accepted-papers). Compose with harden-paper (which calls it), draft-paper (generative counterpart), render-paper.
|
|
68
|
+
|
|
69
|
+
── A6 (grade-paper-writing, 298 chars)
|
|
70
|
+
Use when asking "does this paper read well?" / "is the writing any good?" / "it reads like a wall of text and jargon" on a draft. Runs the cold-read stall pass with TWO committed personas (a non-academic engineer per section, and a workshop reviewer skimming abstract, introduction and conclusion).
|
|
71
|
+
|
|
72
|
+
building each arm's skills dir under <scratch>/gpw-ablation (no real file is written) …
|
|
73
|
+
A0 → <scratch>/gpw-ablation/arm-A0
|
|
74
|
+
A1 → <scratch>/gpw-ablation/arm-A1
|
|
75
|
+
A2 → <scratch>/gpw-ablation/arm-A2
|
|
76
|
+
A3 → <scratch>/gpw-ablation/arm-A3
|
|
77
|
+
A4 → <scratch>/gpw-ablation/arm-A4
|
|
78
|
+
A5 → <scratch>/gpw-ablation/arm-A5
|
|
79
|
+
A6 → <scratch>/gpw-ablation/arm-A6
|
|
80
|
+
|
|
81
|
+
ALL PREFLIGHT GUARDS PASSED. No tokens spent. Run --mode main next.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
|
|
2
|
+
26 skills installed → 25 competitors per run
|
|
3
|
+
|
|
4
|
+
ARMS — description length, word-set delta vs A0, mean prompt overlap
|
|
5
|
+
arm label chars words − + ovAH ovSH
|
|
6
|
+
A0 baseline (verbatim) 1371 103 0 0 0.85 0.78
|
|
7
|
+
A1 short (sentences 1-2 only) 618 51 52 0 0.71 0.78
|
|
8
|
+
A2 no-subordination 1189 94 9 0 0.85 0.78
|
|
9
|
+
A3 no-negation 1141 92 11 0 0.85 0.78
|
|
10
|
+
A4 no-machinery 670 45 58 0 0.44 0.35
|
|
11
|
+
A5 renamed (description identical) 1371 103 0 0 0.85 0.78
|
|
12
|
+
A6 persona-only (A1's mirror) 298 28 75 0 0.23 0.42
|
|
13
|
+
|
|
14
|
+
⚠ ovAH/ovSH FALL AS TEXT IS DELETED — caveat 2 in the header, quantified. The deletion arms carry
|
|
15
|
+
a vocabulary handicap against the parent's dominant factor. A rising deletion arm rose DESPITE it;
|
|
16
|
+
a flat one may be a real gain cancelled by it, and this design cannot tell. A5 is the only arm
|
|
17
|
+
with zero handicap (identical word set).
|
|
18
|
+
|
|
19
|
+
HARNESS OPTIONS — this file vs the parent (extracted from both sources)
|
|
20
|
+
option ablation parent
|
|
21
|
+
allowedTools ["Skill" ["Skill"
|
|
22
|
+
trials TRIALS TRIALS
|
|
23
|
+
concurrency 3 3
|
|
24
|
+
spacingSec 2 2
|
|
25
|
+
timeoutMs 180000 180000
|
|
26
|
+
minPrompts 4 4
|
|
27
|
+
fixture /.exec(src)?.[0] ?? "" FIXTURE
|
|
28
|
+
skillsDir dir SKILLS_DIR
|
|
29
|
+
|
|
30
|
+
fixture sha256/16 ablation 89d1b720c4cedde6
|
|
31
|
+
FIXTURE source block identical to the parent's: YES
|
|
32
|
+
fired predicate identical (modulo the id it matches): YES
|
|
33
|
+
firedSkills() helper identical: YES
|
|
34
|
+
|
|
35
|
+
ARM DIR INTEGRITY — sha256/16 of each SKILL.md frontmatter vs the real .claude/skills
|
|
36
|
+
A0 26 skills · unintended frontmatter diffs: none
|
|
37
|
+
A1 26 skills · unintended frontmatter diffs: none
|
|
38
|
+
A2 26 skills · unintended frontmatter diffs: none
|
|
39
|
+
A3 26 skills · unintended frontmatter diffs: none
|
|
40
|
+
A4 26 skills · unintended frontmatter diffs: none
|
|
41
|
+
A5 26 skills · unintended frontmatter diffs: none
|
|
42
|
+
A6 26 skills · unintended frontmatter diffs: none
|
|
43
|
+
|
|
44
|
+
ROW BY ROW — parent (8 prompts) vs this file's A0 (8 prompts)
|
|
45
|
+
cell parent A0 Δ prompt
|
|
46
|
+
AH 0/3 1/3 +1 grade the writing craft in this draft and name the off
|
|
47
|
+
AH 3/3 3/3 0 run the blind multi-grader panel over the prose clarit
|
|
48
|
+
AH 0/3 3/3 +3 score the title, the abstract and the intro architectu
|
|
49
|
+
AH 0/3 0/3 0 grade how well this reads, hedge stacking included, an
|
|
50
|
+
SH 0/3 0/3 0 the abstract reads like a wall of jargon
|
|
51
|
+
SH 0/3 2/3 +2 the intro architecture is fine but the prose clarity i
|
|
52
|
+
SH 0/3 2/3 +2 there is hedge stacking everywhere and the point never
|
|
53
|
+
SH 2/3 2/3 0 the writing does not read well even though the draft i
|
|
54
|
+
5/24 13/24 +8 TOTAL
|
|
55
|
+
|
|
56
|
+
3 of 8 prompts moved by ≥2 of 3 trials. Spread across many prompts ⇒ a global shift
|
|
57
|
+
(session, load, model routing). Concentrated in one or two ⇒ something prompt-specific.
|
|
58
|
+
|
|
59
|
+
SETUPDIFF COMPLETE. No tokens spent.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"skill":"grade-paper-writing","model":"sonnet","trials":1,"rate":0.875,"falsePositiveRate":0,"precision":1,"competitors":25,"perPrompt":[{"prompt":"оцени как написано — читается как стена жаргона","rate":1},{"prompt":"is the writing any good or does it read like shit","rate":1},{"prompt":"abstract звучит криво хотя по смыслу всё на месте, дай оценку прозе","rate":1},{"prompt":"grade the craft: title, abstract, sentence clarity, hedge stacking","rate":1},{"prompt":"прочитай черновик и скажи честно, нормально ли он читается","rate":0},{"prompt":"the reviewer says our paper reads like a blog post — is he right about the prose","rate":1},{"prompt":"каждое предложение по отдельности понятно, а абзацы всё равно сливаются в сплошную простыню","rate":1},{"prompt":"grade the prose in section 3 and give me the sentences to rewrite","rate":1}]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Spent: 1,807,963 tokens (88 in · 12.6k out · 1562.4k cache) · ~$1.30 API-equivalent
|
|
2
|
+
Billed to: your Claude subscription — $0 metered ✅
|
|
3
|
+
|
|
4
|
+
grade-paper-writing — prose craft — the sentence is the unit, NOT the section [model: sonnet]
|
|
5
|
+
trigger-rate: 88% (8 runs)
|
|
6
|
+
1.00 оцени как написано — читается как стена жаргона
|
|
7
|
+
1.00 is the writing any good or does it read like shit
|
|
8
|
+
1.00 abstract звучит криво хотя по смыслу всё на месте, дай оценк
|
|
9
|
+
1.00 grade the craft: title, abstract, sentence clarity, hedge st
|
|
10
|
+
0.00 прочитай черновик и скажи честно, нормально ли он читается
|
|
11
|
+
1.00 the reviewer says our paper reads like a blog post — is he r
|
|
12
|
+
1.00 каждое предложение по отдельности понятно, а абзацы всё равн
|
|
13
|
+
1.00 grade the prose in section 3 and give me the sentences to re
|
|
14
|
+
false-positive: 0% precision: 100%
|
|
15
|
+
0.00 [irrelevant] статья раздулась, середина провисает — что резат
|
|
16
|
+
0.00 [irrelevant] does the paper actually carry a reader to one co
|
|
17
|
+
0.00 [irrelevant] поправил формулировки в 4.2, прогони свежим чита
|
|
18
|
+
0.00 [irrelevant] what is our desk reject risk and where do we ove
|
|
19
|
+
0.00 [irrelevant] какая вероятность принятия у этой статьи, если ч
|
|
20
|
+
0.00 [irrelevant] статья готова к сабмиту или нет
|
|
21
|
+
0.00 [irrelevant] посмотри что принимали на этой площадке и чем те
|
|
22
|
+
whole-harness: measured against 25 competing skill(s)
|
|
@@ -25,6 +25,10 @@ the session.
|
|
|
25
25
|
| `2026-08-08-parent-replication.mjs` | the replication driver | Runs `framing-vs-vocabulary.eval.mjs` **itself** with two asserted patches (main loop → this skill + AH/SH; output path), everything else untouched, against the real `.claude/skills`. Written because the ablation's control contradicted the parent. |
|
|
26
26
|
| `2026-08-08-parent-replication-gpw.log` | that driver's run | 🔴 **The parent's own code returns AH 9/12 + SH 3/12 = 12/24 (50%)** hours after the same code returned 3/12 + 2/12 = 5/24 (21%). |
|
|
27
27
|
| `2026-08-08-parent-replication-gpw.json` | per-run rows for the above | The parent's own row schema, so it diffs directly against `2026-08-08-framing-vs-vocabulary.json`. |
|
|
28
|
+
| `2026-10-13-grade-paper-writing-trigger.log` | `grade-paper-writing/grade-paper-writing.eval.mjs`, the rewritten 499-char description (ledger `description_sha` dc41f0994474b368) | 1 trial, sonnet, 25 competing skills. Recall **7/8 (88%)**: the four measured prompts 4/4, the four new ones 3/4 (missed: «прочитай черновик и скажи честно, нормально ли он читается»). False positives **0/7**, one prompt from each collider. One trial is a smoke run, not a rate. |
|
|
29
|
+
| `2026-10-13-grade-paper-writing-trigger.jsonl` | per-prompt rows for the above | The kit's `VIGILES_RESULTS` row: rate per should-fire prompt. |
|
|
30
|
+
| `2026-10-13-grade-paper-writing-ablation-preflight-before.log`, `…-after.log` | `grade-paper-writing-ablation.eval.mjs --mode preflight`, **free**, before and after its A0 was pinned | Byte-identical: every arm builds from the same text after the live description was rewritten. Scratch paths replaced by `<scratch>`. |
|
|
31
|
+
| `2026-10-13-grade-paper-writing-ablation-setupdiff.log` | the same file's `--mode setupdiff`, **free**, after the pin | Passes; the parent-vs-A0 row-by-row is the recorded 2026-08-08 data, unchanged. |
|
|
28
32
|
|
|
29
33
|
## How to read these, and the trap in them
|
|
30
34
|
|
|
@@ -400,7 +400,7 @@ process.on("exit", () => rmSync(TMP, { recursive: true, force: true }));
|
|
|
400
400
|
{
|
|
401
401
|
const { spawnSync } = await import("node:child_process");
|
|
402
402
|
const dir = join(TMP, "e2e");
|
|
403
|
-
mkdirSync(join(dir, "repro"), { recursive: true });
|
|
403
|
+
mkdirSync(join(dir, "repro", "data"), { recursive: true });
|
|
404
404
|
const paper =
|
|
405
405
|
"@misc{lovelace2025,\n author={Lovelace, Ada and Hopper, Grace},\n title={A Study},\n" +
|
|
406
406
|
" note={arXiv:2503.09002},\n year={2025}}\n";
|
|
@@ -411,7 +411,7 @@ process.on("exit", () => rmSync(TMP, { recursive: true, force: true }));
|
|
|
411
411
|
);
|
|
412
412
|
built(dir);
|
|
413
413
|
writeFileSync(
|
|
414
|
-
join(dir, "repro", "refs-cache.json"),
|
|
414
|
+
join(dir, "repro", "data", "refs-cache.json"),
|
|
415
415
|
JSON.stringify({
|
|
416
416
|
"arxiv:2503.09002": {
|
|
417
417
|
httpStatus: 200,
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
* only one that returns a STRUCTURED name; with any other the surname would have to be cut out by
|
|
47
47
|
* hand, that is, we would be writing ourselves the very half that was broken.
|
|
48
48
|
*
|
|
49
|
-
* 🔴 THE CACHE IS EVIDENCE, NOT A SECOND DECLARATION. `<paper>/repro/refs-cache.json` keeps the RAW
|
|
49
|
+
* 🔴 THE CACHE IS EVIDENCE, NOT A SECOND DECLARATION. `<paper>/repro/data/refs-cache.json` keeps the RAW
|
|
50
50
|
* BODIES of the registries' responses and is committed (for `<paper-a>` it has been in git since
|
|
51
51
|
* 16.08). It cannot be made up — only refreshed from the registry. The facts in `_build/` are
|
|
52
52
|
* derived from it and from the bibliography, which is why `_build/` is in `.gitignore` while the
|
|
@@ -450,7 +450,7 @@ async function main(argv) {
|
|
|
450
450
|
const { paperDir, texts } = found;
|
|
451
451
|
const cachePath = opt("cache")
|
|
452
452
|
? resolve(opt("cache"))
|
|
453
|
-
: join(paperDir, "repro", "refs-cache.json");
|
|
453
|
+
: join(paperDir, "repro", "data", "refs-cache.json");
|
|
454
454
|
const out = opt("out")
|
|
455
455
|
? resolve(opt("out"))
|
|
456
456
|
: join(paperDir, "_build", "refs.facts.json");
|
|
@@ -236,7 +236,9 @@ test("online: hits are fetched and cached, a transport failure is named and stay
|
|
|
236
236
|
stdout: r.stdout,
|
|
237
237
|
stderr: r.stderr,
|
|
238
238
|
cached: Object.keys(
|
|
239
|
-
JSON.parse(
|
|
239
|
+
JSON.parse(
|
|
240
|
+
readFileSync(join(root, "paper/repro/data/refs-cache.json")),
|
|
241
|
+
),
|
|
240
242
|
),
|
|
241
243
|
},
|
|
242
244
|
{
|
|
@@ -265,7 +267,7 @@ test("the paper file itself as the target, with --cache, --out and --offline", (
|
|
|
265
267
|
const r = cli([
|
|
266
268
|
join(root, "paper/refs.bib"),
|
|
267
269
|
"--offline",
|
|
268
|
-
`--cache=${join(root, "paper/repro/refs-cache.json")}`,
|
|
270
|
+
`--cache=${join(root, "paper/repro/data/refs-cache.json")}`,
|
|
269
271
|
`--out=${join(root, "out/facts.json")}`,
|
|
270
272
|
]);
|
|
271
273
|
assert.deepEqual(r, {
|
|
@@ -79,8 +79,13 @@ function fixture({ scripts = {}, allow = null, bundle = {}, at = "repro" }) {
|
|
|
79
79
|
mkdirSync(join(d, at, "artifact-anon", dirname(p)), { recursive: true });
|
|
80
80
|
writeFileSync(join(d, at, "artifact-anon", p), src);
|
|
81
81
|
}
|
|
82
|
-
if (allow !== null)
|
|
83
|
-
|
|
82
|
+
if (allow !== null) {
|
|
83
|
+
mkdirSync(join(d, at, "tools"), { recursive: true });
|
|
84
|
+
writeFileSync(
|
|
85
|
+
join(d, at, "tools", "generated-code-grandfathered.txt"),
|
|
86
|
+
allow,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
84
89
|
return d;
|
|
85
90
|
}
|
|
86
91
|
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
* 🔴 AND THE SAME FALSE-POSITIVE DISCIPLINE AS THE REVERSE COVERAGE LEG. `repro/` is mostly not
|
|
43
43
|
* analysis code, so an ignore set is unavoidable — and an ignore set applied in silence is how a
|
|
44
44
|
* check becomes a green light. Every structural rule prints the names it swallowed, and
|
|
45
|
-
* `repro/generated-code-grandfathered.txt` prints every row and every reason, on every run,
|
|
45
|
+
* `repro/tools/generated-code-grandfathered.txt` prints every row and every reason, on every run,
|
|
46
46
|
* findings or none. Same reasoning as `check_grandfather` in `repro/paper_numbers.py`.
|
|
47
47
|
*/
|
|
48
48
|
import { readFileSync, existsSync, readdirSync, statSync } from "node:fs";
|
|
@@ -97,8 +97,12 @@ const repro = roots[0];
|
|
|
97
97
|
// model synthesised and is the most literal reading of "generated code" there is. Below that are
|
|
98
98
|
// fixtures, working clones and raw transcripts; going deeper buys tens of thousands of files and no
|
|
99
99
|
// analysis. This is a SCOPE and therefore a blind spot, and it is printed as one.
|
|
100
|
+
// `repro/tools/` (the paper's shared scripts, by the repro/ layout) is a root of its own: the layout
|
|
101
|
+
// moved `repro/<pkg>/src/…` to `repro/tools/<pkg>/src/…`, and counting tools/ as a level would have
|
|
102
|
+
// dropped that code out of the scan.
|
|
100
103
|
const EXT = /\.(py|mjs|cjs|js)$/;
|
|
101
104
|
const MAX_DEPTH = 3;
|
|
105
|
+
const TOOLS_DIR = "tools";
|
|
102
106
|
const swallowed = new Map([
|
|
103
107
|
[
|
|
104
108
|
"the released bundle — `check-anon.sh` cat. 5 owns it, and it asks a different question there " +
|
|
@@ -155,13 +159,13 @@ const files = [];
|
|
|
155
159
|
swallowed.get(RULE[2]).push(relative(repro, p));
|
|
156
160
|
continue;
|
|
157
161
|
}
|
|
158
|
-
walk(p, depth + 1);
|
|
162
|
+
walk(p, abs === repro && name === TOOLS_DIR ? depth : depth + 1);
|
|
159
163
|
} else if (EXT.test(name)) files.push(p);
|
|
160
164
|
}
|
|
161
165
|
})(repro, 1);
|
|
162
166
|
|
|
163
167
|
// ── the allow file ─────────────────────────────────────────────────────────────────────────────
|
|
164
|
-
const allowPath = join(repro, "generated-code-grandfathered.txt");
|
|
168
|
+
const allowPath = join(repro, TOOLS_DIR, "generated-code-grandfathered.txt");
|
|
165
169
|
const allowed = new Map();
|
|
166
170
|
if (existsSync(allowPath)) {
|
|
167
171
|
for (const line of readFileSync(allowPath, "utf8").split("\n")) {
|
|
@@ -305,7 +309,7 @@ for (const [rule, names] of swallowed) {
|
|
|
305
309
|
);
|
|
306
310
|
}
|
|
307
311
|
ledger.push(
|
|
308
|
-
` • ${ignored.length} row(s) in repro/generated-code-grandfathered.txt — every row, every reason:`,
|
|
312
|
+
` • ${ignored.length} row(s) in repro/tools/generated-code-grandfathered.txt — every row, every reason:`,
|
|
309
313
|
);
|
|
310
314
|
for (const [key, reason] of ignored) ledger.push(` ${key} → ${reason}`);
|
|
311
315
|
if (!ignored.length) ledger.push(" (nothing is being waved through)");
|
|
@@ -46,7 +46,7 @@ test("repro/: a dangling link is passed over; skipped trees are named, more than
|
|
|
46
46
|
"repro/__pycache__/x.py": "",
|
|
47
47
|
// Draws randomness unseeded: a NO_SEED finding, which the reasonless row below waves through.
|
|
48
48
|
"repro/exp/run.py": "import random\nprint(random.random())\n",
|
|
49
|
-
"repro/generated-code-grandfathered.txt": "exp/run.py\t*\n",
|
|
49
|
+
"repro/tools/generated-code-grandfathered.txt": "exp/run.py\t*\n",
|
|
50
50
|
});
|
|
51
51
|
symlinkSync(join(root, "gone"), join(dir, "repro", "dangling.py"));
|
|
52
52
|
const out = run(dir).stdout;
|
|
@@ -60,3 +60,17 @@ test("repro/: a dangling link is passed over; skipped trees are named, more than
|
|
|
60
60
|
);
|
|
61
61
|
assert.match(out, / {7}exp\/run\.py · NO_SEED {2}→ {2}\(NO REASON GIVEN\)/);
|
|
62
62
|
});
|
|
63
|
+
|
|
64
|
+
test("🔴 shared code under repro/tools/ is scanned as deep as a study's: tools/ is a root of its own, not a level of the scan", () => {
|
|
65
|
+
const dir = writeTree(join(root, "paper-tools"), {
|
|
66
|
+
// `repro/<pkg>/src/check.py` was scanned before the layout moved shared code under tools/.
|
|
67
|
+
"repro/tools/pkg/src/check.py": "import random\nprint(random.random())\n",
|
|
68
|
+
"repro/tools/pkg/src/deeper/x.py": "print(1)\n",
|
|
69
|
+
});
|
|
70
|
+
const out = run(dir).stdout;
|
|
71
|
+
assert.match(out, /NO_SEED {3}repro\/tools\/pkg\/src\/check\.py — /);
|
|
72
|
+
assert.match(
|
|
73
|
+
out,
|
|
74
|
+
/• 1 tree\(s\) not entered — nested deeper than 3 levels[^\n]*\n {7}tools\/pkg\/src\/deeper/,
|
|
75
|
+
);
|
|
76
|
+
});
|
|
@@ -4,7 +4,7 @@ description: Answer "what's the status of the paper?" in one pass — MEASURE wh
|
|
|
4
4
|
allowed-tools: [Bash, Read, Grep, Glob]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- vigiles:sha256:
|
|
7
|
+
<!-- vigiles:sha256:c28cf2904fc2aaeb compiled from skills/paper-status/SKILL.md.spec.ts -->
|
|
8
8
|
|
|
9
9
|
# paper-status — state, measured before it is narrated
|
|
10
10
|
|
|
@@ -51,7 +51,7 @@ status; the status is what that measurement makes possible next.
|
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
53
|
cd <paper-dir>
|
|
54
|
-
bash repro/build-submission.sh 2>&1 | grep -Ei 'body pages|VERDICT|Overfull|undefined|anonymity'
|
|
54
|
+
bash repro/tools/build-submission.sh 2>&1 | grep -Ei 'body pages|VERDICT|Overfull|undefined|anonymity'
|
|
55
55
|
git status --porcelain # uncommitted work
|
|
56
56
|
git log --oneline @{u}..HEAD # unpushed commits
|
|
57
57
|
```
|
|
@@ -57,7 +57,7 @@ status; the status is what that measurement makes possible next.
|
|
|
57
57
|
|
|
58
58
|
\`\`\`bash
|
|
59
59
|
cd <paper-dir>
|
|
60
|
-
bash repro/build-submission.sh 2>&1 | grep -Ei 'body pages|VERDICT|Overfull|undefined|anonymity'
|
|
60
|
+
bash repro/tools/build-submission.sh 2>&1 | grep -Ei 'body pages|VERDICT|Overfull|undefined|anonymity'
|
|
61
61
|
git status --porcelain # uncommitted work
|
|
62
62
|
git log --oneline @{u}..HEAD # unpushed commits
|
|
63
63
|
\`\`\`
|
|
@@ -1,51 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* plan-paper-timeline — the EFFECTS tier. What the run
|
|
3
|
-
* SKILL.md says it
|
|
2
|
+
* plan-paper-timeline — the EFFECTS tier. What the run actually does, not what
|
|
3
|
+
* SKILL.md says it does.
|
|
4
4
|
*
|
|
5
5
|
* SIBLING, NOT REPLACEMENT. `plan-paper-timeline.harness.mjs` next door is static
|
|
6
6
|
* (`checkSkill()`): frontmatter, wiring, script paths, verdict vocabulary. It is untouched.
|
|
7
7
|
* This file runs the REAL `claude` CLI against a SCRIPTED MOCK MODEL (`runHarnessTest`),
|
|
8
|
-
* so it costs $0 and no API key
|
|
9
|
-
* cannot: whether the tools this skill DECLARES EXIST WHERE IT RUNS.
|
|
8
|
+
* so it costs $0 and no API key.
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* declared entries are MCP calendar tools. A declaration naming a tool that is not there is
|
|
15
|
-
* invisible to every static check in this repo and to `vigiles audit`, which scores this
|
|
16
|
-
* corpus Structure 100.
|
|
10
|
+
* Run A: the skill activates, its body reaches the model, and a declared, granted tool
|
|
11
|
+
* (`Read`) works. Run B: §3's prescribed `create_event` call, parsed out of SKILL.md,
|
|
12
|
+
* replayed against a strict calendar double.
|
|
17
13
|
*
|
|
18
|
-
* ──
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* ── WHAT THIS PINS (a characterization test, deliberately) ───────────────────────
|
|
27
|
-
* Under `claude -p` at `CHARACTERIZED_CLI` (`lib/agent-cli-version.mjs`, 2.1.227) the whole
|
|
28
|
-
* `mcp__*` surface is ABSENT, and so is `ToolSearch`.
|
|
29
|
-
*
|
|
30
|
-
* 🔴 THAT NUMBER IS A VALUE, NOT PROSE, and it was prose until issue #7. The probe below used
|
|
31
|
-
* to run with `stdio: "ignore"`, so the version the CLI printed was never read — this tier
|
|
32
|
-
* characterized whatever the runner installed that day while this paragraph kept saying 2.1.227.
|
|
33
|
-
* Measured: 2.1.273 on the reporter's machine and on this one, forty-six patch releases of drift
|
|
34
|
-
* that nothing in a green log could show. The version is now OBSERVED, reported in the summary
|
|
35
|
-
* below, and named in every failure message — so a red says which version it characterized.
|
|
36
|
-
* That means:
|
|
37
|
-
* 1. §3 of this skill is UNEXECUTABLE in any headless / CI context. It is an
|
|
38
|
-
* interactive-session-only step. Nothing in the file says so.
|
|
39
|
-
* 2. 🔴 THE RECORDED `ToolSearch` FINDING DOES NOT REPRODUCE HERE, AND THE CORRECTION
|
|
40
|
-
* MATTERS. `.claude/lib/skill-effects-results/README.md` (2026-08-10, $0.82)
|
|
41
|
-
* recorded "the model called ToolSearch … it isn't in allowed-tools," with the caveat
|
|
42
|
-
* that it might be an artifact of the headless environment. It is the opposite:
|
|
43
|
-
* headless has NO ToolSearch to call. Adding `ToolSearch` to `allowed-tools` would
|
|
44
|
-
* therefore fix nothing here. The reachability of these four tools is a property of
|
|
45
|
-
* the ENVIRONMENT, not of the declaration.
|
|
46
|
-
*
|
|
47
|
-
* If either fact changes, this file fails and says which one — that is its whole job.
|
|
48
|
-
* It is not asserting that absence is good.
|
|
14
|
+
* ── WHY RUN A NO LONGER PROBES THE CALENDAR ─────────────────────────────────────
|
|
15
|
+
* It used to call `mcp__Google_Calendar__list_events` and `ToolSearch` and pin "No such
|
|
16
|
+
* tool available" as a finding about headless runs. It was a finding about the FIXTURE:
|
|
17
|
+
* the run happens in an empty `mkdtemp` with no MCP server configured, so the calendar
|
|
18
|
+
* tool is missing by construction, whatever the CLI can do. vigiles 38 refuses a
|
|
19
|
+
* scripted call to a tool the CLI does not have, for exactly this reason. Run B is
|
|
20
|
+
* where the calendar step is tested, with the surface supplied.
|
|
49
21
|
*
|
|
50
22
|
* Cost: $0 (scripted mock model, no API key). Wall clock ~30-60s for one CLI spawn.
|
|
51
23
|
*/
|
|
@@ -114,37 +86,19 @@ const r = await runHarnessTest({
|
|
|
114
86
|
transcript: true,
|
|
115
87
|
timeoutMs: 180_000,
|
|
116
88
|
prompt: "plan the AISec timeline",
|
|
117
|
-
// The SESSION grant
|
|
118
|
-
|
|
119
|
-
// a control and a measurement inside ONE permission configuration.
|
|
120
|
-
allowedTools: ["Read", "Write", "Skill", "ToolSearch", ...declaredMcp],
|
|
89
|
+
// The SESSION grant: the tools the script below calls, and no others.
|
|
90
|
+
allowedTools: ["Read", "Skill"],
|
|
121
91
|
files: { "cfp.md": "AISec 2026 — submission 24 Jul AoE\n" },
|
|
122
92
|
model: [
|
|
123
93
|
{ tool: "Skill", input: { skill: "plan-paper-timeline" } },
|
|
124
|
-
// CONTROL: a tool that is present and permitted.
|
|
125
|
-
// verdict below would be a broken run, not a finding.
|
|
94
|
+
// CONTROL: a tool that is present and permitted.
|
|
126
95
|
{ tool: "Read", input: { file_path: "cfp.md" } },
|
|
127
|
-
// READ-ONLY calendar probe. Never create_event / update_event — see header.
|
|
128
|
-
{
|
|
129
|
-
tool: "mcp__Google_Calendar__list_events",
|
|
130
|
-
input: { calendarId: "primary" },
|
|
131
|
-
},
|
|
132
|
-
// The tool the 2026-08-10 sweep said was missing from the declaration.
|
|
133
|
-
{
|
|
134
|
-
tool: "ToolSearch",
|
|
135
|
-
input: {
|
|
136
|
-
query: "select:mcp__Google_Calendar__create_event",
|
|
137
|
-
max_results: 1,
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
96
|
{ text: "done" },
|
|
141
97
|
],
|
|
142
98
|
});
|
|
143
99
|
|
|
144
100
|
try {
|
|
145
101
|
const call = (name) => r.toolCalls.find((c) => c.name === name);
|
|
146
|
-
const absent = (c) =>
|
|
147
|
-
c !== undefined && c.isError && /No such tool available/.test(c.resultText);
|
|
148
102
|
|
|
149
103
|
// ── 1. The run actually happened and the skill actually loaded ──────────────────
|
|
150
104
|
// Asserted FIRST and separately from everything below. A confident "nothing was
|
|
@@ -172,48 +126,14 @@ try {
|
|
|
172
126
|
throw new Error(
|
|
173
127
|
`POSITIVE CONTROL FAILED: Read — a tool this skill declares and the session grants — ` +
|
|
174
128
|
`did not succeed (${ctrl ? ctrl.resultText.slice(0, 160) : "never called"}). ` +
|
|
175
|
-
`
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
// ── 2. The pinned environment fact: the declared MCP surface is not there ───────
|
|
179
|
-
const cal = call("mcp__Google_Calendar__list_events");
|
|
180
|
-
if (!absent(cal))
|
|
181
|
-
throw new Error(
|
|
182
|
-
`THE ENVIRONMENT CHANGED — and this is good news that must be read, not silenced. ` +
|
|
183
|
-
`Observed \`claude\` ${cli.version} (characterized against ${cli.characterized}). ` +
|
|
184
|
-
`\`mcp__Google_Calendar__list_events\` is now REACHABLE from \`claude -p\` ` +
|
|
185
|
-
`(result: ${cal ? cal.resultText.slice(0, 200) : "no call recorded"}). ` +
|
|
186
|
-
`Consequences: (a) §3 of this skill is now executable headlessly, so it can finally be ` +
|
|
187
|
-
`tested for real instead of characterized; (b) 🔴 every future run of this tier can now ` +
|
|
188
|
-
`WRITE A REAL CALENDAR — re-check the safety argument in this file's header BEFORE ` +
|
|
189
|
-
`adding a create_event probe; (c) update this assertion deliberately, do not delete it.`,
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
const ts = call("ToolSearch");
|
|
193
|
-
if (!absent(ts))
|
|
194
|
-
throw new Error(
|
|
195
|
-
`\`ToolSearch\` is now available under \`claude -p\` ${cli.version} ` +
|
|
196
|
-
`(characterized against ${cli.characterized}) (result: ` +
|
|
197
|
-
`${ts ? ts.resultText.slice(0, 200) : "no call recorded"}). The 2026-08-10 sweep recorded ` +
|
|
198
|
-
`"ToolSearch missing from allowed-tools" as a finding about THIS SKILL; measured on ` +
|
|
199
|
-
`2026-08-11 it was a fact about the ENVIRONMENT (headless had no ToolSearch at all). ` +
|
|
200
|
-
`If it exists now, that finding becomes actionable again: add it to allowed-tools.`,
|
|
129
|
+
`The skill loaded but the run cannot use the tools it declares.`,
|
|
201
130
|
);
|
|
202
131
|
|
|
203
|
-
// ──
|
|
132
|
+
// ── 2. The version goes in the REPORT, not only into failures ──────────────────
|
|
204
133
|
console.log(
|
|
205
134
|
`✓ plan-paper-timeline [effects]: skill activated and its body reached the model; ` +
|
|
206
135
|
`Read (declared+granted) works — the run is live.\n` +
|
|
207
|
-
|
|
208
|
-
// silently still holds is indistinguishable from one nobody re-checked, so the run says
|
|
209
|
-
// which version it held against — and says it whether or not the numbers agree.
|
|
210
|
-
` CLI: ${cli.note}\n` +
|
|
211
|
-
` PINNED: ${String(declaredMcp.length)} of its 10 declared entries are MCP calendar tools, ` +
|
|
212
|
-
`and the whole mcp__* surface is ABSENT under \`claude -p\`; \`ToolSearch\` is absent too.\n` +
|
|
213
|
-
` → §3 ("Create the calendar events") is an INTERACTIVE-SESSION-ONLY step. Nothing in ` +
|
|
214
|
-
`SKILL.md says so, and no static check can see it.\n` +
|
|
215
|
-
` → Corrects the 2026-08-10 sweep: the ToolSearch gap was environmental, not a defect ` +
|
|
216
|
-
`in this declaration.`,
|
|
136
|
+
` CLI: ${cli.note}`,
|
|
217
137
|
);
|
|
218
138
|
} finally {
|
|
219
139
|
r.cleanup();
|
|
@@ -222,9 +142,8 @@ try {
|
|
|
222
142
|
// ════════════════════════════════════════════════════════════════════════════════
|
|
223
143
|
// RUN B — §3 EXECUTED, not characterized
|
|
224
144
|
//
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
// checked by anything. Run B supplies the surface with a stand-in
|
|
145
|
+
// A headless run in an empty work dir has no calendar surface, so without a stand-in
|
|
146
|
+
// the skill's CENTRAL STEP is checked by nothing. Run B supplies the surface with a stand-in
|
|
228
147
|
// (`fixtures/fake-google-calendar.ts`) carrying the REAL API's required-field sets,
|
|
229
148
|
// so the step becomes executable for the first time.
|
|
230
149
|
//
|