From 5cd042762c7631ba76974ba4c2454f905c7b858e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:15:10 +0000 Subject: [PATCH 1/3] Initial plan From 103669467501befe9a8c8bd802d69c9f08b17889 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:27:34 +0000 Subject: [PATCH 2/3] Add requirement granularity guidance to README, AGENTS.md section, and spec template --- AGENTS.md | 42 ++++++++++++---- README.md | 72 +++++++++++++++++++++++++++ package-lock.json | 4 -- specs/REQ-010-granularity-guidance.md | 32 ++++++++++++ src/init.ts | 38 ++++++++++++-- tests/granularity.test.ts | 34 +++++++++++++ 6 files changed, 204 insertions(+), 18 deletions(-) create mode 100644 specs/REQ-010-granularity-guidance.md create mode 100644 tests/granularity.test.ts diff --git a/AGENTS.md b/AGENTS.md index 120de08..8e20de7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,17 +5,39 @@ This repository enforces spec-driven testing with [2119](https://www.rfc-editor. **When planning a feature**, write or update a spec in `specs/` first. Every requirement is a numbered item under a `### REQ-NNN.M` heading with exactly one -RFC 2119 keyword. Run `npx 2119 lint` after editing specs. +RFC 2119 keyword, stating an observable outcome — not an implementation +mechanism. Run `npx rfc2119 lint` after editing specs. **Before writing tests +against a new spec**, dispatch a fresh-context reviewer to critique the draft +requirements themselves: outcome-stated, individually testable, one obligation +each. A flawed requirement steers the whole implementation wrong. + +**Requirement granularity**: A first-pass feature spec should aim for around +3–8 enforced `MUST` requirements. Prefer workflow-level requirements (what the +user can observably do) over implementation-step requirements (how the code +achieves it). Spec sizing smells — reconsider the spec if: one feature produces +more than ~10 enforced requirements before tests exist; most requirements +restate internal steps rather than user-visible outcomes; a single test would +cover many requirements at once; or requirements say "MUST cover" or "MUST test" +instead of describing product behavior. Use `SHOULD` for polish and edge cases, +`[manual]` for UI-only behaviors, and notes or acceptance-checklist bullets for +implementation details rather than making every detail an enforced `MUST`. **When implementing**, every MUST/SHALL requirement needs at least one test -annotated with a comment containing its ID, e.g. `// 2119: REQ-001.2.3`. -Write tests that would genuinely fail if the requirement were violated — a -fresh-context reviewer will judge each test's honesty, and tautological or -over-mocked tests will be rejected. +annotated with a comment containing its ID, e.g. `// 2119: REQ-001.2.3` (the +marker line must start with a comment leader). Write tests that would genuinely +fail if the requirement were violated — including its negative space: what the +requirement forbids needs a rejection test, not just what it allows. A +fresh-context reviewer judges each test's honesty; tautological or over-mocked +tests will be rejected. + +**Reviewer diversity**: use reviewer models from different providers, routinely +or as periodic `npx rfc2119 review --audit` sweeps — adversarial audits of +passing verdicts. Audit especially the challenging or high-consequence +requirements; a single model family shares blind spots. -**Before finishing any task**, run `npx 2119 check`. It must exit 0. If it -reports pending judgment reviews, run `npx 2119 review` and dispatch each -instruction file in `.2119/reviews/` to a fresh-context subagent (never -review your own work in the same context). CI runs the same check, so skipping -it locally only defers the failure. +**Before finishing any task**, run `npx rfc2119 check`. It must exit 0. If it +reports pending judgment reviews, run `npx rfc2119 review --dispatch` and +dispatch each instruction file in `.2119/reviews/` to a fresh-context subagent +(never review your own work in the same context). CI runs the same check, so +skipping it locally only defers the failure. diff --git a/README.md b/README.md index f26b517..8d80706 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,78 @@ Here are some anti-patterns to avoid: - **A keyword-grep test standing in for a judgment call** (e.g. `assert "fix" in error_message` for "errors MUST tell the user how to fix the problem") — the substring "fix" appearing proves nothing about whether the message actually explains the fix; "could not fix" passes it. The test can't fail honestly. Use `[review]` instead. - **A review used on a machine-checkable fact** (e.g. using a reviewer to "check the version field equals 2") — that's judgment spent where a test is stronger. +## Requirement granularity + +When drafting requirements for a feature, prefer a small number of user-meaningful, +workflow-level requirements over many implementation-step requirements. + +A first-pass feature spec should usually contain **around 3–8 enforced `MUST` +requirements**. More granular requirements are appropriate only when each one +represents a distinct user promise, safety invariant, compatibility guarantee, or +independently valuable behavior. + +Avoid turning every implementation detail into a separate `MUST`. Instead: + +- Use `[manual]` for behavior that is primarily verified through UI or manual inspection. +- Use `SHOULD` for polish, edge cases, and preferred behavior that should not block the first enforcement pass. +- Use explanatory notes or acceptance-checklist bullets (in the spec's notes section) for implementation details. +- Split requirements only when each resulting requirement has a clear independent test or review value. + +**Good:** + +> A user MUST be able to paste an image into the composer, see it appear as an +> attachment chip, and send it as an image attachment. + +**Less good as separate first-pass requirements:** + +> The paste handler MUST read from the pasteboard. +> The classifier MUST create an image attachment. +> The chip area MUST become visible. +> The chip MUST show a thumbnail. +> The RPC payload MUST contain an image object. +> The transcript MUST show the image. + +Those details may be useful, but they are often better expressed as notes, +manual criteria, or later hardening requirements unless each one needs independent +enforcement. + +### Spec sizing smells + +Reconsider the spec if: + +- One feature produces more than ~10 enforced `MUST`s before tests exist. +- Most requirements are restating internal implementation steps. +- A reviewer would need to approve many requirements using the same single test. +- The requirement says "MUST cover" or "MUST test" instead of describing product behavior. +- Many requirements differ only by small UI details. + +### Starter spec structure + +The template that `2119 init` creates nudges toward this shape: + +```markdown +### REQ-001.1: Core workflows + +List 3–5 user workflows as `MUST`s. + +### REQ-001.2: Safety and compatibility invariants + +List only critical invariants as `MUST`s. + +### REQ-001.3: Manual acceptance criteria + +Use `[manual]` for visual/UI workflows that are not automated yet. + +## Notes and non-goals + +Put implementation details and deferred polish here instead of making them +enforced requirements. +``` + +This keeps 2119 adoption lightweight. Teams can start with a manageable enforced +surface, then split or harden requirements later when individual behaviors prove +important enough to test or review independently. + ## Commands | Command | Does | diff --git a/package-lock.json b/package-lock.json index 58a677c..5c816ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -855,7 +855,6 @@ "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -1238,7 +1237,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -1452,7 +1450,6 @@ "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", @@ -1640,7 +1637,6 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, diff --git a/specs/REQ-010-granularity-guidance.md b/specs/REQ-010-granularity-guidance.md new file mode 100644 index 0000000..e2e82c1 --- /dev/null +++ b/specs/REQ-010-granularity-guidance.md @@ -0,0 +1,32 @@ +# REQ-010: Requirement Granularity Guidance + +## Overview + +When agents draft a first-pass feature spec, 2119 should encourage workflow-level +requirements and warn against exploding a single feature into many +implementation-step `MUST`s. Without guidance, an agent can over-decompose one +feature into dozens of independently enforced requirements, making the +`cover`/`review` cycle disproportionately heavy before the team has even decided +which behaviors are core product promises versus implementation details, UI +polish, or manual acceptance criteria. + +This spec governs the granularity guidance that 2119 surfaces in three places: +the generated AGENTS.md workflow section, the starter spec template, and the +README. All three should consistently nudge agents toward a small, user-meaningful +enforced surface that teams can grow incrementally. + +## Requirements + +### REQ-010.1: Agent instruction guidance + +1. The AGENTS.md section MUST include guidance recommending around 3–8 enforced `MUST` requirements for a first-pass feature spec, with the rationale that workflow-level requirements are preferred over many implementation-step requirements. +2. The AGENTS.md section MUST include spec sizing smells — identifiable symptoms that a spec may be over-decomposed — such as a single feature producing more than ~10 enforced requirements before tests exist, requirements that restate internal implementation steps, or requirements that say "`MUST` cover" or "`MUST` test" instead of describing product behavior. + +### REQ-010.2: Spec template structure + +1. The starter spec template MUST include a dedicated section for core user workflows as `MUST` requirements. +2. The starter spec template MUST include a notes and non-goals section outside the `## Requirements` block, to give authors a designated place for implementation details and deferred polish rather than turning them into enforced requirements. + +### REQ-010.3: README guidance + +1. The README MUST include a requirement granularity section with guidance on appropriate scope for first-pass feature specs and examples of well-scoped versus over-decomposed requirements. [verify: node -e "const s = require('fs').readFileSync('README.md','utf8'); if (!s.includes('Requirement granularity')) process.exit(1)"] diff --git a/src/init.ts b/src/init.ts index e79c317..d3361af 100644 --- a/src/init.ts +++ b/src/init.ts @@ -44,7 +44,7 @@ const CONFIG_TEMPLATE = `# 2119 configuration — https://github.com/Unsupervise # audit: "always" `; -const SPEC_TEMPLATE = `# REQ-001: +export const SPEC_TEMPLATE = `# REQ-001: ## Overview @@ -53,12 +53,31 @@ Use imperatives sparingly (RFC 2119 §6): constrain observable outcomes, not implementation methods. Elaborate security implications of security-relevant requirements (RFC 2119 §7). +Aim for 3–8 enforced \`MUST\` requirements in a first-pass spec. Prefer +workflow-level requirements (what the user observably can do) over +implementation-step requirements (how the code achieves it). Use \`SHOULD\` for +polish and edge cases, \`[manual]\` for UI-only behaviors, and notes or +acceptance-checklist bullets in the Notes section for implementation details. + ## Requirements -### REQ-001.1:
+### REQ-001.1: Core workflows + +1. The user MUST be able to . + +### REQ-001.2: Safety and compatibility invariants + +1. The system MUST NOT . -1. The system MUST . -2. The system SHOULD . +### REQ-001.3: Manual acceptance criteria + +1. The user MUST be able to . [manual] + +## Notes and non-goals + +Implementation details and deferred polish belong here as prose rather than +enforced requirements. Acceptance-checklist items, out-of-scope behaviors, and +internal implementation notes go here instead of as additional \`MUST\`s. `; export const AGENTS_MD_SECTION = ` @@ -74,6 +93,17 @@ against a new spec**, dispatch a fresh-context reviewer to critique the draft requirements themselves: outcome-stated, individually testable, one obligation each. A flawed requirement steers the whole implementation wrong. +**Requirement granularity**: A first-pass feature spec should aim for around +3–8 enforced \`MUST\` requirements. Prefer workflow-level requirements (what the +user can observably do) over implementation-step requirements (how the code +achieves it). Spec sizing smells — reconsider the spec if: one feature produces +more than ~10 enforced requirements before tests exist; most requirements +restate internal steps rather than user-visible outcomes; a single test would +cover many requirements at once; or requirements say "MUST cover" or "MUST test" +instead of describing product behavior. Use \`SHOULD\` for polish and edge cases, +\`[manual]\` for UI-only behaviors, and notes or acceptance-checklist bullets for +implementation details rather than making every detail an enforced \`MUST\`. + **When implementing**, every MUST/SHALL requirement needs at least one test annotated with a comment containing its ID, e.g. \`// 2119: REQ-001.2.3\` (the marker line must start with a comment leader). Write tests that would genuinely diff --git a/tests/granularity.test.ts b/tests/granularity.test.ts new file mode 100644 index 0000000..e3d433d --- /dev/null +++ b/tests/granularity.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; +import { AGENTS_MD_SECTION, SPEC_TEMPLATE } from "../src/init.js"; + +describe("requirement granularity guidance", () => { + // 2119: REQ-010.1.1 + it("AGENTS.md section includes granularity guidance with 3–8 recommendation", () => { + expect(AGENTS_MD_SECTION).toContain("3–8"); + expect(AGENTS_MD_SECTION).toContain("workflow-level"); + }); + + // 2119: REQ-010.1.2 + it("AGENTS.md section includes spec sizing smells", () => { + expect(AGENTS_MD_SECTION).toContain("sizing smells"); + expect(AGENTS_MD_SECTION).toContain("~10"); + expect(AGENTS_MD_SECTION).toContain("internal steps"); + }); + + // 2119: REQ-010.2.1 + it("spec template includes core workflows and manual acceptance criteria sections", () => { + expect(SPEC_TEMPLATE).toContain("Core workflows"); + expect(SPEC_TEMPLATE).toContain("Safety and compatibility invariants"); + expect(SPEC_TEMPLATE).toContain("[manual]"); + }); + + // 2119: REQ-010.2.2 + it("spec template includes a notes and non-goals section outside Requirements", () => { + expect(SPEC_TEMPLATE).toContain("## Notes and non-goals"); + // The notes section must come after the ## Requirements block. + const reqIdx = SPEC_TEMPLATE.indexOf("## Requirements"); + const notesIdx = SPEC_TEMPLATE.indexOf("## Notes and non-goals"); + expect(reqIdx).toBeGreaterThan(-1); + expect(notesIdx).toBeGreaterThan(reqIdx); + }); +}); From 8eb936d2dfb611c5e56eb4729523d291ed33bb86 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:33:23 +0000 Subject: [PATCH 3/3] Strengthen granularity tests and add passing judgment verdicts --- .2119/verdicts/REQ-003.2.2--5aad1d64f506.json | 8 ++++++++ .2119/verdicts/REQ-003.4.2--020a385e7cde.json | 8 ++++++++ .2119/verdicts/REQ-005.2.6--2013df807fe7.json | 8 ++++++++ .2119/verdicts/REQ-008.1.2--b5bebba2533c.json | 8 ++++++++ .2119/verdicts/REQ-008.2.2--262945618870.json | 8 ++++++++ .2119/verdicts/REQ-010.1.1--0ffef5bf595d.json | 8 ++++++++ .2119/verdicts/REQ-010.1.1--321048fefa44.json | 8 ++++++++ .2119/verdicts/REQ-010.1.2--251ba2832873.json | 8 ++++++++ .2119/verdicts/REQ-010.1.2--251c3b25ce21.json | 8 ++++++++ .2119/verdicts/REQ-010.2.1--85413e6bde7b.json | 8 ++++++++ .2119/verdicts/REQ-010.2.1--92310078f9d2.json | 8 ++++++++ .2119/verdicts/REQ-010.2.2--324f15927592.json | 8 ++++++++ tests/granularity.test.ts | 20 +++++++++++++++---- 13 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 .2119/verdicts/REQ-003.2.2--5aad1d64f506.json create mode 100644 .2119/verdicts/REQ-003.4.2--020a385e7cde.json create mode 100644 .2119/verdicts/REQ-005.2.6--2013df807fe7.json create mode 100644 .2119/verdicts/REQ-008.1.2--b5bebba2533c.json create mode 100644 .2119/verdicts/REQ-008.2.2--262945618870.json create mode 100644 .2119/verdicts/REQ-010.1.1--0ffef5bf595d.json create mode 100644 .2119/verdicts/REQ-010.1.1--321048fefa44.json create mode 100644 .2119/verdicts/REQ-010.1.2--251ba2832873.json create mode 100644 .2119/verdicts/REQ-010.1.2--251c3b25ce21.json create mode 100644 .2119/verdicts/REQ-010.2.1--85413e6bde7b.json create mode 100644 .2119/verdicts/REQ-010.2.1--92310078f9d2.json create mode 100644 .2119/verdicts/REQ-010.2.2--324f15927592.json diff --git a/.2119/verdicts/REQ-003.2.2--5aad1d64f506.json b/.2119/verdicts/REQ-003.2.2--5aad1d64f506.json new file mode 100644 index 0000000..967cf9e --- /dev/null +++ b/.2119/verdicts/REQ-003.2.2--5aad1d64f506.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-003.2.2--5aad1d64f506", + "requirementId": "REQ-003.2.2", + "hash": "5aad1d64f506", + "verdict": "pass", + "summary": "init.ts gitignores only .2119/reviews/, verdict.ts writes plain JSON to .2119/verdicts/, and git ls-files confirms verdict files are committed and tracked", + "timestamp": "2026-07-22T18:27:54.589Z" +} diff --git a/.2119/verdicts/REQ-003.4.2--020a385e7cde.json b/.2119/verdicts/REQ-003.4.2--020a385e7cde.json new file mode 100644 index 0000000..3d9cf19 --- /dev/null +++ b/.2119/verdicts/REQ-003.4.2--020a385e7cde.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-003.4.2--020a385e7cde", + "requirementId": "REQ-003.4.2", + "hash": "020a385e7cde", + "verdict": "pass", + "summary": "README Risks section explicitly names all four required elements: agent can self-pass, committed+auditable verdicts, hash invalidation prevents stale reuse, and CI re-verification", + "timestamp": "2026-07-22T18:27:58.258Z" +} diff --git a/.2119/verdicts/REQ-005.2.6--2013df807fe7.json b/.2119/verdicts/REQ-005.2.6--2013df807fe7.json new file mode 100644 index 0000000..4b1ca53 --- /dev/null +++ b/.2119/verdicts/REQ-005.2.6--2013df807fe7.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-005.2.6--2013df807fe7", + "requirementId": "REQ-005.2.6", + "hash": "2013df807fe7", + "verdict": "pass", + "summary": "README line 73 states verbatim that verify commands execute arbitrary shell from spec files and carry the same trust level as package.json scripts", + "timestamp": "2026-07-22T18:28:05.520Z" +} diff --git a/.2119/verdicts/REQ-008.1.2--b5bebba2533c.json b/.2119/verdicts/REQ-008.1.2--b5bebba2533c.json new file mode 100644 index 0000000..96a1b8d --- /dev/null +++ b/.2119/verdicts/REQ-008.1.2--b5bebba2533c.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-008.1.2--b5bebba2533c", + "requirementId": "REQ-008.1.2", + "hash": "b5bebba2533c", + "verdict": "pass", + "summary": "README has bold 'What 2119 is not:' block with all three items (test runner, CI replacement, security boundary) and a link to docs/design.md, appearing before the '## Use it in your repo' adoption section", + "timestamp": "2026-07-22T18:28:07.426Z" +} diff --git a/.2119/verdicts/REQ-008.2.2--262945618870.json b/.2119/verdicts/REQ-008.2.2--262945618870.json new file mode 100644 index 0000000..0e55eaf --- /dev/null +++ b/.2119/verdicts/REQ-008.2.2--262945618870.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-008.2.2--262945618870", + "requirementId": "REQ-008.2.2", + "hash": "262945618870", + "verdict": "pass", + "summary": "Both README and scaling.md advise periodic cross-provider review --audit sweeps and targeted audits for high-consequence requirements", + "timestamp": "2026-07-22T18:27:58.700Z" +} diff --git a/.2119/verdicts/REQ-010.1.1--0ffef5bf595d.json b/.2119/verdicts/REQ-010.1.1--0ffef5bf595d.json new file mode 100644 index 0000000..162335a --- /dev/null +++ b/.2119/verdicts/REQ-010.1.1--0ffef5bf595d.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-010.1.1--0ffef5bf595d", + "requirementId": "REQ-010.1.1", + "hash": "0ffef5bf595d", + "verdict": "pass", + "summary": "All three requirement conjuncts checked: '3–8', 'workflow-level', and 'implementation-step'; removing any one fails the test; no tautology or over-mocking", + "timestamp": "2026-07-22T18:31:02.798Z" +} diff --git a/.2119/verdicts/REQ-010.1.1--321048fefa44.json b/.2119/verdicts/REQ-010.1.1--321048fefa44.json new file mode 100644 index 0000000..ecc1f50 --- /dev/null +++ b/.2119/verdicts/REQ-010.1.1--321048fefa44.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-010.1.1--321048fefa44", + "requirementId": "REQ-010.1.1", + "hash": "321048fefa44", + "verdict": "fail", + "summary": "Keyword theater: test checks toContain('workflow-level') but not 'implementation-step' or the preference framing; a rewrite dropping 'over implementation-step requirements' keeps both checked strings and passes while violating the stated rationale", + "timestamp": "2026-07-22T18:28:37.891Z" +} diff --git a/.2119/verdicts/REQ-010.1.2--251ba2832873.json b/.2119/verdicts/REQ-010.1.2--251ba2832873.json new file mode 100644 index 0000000..a388b5c --- /dev/null +++ b/.2119/verdicts/REQ-010.1.2--251ba2832873.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-010.1.2--251ba2832873", + "requirementId": "REQ-010.1.2", + "hash": "251ba2832873", + "verdict": "pass", + "summary": "All three required sizing smells checked with toContain that fail on removal: ~10 threshold, internal steps restatement, and quoted MUST cover/MUST test forms; string matching is appropriate for documentation-presence requirement", + "timestamp": "2026-07-22T18:31:17.129Z" +} diff --git a/.2119/verdicts/REQ-010.1.2--251c3b25ce21.json b/.2119/verdicts/REQ-010.1.2--251c3b25ce21.json new file mode 100644 index 0000000..6a73c2f --- /dev/null +++ b/.2119/verdicts/REQ-010.1.2--251c3b25ce21.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-010.1.2--251c3b25ce21", + "requirementId": "REQ-010.1.2", + "hash": "251c3b25ce21", + "verdict": "fail", + "summary": "Test omits the 'MUST cover'/'MUST test' smell: removing that clause from AGENTS_MD_SECTION would pass all three assertions while violating the requirement's third explicitly-named conjunct", + "timestamp": "2026-07-22T18:28:25.353Z" +} diff --git a/.2119/verdicts/REQ-010.2.1--85413e6bde7b.json b/.2119/verdicts/REQ-010.2.1--85413e6bde7b.json new file mode 100644 index 0000000..e238305 --- /dev/null +++ b/.2119/verdicts/REQ-010.2.1--85413e6bde7b.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-010.2.1--85413e6bde7b", + "requirementId": "REQ-010.2.1", + "hash": "85413e6bde7b", + "verdict": "pass", + "summary": "Core counterexamples pass: renamed section and SHOULD-only section both cause test failure; minor unrelated assertions (manual criteria checks) do not undermine REQ-010.2.1 coverage", + "timestamp": "2026-07-22T18:32:07.372Z" +} diff --git a/.2119/verdicts/REQ-010.2.1--92310078f9d2.json b/.2119/verdicts/REQ-010.2.1--92310078f9d2.json new file mode 100644 index 0000000..a3cfd1c --- /dev/null +++ b/.2119/verdicts/REQ-010.2.1--92310078f9d2.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-010.2.1--92310078f9d2", + "requirementId": "REQ-010.2.1", + "hash": "92310078f9d2", + "verdict": "fail", + "summary": "Test checks string presence of 'Core workflows' but never asserts that the section contains MUST requirements — the requirement's core obligation — so a Core workflows section with no MUST items would pass undetected (keyword theater)", + "timestamp": "2026-07-22T18:28:08.946Z" +} diff --git a/.2119/verdicts/REQ-010.2.2--324f15927592.json b/.2119/verdicts/REQ-010.2.2--324f15927592.json new file mode 100644 index 0000000..36feb4c --- /dev/null +++ b/.2119/verdicts/REQ-010.2.2--324f15927592.json @@ -0,0 +1,8 @@ +{ + "reviewId": "REQ-010.2.2--324f15927592", + "requirementId": "REQ-010.2.2", + "hash": "324f15927592", + "verdict": "pass", + "summary": "Both violations covered: missing section fails toContain, notes before Requirements fails index ordering; SPEC_TEMPLATE is real (not mocked); ## heading level prevents sub-heading bypass", + "timestamp": "2026-07-22T18:28:24.372Z" +} diff --git a/tests/granularity.test.ts b/tests/granularity.test.ts index e3d433d..7b28e45 100644 --- a/tests/granularity.test.ts +++ b/tests/granularity.test.ts @@ -3,22 +3,34 @@ import { AGENTS_MD_SECTION, SPEC_TEMPLATE } from "../src/init.js"; describe("requirement granularity guidance", () => { // 2119: REQ-010.1.1 - it("AGENTS.md section includes granularity guidance with 3–8 recommendation", () => { + it("AGENTS.md section includes granularity guidance with 3–8 recommendation and implementation-step contrast", () => { expect(AGENTS_MD_SECTION).toContain("3–8"); expect(AGENTS_MD_SECTION).toContain("workflow-level"); + // The rationale must name implementation-step requirements as what to avoid. + expect(AGENTS_MD_SECTION).toContain("implementation-step"); }); // 2119: REQ-010.1.2 - it("AGENTS.md section includes spec sizing smells", () => { + it("AGENTS.md section includes all required spec sizing smells", () => { expect(AGENTS_MD_SECTION).toContain("sizing smells"); expect(AGENTS_MD_SECTION).toContain("~10"); expect(AGENTS_MD_SECTION).toContain("internal steps"); + // The third smell: requirements that say "MUST cover" or "MUST test". + expect(AGENTS_MD_SECTION).toContain('"MUST cover"'); + expect(AGENTS_MD_SECTION).toContain('"MUST test"'); }); // 2119: REQ-010.2.1 - it("spec template includes core workflows and manual acceptance criteria sections", () => { + it("spec template includes core workflows section with MUST requirement and manual acceptance criteria", () => { + // The "Core workflows" section heading must be present. expect(SPEC_TEMPLATE).toContain("Core workflows"); - expect(SPEC_TEMPLATE).toContain("Safety and compatibility invariants"); + // The section must contain at least one MUST requirement (not just the heading). + const coreIdx = SPEC_TEMPLATE.indexOf("Core workflows"); + const nextSectionIdx = SPEC_TEMPLATE.indexOf("###", coreIdx + 1); + const coreSection = SPEC_TEMPLATE.slice(coreIdx, nextSectionIdx > -1 ? nextSectionIdx : undefined); + expect(coreSection).toContain("MUST"); + // Manual acceptance criteria section must also be present. + expect(SPEC_TEMPLATE).toContain("Manual acceptance criteria"); expect(SPEC_TEMPLATE).toContain("[manual]"); });