paperlint 3.2.0 → 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/CLAUDE.md +2 -2
- 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 +8 -11
- 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 +9 -4
- 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/process.io.d.ts +6 -3
- package/dist/adapters/node/process.io.d.ts.map +1 -1
- 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/references/index.d.ts.map +1 -1
- package/dist/adapters/references/index.js +4 -2
- package/dist/adapters/references/index.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 +8 -1
- 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 +5 -6
- 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 +62 -12
- 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 +2 -1
- package/dist/doctor.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/engine.d.ts +23 -22
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js.map +1 -1
- package/dist/eslint-rules/bib-reachable-entry.d.ts +1 -1
- package/dist/eslint-rules/bib-reachable-entry.js.map +1 -1
- package/dist/eslint-rules/install-path-literals.d.ts +2 -2
- package/dist/eslint-rules/install-path-literals.js.map +1 -1
- package/dist/eslint-rules/paper-research-question.d.ts +1 -1
- package/dist/eslint-rules/paper-research-question.js.map +1 -1
- package/dist/eslint-rules/paper-stages.d.ts +2 -2
- package/dist/eslint-rules/paper-stages.js.map +1 -1
- package/dist/eslint-rules/paper-typography.d.ts +6 -6
- package/dist/eslint-rules/paper-typography.js.map +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.d.ts +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.js.map +1 -1
- package/dist/eslint-rules/review-frontmatter.d.ts +2 -2
- package/dist/eslint-rules/review-frontmatter.js.map +1 -1
- package/dist/eslint-rules/sibling-frontmatter.d.ts +1 -1
- package/dist/eslint-rules/sibling-frontmatter.d.ts.map +1 -1
- package/dist/eslint-rules/temp-root-realpath.d.ts +1 -1
- package/dist/eslint-rules/temp-root-realpath.js.map +1 -1
- package/dist/eslint-rules/tex-build.d.ts +2 -2
- package/dist/eslint-rules/tex-build.js.map +1 -1
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +29 -26
- package/dist/facts-file.js.map +1 -1
- package/dist/hooks-settings.d.ts.map +1 -1
- package/dist/hooks-settings.js +17 -2
- package/dist/hooks-settings.js.map +1 -1
- package/dist/init.d.ts +3 -4
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +18 -8
- package/dist/init.js.map +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +1 -5
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +5 -1
- 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.js +3 -3
- 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 +23 -15
- package/dist/pdf-facts.js.map +1 -1
- package/dist/pdf-geometry.d.ts.map +1 -1
- package/dist/pdf-geometry.js +2 -3
- 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 +16 -4
- package/dist/presets.js.map +1 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +4 -4
- 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 +9 -9
- package/dist/rules-config.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 +14 -2
- package/dist/tex-requirements.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 +20 -7
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +2 -2
- package/eslint-rules/bib-reachable-entry.ts +1 -1
- package/eslint-rules/install-path-literals.ts +2 -2
- package/eslint-rules/paper-research-question.ts +1 -1
- package/eslint-rules/paper-stages.ts +2 -2
- package/eslint-rules/paper-typography.ts +2 -2
- package/eslint-rules/pdf-last-page-balance.ts +1 -1
- package/eslint-rules/review-frontmatter.ts +1 -1
- package/eslint-rules/temp-root-realpath.ts +1 -1
- package/eslint-rules/tex-build.ts +2 -2
- package/eslint.config.mjs +7 -0
- 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/hooks/paper-status-gates.sh +9 -19
- package/lib/paper-config.harness.mjs +1 -1
- package/lib/paper-config.ts +1 -5
- package/lib/skill-checks.mjs +24 -381
- package/lib/skill-checks.test.mjs +63 -115
- package/lib/skill-corpus.mjs +10 -251
- package/lib/skill-corpus.test.mjs +2 -13
- package/lib/skill-trigger-cases.mjs +1 -1
- package/package.json +1 -1
- package/scripts/coverage-config.test.ts +0 -1
- package/scripts/harness-api.frozen.json +0 -1
- 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 +2 -3
- package/skills/grade-paper-writing/prose-lint.test.ts +1 -1
- 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.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/grade-paper-writing-ablation.eval.mjs +1 -1
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +25 -40
- 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/consumer.harness.mjs +6 -104
- package/skills/paper-pipeline/scripts/consumer.mjs +23 -104
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +2 -3
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +3 -3
- 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/render-paper/SKILL.md +1 -37
- package/skills/render-paper/SKILL.md.spec.ts +0 -36
- 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 +4 -11
- package/skills/verify-citations/SKILL.md +2 -38
- package/skills/verify-citations/SKILL.md.spec.ts +1 -37
- package/src/adapters/banal/failure.ts +9 -10
- package/src/adapters/banal/index.test.ts +2 -2
- package/src/adapters/banal/index.ts +8 -10
- package/src/adapters/banal/install.ts +9 -4
- package/src/adapters/banal/invocation.test.ts +20 -8
- package/src/adapters/banal/invocation.ts +23 -8
- package/src/adapters/banal/locate.test.ts +2 -2
- package/src/adapters/banal/locate.ts +27 -21
- package/src/adapters/banal/run.test.ts +2 -2
- package/src/adapters/banal/run.ts +16 -10
- package/src/adapters/banal/settings.ts +2 -2
- package/src/adapters/curl/download.test.ts +4 -4
- package/src/adapters/memory/index.ts +4 -3
- package/src/adapters/node/files.test.ts +5 -3
- package/src/adapters/node/process.io.ts +9 -2
- package/src/adapters/node/process.test.ts +4 -4
- package/src/adapters/node/workspace.io.ts +9 -4
- package/src/adapters/references/index.ts +7 -2
- package/src/build-engine.test.ts +11 -6
- package/src/build-engine.ts +10 -5
- package/src/build.test.ts +10 -11
- package/src/build.ts +8 -9
- package/src/caller-path.ts +13 -0
- package/src/cli.harness.mjs +0 -2
- package/src/cli.test.ts +19 -8
- package/src/cli.ts +82 -25
- package/src/doctor.test.ts +1 -1
- package/src/doctor.ts +14 -5
- 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/sha256.ts +5 -3
- package/src/engine.ts +30 -2
- package/src/facts-file.ts +43 -28
- package/src/hooks-settings.harness.ts +17 -0
- package/src/hooks-settings.ts +28 -4
- package/src/init.test.ts +25 -5
- package/src/init.ts +26 -12
- package/src/new-paper.harness.mjs +7 -23
- package/src/new-paper.ts +7 -3
- package/src/paper-files.test.ts +22 -19
- package/src/paper-files.ts +16 -27
- package/src/paper-settings.test.ts +2 -2
- package/src/paper-settings.ts +5 -5
- package/src/pdf-facts.test.ts +16 -5
- package/src/pdf-facts.ts +79 -22
- package/src/pdf-geometry.ts +5 -3
- package/src/ports/tool-installer.ts +2 -17
- package/src/presets.ts +28 -14
- package/src/references.test.ts +25 -19
- package/src/references.ts +4 -5
- package/src/rules-config.ts +40 -11
- package/src/tex-requirements.test.ts +21 -0
- package/src/tex-requirements.ts +29 -6
- package/src/toolchain.test.ts +9 -5
- package/src/toolchain.ts +2 -2
- package/src/types.ts +5 -3
- package/src/venue-rules.test.ts +8 -4
- package/src/venue-rules.ts +21 -11
- 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.ts +0 -100
- 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 -750
- 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/src/toolchain.ts
CHANGED
|
@@ -295,8 +295,8 @@ const quiet = (io: ToolchainIO, timeout?: number) => ({
|
|
|
295
295
|
/** The last lines a process printed — what a failure shows. */
|
|
296
296
|
function tail(
|
|
297
297
|
r: {
|
|
298
|
-
readonly stdout
|
|
299
|
-
readonly stderr
|
|
298
|
+
readonly stdout?: string | undefined;
|
|
299
|
+
readonly stderr?: string | undefined;
|
|
300
300
|
},
|
|
301
301
|
n = 12,
|
|
302
302
|
): string[] {
|
package/src/types.ts
CHANGED
|
@@ -12,10 +12,12 @@ import type { RuleBlock } from "./rules-config.ts";
|
|
|
12
12
|
*/
|
|
13
13
|
export interface PaperlintConfig {
|
|
14
14
|
/** The paper director(ies), relative to the project root. Default `papers`. The field name is
|
|
15
|
-
* `PAPERS_DIR_FIELD` in lib/paper-config.mjs; code reads it through `papersDirOf()` in cli.ts.
|
|
16
|
-
|
|
15
|
+
* `PAPERS_DIR_FIELD` in lib/paper-config.mjs; code reads it through `papersDirOf()` in cli.ts.
|
|
16
|
+
* As written in the file: `toPaths` turns a string or a list of strings into directories, and
|
|
17
|
+
* reads anything else as none. */
|
|
18
|
+
papersDir?: unknown;
|
|
17
19
|
/** Which files a paper directory must carry; `false` turns the check off entirely. */
|
|
18
|
-
structure?: StructureConfig | false;
|
|
20
|
+
structure?: StructureConfig | false | undefined;
|
|
19
21
|
/** ESLint config blocks appended after paperlint's own — PARSED by `parseSettings` in cli.ts. */
|
|
20
22
|
rules?: readonly RuleBlock[];
|
|
21
23
|
/** The default venue preset of every paper that names none (`src/paper-settings.ts`). */
|
package/src/venue-rules.test.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { sha256Hex } from "./domain/sha256.ts";
|
|
|
15
15
|
import { packageVenuesDir } from "../skills/paper-pipeline/scripts/consumer.mjs";
|
|
16
16
|
import { VENUE_RULE_LEVELS, venueRules } from "./venue-rules.ts";
|
|
17
17
|
import { buildConfig, OPTIONAL_RULES, SHIPPED_RULES } from "./cli.ts";
|
|
18
|
+
import { present } from "../test/support.ts";
|
|
18
19
|
|
|
19
20
|
const VENUES = packageVenuesDir();
|
|
20
21
|
const PAPER = "/work/papers/p";
|
|
@@ -529,12 +530,15 @@ describe("where a finding points", () => {
|
|
|
529
530
|
});
|
|
530
531
|
|
|
531
532
|
describe("paperlint's own config turns the venue rules on for every paper.tex", () => {
|
|
532
|
-
const
|
|
533
|
-
(
|
|
534
|
-
|
|
533
|
+
const texRules = present(
|
|
534
|
+
buildConfig({}, { sentinel: "tex language" }).find((b) =>
|
|
535
|
+
(b.files ?? []).includes("**/paper.tex"),
|
|
536
|
+
)?.rules,
|
|
537
|
+
"the paper.tex block's rules",
|
|
538
|
+
);
|
|
535
539
|
|
|
536
540
|
it.each(Object.entries(VENUE_RULE_LEVELS))("%s is on at %s", (id, level) => {
|
|
537
|
-
expect(
|
|
541
|
+
expect(texRules[id]).toBe(level);
|
|
538
542
|
expect(SHIPPED_RULES.has(id)).toBe(true);
|
|
539
543
|
expect(OPTIONAL_RULES.has(id)).toBe(false);
|
|
540
544
|
});
|
package/src/venue-rules.ts
CHANGED
|
@@ -45,8 +45,9 @@ import {
|
|
|
45
45
|
import type { KindLimits, VenueFormat } from "./tex-requirements.ts";
|
|
46
46
|
import { paperPreset, presetProblemText } from "./presets.ts";
|
|
47
47
|
import type { FlatGeometry } from "./domain/geometry.ts";
|
|
48
|
-
import
|
|
48
|
+
import { callerPath } from "./caller-path.ts";
|
|
49
49
|
import { sha256Hex } from "./domain/sha256.ts";
|
|
50
|
+
import { fieldOf } from "./domain/record.ts";
|
|
50
51
|
import type { Files } from "./ports/files.ts";
|
|
51
52
|
import { CONFIG_FILE } from "#lib/paper-config";
|
|
52
53
|
|
|
@@ -92,9 +93,8 @@ export interface VenueRuleDeps {
|
|
|
92
93
|
readonly venuesDir: string;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
const at = (p: string): AbsolutePath => p as AbsolutePath;
|
|
96
96
|
const text = (files: Files, p: string): string | null => {
|
|
97
|
-
const b = files.readBytes(
|
|
97
|
+
const b = files.readBytes(callerPath(p));
|
|
98
98
|
return b === null ? null : new TextDecoder().decode(b);
|
|
99
99
|
};
|
|
100
100
|
|
|
@@ -138,7 +138,7 @@ function freshFacts(
|
|
|
138
138
|
: finding("factsBroken", { why: parsed.error.why });
|
|
139
139
|
const f = parsed.value;
|
|
140
140
|
const pdf = files.readBytes(
|
|
141
|
-
|
|
141
|
+
callerPath(isAbsolute(f.pdf) ? f.pdf : join(paperDir, f.pdf)),
|
|
142
142
|
);
|
|
143
143
|
if (pdf === null) return finding("pdfMissing", { pdf: f.pdf });
|
|
144
144
|
return sha256Hex(pdf) === f.sha ? f : finding("stale", { pdf: f.pdf });
|
|
@@ -373,8 +373,7 @@ const JUDGES: Readonly<Record<VenueRuleName, Judge>> = {
|
|
|
373
373
|
a.facts.geometry,
|
|
374
374
|
a.venue.format,
|
|
375
375
|
a.venue.venue,
|
|
376
|
-
(options[0]
|
|
377
|
-
DEFAULT_DIM_TOL_IN,
|
|
376
|
+
dimTolOf(options[0]),
|
|
378
377
|
)
|
|
379
378
|
: [],
|
|
380
379
|
limits: (a) =>
|
|
@@ -390,6 +389,12 @@ const JUDGES: Readonly<Record<VenueRuleName, Judge>> = {
|
|
|
390
389
|
/** How far, in inches, a measured page dimension may be from the preset's. */
|
|
391
390
|
export const DEFAULT_DIM_TOL_IN = 0.05;
|
|
392
391
|
|
|
392
|
+
/** `geometry`'s `dimTol` option in inches, or the default when the rule was given none. */
|
|
393
|
+
function dimTolOf(options: unknown): number {
|
|
394
|
+
const tol = fieldOf(options, "dimTol");
|
|
395
|
+
return typeof tol === "number" ? tol : DEFAULT_DIM_TOL_IN;
|
|
396
|
+
}
|
|
397
|
+
|
|
393
398
|
type Meta = Pick<VenueRuleModule["meta"], "docs" | "messages"> & {
|
|
394
399
|
readonly type?: "suggestion";
|
|
395
400
|
readonly schema?: readonly object[];
|
|
@@ -565,9 +570,14 @@ function rule(name: VenueRuleName, deps: VenueRuleDeps): VenueRuleModule {
|
|
|
565
570
|
export function venueRules(
|
|
566
571
|
deps: VenueRuleDeps,
|
|
567
572
|
): Record<VenueRuleName, VenueRuleModule> {
|
|
568
|
-
|
|
569
|
-
return
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
+
// Every name listed: a record missing one is a compile error.
|
|
574
|
+
return {
|
|
575
|
+
fresh: rule("fresh", deps),
|
|
576
|
+
profile: rule("profile", deps),
|
|
577
|
+
measured: rule("measured", deps),
|
|
578
|
+
fonts: rule("fonts", deps),
|
|
579
|
+
geometry: rule("geometry", deps),
|
|
580
|
+
limits: rule("limits", deps),
|
|
581
|
+
"body-size": rule("body-size", deps),
|
|
582
|
+
};
|
|
573
583
|
}
|
|
@@ -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.ts";
|
|
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,100 +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
|
-
/** What a test may replace in one row: any cell, and for a GATES row its `Requires` cell. */
|
|
8
|
-
export interface RowOverride {
|
|
9
|
-
readonly status?: string;
|
|
10
|
-
readonly date?: string;
|
|
11
|
-
readonly skill?: string;
|
|
12
|
-
readonly result?: string;
|
|
13
|
-
readonly requires?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Per-row overrides by row id, plus the four free-text parts of the file. */
|
|
17
|
-
export interface ScorecardOverrides {
|
|
18
|
-
readonly verdict?: string;
|
|
19
|
-
readonly deadline?: string;
|
|
20
|
-
readonly tail?: string;
|
|
21
|
-
readonly preamble?: string;
|
|
22
|
-
readonly [id: string]: RowOverride | string | undefined;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface Row extends RowOverride {
|
|
26
|
-
readonly id: string;
|
|
27
|
-
readonly status: string;
|
|
28
|
-
readonly date: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** A row's overrides; the free-text keys never name a row, so a string here is none. */
|
|
32
|
-
const cellsOf = (v: RowOverride | string | undefined): RowOverride =>
|
|
33
|
-
typeof v === "object" ? v : {};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* A scorecard with the four sections the template requires, all green. `over` replaces individual
|
|
37
|
-
* cells: `{ cites: { date: "2020-01-01" } }`, `{ verdict: "…" }`, `{ deadline: "2026-08-18" }`,
|
|
38
|
-
* `{ tail: "…" }` for anything appended after the last section, `{ preamble: "…" }` for anything
|
|
39
|
-
* inserted BEFORE the first heading (the only way to plant a row under no heading at all).
|
|
40
|
-
*/
|
|
41
|
-
export function scorecard(
|
|
42
|
-
over: ScorecardOverrides = {},
|
|
43
|
-
today: string = new Date().toISOString().slice(0, 10),
|
|
44
|
-
): string {
|
|
45
|
-
const r = (id: string, status = "☑", date = today): Row => ({
|
|
46
|
-
id,
|
|
47
|
-
status,
|
|
48
|
-
date,
|
|
49
|
-
...cellsOf(over[id]),
|
|
50
|
-
});
|
|
51
|
-
const row = (o: Row, ...mid: string[]): string =>
|
|
52
|
-
`| ${o.id} | work | ${o.skill ?? "skill"} | ${mid.length ? mid.join(" | ") + " | " : ""}${o.status} | ${o.date} | ${o.result ?? "result"} | — |`;
|
|
53
|
-
// The GATES `Requires` cell, canonical by default so the baseline is silent — `{ structure: {
|
|
54
|
-
// requires: "render" } }` plants a dropped edge. `harden` deliberately declares four of its five
|
|
55
|
-
// canonical inputs: the fifth (`priordelta`) has no row in this fixture, and the clean case asserts that the checker stays
|
|
56
|
-
// quiet about an edge there is nowhere to point at.
|
|
57
|
-
const req = (id: string, dflt: string): string =>
|
|
58
|
-
cellsOf(over[id]).requires ?? dflt;
|
|
59
|
-
const verdict =
|
|
60
|
-
over.verdict ??
|
|
61
|
-
"Submit-ready — every gate green, artifact reproduces clean, nothing blocking.";
|
|
62
|
-
return [
|
|
63
|
-
"# PIPELINE-STATUS — harness fixture",
|
|
64
|
-
`Venue: Fixture Workshop · Deadline: ${over.deadline ?? FAR} · Blind: double · State: drafting`,
|
|
65
|
-
"",
|
|
66
|
-
`**Readiness verdict:** ${verdict}`,
|
|
67
|
-
"",
|
|
68
|
-
over.preamble ?? "",
|
|
69
|
-
"",
|
|
70
|
-
"### SETUP",
|
|
71
|
-
"| id | Work | Skill | Status | Date | Result | Open |",
|
|
72
|
-
"|----|------|-------|--------|------|--------|------|",
|
|
73
|
-
row(r("idea")),
|
|
74
|
-
row(r("access")),
|
|
75
|
-
row(r("frame")),
|
|
76
|
-
"",
|
|
77
|
-
"### LOOP",
|
|
78
|
-
"| id | Work | Skill | Status | Date | Result | Open |",
|
|
79
|
-
"|----|------|-------|--------|------|--------|------|",
|
|
80
|
-
row(r("study")),
|
|
81
|
-
row(r("draft")),
|
|
82
|
-
row(r("arc")),
|
|
83
|
-
"",
|
|
84
|
-
"### CONTINUOUS",
|
|
85
|
-
"| id | Trigger | Skill | Status | Date | Result | Open |",
|
|
86
|
-
"|----|---------|-------|--------|------|--------|------|",
|
|
87
|
-
row(r("cites")),
|
|
88
|
-
row(r("render")),
|
|
89
|
-
"",
|
|
90
|
-
"### GATES",
|
|
91
|
-
"| id | Gate | Skill | Requires | Status | Date | Result | Open |",
|
|
92
|
-
"|----|------|-------|----------|--------|------|--------|------|",
|
|
93
|
-
row(r("structure"), req("structure", "render, arc")),
|
|
94
|
-
row(r("writing"), req("writing", "draft, arc, structure")),
|
|
95
|
-
row(r("panel"), req("panel", "structure, writing")),
|
|
96
|
-
row(r("harden"), req("harden", "panel, structure, writing, cites")),
|
|
97
|
-
"",
|
|
98
|
-
over.tail ?? "",
|
|
99
|
-
].join("\n");
|
|
100
|
-
}
|