paperlint 3.1.3 → 4.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/workflows/ci.yml +12 -7
- package/CLAUDE.md +5 -5
- package/CONTRIBUTING.md +34 -5
- package/dist/adapters/banal/failure.d.ts +1 -7
- package/dist/adapters/banal/failure.d.ts.map +1 -1
- package/dist/adapters/banal/failure.js +5 -7
- package/dist/adapters/banal/failure.js.map +1 -1
- package/dist/adapters/banal/index.d.ts.map +1 -1
- package/dist/adapters/banal/index.js +4 -3
- package/dist/adapters/banal/index.js.map +1 -1
- package/dist/adapters/banal/install.d.ts.map +1 -1
- package/dist/adapters/banal/install.js +4 -3
- package/dist/adapters/banal/install.js.map +1 -1
- package/dist/adapters/banal/invocation.d.ts +10 -5
- package/dist/adapters/banal/invocation.d.ts.map +1 -1
- package/dist/adapters/banal/invocation.js +13 -1
- package/dist/adapters/banal/invocation.js.map +1 -1
- package/dist/adapters/banal/locate.d.ts +12 -9
- package/dist/adapters/banal/locate.d.ts.map +1 -1
- package/dist/adapters/banal/locate.js +19 -12
- package/dist/adapters/banal/locate.js.map +1 -1
- package/dist/adapters/banal/run.d.ts +10 -1
- package/dist/adapters/banal/run.d.ts.map +1 -1
- package/dist/adapters/banal/run.js +8 -4
- package/dist/adapters/banal/run.js.map +1 -1
- package/dist/adapters/banal/settings.d.ts +1 -1
- package/dist/adapters/banal/settings.d.ts.map +1 -1
- package/dist/adapters/banal/settings.js +2 -1
- package/dist/adapters/banal/settings.js.map +1 -1
- package/dist/adapters/memory/index.d.ts.map +1 -1
- package/dist/adapters/memory/index.js +8 -2
- package/dist/adapters/memory/index.js.map +1 -1
- package/dist/adapters/node/files.io.d.ts.map +1 -1
- package/dist/adapters/node/files.io.js +2 -1
- package/dist/adapters/node/files.io.js.map +1 -1
- package/dist/adapters/node/process.io.d.ts +5 -7
- package/dist/adapters/node/process.io.d.ts.map +1 -1
- package/dist/adapters/node/process.io.js +4 -3
- package/dist/adapters/node/process.io.js.map +1 -1
- package/dist/adapters/node/workspace.io.d.ts.map +1 -1
- package/dist/adapters/node/workspace.io.js +4 -2
- package/dist/adapters/node/workspace.io.js.map +1 -1
- package/dist/adapters/pdfjs/fill.d.ts.map +1 -1
- package/dist/adapters/pdfjs/fill.js +13 -7
- package/dist/adapters/pdfjs/fill.js.map +1 -1
- package/dist/adapters/references/index.d.ts.map +1 -1
- package/dist/adapters/references/index.js +8 -7
- package/dist/adapters/references/index.js.map +1 -1
- package/dist/adapters/references/pool.d.ts.map +1 -1
- package/dist/adapters/references/pool.js +4 -5
- package/dist/adapters/references/pool.js.map +1 -1
- package/dist/adapters/references/reach.io.d.ts.map +1 -1
- package/dist/adapters/references/reach.io.js +2 -1
- package/dist/adapters/references/reach.io.js.map +1 -1
- package/dist/build-engine.d.ts +1 -1
- package/dist/build-engine.d.ts.map +1 -1
- package/dist/build-engine.js +10 -3
- package/dist/build-engine.js.map +1 -1
- package/dist/build.d.ts +2 -3
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +19 -17
- package/dist/build.js.map +1 -1
- package/dist/caller-path.d.ts +3 -0
- package/dist/caller-path.d.ts.map +1 -0
- package/dist/caller-path.js +13 -0
- package/dist/caller-path.js.map +1 -0
- package/dist/cli.d.ts +10 -17
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +93 -46
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts +12 -3
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +5 -3
- package/dist/doctor.js.map +1 -1
- package/dist/domain/lookup-cache.d.ts.map +1 -1
- package/dist/domain/lookup-cache.js +10 -8
- package/dist/domain/lookup-cache.js.map +1 -1
- package/dist/domain/paths.d.ts +8 -2
- package/dist/domain/paths.d.ts.map +1 -1
- package/dist/domain/paths.js +12 -1
- package/dist/domain/paths.js.map +1 -1
- package/dist/domain/ready.d.ts +24 -0
- package/dist/domain/ready.d.ts.map +1 -0
- package/dist/domain/ready.js +11 -0
- package/dist/domain/ready.js.map +1 -0
- package/dist/domain/record.d.ts +8 -0
- package/dist/domain/record.d.ts.map +1 -0
- package/dist/domain/record.js +8 -0
- package/dist/domain/record.js.map +1 -0
- package/dist/domain/sha256.d.ts.map +1 -1
- package/dist/domain/sha256.js +4 -2
- package/dist/domain/sha256.js.map +1 -1
- package/dist/domain/text.d.ts +12 -0
- package/dist/domain/text.d.ts.map +1 -1
- package/dist/domain/text.js +17 -0
- package/dist/domain/text.js.map +1 -1
- package/dist/engine.d.ts +23 -22
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +4 -3
- package/dist/engine.js.map +1 -1
- package/dist/eslint-rules/bib-reachable-entry.d.ts +22 -0
- package/dist/eslint-rules/bib-reachable-entry.d.ts.map +1 -0
- package/dist/eslint-rules/bib-reachable-entry.js +75 -0
- package/dist/eslint-rules/bib-reachable-entry.js.map +1 -0
- package/dist/eslint-rules/install-path-literals.d.ts +80 -0
- package/dist/eslint-rules/install-path-literals.d.ts.map +1 -0
- package/dist/eslint-rules/install-path-literals.js +105 -0
- package/dist/eslint-rules/install-path-literals.js.map +1 -0
- package/dist/eslint-rules/latex-language.d.ts +136 -0
- package/dist/eslint-rules/latex-language.d.ts.map +1 -0
- package/dist/eslint-rules/latex-language.js +639 -0
- package/dist/eslint-rules/latex-language.js.map +1 -0
- package/dist/eslint-rules/paper-research-question.d.ts +31 -0
- package/dist/eslint-rules/paper-research-question.d.ts.map +1 -0
- package/dist/eslint-rules/paper-research-question.js +188 -0
- package/dist/eslint-rules/paper-research-question.js.map +1 -0
- package/dist/eslint-rules/paper-stages.d.ts +83 -0
- package/dist/eslint-rules/paper-stages.d.ts.map +1 -0
- package/dist/eslint-rules/paper-stages.js +358 -0
- package/dist/eslint-rules/paper-stages.js.map +1 -0
- package/dist/eslint-rules/paper-typography.d.ts +74 -0
- package/dist/eslint-rules/paper-typography.d.ts.map +1 -0
- package/dist/eslint-rules/paper-typography.js +404 -0
- package/dist/eslint-rules/paper-typography.js.map +1 -0
- package/dist/eslint-rules/papers.d.ts +42 -0
- package/dist/eslint-rules/papers.d.ts.map +1 -0
- package/dist/eslint-rules/papers.js +145 -0
- package/dist/eslint-rules/papers.js.map +1 -0
- package/dist/eslint-rules/pdf-last-page-balance.d.ts +72 -0
- package/dist/eslint-rules/pdf-last-page-balance.d.ts.map +1 -0
- package/dist/eslint-rules/pdf-last-page-balance.js +237 -0
- package/dist/eslint-rules/pdf-last-page-balance.js.map +1 -0
- package/dist/eslint-rules/review-frontmatter.d.ts +57 -0
- package/dist/eslint-rules/review-frontmatter.d.ts.map +1 -0
- package/dist/eslint-rules/review-frontmatter.js +126 -0
- package/dist/eslint-rules/review-frontmatter.js.map +1 -0
- package/dist/eslint-rules/review-frontmatter.schema.json +36 -0
- package/dist/eslint-rules/rule-context.d.ts +55 -0
- package/dist/eslint-rules/rule-context.d.ts.map +1 -0
- package/dist/eslint-rules/rule-context.js +9 -0
- package/dist/eslint-rules/rule-context.js.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.d.ts +25 -0
- package/dist/eslint-rules/sibling-frontmatter.d.ts.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.js +16 -0
- package/dist/eslint-rules/sibling-frontmatter.js.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.schema.json +14 -0
- package/dist/eslint-rules/temp-root-realpath.d.ts +71 -0
- package/dist/eslint-rules/temp-root-realpath.d.ts.map +1 -0
- package/dist/eslint-rules/temp-root-realpath.js +139 -0
- package/dist/eslint-rules/temp-root-realpath.js.map +1 -0
- package/dist/eslint-rules/tex-build.d.ts +35 -0
- package/dist/eslint-rules/tex-build.d.ts.map +1 -0
- package/dist/eslint-rules/tex-build.js +313 -0
- package/dist/eslint-rules/tex-build.js.map +1 -0
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +31 -27
- package/dist/facts-file.js.map +1 -1
- package/dist/hooks-settings.d.ts +1 -1
- package/dist/hooks-settings.d.ts.map +1 -1
- package/dist/hooks-settings.js +31 -11
- package/dist/hooks-settings.js.map +1 -1
- package/dist/init.d.ts +8 -9
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +33 -15
- package/dist/init.js.map +1 -1
- package/dist/latex-loop.d.ts +2 -2
- package/dist/latex-loop.d.ts.map +1 -1
- package/dist/latex-loop.js +2 -2
- package/dist/latex-loop.js.map +1 -1
- package/dist/lib/agent-cli-version.d.ts +65 -0
- package/dist/lib/agent-cli-version.d.ts.map +1 -0
- package/dist/lib/agent-cli-version.js +77 -0
- package/dist/lib/agent-cli-version.js.map +1 -0
- package/dist/lib/check.d.ts +19 -0
- package/dist/lib/check.d.ts.map +1 -0
- package/dist/lib/check.js +52 -0
- package/dist/lib/check.js.map +1 -0
- package/dist/lib/markdown.d.ts +180 -0
- package/dist/lib/markdown.d.ts.map +1 -0
- package/dist/lib/markdown.js +302 -0
- package/dist/lib/markdown.js.map +1 -0
- package/dist/lib/paper-config.d.ts +84 -0
- package/dist/lib/paper-config.d.ts.map +1 -0
- package/dist/lib/paper-config.js +138 -0
- package/dist/lib/paper-config.js.map +1 -0
- package/dist/lib/skill-eval-fixture.d.ts +29 -0
- package/dist/lib/skill-eval-fixture.d.ts.map +1 -0
- package/dist/lib/skill-eval-fixture.js +62 -0
- package/dist/lib/skill-eval-fixture.js.map +1 -0
- package/dist/link-skills.d.ts.map +1 -1
- package/dist/link-skills.js +5 -4
- package/dist/link-skills.js.map +1 -1
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +7 -3
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-files.d.ts +4 -4
- package/dist/paper-files.d.ts.map +1 -1
- package/dist/paper-files.js +6 -6
- package/dist/paper-files.js.map +1 -1
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +8 -7
- package/dist/paper-settings.js.map +1 -1
- package/dist/pdf-facts.d.ts +51 -1
- package/dist/pdf-facts.d.ts.map +1 -1
- package/dist/pdf-facts.js +25 -16
- package/dist/pdf-facts.js.map +1 -1
- package/dist/pdf-geometry.d.ts.map +1 -1
- package/dist/pdf-geometry.js +3 -4
- package/dist/pdf-geometry.js.map +1 -1
- package/dist/ports/tool-installer.d.ts +2 -14
- package/dist/ports/tool-installer.d.ts.map +1 -1
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +19 -6
- package/dist/presets.js.map +1 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +15 -10
- package/dist/references.js.map +1 -1
- package/dist/rules-config.d.ts +26 -1
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +15 -12
- package/dist/rules-config.js.map +1 -1
- package/dist/structure.js +1 -1
- package/dist/structure.js.map +1 -1
- package/dist/tex-requirements.d.ts +4 -0
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +22 -5
- package/dist/tex-requirements.js.map +1 -1
- package/dist/toolchain.d.ts.map +1 -1
- package/dist/toolchain.js +21 -16
- package/dist/toolchain.js.map +1 -1
- package/dist/types.d.ts +5 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/venue-rules.d.ts.map +1 -1
- package/dist/venue-rules.js +21 -8
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +2 -2
- package/docs/e2e.md +7 -7
- package/docs/install.md +1 -1
- package/docs/prior-art/README.md +1 -1
- package/docs/prior-art/package-location.md +5 -5
- package/docs/prior-art/repro/README.md +1 -1
- package/docs/prior-art/test-tooling.md +2 -2
- package/docs/testing.md +11 -8
- package/docs/toolchain.md +1 -1
- package/eslint-rules/{bib-reachable-entry.mjs → bib-reachable-entry.ts} +5 -4
- package/eslint-rules/install-path-literals.harness.mjs +1 -1
- package/eslint-rules/{install-path-literals.mjs → install-path-literals.ts} +18 -10
- package/eslint-rules/latex-language.harness.mjs +2 -2
- package/eslint-rules/latex-language.test.mjs +7 -1
- package/eslint-rules/{latex-language.mjs → latex-language.ts} +297 -109
- package/eslint-rules/paper-research-question.harness.mjs +3 -3
- package/eslint-rules/{paper-research-question.mjs → paper-research-question.ts} +35 -16
- package/eslint-rules/paper-stages.harness.mjs +2 -2
- package/eslint-rules/paper-stages.test.mjs +8 -2
- package/eslint-rules/{paper-stages.mjs → paper-stages.ts} +76 -31
- package/eslint-rules/paper-typography.test.mjs +3 -3
- package/eslint-rules/{paper-typography.mjs → paper-typography.ts} +134 -56
- package/eslint-rules/papers.harness.mjs +2 -2
- package/eslint-rules/{papers.mjs → papers.ts} +7 -4
- package/eslint-rules/pdf-last-page-balance.harness.mjs +3 -3
- package/eslint-rules/{pdf-last-page-balance.mjs → pdf-last-page-balance.ts} +89 -32
- package/eslint-rules/review-frontmatter.test.mjs +2 -2
- package/eslint-rules/{review-frontmatter.mjs → review-frontmatter.ts} +38 -16
- package/eslint-rules/rule-context.ts +62 -0
- package/eslint-rules/{sibling-frontmatter.mjs → sibling-frontmatter.ts} +1 -1
- package/eslint-rules/temp-root-realpath.harness.mjs +1 -1
- package/eslint-rules/{temp-root-realpath.mjs → temp-root-realpath.ts} +20 -7
- package/eslint-rules/tex-build.harness.mjs +2 -2
- package/eslint-rules/{tex-build.mjs → tex-build.ts} +6 -5
- package/eslint.config.mjs +146 -30
- package/fixtures/install-path-literals/clean.fixture.mjs +1 -1
- package/fixtures/install-path-literals/clean.md +2 -2
- package/fixtures/install-path-literals/defect.fixture.mjs +1 -1
- package/fixtures/install-path-literals/defect.md +2 -2
- package/fixtures/pdf-facts/README.md +2 -2
- package/fixtures/real-markdown-paper/{baseline.mjs → baseline.ts} +31 -10
- package/hooks/{hooks.harness.mjs → hooks.harness.ts} +51 -34
- package/hooks/paper-edit-guard.hook.mjs +1 -1
- package/hooks/{paper-edit-guard.test.mjs → paper-edit-guard.test.ts} +3 -7
- package/hooks/paper-skills-nudge.hook.mjs +1 -1
- package/hooks/{paper-skills-nudge.test.mjs → paper-skills-nudge.test.ts} +2 -6
- package/hooks/paper-status-gates.sh +9 -19
- package/hooks/{paper-status-gates.test.mjs → paper-status-gates.test.ts} +2 -6
- package/lib/agent-cli-version.harness.mjs +1 -1
- package/lib/{agent-cli-version.mjs → agent-cli-version.ts} +32 -18
- package/lib/check.test.ts +14 -9
- package/lib/{check.mjs → check.ts} +22 -9
- package/lib/markdown.test.mjs +7 -7
- package/lib/{markdown.mjs → markdown.ts} +68 -29
- package/lib/paper-config.harness.mjs +9 -9
- package/lib/{paper-config.mjs → paper-config.ts} +20 -19
- package/lib/skill-checks.mjs +24 -381
- package/lib/skill-checks.test.mjs +64 -116
- package/lib/skill-corpus.mjs +10 -251
- package/lib/skill-corpus.test.mjs +2 -13
- package/lib/skill-eval-kit.mjs +1 -1
- package/lib/skill-trigger-cases.mjs +1 -1
- package/package.json +42 -10
- package/scripts/{check.harness.mjs → check.harness.ts} +111 -10
- package/scripts/{check.test.mjs → check.test.ts} +13 -10
- package/scripts/{check.mjs → check.ts} +116 -42
- package/scripts/coverage-config.test.ts +80 -38
- package/scripts/eslint-report-guard.test.mjs +1 -1
- package/scripts/harness-api.frozen.json +14 -16
- package/scripts/harness-api.test.ts +8 -5
- package/scripts/layer-legacy-frozen.test.ts +17 -13
- package/scripts/{layer-legacy-frozen.mjs → layer-legacy-frozen.ts} +128 -39
- package/scripts/release-config.test.ts +12 -4
- package/scripts/rules-see-files.test.mjs +1 -1
- package/scripts/test.test.ts +78 -0
- package/scripts/test.ts +87 -0
- package/skills/analyze-sibling-paper/SKILL.md +1 -39
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +0 -38
- package/skills/argument-arc/SKILL.md +2 -36
- package/skills/argument-arc/SKILL.md.spec.ts +1 -43
- package/skills/build-benchmark/SKILL.md +1 -41
- package/skills/build-benchmark/SKILL.md.spec.ts +0 -40
- package/skills/camera-ready/SKILL.md +1 -34
- package/skills/camera-ready/SKILL.md.spec.ts +0 -33
- package/skills/cold-read-diff/SKILL.md +1 -35
- package/skills/cold-read-diff/SKILL.md.spec.ts +0 -34
- package/skills/draft-paper/SKILL.md +2 -41
- package/skills/draft-paper/SKILL.md.spec.ts +1 -50
- package/skills/extend-paper/SKILL.md +2 -33
- package/skills/extend-paper/SKILL.md.spec.ts +1 -42
- package/skills/find-venue/SKILL.md +2 -38
- package/skills/find-venue/SKILL.md.spec.ts +1 -47
- package/skills/grade-paper-writing/SKILL.md +3 -38
- package/skills/grade-paper-writing/SKILL.md.spec.ts +2 -47
- package/skills/grade-paper-writing/prose-lint.mjs +3 -4
- package/skills/grade-paper-writing/{prose-lint.test.mjs → prose-lint.test.ts} +3 -3
- package/skills/harden-paper/SKILL.md +1 -39
- package/skills/harden-paper/SKILL.md.spec.ts +0 -38
- package/skills/map-prior-work/SKILL.md +1 -35
- package/skills/map-prior-work/SKILL.md.spec.ts +0 -34
- package/skills/osf-artifact-upload/{osf-artifact-upload.harness.mjs → osf-artifact-upload.harness.ts} +3 -4
- package/skills/paper-adversarial-review/SKILL.md +2 -35
- package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -43
- package/skills/paper-pipeline/SKILL.md +2 -28
- package/skills/paper-pipeline/SKILL.md.spec.ts +1 -27
- package/skills/paper-pipeline/description-language.eval.mjs +1 -1
- package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +1 -1
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +2 -2
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +25 -40
- package/skills/paper-pipeline/pipeline-firing.eval.mjs +1 -1
- package/skills/paper-pipeline/pipeline-language.eval.mjs +1 -1
- package/skills/paper-pipeline/references/acceptance-gate.md +1 -6
- package/skills/paper-pipeline/references/pipeline-status-template.md +8 -35
- package/skills/paper-pipeline/scripts/README.md +30 -225
- package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +4 -8
- package/skills/paper-pipeline/scripts/artifact-coverage.mjs +1 -1
- package/skills/paper-pipeline/scripts/{artifact-coverage.test.mjs → artifact-coverage.test.ts} +2 -2
- package/skills/paper-pipeline/scripts/consumer.harness.mjs +6 -104
- package/skills/paper-pipeline/scripts/consumer.mjs +24 -109
- package/skills/paper-pipeline/scripts/consumer.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +1 -1
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +1 -4
- package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +2 -3
- package/skills/paper-pipeline/scripts/{generated-code.test.mjs → generated-code.test.ts} +3 -3
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +3 -3
- package/skills/paper-pipeline/scripts/population-map.mjs +1 -4
- package/skills/paper-pipeline/scripts/population-map.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/{round-diff.harness.mjs → round-diff.harness.ts} +45 -18
- package/skills/paper-pipeline/scripts/round-diff.mjs +1 -1
- package/skills/paper-pipeline/scripts/round-diff.test.mjs +1 -1
- package/skills/paper-status/SKILL.md +2 -42
- package/skills/paper-status/SKILL.md.spec.ts +1 -41
- package/skills/pc-panel-review/SKILL.md +2 -46
- package/skills/pc-panel-review/SKILL.md.spec.ts +1 -45
- package/skills/plan-paper-timeline/SKILL.md +2 -36
- package/skills/plan-paper-timeline/SKILL.md.spec.ts +0 -36
- package/skills/plan-paper-timeline/fixtures/{fake-google-calendar.mjs → fake-google-calendar.ts} +101 -70
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +3 -3
- package/skills/render-paper/SKILL.md +1 -37
- package/skills/render-paper/SKILL.md.spec.ts +0 -36
- package/skills/render-paper/{extract-pdf-facts.harness.mjs → extract-pdf-facts.harness.ts} +34 -9
- package/skills/render-paper/render-paper.harness.mjs +2 -2
- package/skills/research-ideate/SKILL.md +2 -39
- package/skills/research-ideate/SKILL.md.spec.ts +1 -47
- package/skills/study-accepted-papers/SKILL.md +1 -34
- package/skills/study-accepted-papers/SKILL.md.spec.ts +0 -33
- package/skills/submit-paper/SKILL.md +1 -33
- package/skills/submit-paper/SKILL.md.spec.ts +0 -32
- package/skills/sweep-design-space/SKILL.md +1 -38
- package/skills/sweep-design-space/SKILL.md.spec.ts +0 -37
- package/skills/tighten-paper/SKILL.md +2 -39
- package/skills/tighten-paper/SKILL.md.spec.ts +1 -47
- package/skills/tighten-paper/structure.mjs +5 -12
- package/skills/tighten-paper/{structure.test.mjs → structure.test.ts} +4 -3
- package/skills/verify-citations/SKILL.md +2 -38
- package/skills/verify-citations/SKILL.md.spec.ts +1 -37
- package/skills/verify-citations/scripts/{bib-authors.cli.test.mjs → bib-authors.cli.test.ts} +14 -4
- package/skills/verify-citations/scripts/bib-authors.d.mts +63 -0
- package/skills/verify-citations/scripts/bib-authors.mjs +1 -4
- package/skills/verify-citations/scripts/{verify-cites.cli.test.mjs → verify-cites.cli.test.ts} +32 -9
- package/skills/verify-citations/scripts/verify-cites.d.mts +58 -0
- package/src/CLAUDE.md +1 -1
- package/src/adapters/banal/failure.ts +9 -10
- package/src/adapters/banal/index.test.ts +5 -8
- package/src/adapters/banal/index.ts +8 -7
- package/src/adapters/banal/install.ts +9 -4
- package/src/adapters/banal/invocation.test.ts +23 -9
- package/src/adapters/banal/invocation.ts +24 -9
- package/src/adapters/banal/locate.test.ts +2 -2
- package/src/adapters/banal/locate.ts +27 -21
- package/src/adapters/banal/output.test.ts +1 -1
- package/src/adapters/banal/run.test.ts +5 -5
- package/src/adapters/banal/run.ts +16 -10
- package/src/adapters/banal/settings.ts +2 -2
- package/src/adapters/banal/xml.test.ts +1 -1
- package/src/adapters/curl/download.test.ts +8 -6
- package/src/adapters/memory/index.ts +4 -3
- package/src/adapters/node/files.io.ts +2 -2
- package/src/adapters/node/files.test.ts +8 -4
- package/src/adapters/node/process.io.ts +13 -5
- package/src/adapters/node/process.test.ts +5 -5
- package/src/adapters/node/workspace.io.ts +9 -4
- package/src/adapters/node/workspace.test.ts +3 -1
- package/src/adapters/pdfjs/fill.test.ts +2 -2
- package/src/adapters/pdfjs/fill.ts +14 -7
- package/src/adapters/references/index.test.ts +31 -38
- package/src/adapters/references/index.ts +33 -60
- package/src/adapters/references/pool.ts +3 -5
- package/src/adapters/references/reach.io.ts +2 -1
- package/src/build-engine.harness.mjs +1 -1
- package/src/build-engine.test.ts +13 -8
- package/src/build-engine.ts +12 -7
- package/src/build.harness.mjs +2 -2
- package/src/build.test.ts +24 -24
- package/src/build.ts +34 -26
- package/src/caller-path.ts +13 -0
- package/src/cli.harness.mjs +6 -8
- package/src/cli.test.ts +31 -13
- package/src/cli.ts +117 -58
- package/src/doctor.harness.mjs +3 -3
- package/src/doctor.test.ts +1 -1
- package/src/doctor.ts +17 -7
- package/src/domain/lookup-cache.ts +21 -11
- package/src/domain/paths.test.ts +15 -0
- package/src/domain/paths.ts +20 -1
- package/src/domain/ready.ts +31 -0
- package/src/domain/record.test.ts +20 -0
- package/src/domain/record.ts +12 -0
- package/src/domain/result.test.ts +2 -2
- package/src/domain/sha256.ts +5 -3
- package/src/domain/text.test.ts +32 -0
- package/src/domain/text.ts +23 -0
- package/src/engine.harness.mjs +2 -2
- package/src/engine.ts +34 -5
- package/src/facts-file.test.ts +9 -7
- package/src/facts-file.ts +45 -29
- package/src/{hooks-settings.harness.mjs → hooks-settings.harness.ts} +56 -20
- package/src/hooks-settings.ts +48 -13
- package/src/init.test.ts +37 -14
- package/src/init.ts +48 -24
- package/src/{latex-log.harness.mjs → latex-log.harness.ts} +14 -14
- package/src/{latex-loop.harness.mjs → latex-loop.harness.ts} +64 -36
- package/src/latex-loop.ts +3 -3
- package/src/{link-skills.harness.mjs → link-skills.harness.ts} +19 -19
- package/src/link-skills.test.ts +3 -3
- package/src/link-skills.ts +5 -4
- package/src/lint-fix.test.ts +4 -6
- package/src/linted-set.test.ts +2 -2
- package/src/new-paper.harness.mjs +9 -25
- package/src/new-paper.test.ts +8 -10
- package/src/new-paper.ts +9 -5
- package/src/paper-files.test.ts +25 -24
- package/src/paper-files.ts +16 -27
- package/src/paper-settings-commands.test.ts +5 -4
- package/src/paper-settings.test.ts +7 -7
- package/src/paper-settings.ts +13 -14
- package/src/{pdf-facts.harness.mjs → pdf-facts.harness.ts} +9 -8
- package/src/pdf-facts.test.ts +25 -15
- package/src/pdf-facts.ts +81 -23
- package/src/{pdf-geometry.harness.mjs → pdf-geometry.harness.ts} +19 -12
- package/src/pdf-geometry.ts +8 -4
- package/src/ports/tool-installer.ts +2 -17
- package/src/presets.ts +31 -16
- package/src/references.test.ts +76 -62
- package/src/references.ts +18 -12
- package/src/{rules-config.harness.mjs → rules-config.harness.ts} +7 -13
- package/src/rules-config.ts +46 -14
- package/src/rules-off.test.ts +6 -4
- package/src/{structure.harness.mjs → structure.harness.ts} +26 -15
- package/src/structure.ts +1 -1
- package/src/{tex-requirements.harness.mjs → tex-requirements.harness.ts} +50 -22
- package/src/tex-requirements.test.ts +21 -0
- package/src/tex-requirements.ts +37 -11
- package/src/toolchain.harness.mjs +2 -2
- package/src/toolchain.test.ts +10 -6
- package/src/toolchain.ts +31 -17
- package/src/types.ts +5 -3
- package/src/venue-rules.test.ts +70 -68
- package/src/venue-rules.ts +22 -12
- package/tsconfig.json +6 -3
- package/tsconfig.pkg.json +10 -0
- package/lib/check.d.mts +0 -17
- package/lib/paper-config.d.mts +0 -31
- package/scripts/layer-legacy-frozen.d.mts +0 -36
- package/scripts/rules-are-content-only.harness.mjs +0 -105
- package/scripts/rules-are-content-only.mjs +0 -148
- package/scripts/rules-are-content-only.test.mjs +0 -61
- package/scripts/test.mjs +0 -44
- package/scripts/test.test.mjs +0 -52
- package/skills/paper-pipeline/scripts/announce.mjs +0 -67
- package/skills/paper-pipeline/scripts/announce.test.mjs +0 -102
- package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +0 -51
- package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +0 -52
- package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +0 -6
- package/skills/paper-pipeline/scripts/fixtures/scorecard.mjs +0 -71
- package/skills/paper-pipeline/scripts/ledger.cli.test.mjs +0 -302
- package/skills/paper-pipeline/scripts/ledger.mjs +0 -623
- package/skills/paper-pipeline/scripts/ledger.test.mjs +0 -254
- package/skills/paper-pipeline/scripts/pipeline-check.cli.test.mjs +0 -474
- package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +0 -328
- package/skills/paper-pipeline/scripts/pipeline-check.mjs +0 -753
- package/skills/paper-pipeline/scripts/pipeline-edges.mjs +0 -169
- package/skills/paper-pipeline/scripts/pipeline-edges.test.mjs +0 -73
- package/skills/paper-pipeline/scripts/run-mechanical.mjs +0 -648
- package/skills/paper-pipeline/scripts/run-mechanical.test.mjs +0 -468
- package/skills/paper-pipeline/scripts/status.mjs +0 -295
- package/skills/paper-pipeline/scripts/status.test.mjs +0 -232
- /package/bin/{paperlint.test.mjs → paperlint.test.ts} +0 -0
- /package/lib/{skill-eval-fixture.mjs → skill-eval-fixture.ts} +0 -0
- /package/skills/grade-paper-writing/__snapshots__/{prose-lint.test.mjs.snap → prose-lint.test.ts.snap} +0 -0
- /package/skills/tighten-paper/__snapshots__/{structure.test.mjs.snap → structure.test.ts.snap} +0 -0
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A RULE MAY NOT ASK GIT.
|
|
3
|
-
*
|
|
4
|
-
* 🔴 The defect it exists for, measured 2026-09-16. `paper/source` bound a paper's stage to a
|
|
5
|
-
* commit sha and verified it with `git cat-file -e`. Of four shas recorded in the consumer's
|
|
6
|
-
* front matter, ONE still resolved ninety minutes later: a squash-merge had orphaned the branch
|
|
7
|
-
* commits and `gc` collected them. A recorded sha is a pointer to a pointer, and both hops are
|
|
8
|
-
* removed by ROUTINE maintenance — squash, rebase, gc, force-push, filter-repo. Nobody is at
|
|
9
|
-
* fault, so nobody is on the hook to fix it; the rule simply turns red and gets switched off.
|
|
10
|
-
*
|
|
11
|
-
* ── THE STRONGER LEG, AND THE REASON THIS IS A FLOOR CHECK ──────────────────
|
|
12
|
-
* `actions/checkout` defaults to `fetch-depth: 1` — exactly one commit. Measured in the
|
|
13
|
-
* consumer the same day: six checkouts, not one override. So a git-reading rule does not
|
|
14
|
-
* resolve even a LIVE sha under CI, which is the one place it has to hold. Locally it stays
|
|
15
|
-
* green, so the failure is one-directional and in the flattering direction.
|
|
16
|
-
*
|
|
17
|
-
* ── WHAT IT CHECKS, AND WHY NOT A GREP ──────────────────────────────────────
|
|
18
|
-
* A `child_process` spawner called with `git` as the program, read from the AST. Parsed, not
|
|
19
|
-
* grepped, so the words `git cat-file` in this very comment are not a finding — a text guard
|
|
20
|
-
* would have to exempt itself, which is the failure mode that makes text guards unmaintainable.
|
|
21
|
-
*
|
|
22
|
-
* ⚠️ THE BOUND, stated so the check is not mistaken for more than it is. Two things pass: a
|
|
23
|
-
* rule that opens `.git/` with `fs` (indistinguishable at this level from reading a data file),
|
|
24
|
-
* and a rule that assembles the program name at runtime. Both accepted deliberately — see the
|
|
25
|
-
* note on `SPAWNERS` for the false positive that forced the predicate this narrow.
|
|
26
|
-
*
|
|
27
|
-
* Run: `node scripts/rules-are-content-only.mjs` (exit 1 and a named rule on a finding)
|
|
28
|
-
* Tested by: `scripts/rules-are-content-only.harness.mjs` — quiet on the real corpus, firing on
|
|
29
|
-
* a planted rule.
|
|
30
|
-
*/
|
|
31
|
-
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
32
|
-
import { join } from "node:path";
|
|
33
|
-
import { parse } from "espree";
|
|
34
|
-
import { isMain } from "../skills/paper-pipeline/scripts/consumer.mjs";
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 🔴 THE PREDICATE IS "RUNS GIT", NOT "SPAWNS A PROCESS", and the narrowing was forced by a
|
|
38
|
-
* FALSE POSITIVE on the consumer's corpus the hour this check shipped: `paper-texcount.mjs`
|
|
39
|
-
* shells out to `texcount` to count words in a .tex, which is a measuring tool, not history.
|
|
40
|
-
* A false positive on an `error` gate is worse than a miss — the gate that cannot be cleared
|
|
41
|
-
* gets switched off, and this one would have been switched off on its first run.
|
|
42
|
-
*
|
|
43
|
-
* ⚠️ THE COST OF NARROWING, stated rather than hidden: a rule that builds the program name at
|
|
44
|
-
* runtime (`const g = "gi" + "t"`) passes. That is accepted. The defect has taken exactly one
|
|
45
|
-
* form — a literal `git` handed to a `child_process` function — and a check that also caught
|
|
46
|
-
* the contrived form would have to claim every spawn, which is the false positive above.
|
|
47
|
-
*/
|
|
48
|
-
const SPAWNERS = new Set([
|
|
49
|
-
"exec",
|
|
50
|
-
"execSync",
|
|
51
|
-
"execFile",
|
|
52
|
-
"execFileSync",
|
|
53
|
-
"spawn",
|
|
54
|
-
"spawnSync",
|
|
55
|
-
"fork",
|
|
56
|
-
]);
|
|
57
|
-
|
|
58
|
-
/** `"git"` as the program, or `"git …"` as the head of a shell line handed to `exec`. */
|
|
59
|
-
const isGit = (v) =>
|
|
60
|
-
typeof v === "string" && (v === "git" || v.startsWith("git "));
|
|
61
|
-
|
|
62
|
-
/** Rule sources only: a harness plants defects on purpose and asserts about them. */
|
|
63
|
-
const isRuleSource = (f) => f.endsWith(".mjs") && !f.endsWith(".harness.mjs");
|
|
64
|
-
|
|
65
|
-
/** @param {string} src @returns {string[]} the git invocations this source makes */
|
|
66
|
-
export function processImports(src) {
|
|
67
|
-
const ast = parse(src, {
|
|
68
|
-
ecmaVersion: "latest",
|
|
69
|
-
sourceType: "module",
|
|
70
|
-
range: false,
|
|
71
|
-
});
|
|
72
|
-
const found = [];
|
|
73
|
-
const walk = (n) => {
|
|
74
|
-
if (n === null || typeof n !== "object") return;
|
|
75
|
-
if (Array.isArray(n)) return n.forEach(walk);
|
|
76
|
-
// Both spellings of the callee: `execFileSync(…)` after a named import, and
|
|
77
|
-
// `cp.execFileSync(…)` after a namespace import. Listed, not described — the node types a
|
|
78
|
-
// check walks are the only honest statement of its coverage.
|
|
79
|
-
if (n.type === "CallExpression") {
|
|
80
|
-
const name =
|
|
81
|
-
n.callee?.type === "MemberExpression"
|
|
82
|
-
? n.callee.property?.name
|
|
83
|
-
: n.callee?.name;
|
|
84
|
-
if (SPAWNERS.has(String(name)) && isGit(n.arguments?.[0]?.value))
|
|
85
|
-
found.push(String(n.arguments[0].value));
|
|
86
|
-
}
|
|
87
|
-
for (const k of Object.keys(n)) if (k !== "parent") walk(n[k]);
|
|
88
|
-
};
|
|
89
|
-
walk(ast);
|
|
90
|
-
return found;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** @param {{cwd: string}} options */
|
|
94
|
-
export function rulesAreContentOnly({ cwd }) {
|
|
95
|
-
const dir = join(cwd, "eslint-rules");
|
|
96
|
-
const checked = [];
|
|
97
|
-
const findings = [];
|
|
98
|
-
// A repository with no `eslint-rules/` has no rule sources: `checked` stays empty and the gate
|
|
99
|
-
// says so by name. `readdirSync` would throw ENOENT instead — a stack trace, not the refusal.
|
|
100
|
-
const names = existsSync(dir) ? readdirSync(dir) : [];
|
|
101
|
-
for (const f of names.filter(isRuleSource)) {
|
|
102
|
-
const hits = processImports(readFileSync(join(dir, f), "utf8"));
|
|
103
|
-
// 🔴 The counter increments WITH the verdict, not before it: a `checked` that keeps
|
|
104
|
-
// counting while the verdict stops being reached is the failure recorded in the consumer's
|
|
105
|
-
// rules as "a counter that counts what it ignores".
|
|
106
|
-
checked.push(f);
|
|
107
|
-
for (const h of hits) findings.push({ file: f, specifier: h });
|
|
108
|
-
}
|
|
109
|
-
return { checked, findings };
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* The gate over `cwd`'s `eslint-rules/`: exit 1 on no rule sources (a silent zero would read as
|
|
114
|
-
* clean) or on any rule asking git; 0 otherwise.
|
|
115
|
-
*
|
|
116
|
-
* 🔴 `cwd` is `process.cwd()`, NOT the package root. A consumer installs this package and runs the
|
|
117
|
-
* script from its own repository, where the rules that matter are ITS `eslint-rules/` — the
|
|
118
|
-
* package's own are already checked by the package's own gate. Anchored to the package root the
|
|
119
|
-
* consumer's gate would re-check the same eight files and report a confident zero about rules it
|
|
120
|
-
* never opened: a counter that counts what it ignores.
|
|
121
|
-
*/
|
|
122
|
-
export function main({
|
|
123
|
-
cwd = process.cwd(),
|
|
124
|
-
log = console.log,
|
|
125
|
-
err = console.error,
|
|
126
|
-
} = {}) {
|
|
127
|
-
const { checked, findings } = rulesAreContentOnly({ cwd });
|
|
128
|
-
if (checked.length === 0) {
|
|
129
|
-
err(
|
|
130
|
-
`${join(cwd, "eslint-rules")}: no rule sources. Either this is not a repository with ` +
|
|
131
|
-
`ESLint rules, or the directory moved — a silent zero here would read as a clean run.`,
|
|
132
|
-
);
|
|
133
|
-
return 1;
|
|
134
|
-
}
|
|
135
|
-
for (const { file, specifier } of findings) {
|
|
136
|
-
err(
|
|
137
|
-
`${file}: imports \`${specifier}\`. A rule may not ask git: history is rewritten by ` +
|
|
138
|
-
`routine maintenance and CI clones one commit deep, so the fact does not survive where ` +
|
|
139
|
-
`the rule has to hold. Put the fact on disk and check it by bytes.`,
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
log(
|
|
143
|
-
`rules-are-content-only: ${checked.length} rule sources under ${cwd}, ${findings.length} findings`,
|
|
144
|
-
);
|
|
145
|
-
return findings.length === 0 ? 0 : 1;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (isMain(import.meta.url)) process.exit(main());
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* rules-are-content-only's gate over a consumer's `eslint-rules/`: temp trees with planted rules.
|
|
3
|
-
*/
|
|
4
|
-
import assert from "node:assert/strict";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { spawnSync } from "node:child_process";
|
|
7
|
-
import { test } from "vitest";
|
|
8
|
-
import { useTempDir, writeTree } from "../test/support.mjs";
|
|
9
|
-
import { main as contentMain } from "./rules-are-content-only.mjs";
|
|
10
|
-
|
|
11
|
-
const capture = () => {
|
|
12
|
-
const out = [];
|
|
13
|
-
const io = { log: (s) => out.push(s), err: (s) => out.push(`E ${s}`) };
|
|
14
|
-
return { out, io };
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const root = useTempDir("content-only-");
|
|
18
|
-
|
|
19
|
-
test("rules-are-content-only: no rules is a failure, a rule asking git is a finding, clean rules pass", () => {
|
|
20
|
-
writeTree(root, {
|
|
21
|
-
"empty/.keep": "",
|
|
22
|
-
"dirty/eslint-rules/asks-git.mjs":
|
|
23
|
-
'import { execFileSync } from "node:child_process";\nexecFileSync("git", ["log"]);\n',
|
|
24
|
-
"dirty/eslint-rules/clean.mjs": "export default {};\n",
|
|
25
|
-
"clean/eslint-rules/clean.mjs": "export default {};\n",
|
|
26
|
-
});
|
|
27
|
-
const runs = ["empty", "dirty", "clean"].map((d) => {
|
|
28
|
-
const { out, io } = capture();
|
|
29
|
-
return [
|
|
30
|
-
contentMain({ cwd: `${root}/${d}`, ...io }),
|
|
31
|
-
out.map((l) => l.replace(root, "<root>").split(". ")[0]),
|
|
32
|
-
];
|
|
33
|
-
});
|
|
34
|
-
assert.deepEqual(runs, [
|
|
35
|
-
[1, ["E <root>/empty/eslint-rules: no rule sources"]],
|
|
36
|
-
[
|
|
37
|
-
1,
|
|
38
|
-
[
|
|
39
|
-
"E asks-git.mjs: imports `git`",
|
|
40
|
-
"rules-are-content-only: 2 rule sources under <root>/dirty, 1 findings",
|
|
41
|
-
],
|
|
42
|
-
],
|
|
43
|
-
[
|
|
44
|
-
0,
|
|
45
|
-
["rules-are-content-only: 1 rule sources under <root>/clean, 0 findings"],
|
|
46
|
-
],
|
|
47
|
-
]);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test("run as a program over this repository: every rule source is content-only, exit 0", () => {
|
|
51
|
-
const r = spawnSync(
|
|
52
|
-
process.execPath,
|
|
53
|
-
[fileURLToPath(new URL("./rules-are-content-only.mjs", import.meta.url))],
|
|
54
|
-
{ cwd: fileURLToPath(new URL("..", import.meta.url)), encoding: "utf8" },
|
|
55
|
-
);
|
|
56
|
-
assert.equal(r.status, 0, r.stderr);
|
|
57
|
-
assert.match(
|
|
58
|
-
r.stdout,
|
|
59
|
-
/^rules-are-content-only: \d+ rule sources under .*, 0 findings\n$/,
|
|
60
|
-
);
|
|
61
|
-
});
|
package/scripts/test.mjs
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `npm test`: the unit tests (vitest), then the harnesses (`vigiles test`). BOTH always run.
|
|
3
|
-
*
|
|
4
|
-
* Until #52 this was `vitest run && vigiles test --min=1`. Under `npm run coverage` a single
|
|
5
|
-
* failing vitest test then skipped every harness, and what the run printed last was c8's summary:
|
|
6
|
-
* lines, branches and functions each some six points below the floor. The one failing test sat
|
|
7
|
-
* above that, looking like a consequence rather than the cause. Running both suites keeps the
|
|
8
|
-
* coverage report whole, so a failing test is reported as itself and the coverage figures still
|
|
9
|
-
* mean what they say.
|
|
10
|
-
*
|
|
11
|
-
* Arguments are the harness runner's (`npm test -- --no-skip`), as they were before.
|
|
12
|
-
*/
|
|
13
|
-
import { spawnSync } from "node:child_process";
|
|
14
|
-
import { isMain } from "../skills/paper-pipeline/scripts/consumer.mjs";
|
|
15
|
-
|
|
16
|
-
/** The two suites, in order: what a failure is named as, and the command. */
|
|
17
|
-
export const SUITES = [
|
|
18
|
-
{ name: "vitest", command: ["vitest", "run"] },
|
|
19
|
-
{ name: "harnesses", command: ["vigiles", "test", "--min=1"] },
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Run every suite, whatever the one before it returned, and name the ones that failed.
|
|
24
|
-
* @returns 0 when every suite passed; otherwise the first failing suite's exit code (1 for a signal).
|
|
25
|
-
*/
|
|
26
|
-
export function runSuites(
|
|
27
|
-
args,
|
|
28
|
-
{ spawn = spawnSync, err = console.error, suites = SUITES } = {},
|
|
29
|
-
) {
|
|
30
|
-
const failed = suites.flatMap(({ name, command }) => {
|
|
31
|
-
const [file, ...rest] = command;
|
|
32
|
-
const r = spawn(file, [...rest, ...(name === "harnesses" ? args : [])], {
|
|
33
|
-
stdio: "inherit",
|
|
34
|
-
});
|
|
35
|
-
return r.status === 0 ? [] : [{ name, code: r.status ?? 1 }];
|
|
36
|
-
});
|
|
37
|
-
for (const f of failed)
|
|
38
|
-
err(
|
|
39
|
-
`✗ ${f.name} failed (exit ${String(f.code)}) — its own report is above`,
|
|
40
|
-
);
|
|
41
|
-
return failed.length === 0 ? 0 : failed[0].code;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (isMain(import.meta.url)) process.exit(runSuites(process.argv.slice(2)));
|
package/scripts/test.test.mjs
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `npm test`'s runner: both suites run whatever the first returned, each failure is named, and
|
|
3
|
-
* the harness arguments reach the harness runner only.
|
|
4
|
-
*/
|
|
5
|
-
import assert from "node:assert/strict";
|
|
6
|
-
import { test } from "vitest";
|
|
7
|
-
import { runSuites, SUITES } from "./test.mjs";
|
|
8
|
-
|
|
9
|
-
const fake = (status) => {
|
|
10
|
-
const calls = [];
|
|
11
|
-
return {
|
|
12
|
-
calls,
|
|
13
|
-
spawn: (file, args) => {
|
|
14
|
-
calls.push([file, ...args]);
|
|
15
|
-
return { status: status[file] };
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
test("a failing vitest does not skip the harnesses, and is named as the failure", () => {
|
|
21
|
-
const { calls, spawn } = fake({ vitest: 1, vigiles: 0 });
|
|
22
|
-
const said = [];
|
|
23
|
-
assert.equal(
|
|
24
|
-
runSuites(["--no-skip"], { spawn, err: (s) => said.push(s) }),
|
|
25
|
-
1,
|
|
26
|
-
);
|
|
27
|
-
assert.deepEqual(calls, [
|
|
28
|
-
["vitest", "run"],
|
|
29
|
-
["vigiles", "test", "--min=1", "--no-skip"],
|
|
30
|
-
]);
|
|
31
|
-
assert.deepEqual(said, [
|
|
32
|
-
"✗ vitest failed (exit 1) — its own report is above",
|
|
33
|
-
]);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test("both passing is 0 and silent; a harness killed by a signal is exit 1, named", () => {
|
|
37
|
-
const ok = fake({ vitest: 0, vigiles: 0 });
|
|
38
|
-
assert.equal(runSuites([], { spawn: ok.spawn, err: assert.fail }), 0);
|
|
39
|
-
const killed = fake({ vitest: 0, vigiles: null });
|
|
40
|
-
const said = [];
|
|
41
|
-
assert.equal(
|
|
42
|
-
runSuites([], { spawn: killed.spawn, err: (s) => said.push(s) }),
|
|
43
|
-
1,
|
|
44
|
-
);
|
|
45
|
-
assert.deepEqual(said, [
|
|
46
|
-
"✗ harnesses failed (exit 1) — its own report is above",
|
|
47
|
-
]);
|
|
48
|
-
assert.deepEqual(
|
|
49
|
-
SUITES.map((s) => s.name),
|
|
50
|
-
["vitest", "harnesses"],
|
|
51
|
-
);
|
|
52
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// announce.mjs — a skill says out loud that it started, and the ledger remembers that it did.
|
|
2
|
-
//
|
|
3
|
-
// vigiles:local-by-design — takes a skill name as an argument and so names none itself, which reads
|
|
4
|
-
// generic; it is not. It writes THIS repo's ledger row format, consumed by `status.mjs`'s gate table
|
|
5
|
-
// and `ledger.mjs`'s verdict vocabulary, both of which are conventions of this knowledge base rather
|
|
6
|
-
// than of any product. Moving it would export a schema nobody else has.
|
|
7
|
-
//
|
|
8
|
-
// WHY. Repository owner's request, 2026-08-07: "lack observability into pipeline status and whether
|
|
9
|
-
// skills are actually being called — let's ensure each skill outputs something when activated".
|
|
10
|
-
//
|
|
11
|
-
// The failure behind that sentence is specific and it has happened three times in this repo. An
|
|
12
|
-
// advisory check CANNOT BE SEEN FAILING: silence is both its error state and its normal state.
|
|
13
|
-
// `paper-skills-nudge.sh` was dead for twelve days and was found only because it writes a throttle
|
|
14
|
-
// stamp whose mtime had frozen. Two inline hooks were dead for their entire existence and nobody
|
|
15
|
-
// noticed at all. And on 2026-08-06 a whole session of paper work ran with no skill invoked once.
|
|
16
|
-
//
|
|
17
|
-
// So: starting is an EVENT, and events get written down. A skill that announces leaves two traces —
|
|
18
|
-
// one the human sees immediately, one the ledger keeps. Their disagreement is itself information:
|
|
19
|
-
//
|
|
20
|
-
// announced, never recorded → the skill started and died, or the author abandoned it midway
|
|
21
|
-
// recorded, never announced → someone wrote a verdict without running the gate
|
|
22
|
-
// neither → it did not run, whatever any status file claims
|
|
23
|
-
//
|
|
24
|
-
// This is the "no trace means it did not work" rule the project already applies to hooks, made
|
|
25
|
-
// available to skills, which had no equivalent.
|
|
26
|
-
|
|
27
|
-
import { record, skillHash, inputHash } from "./ledger.mjs";
|
|
28
|
-
import { existsSync } from "node:fs";
|
|
29
|
-
import { resolve, basename } from "node:path";
|
|
30
|
-
import { isMain } from "./consumer.mjs";
|
|
31
|
-
|
|
32
|
-
export function announce(skill, paperDir) {
|
|
33
|
-
const dir = resolve(paperDir || ".");
|
|
34
|
-
const has = existsSync(dir);
|
|
35
|
-
const input = has ? inputHash(dir) : null;
|
|
36
|
-
|
|
37
|
-
const lines = [
|
|
38
|
-
`▶ ${skill} — ${has ? basename(dir) : "no paper dir"}`,
|
|
39
|
-
` paper ${input ? input.slice(0, 8) : "(none)"} · skill ${(skillHash(skill) || "????????").slice(0, 8)}`,
|
|
40
|
-
];
|
|
41
|
-
// stderr, not stdout: the skill's own output is the product, and a banner that pollutes a pipe
|
|
42
|
-
// is a banner someone will remove.
|
|
43
|
-
console.error(lines.join("\n"));
|
|
44
|
-
|
|
45
|
-
// An abstention with reason `started`, not an ERROR row. Before 2026-08-10 this wrote `ERROR`,
|
|
46
|
-
// which meant "the check errored" — so every announce looked like a crash until its terminal row
|
|
47
|
-
// landed, and `started` and `crashed` were the same word. Both are abstentions and neither is a
|
|
48
|
-
// judgement about the paper; the reason is what tells them apart.
|
|
49
|
-
record({
|
|
50
|
-
skill,
|
|
51
|
-
check: skill,
|
|
52
|
-
paper: dir,
|
|
53
|
-
kind: "ABSTAINED",
|
|
54
|
-
reason: "started",
|
|
55
|
-
note: "no verdict recorded yet",
|
|
56
|
-
});
|
|
57
|
-
return { skill, paper: basename(dir), input };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (isMain(import.meta.url)) {
|
|
61
|
-
const [skill, paperDir] = process.argv.slice(2);
|
|
62
|
-
if (!skill) {
|
|
63
|
-
console.error("usage: announce.mjs <skill-name> [paper-dir]");
|
|
64
|
-
process.exit(2);
|
|
65
|
-
}
|
|
66
|
-
announce(skill, paperDir);
|
|
67
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* announce.mjs — the first line of every wired skill's `## Run me` block: a banner on stderr naming
|
|
3
|
-
* the paper and skill versions, and a `started` abstention in the ledger. Run as the skills run it,
|
|
4
|
-
* against a temp consumer and a temp ledger.
|
|
5
|
-
*/
|
|
6
|
-
import assert from "node:assert/strict";
|
|
7
|
-
import { cpSync, readFileSync, rmSync } from "node:fs";
|
|
8
|
-
import { dirname, join } from "node:path";
|
|
9
|
-
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { afterEach, test } from "vitest";
|
|
11
|
-
import { runNode, useTempDir, writeTree } from "../../../test/support.mjs";
|
|
12
|
-
|
|
13
|
-
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
14
|
-
const SCRIPT = join(HERE, "announce.mjs");
|
|
15
|
-
const root = useTempDir("announce-");
|
|
16
|
-
const consumer = join(root, "consumer");
|
|
17
|
-
const LEDGER = join(root, "runs.jsonl");
|
|
18
|
-
writeTree(root, { "consumer/papers/p/paper.md": "# P\n\ntext\n" });
|
|
19
|
-
cpSync(
|
|
20
|
-
join(HERE, "..", "..", "cold-read-diff"),
|
|
21
|
-
join(consumer, ".claude", "skills", "cold-read-diff"),
|
|
22
|
-
{
|
|
23
|
-
recursive: true,
|
|
24
|
-
verbatimSymlinks: true,
|
|
25
|
-
},
|
|
26
|
-
);
|
|
27
|
-
const env = { CLAUDE_PROJECT_DIR: consumer, PIPELINE_LEDGER: LEDGER };
|
|
28
|
-
process.env.CLAUDE_PROJECT_DIR = consumer;
|
|
29
|
-
process.env.PIPELINE_LEDGER = LEDGER;
|
|
30
|
-
const { inputHash, skillHash } = await import("./ledger.mjs");
|
|
31
|
-
|
|
32
|
-
const rows = () =>
|
|
33
|
-
readFileSync(LEDGER, "utf8")
|
|
34
|
-
.trim()
|
|
35
|
-
.split("\n")
|
|
36
|
-
.map((l) => JSON.parse(l))
|
|
37
|
-
.map(({ skill, check, paper, kind, reason, note }) => ({
|
|
38
|
-
skill,
|
|
39
|
-
check,
|
|
40
|
-
paper,
|
|
41
|
-
kind,
|
|
42
|
-
reason,
|
|
43
|
-
note,
|
|
44
|
-
}));
|
|
45
|
-
afterEach(() => rmSync(LEDGER, { force: true }));
|
|
46
|
-
|
|
47
|
-
test("no skill name: the usage line, exit 2, nothing recorded", () => {
|
|
48
|
-
assert.deepEqual(runNode(SCRIPT, [], { env }), {
|
|
49
|
-
status: 2,
|
|
50
|
-
stdout: "",
|
|
51
|
-
stderr: "usage: announce.mjs <skill-name> [paper-dir]\n",
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("a skill on a paper: the banner names both versions, and a `started` row is recorded", () => {
|
|
56
|
-
const paper = join(consumer, "papers", "p");
|
|
57
|
-
const r = runNode(SCRIPT, ["cold-read-diff", paper], { env });
|
|
58
|
-
assert.deepEqual(
|
|
59
|
-
{ ...r, rows: rows() },
|
|
60
|
-
{
|
|
61
|
-
status: 0,
|
|
62
|
-
stdout: "",
|
|
63
|
-
stderr:
|
|
64
|
-
"▶ cold-read-diff — p\n" +
|
|
65
|
-
` paper ${inputHash(paper).slice(0, 8)} · skill ${skillHash("cold-read-diff").slice(0, 8)}\n`,
|
|
66
|
-
rows: [
|
|
67
|
-
{
|
|
68
|
-
skill: "cold-read-diff",
|
|
69
|
-
check: "cold-read-diff",
|
|
70
|
-
paper: "p",
|
|
71
|
-
kind: "ABSTAINED",
|
|
72
|
-
reason: "started",
|
|
73
|
-
note: "no verdict recorded yet",
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
},
|
|
77
|
-
);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test("no paper directory and an unknown skill still announce, with placeholders", () => {
|
|
81
|
-
const r = runNode(SCRIPT, ["no-such-skill", join(root, "nowhere")], { env });
|
|
82
|
-
assert.deepEqual(
|
|
83
|
-
{ status: r.status, stderr: r.stderr, kind: rows()[0].kind },
|
|
84
|
-
{
|
|
85
|
-
status: 0,
|
|
86
|
-
stderr:
|
|
87
|
-
"▶ no-such-skill — no paper dir\n paper (none) · skill ????????\n",
|
|
88
|
-
kind: "ABSTAINED",
|
|
89
|
-
},
|
|
90
|
-
);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test("no paper argument means the current directory", () => {
|
|
94
|
-
const r = runNode(SCRIPT, ["cold-read-diff"], {
|
|
95
|
-
env,
|
|
96
|
-
cwd: join(consumer, "papers", "p"),
|
|
97
|
-
});
|
|
98
|
-
assert.deepEqual(
|
|
99
|
-
{ status: r.status, firstLine: r.stderr.split("\n")[0] },
|
|
100
|
-
{ status: 0, firstLine: "▶ cold-read-diff — p" },
|
|
101
|
-
);
|
|
102
|
-
});
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# PIPELINE-STATUS — fixture: nothing to report
|
|
2
|
-
Venue: Fixture Workshop · Deadline: 2027-12-31 · Blind: double · State: drafting
|
|
3
|
-
Updated: 2026-08-03
|
|
4
|
-
|
|
5
|
-
**Readiness verdict:** Submit-ready — every gate green, artifact reproduces clean, nothing blocking.
|
|
6
|
-
|
|
7
|
-
This fixture deliberately carries NO paper source file, so `newestSourceDate` is null and the
|
|
8
|
-
staleness comparison has nothing to compare against. That keeps the clean case deterministic
|
|
9
|
-
regardless of when the repo was checked out — the staleness rule is exercised by `dirty/`.
|
|
10
|
-
|
|
11
|
-
### SETUP
|
|
12
|
-
| id | Work | Skill | Status | Date | Result | Open |
|
|
13
|
-
|----|------|-------|--------|------|--------|------|
|
|
14
|
-
| idea | Validate idea | research-ideate | ☑ | 2026-08-01 | go. judge: opus, judge: author | — |
|
|
15
|
-
| priorwork | Map competitors | map-prior-work | ☑ | 2026-08-01 | 6 siblings. judge: sonnet, judge: author | siblings/ |
|
|
16
|
-
| venue | Pick venue | find-venue | ☑ | 2026-08-01 | fixture. judge: sonnet, judge: author | — |
|
|
17
|
-
| venuebar | Venue bar / levers | study-accepted-papers | ☑ | 2026-08-01 | 34 measured. judge: sonnet, judge: author | — |
|
|
18
|
-
| **access** | 🔴 **Can you physically submit?** | plan-paper-timeline | ☑ | 2026-08-01 | profile ACTIVE since 2026-08-01. judge: author, judge: author | — |
|
|
19
|
-
| schedule | Schedule + calendar | plan-paper-timeline | ☑ | 2026-08-01 | —. judge: author, judge: author | — |
|
|
20
|
-
| **frame** | **Claim stated before the runs** | argument-arc (frame) | ☑ | 2026-07-20 | one paragraph filed | — |
|
|
21
|
-
|
|
22
|
-
### LOOP
|
|
23
|
-
| id | Work | Skill | Status | Date | Result | Open |
|
|
24
|
-
|----|------|-------|--------|------|--------|------|
|
|
25
|
-
| study | Study + artifact | build-benchmark | ☑ | 2026-08-01 | ran | — |
|
|
26
|
-
| draft | Draft | draft-paper | ☑ | 2026-08-01 | — | — |
|
|
27
|
-
| arc | Argument arc | argument-arc | ☑ | 2026-08-01 | holds. judge: opus, judge: author | — |
|
|
28
|
-
|
|
29
|
-
### CONTINUOUS
|
|
30
|
-
| id | Trigger | Skill | Status | Date | Result | Open |
|
|
31
|
-
|----|---------|-------|--------|------|--------|------|
|
|
32
|
-
| cites | any cite added/moved | verify-citations | ☑ | 2026-08-02 | clean | — |
|
|
33
|
-
| siblings | a sibling surfaces | analyze-sibling-paper | ☑ | 2026-08-02 | 6 read. judge: opus, judge: author | siblings/ |
|
|
34
|
-
| priordelta | framing moved | map-prior-work (delta) | ☑ | 2026-08-02 | no new | — |
|
|
35
|
-
| render | any source edit | render-paper + page count | ☑ | 2026-08-02 | 8 pages / limit 8 | — |
|
|
36
|
-
|
|
37
|
-
### GATES
|
|
38
|
-
| id | Gate | Skill | Requires | Status | Date | Result | Open |
|
|
39
|
-
|----|------|-------|----------|--------|------|--------|------|
|
|
40
|
-
| structure | Structure | tighten-paper | render, arc | ☑ | 2026-08-02 | cut plan applied. judge: opus, judge: author | — |
|
|
41
|
-
| writing | Writing craft | grade-paper-writing | draft, arc, structure | ☑ | 2026-08-02 | 44/60. judge: sonnet, judge: author | — |
|
|
42
|
-
| panel | Review decision | pc-panel-review | structure, writing | ☑ | 2026-08-03 | accept; judge: opus, judge: author | — |
|
|
43
|
-
| claims | Claim preservation | Fable diff | draft, writing | ☑ | 2026-08-03 | clean | — |
|
|
44
|
-
| harden | Harden (all axes) | harden-paper | panel, structure, writing, cites, priordelta | ☑ | 2026-08-03 | all axes green ; judge: opus, judge: author | — |
|
|
45
|
-
| submit | Submit | submit-paper | harden, access | ☑ | 2026-08-03 | uploaded | — |
|
|
46
|
-
|
|
47
|
-
### AFTER
|
|
48
|
-
| id | Work | Skill | Status | Date | Result | Open |
|
|
49
|
-
|----|------|-------|--------|------|--------|------|
|
|
50
|
-
| cameraready | Camera-ready | camera-ready | n/a | — | pre-acceptance | — |
|
|
51
|
-
| extend | Extend | extend-paper | n/a | — | post-acceptance | — |
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# PIPELINE-STATUS — fixture: every failure this checker exists for
|
|
2
|
-
Venue: Fixture Workshop · Deadline: 2026-08-06 · Blind: double · State: drafting
|
|
3
|
-
Updated: 2026-01-01
|
|
4
|
-
|
|
5
|
-
**Readiness verdict:** 88% accept probability, looking good.
|
|
6
|
-
|
|
7
|
-
The `structure` row is missing `arc` from its Requires cell **on purpose** — that is the planted
|
|
8
|
-
`undeclared-input`, copied from a defect found live on a real paper in August 2026. Every
|
|
9
|
-
other gate cell here is the canonical set from `../../pipeline-edges.mjs`, so exactly one edge is
|
|
10
|
-
undeclared and the finding cannot come from somewhere else.
|
|
11
|
-
|
|
12
|
-
### SETUP
|
|
13
|
-
| id | Work | Skill | Status | Date | Result | Open |
|
|
14
|
-
|----|------|-------|--------|------|--------|------|
|
|
15
|
-
| idea | Validate idea | research-ideate | ☑ | 2026-01-01 | go | — |
|
|
16
|
-
| priorwork | Map competitors | map-prior-work | ☑ | 2026-01-01 | 6 siblings | siblings/ |
|
|
17
|
-
| venue | Pick venue | find-venue | ☑ | 2026-01-01 | fixture | — |
|
|
18
|
-
| venuebar | Venue bar / levers | study-accepted-papers | ☐ | — | — | — |
|
|
19
|
-
| **access** | 🔴 **Can you physically submit?** | plan-paper-timeline | ☐ | — | profile pending moderation | — |
|
|
20
|
-
| schedule | Schedule + calendar | plan-paper-timeline | ☑ | 2026-01-01 | — | — |
|
|
21
|
-
| **frame** | **Claim stated before the runs** | argument-arc (frame) | ☐ | — | — | — |
|
|
22
|
-
|
|
23
|
-
### LOOP
|
|
24
|
-
| id | Work | Skill | Status | Date | Result | Open |
|
|
25
|
-
|----|------|-------|--------|------|--------|------|
|
|
26
|
-
| study | Study + artifact | build-benchmark | ☑ | 2026-01-01 | ran | — |
|
|
27
|
-
| draft | Draft | draft-paper | ☑ | 2026-01-01 | — | — |
|
|
28
|
-
| arc | Argument arc | argument-arc | ☐ | — | — | — |
|
|
29
|
-
|
|
30
|
-
### CONTINUOUS
|
|
31
|
-
| id | Trigger | Skill | Status | Date | Result | Open |
|
|
32
|
-
|----|---------|-------|--------|------|--------|------|
|
|
33
|
-
| cites | any cite added/moved | verify-citations | ☑ | 2026-01-01 | clean | — |
|
|
34
|
-
| siblings | a sibling surfaces | analyze-sibling-paper | ☑ | — | done | siblings/ |
|
|
35
|
-
| priordelta | framing moved | map-prior-work (delta) | ☐ | — | — | — |
|
|
36
|
-
| render | any source edit | render-paper + page count | ☑ | 2026-01-01 | 8 pages / limit 8 | — |
|
|
37
|
-
|
|
38
|
-
### GATES
|
|
39
|
-
| id | Gate | Skill | Requires | Status | Date | Result | Open |
|
|
40
|
-
|----|------|-------|----------|--------|------|--------|------|
|
|
41
|
-
| structure | Structure | tighten-paper | render | ☑ | 2026-01-01 | cut plan | — |
|
|
42
|
-
| writing | Writing craft | grade-paper-writing | draft, arc, structure | ☐ | — | — | — |
|
|
43
|
-
| panel | Review decision | pc-panel-review | structure, writing | ☑ | 2026-01-01 | borderline | — |
|
|
44
|
-
| claims | Claim preservation | Fable diff | draft, writing | ☐ | — | — | — |
|
|
45
|
-
| harden | Harden (all axes) | harden-paper | panel, structure, writing, cites, priordelta | ☐ | — | — | — |
|
|
46
|
-
| submit | Submit | submit-paper | harden, access | ☐ | — | — | — |
|
|
47
|
-
|
|
48
|
-
### AFTER
|
|
49
|
-
| id | Work | Skill | Status | Date | Result | Open |
|
|
50
|
-
|----|------|-------|--------|------|--------|------|
|
|
51
|
-
| cameraready | Camera-ready | camera-ready | n/a | — | pre-acceptance | — |
|
|
52
|
-
| extend | Extend | extend-paper | n/a | — | post-acceptance | — |
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
# Fixture paper source
|
|
2
|
-
|
|
3
|
-
This file exists only so `newestSourceDate` finds something. Its mtime is whenever the
|
|
4
|
-
repo was checked out, which is always later than the 2026-01-01 dates in the fixture's
|
|
5
|
-
CONTINUOUS rows — so the `stale-continuous` check fires deterministically without the
|
|
6
|
-
test having to touch mtimes.
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A PIPELINE-STATUS.md fixture shared by the pipeline-check harness and its CLI test: the four
|
|
3
|
-
* template sections, every row green and dated `today`, so a test plants exactly one defect.
|
|
4
|
-
*/
|
|
5
|
-
export const FAR = "2027-12-31";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A scorecard with the four sections the template requires, all green. `over` replaces individual
|
|
9
|
-
* cells: `{ cites: { date: "2020-01-01" } }`, `{ verdict: "…" }`, `{ deadline: "2026-08-18" }`,
|
|
10
|
-
* `{ tail: "…" }` for anything appended after the last section, `{ preamble: "…" }` for anything
|
|
11
|
-
* inserted BEFORE the first heading (the only way to plant a row under no heading at all).
|
|
12
|
-
*/
|
|
13
|
-
export function scorecard(
|
|
14
|
-
over = {},
|
|
15
|
-
today = new Date().toISOString().slice(0, 10),
|
|
16
|
-
) {
|
|
17
|
-
const r = (id, status = "☑", date = today) => ({
|
|
18
|
-
id,
|
|
19
|
-
status,
|
|
20
|
-
date,
|
|
21
|
-
...(over[id] ?? {}),
|
|
22
|
-
});
|
|
23
|
-
const row = (o, ...mid) =>
|
|
24
|
-
`| ${o.id} | work | ${o.skill ?? "skill"} | ${mid.length ? mid.join(" | ") + " | " : ""}${o.status} | ${o.date} | ${o.result ?? "result"} | — |`;
|
|
25
|
-
// The GATES `Requires` cell, canonical by default so the baseline is silent — `{ structure: {
|
|
26
|
-
// requires: "render" } }` plants a dropped edge. `harden` deliberately declares four of its five
|
|
27
|
-
// canonical inputs: the fifth (`priordelta`) has no row in this fixture, and the clean case asserts that the checker stays
|
|
28
|
-
// quiet about an edge there is nowhere to point at.
|
|
29
|
-
const req = (id, dflt) => over[id]?.requires ?? dflt;
|
|
30
|
-
const verdict =
|
|
31
|
-
over.verdict ??
|
|
32
|
-
"Submit-ready — every gate green, artifact reproduces clean, nothing blocking.";
|
|
33
|
-
return [
|
|
34
|
-
"# PIPELINE-STATUS — harness fixture",
|
|
35
|
-
`Venue: Fixture Workshop · Deadline: ${over.deadline ?? FAR} · Blind: double · State: drafting`,
|
|
36
|
-
"",
|
|
37
|
-
`**Readiness verdict:** ${verdict}`,
|
|
38
|
-
"",
|
|
39
|
-
over.preamble ?? "",
|
|
40
|
-
"",
|
|
41
|
-
"### SETUP",
|
|
42
|
-
"| id | Work | Skill | Status | Date | Result | Open |",
|
|
43
|
-
"|----|------|-------|--------|------|--------|------|",
|
|
44
|
-
row(r("idea")),
|
|
45
|
-
row(r("access")),
|
|
46
|
-
row(r("frame")),
|
|
47
|
-
"",
|
|
48
|
-
"### LOOP",
|
|
49
|
-
"| id | Work | Skill | Status | Date | Result | Open |",
|
|
50
|
-
"|----|------|-------|--------|------|--------|------|",
|
|
51
|
-
row(r("study")),
|
|
52
|
-
row(r("draft")),
|
|
53
|
-
row(r("arc")),
|
|
54
|
-
"",
|
|
55
|
-
"### CONTINUOUS",
|
|
56
|
-
"| id | Trigger | Skill | Status | Date | Result | Open |",
|
|
57
|
-
"|----|---------|-------|--------|------|--------|------|",
|
|
58
|
-
row(r("cites")),
|
|
59
|
-
row(r("render")),
|
|
60
|
-
"",
|
|
61
|
-
"### GATES",
|
|
62
|
-
"| id | Gate | Skill | Requires | Status | Date | Result | Open |",
|
|
63
|
-
"|----|------|-------|----------|--------|------|--------|------|",
|
|
64
|
-
row(r("structure"), req("structure", "render, arc")),
|
|
65
|
-
row(r("writing"), req("writing", "draft, arc, structure")),
|
|
66
|
-
row(r("panel"), req("panel", "structure, writing")),
|
|
67
|
-
row(r("harden"), req("harden", "panel, structure, writing, cites")),
|
|
68
|
-
"",
|
|
69
|
-
over.tail ?? "",
|
|
70
|
-
].join("\n");
|
|
71
|
-
}
|