test: strengthen fix branch workflow evidence

This commit is contained in:
sechmachine
2026-08-15 14:32:26 +07:00
parent d617769499
commit 719e02ea90
@@ -3,8 +3,9 @@
- **Test type:** Unit (documentation contract) - **Test type:** Unit (documentation contract)
- **Requirement IDs:** `OPS-019`, `TST-009`, `TST-010` - **Requirement IDs:** `OPS-019`, `TST-009`, `TST-010`
- **Scenario IDs:** `AC-TST-001` - **Scenario IDs:** `AC-TST-001`
- **Test class/method:** Shell documentation contract: `fixBranchWorkflowRule` - **Test class/method:** `scripts/verify-fix-branch-workflow.cjs --self-test`
- **Implementation commit:** `f013ad7707b36959ddca891fe0d52f81bba3ee80` - **Implementation commit:** `f013ad7707b36959ddca891fe0d52f81bba3ee80`
- **Review-fix commit:** `d617769499362e92d058684501af3c1ae6b145b0`
## Protected behavior ## Protected behavior
@@ -15,17 +16,18 @@ the impossible `work/<feature>/fix/<what-fix>` form while persistent
## Test method ## Test method
Use fixed-string repository searches rather than an artificial Java test. The Use the tracked Node validator rather than an artificial Java test. It requires
RED proves the required branch name was absent from the four contributor guides. the exact approved statement in each of the six guides, then self-tests that an
The GREEN checks every tracked guide and the design/plan records, then the extra positive nested-branch recommendation is rejected. The original RED
local requirements/SRS generator checks the unchanged requirement and use-case proves the required branch name was absent from the four contributor guides;
counts. the review-fix RED proves the executable regression was absent.
## Hand-derived expected result ## Hand-derived expected result
The required fix-branch spelling appears in all six tracked documentation The required fix-branch spelling appears exactly once in each of the six tracked
artifacts. The four contributor guides and design record identify the nested documentation artifacts, and the only nested-form reference is inside that
form only as forbidden. The existing SRS generator must still report 260 artifact's exact approved statement. A simulated positive nested-branch
recommendation must fail. The existing SRS generator must still report 260
requirements and 14 use cases. requirements and 14 use cases.
## RED ## RED
@@ -45,27 +47,37 @@ exit 1; no matching lines
The failure was expected: the required realizable repair-branch rule was absent The failure was expected: the required realizable repair-branch rule was absent
before this documentation change. before this documentation change.
## GREEN ### Review-fix RED
**Command** **Command**
```text ```text
rg -n -F 'work/fix/<feature>/<what-fix>' AGENTS.md README.md DEVELOPMENT.md TESTING.md docs/superpowers/specs/2026-08-15-access-navigation-icon-intern-picker-design.md docs/superpowers/plans/2026-08-15-access-navigation-icon-intern-picker.md && rg -n -F 'work/<feature>/fix/<what-fix>' AGENTS.md README.md DEVELOPMENT.md TESTING.md docs/superpowers/specs/2026-08-15-access-navigation-icon-intern-picker-design.md docs/superpowers/plans/2026-08-15-access-navigation-icon-intern-picker.md node scripts/verify-fix-branch-workflow.cjs --self-test
``` ```
**Observed result** **Observed result**
```text ```text
exit 0 exit 1
AGENTS.md:123 Error: Cannot find module '.../scripts/verify-fix-branch-workflow.cjs'
README.md:131 ```
DEVELOPMENT.md:68
TESTING.md:124
docs/superpowers/specs/2026-08-15-access-navigation-icon-intern-picker-design.md:17
docs/superpowers/plans/2026-08-15-access-navigation-icon-intern-picker.md:13
The nested form appears only in instructions that call it invalid, forbidden, The executable regression required to reject a positive nested-branch
or a form not to use. recommendation did not exist.
## GREEN
**Command**
```text
node scripts/verify-fix-branch-workflow.cjs --self-test
```
**Observed result**
```text
Fix-branch workflow documentation: 6 approved statements validated
Positive nested branch recommendation: rejected
``` ```
## Affected suite ## Affected suite
@@ -76,13 +88,14 @@ or a form not to use.
node labtimesheet-docs-hub/ui-mockups/build-srs.cjs node labtimesheet-docs-hub/ui-mockups/build-srs.cjs
node -e 'const fs=require("node:fs"); const checks=[["authoritative","labtimesheet-docs-hub/requirements-specification.md",/^\| ([A-Z]{2,4}-\d{3}) \|/gm],["explained","labtimesheet-docs-hub/explained/requirements-specification.md",/^\| ([A-Z]{2,4}-\d{3}) \|/gm],["simple","labtimesheet-docs-hub/explained/requirements-specification-simple.md",/^- \*\*([A-Z]{2,4}-\d{3}):\*\*/gm],["generated SRS","labtimesheet-docs-hub/software-requirements-specification.md",/^\| ([A-Z]{2,4}-\d{3}) \|/gm]]; for (const [name,file,pattern] of checks) { const ids=[...fs.readFileSync(file,"utf8").matchAll(pattern)].map(match=>match[1]); if (ids.length !== 260 || new Set(ids).size !== 260) throw new Error(`${name}: ${ids.length} rows, ${new Set(ids).size} unique`); console.log(`${name}: ${ids.length} rows, ${new Set(ids).size} unique IDs`); } const srs=fs.readFileSync("labtimesheet-docs-hub/software-requirements-specification.md","utf8"); const useCases=(srs.match(/^### 5\.\d+ UC-\d{2} —/gm)||[]).length; if (useCases !== 14) throw new Error(`SRS use cases: ${useCases}`); console.log(`generated SRS: ${useCases} use cases`);' node -e 'const fs=require("node:fs"); const checks=[["authoritative","labtimesheet-docs-hub/requirements-specification.md",/^\| ([A-Z]{2,4}-\d{3}) \|/gm],["explained","labtimesheet-docs-hub/explained/requirements-specification.md",/^\| ([A-Z]{2,4}-\d{3}) \|/gm],["simple","labtimesheet-docs-hub/explained/requirements-specification-simple.md",/^- \*\*([A-Z]{2,4}-\d{3}):\*\*/gm],["generated SRS","labtimesheet-docs-hub/software-requirements-specification.md",/^\| ([A-Z]{2,4}-\d{3}) \|/gm]]; for (const [name,file,pattern] of checks) { const ids=[...fs.readFileSync(file,"utf8").matchAll(pattern)].map(match=>match[1]); if (ids.length !== 260 || new Set(ids).size !== 260) throw new Error(`${name}: ${ids.length} rows, ${new Set(ids).size} unique`); console.log(`${name}: ${ids.length} rows, ${new Set(ids).size} unique IDs`); } const srs=fs.readFileSync("labtimesheet-docs-hub/software-requirements-specification.md","utf8"); const useCases=(srs.match(/^### 5\.\d+ UC-\d{2} —/gm)||[]).length; if (useCases !== 14) throw new Error(`SRS use cases: ${useCases}`); console.log(`generated SRS: ${useCases} use cases`);'
node -e 'const fs=require("node:fs"); const path=require("node:path"); let checked=0; const broken=[]; for (const file of process.argv.slice(1)) { const text=fs.readFileSync(file,"utf8"); for (const match of text.matchAll(/!?\[[^\]]*\]\(([^)]+)\)/g)) { const target=match[1].trim().replace(/^<|>$/g,"").split("#")[0].split("?")[0]; if (!target || /^[a-z][a-z0-9+.-]*:/i.test(target) || target.startsWith("//")) continue; checked += 1; if (!fs.existsSync(path.resolve(path.dirname(file), decodeURIComponent(target)))) broken.push(`${file}: ${target}`); } } if (broken.length) throw new Error(`Broken local Markdown links:\n${broken.join("\n")}`); console.log(`Local Markdown links: ${checked} resolved`);' AGENTS.md README.md DEVELOPMENT.md TESTING.md docs/superpowers/specs/2026-08-15-access-navigation-icon-intern-picker-design.md docs/superpowers/plans/2026-08-15-access-navigation-icon-intern-picker.md docs/tests/unit/fix-branch-workflow-documentation.md node -e 'const fs=require("node:fs"); const path=require("node:path"); let checked=0; const broken=[]; for (const file of process.argv.slice(1)) { const text=fs.readFileSync(file,"utf8"); for (const match of text.matchAll(/!?\[[^\]]*\]\(([^)]+)\)/g)) { const target=match[1].trim().replace(/^<|>$/g,"").split("#")[0].split("?")[0]; if (!target || /^[a-z][a-z0-9+.-]*:/i.test(target) || target.startsWith("//")) continue; checked += 1; if (!fs.existsSync(path.resolve(path.dirname(file), decodeURIComponent(target)))) broken.push(`${file}: ${target}`); } } if (broken.length) throw new Error(`Broken local Markdown links:\n${broken.join("\n")}`); console.log(`Local Markdown links: ${checked} resolved`);' AGENTS.md README.md DEVELOPMENT.md TESTING.md docs/superpowers/specs/2026-08-15-access-navigation-icon-intern-picker-design.md docs/superpowers/plans/2026-08-15-access-navigation-icon-intern-picker.md docs/tests/unit/fix-branch-workflow-documentation.md
git diff --check git diff --check 8be1b754e188367b260981718a5d33fc2d4d8a3b d617769499362e92d058684501af3c1ae6b145b0
``` ```
The SRS regeneration and count assertion ran from the main root because the The SRS regeneration and count assertion ran from the main root because the
ignored requirements hub is local authority there. The link assertion and ignored requirements hub is local authority there. The link assertion and
`git diff --check` ran from this fix worktree; the SRS generator also rejects a the exact base-to-candidate `git diff --check` ran from this fix worktree; the
broken local SRS target before it writes the generated file. SRS generator also rejects a broken local SRS target before it writes the
generated file.
```text ```text
Wrote labtimesheet-docs-hub/software-requirements-specification.md Wrote labtimesheet-docs-hub/software-requirements-specification.md
@@ -92,8 +105,10 @@ explained: 260 rows, 260 unique IDs
simple: 260 rows, 260 unique IDs simple: 260 rows, 260 unique IDs
generated SRS: 260 rows, 260 unique IDs generated SRS: 260 rows, 260 unique IDs
generated SRS: 14 use cases generated SRS: 14 use cases
Fix-branch workflow documentation: 6 approved statements validated
Positive nested branch recommendation: rejected
Local Markdown links: 7 resolved Local Markdown links: 7 resolved
git diff --check: exit 0 git diff --check 8be1b754e188367b260981718a5d33fc2d4d8a3b d617769499362e92d058684501af3c1ae6b145b0: exit 0
``` ```
## External-test boundaries ## External-test boundaries