cde93883bd
- .planning/season-7-end-state.md answers principle-level the three questions per CONTEXT D-08: (a) what rest state means, (b) what the finite Roothold ceiling is tied to (count of authored fragments + Seasons), (c) the coda's tonal register (warm/quiet/specific/final). Cites SEAS-04, SEAS-09, SEAS-10, STRY-08; ROADMAP Phase 7; PITFALLS #1. - Includes the explicit 'What this document is NOT' boundary section so treatment-level scope creep is structurally rejected (binary-choice scene text, ending paragraph text, Lura's final line, credits screen — all authored Phase 7, not Phase 1). - scripts/doctrine.test.ts is the only automated enforcement of both Phase-1 doctrine docs (per CONTEXT D-07: no UX-string lint rule). Asserts file existence + required H2 sections + required source citations + boundary disclaimer. 8 assertions / 2 doc files. - vitest.config.ts include glob extended to scripts/**/*.test.ts so doctrine.test.ts is discovered by 'npm test'. - tsconfig.node.json include extended to scripts/**/*.ts so the strict-TS gate covers the new doc-lint test alongside the existing build configs. - 'npm test' green: 2 test files, 9 tests passing (sentinel + doctrine). - Per CONTEXT D-09: lives in .planning/, not docs/. Rule 3 [Blocking]: vitest.config.ts and tsconfig.node.json include globs extended to discover the new TypeScript test file (existing globs only covered .mjs scripts and src/ tests).
80 lines
3.2 KiB
TypeScript
80 lines
3.2 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { readFileSync, existsSync } from 'node:fs';
|
|
|
|
// PIPE-05 doctrine doc-lint test.
|
|
//
|
|
// Per RESEARCH § "Validation Architecture" PIPE-05 row, this is the only
|
|
// automated enforcement of the Phase-1 doctrine documents. CONTEXT D-07
|
|
// explicitly forbids a lint rule on UX strings, so this structural test
|
|
// asserts (a) both docs exist on disk, (b) each contains its required H2
|
|
// sections, (c) each cites its required source documents.
|
|
//
|
|
// If a future plan moves either doc, update PATH constants below.
|
|
|
|
describe('PIPE-05: doctrine documents exist with required H2 sections', () => {
|
|
describe('.planning/anti-fomo-doctrine.md', () => {
|
|
const PATH = '.planning/anti-fomo-doctrine.md';
|
|
|
|
it('exists', () => {
|
|
expect(existsSync(PATH)).toBe(true);
|
|
});
|
|
|
|
it('contains all 4 required H2 sections', () => {
|
|
const md = readFileSync(PATH, 'utf8');
|
|
expect(md).toMatch(/^## Banned Mechanics$/m);
|
|
expect(md).toMatch(/^## Allowed Engagement$/m);
|
|
expect(md).toMatch(/^## Review Checklist$/m);
|
|
expect(md).toMatch(/^## Source Documents$/m);
|
|
});
|
|
|
|
it('cites all 4 source documents (PROJECT, REQUIREMENTS, CLAUDE, PITFALLS)', () => {
|
|
const md = readFileSync(PATH, 'utf8');
|
|
expect(md).toMatch(/PROJECT\.md/);
|
|
expect(md).toMatch(/REQUIREMENTS\.md/);
|
|
expect(md).toMatch(/CLAUDE\.md/);
|
|
expect(md).toMatch(/PITFALLS\.md/);
|
|
});
|
|
|
|
it('does NOT propose a lint rule on UX strings (CONTEXT D-07 explicit rejection)', () => {
|
|
const md = readFileSync(PATH, 'utf8');
|
|
// The doc may *mention* that lint rules were rejected, but it must not
|
|
// propose adding one. Allow "no lint rule" but reject "add a lint rule".
|
|
expect(md).not.toMatch(/\b(add|implement|propose).{0,40}lint rule/i);
|
|
});
|
|
});
|
|
|
|
describe('.planning/season-7-end-state.md', () => {
|
|
const PATH = '.planning/season-7-end-state.md';
|
|
|
|
it('exists', () => {
|
|
expect(existsSync(PATH)).toBe(true);
|
|
});
|
|
|
|
it('contains all 5 required H2 sections (CONTEXT D-08)', () => {
|
|
const md = readFileSync(PATH, 'utf8');
|
|
expect(md).toMatch(/^## What does \*rest state\* mean\?$/m);
|
|
expect(md).toMatch(/^## What is the finite Roothold ceiling tied to\?$/m);
|
|
expect(md).toMatch(/^## What tonal register does the coda live in\?$/m);
|
|
expect(md).toMatch(/^## What this document is NOT$/m);
|
|
expect(md).toMatch(/^## Source Documents$/m);
|
|
});
|
|
|
|
it('cites SEAS-04, SEAS-09, SEAS-10, STRY-08', () => {
|
|
const md = readFileSync(PATH, 'utf8');
|
|
expect(md).toMatch(/SEAS-04/);
|
|
expect(md).toMatch(/SEAS-09/);
|
|
expect(md).toMatch(/SEAS-10/);
|
|
expect(md).toMatch(/STRY-08/);
|
|
});
|
|
|
|
it('does NOT include treatment-level details forbidden by CONTEXT D-08', () => {
|
|
const md = readFileSync(PATH, 'utf8');
|
|
// Check the "What this document is NOT" section is present — this is the
|
|
// structural guarantee against treatment-level scope creep.
|
|
expect(md).toMatch(/## What this document is NOT/);
|
|
// The doc must explicitly disclaim authoring the ending paragraphs.
|
|
expect(md).toMatch(/authored Phase 7/);
|
|
});
|
|
});
|
|
});
|