diff --git a/README.md b/README.md index 55da715..30f7e3d 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,13 @@ the documentation true. Installed as a plugin, it answers to `harness`: `/harness:task`, `/harness:status`. +![The failing tests are written first, they fail, and you are the one who sees the +failure before any code is written](docs/demo/tests-and-gate.gif) + +Stage 6 of a real task. The tests are written before the feature, they fail for the +reason they were meant to, and the question you are asked is the plugin's — Claude +neither writes it nor sees your answer. Declining sends the task back. + It governs three things, and they are independent of each other: - **Documents** — a short top-level design, a searchable record of decisions, and a @@ -16,9 +23,11 @@ It governs three things, and they are independent of each other: - **Workspace** — one per task, isolated, findable again weeks later. - **Stages** — ten of them, three ending in a dialog you answer. -> **Status: early.** The harness has been through one real task — its own, fixing -> five defects that its first run exposed — and the ten stages, the refusal and the -> approval dialogs all held. +> **Status: early.** The harness has been through two tasks. Its own — fixing five +> defects that its first run exposed — and the one above, run end to end on a +> separate repository it had never seen: interview, design, decision records, +> failing tests, implementation, acceptance, commit. The ten stages and the three +> dialogs all held, and no source file was written before the design was approved. ## Why @@ -51,6 +60,12 @@ advancing is refused unless the stage actually produced something. The stages in bold end with a dialog whose wording the plugin owns — Claude cannot phrase the question you are asked, and your answer never passes through it. +![The design and its test cases are presented, and stage 5 asks whether to accept +them before any code may be written](docs/demo/design-gate.gif) + +Stage 5, from the same task: the test cases are laid out, and accepting them is what +unlocks writing code in the repository. Until then the refusal below is in force. + ## The one refusal Until you approve the design at stage 5, **nothing inside a repository is diff --git a/docs/demo/design-gate.gif b/docs/demo/design-gate.gif new file mode 100644 index 0000000..273bad7 Binary files /dev/null and b/docs/demo/design-gate.gif differ diff --git a/docs/demo/tests-and-gate.gif b/docs/demo/tests-and-gate.gif new file mode 100644 index 0000000..9bb66b4 Binary files /dev/null and b/docs/demo/tests-and-gate.gif differ diff --git a/test/conventions.test.mjs b/test/conventions.test.mjs index 7385c4d..167c2eb 100644 --- a/test/conventions.test.mjs +++ b/test/conventions.test.mjs @@ -87,6 +87,21 @@ test('53 — both top-level documents are within the bound stated for them', () assert.match(read('skills/init/SKILL.md'), /about 200 lines, architecture\s+at about 350/); }); +test('54 — every local file the README points at is there', () => { + const readme = read('README.md'); + + // ![alt](path) and [text](path), minus anything with a scheme — a broken image in + // the first screen of the README is the most visible way for this project to be + // caught saying something untrue about itself. + const links = [...readme.matchAll(/!?\[[^\]]*\]\(([^)]+)\)/g)] + .map((m) => m[1].split('#')[0].trim()) + .filter((target) => target && !/^[a-z][a-z0-9+.-]*:/i.test(target)); + + assert.ok(links.length > 0, 'the README should point at something local'); + const missing = links.filter((target) => !existsSync(join(REPO, target))); + assert.deepEqual(missing, [], 'the README points at files that do not exist'); +}); + test('38 — one version, declared in three files, and an install line that reaches it', () => { const plugin = JSON.parse(read('.claude-plugin/plugin.json')); const marketplace = JSON.parse(read('.claude-plugin/marketplace.json'));