Skip to content

Commit 69a2d0d

Browse files
brabojclaude
andauthored
feat(templates): add a fixture stack and platform the per-stack checks read (#1925) (#1948)
stack-fixture and platform-fixture live under templates/fixture/ and carry fixture: true in the manifest. resolve.py's listings and cache and every block sync.py writes leave them out; a fixture still resolves when named. The smoke checks that read every stack now select by the manifest's stacks: key instead of the templates/stack/ directory, so they keep an input once the concrete stacks move to forks. SYS-14's cases name the fixtures, tests/context-tiers.txt records the fixture category at 200K, and the e2e canary moves from STK-15 to a new STK-24 on the fixture stack. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 447d5fa commit 69a2d0d

15 files changed

Lines changed: 273 additions & 48 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ alters no template carries no entry.
2121

2222
## [Unreleased]
2323

24+
### Added
25+
26+
- `templates/fixture/` adds `stack-fixture` and `platform-fixture`, test
27+
input marked `fixture: true` in the manifest. Listings and `generated/`
28+
omit them; per-stack checks select by the manifest's `stacks:` key, and
29+
the e2e canary is now STK-24 on the fixture.
30+
2431
### Breaking changes
2532

2633
- The concern directories leave `templates/base/`: `templates/base/<concern>/`

‎CLAUDE.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ templates/ # All template source files
2929
backend/ # Backend layer — HTTP, API, database, observability
3030
frontend/ # Frontend layer — UX, accessibility, CSS, SSG
3131
platform/ # CI and security tool mappings per hosting platform
32+
fixture/ # Test-input stack and platform — checked, never listed
3233
stack/ # Concrete stacks — extend base + layer templates
3334
INTERVIEW.md # Agent-driven project setup interview
3435
manifest.yaml # Machine-readable dependency graph
@@ -364,7 +365,7 @@ py tests/run_smoke.py SYS-01 # run one check by ID
364365
py tests/run_conformance.py # the templates' checks, against this repo
365366
py tests/run_conformance.py --list # dispositions only, run nothing
366367

367-
py tests/run_e2e.py # canary only (python-lib, needs API key)
368+
py tests/run_e2e.py # canary only (fixture stack, needs API key)
368369
py tests/run_e2e.py --all # all tests (live, needs API key)
369370
py tests/run_e2e.py --area=STK # run all stack tests
370371
py tests/run_e2e.py STK-01 FMT-01 # run specific tests by ID
@@ -380,7 +381,7 @@ py tests/run_e2e.py --dry-run # build prompts, call no model, write no repo
380381
- CI runs smoke, conformance, `sync.py --check`, `resolve.py --check`,
381382
the redundancy audit and gitleaks on PRs and on push to main
382383
- Live e2e calls a model and costs money, so it runs on a cadence
383-
rather than per change: the STK-15 canary at every release cut,
384+
rather than per change: the STK-24 canary at every release cut,
384385
recorded in the cut PR, and the full suite at each periodic review
385386
(PLAYBOOK, "Run the test suite")
386387
- To validate a new template: run `py tests/run_smoke.py` and

‎docs/PLAYBOOK.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ any entry that no longer applies.
362362
py tests/run_smoke.py # structural checks — seconds
363363
py tests/run_conformance.py # the templates' own checks, run here
364364
py tests/run_conformance.py --list # dispositions only, run nothing
365-
py tests/run_e2e.py # canary test (python-lib)
365+
py tests/run_e2e.py # canary test (fixture stack)
366366
py tests/run_e2e.py --all # all agent tests
367367
py tests/run_e2e.py STK-01 FMT-01 # specific tests only
368368
py tests/run_e2e.py --dry-run # build prompts, call no model, write no report
@@ -393,7 +393,7 @@ full list of specs. Requires `py -m pip install pyyaml` for the manifest
393393
check.
394394

395395
`run_e2e.py` is the one runner that calls a model and costs money, so it
396-
runs on a cadence rather than on every change: the STK-15 canary runs live
396+
runs on a cadence rather than on every change: the STK-24 canary runs live
397397
at every release cut, recorded in the cut's pull request, and the full
398398
suite runs live at each periodic review. It is also the only runner that
399399
reads what the templates generate — smoke and conformance read the
@@ -831,7 +831,7 @@ below exist to prevent. Run them here anyway.
831831
pull request's body is this repository's release proposal: it names
832832
every step of `core/git.md`'s pre-release sequence and the result
833833
it produced, including the checks that carry no step number here.
834-
It also records the STK-15 canary run live against the release commit:
834+
It also records the STK-24 canary run live against the release commit:
835835
the report's tree, provider, model and verdict lines.
836836
The check's two counts are not required to match: a commit touching
837837
no template carries no entry, so a journal or tooling change is

‎docs/SPEC.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ Extend base templates. Never used directly by a project.
4242

4343
Technology-specific rules. Each stack declares which layers it depends on.
4444

45+
### Fixtures (test input)
46+
47+
`templates/fixture/` holds one stack and one platform that exist for the
48+
checks, not for projects: `stack-fixture` (layer `fixture`) and
49+
`platform-fixture`. Each manifest entry carries `fixture: true`, so the
50+
README, this file's listings, the interview and `generated/` leave them out,
51+
while the checks that read every stack or platform read them too. They keep
52+
those checks fed when the concrete stacks and platforms live in forks, and
53+
the e2e canary (STK-24) runs against the fixture stack.
54+
4555
### Directory listings
4656

4757
Generated from `templates/manifest.yaml` — run `py tools/sync.py` to refresh.

‎templates/fixture/platform.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Platform — Fixture
2+
[ID: platform-fixture]
3+
[DEPENDS ON: templates/workflow/quality-gates.md]
4+
5+
Test input for the checks that read a platform, not a platform to pick. It
6+
resolves as its own root, beside the fixture stack and never inside it.
7+
8+
---
9+
10+
## CI
11+
[ID: platform-fixture-ci]
12+
13+
- Run every gate the quality-gate tier names on each pull request
14+
- Fail the pull request when any gate fails; never mark a gate optional

‎templates/fixture/stack.md‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Stack — Fixture
2+
[DEPENDS ON: templates/security/security.md, templates/workflow/quality-gates.md]
3+
4+
Test input for the checks that read every stack, not a stack to pick. It
5+
resolves the security and quality-gate tiers and carries each section a
6+
stack MUST carry, so those checks keep an input in a tree that ships no
7+
stack of its own.
8+
9+
---
10+
11+
## Stack
12+
[ID: fixture-stack]
13+
14+
- Language: [any]
15+
- Service: one HTTP endpoint that returns its request body unchanged
16+
- Build tool: `make`
17+
18+
---
19+
20+
## Commands
21+
[ID: fixture-commands]
22+
23+
```
24+
make install # install dependencies
25+
make test # run the test suite
26+
make lint # lint and format check
27+
```
28+
29+
---
30+
31+
## Project structure
32+
[ID: fixture-structure]
33+
34+
- `src/` — the service, one module per endpoint
35+
- `tests/` — one test file per module under `src/`, named after it

‎templates/manifest.yaml‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# label — human-readable name (stacks only, for interview)
1111
# layer — classification (stacks only, for README table)
1212
# produces — output filename (output entries only)
13+
# fixture — true for test input the checks read and no listing offers
1314

1415
version: "1.0"
1516

@@ -142,6 +143,11 @@ platform:
142143
file: templates/platform/linear.md
143144
description: Label groups, native priority, sub-issues, code-host sync
144145
depends_on: [base-issues]
146+
- id: platform-fixture
147+
file: templates/fixture/platform.md
148+
description: Test input for the platform checks; listed nowhere a project reads
149+
fixture: true
150+
depends_on: [base-quality-gates]
145151

146152
frontend:
147153
- id: frontend-ux
@@ -224,6 +230,14 @@ backend:
224230
description: Server-side rendering, partials, escaping, caching, forms, testing
225231

226232
stacks:
233+
- id: stack-fixture
234+
file: templates/fixture/stack.md
235+
label: Fixture
236+
layer: fixture
237+
description: Test input for the per-stack checks; listed nowhere a project reads
238+
fixture: true
239+
depends_on: [base-security, base-quality-gates]
240+
227241
- id: stack-htmx
228242
file: templates/stack/htmx.md
229243
label: HTMX + server rendering

‎tests/INDEX.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ restated in each.
7979
| `SAIT-E2E-STK-21-001A` | E2E | P1 | Full interview → CLAUDE.md for a NestJS project |
8080
| `SAIT-E2E-STK-22-001A` | E2E | P1 | Full interview → CLAUDE.md for a C embedded project |
8181
| `SAIT-E2E-STK-23-001A` | E2E | P1 | Full interview → CLAUDE.md for a tutorial site project |
82+
| `SAIT-E2E-STK-24-001A` | E2E | P1 | Full interview → CLAUDE.md from the fixture stack (the canary) |
8283
| `SAIT-E2E-DPL-01-001A` | E2E | P1 | Cloud deployment target produces correct deployment rules |
8384
| `SAIT-E2E-DPL-02-001A` | E2E | P1 | Hybrid deployment target produces correct deployment rules |
8485
| `SAIT-E2E-DPL-03-001A` | E2E | P1 | Offline deployment target produces correct deployment rules |

‎tests/cases.py‎

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,6 @@
258258
{
259259
"id": "STK-15",
260260
"spec": "SAIT-E2E-STK-15-001A",
261-
262-
# the canary: the default live test, run at every release cut
263-
"canary": True,
264261
"stack": "templates/stack/python-lib.md",
265262
"answers": {
266263
"Project name": "validify",
@@ -408,6 +405,31 @@
408405
],
409406
"forbidden": ["[your project]", "[owner]", "[repo]"],
410407
},
408+
{
409+
"id": "STK-24",
410+
"spec": "SAIT-E2E-STK-24-001A",
411+
412+
# the canary: the default live test, run at every release cut. It
413+
# reads the fixture stack, which stays in this repository when the
414+
# concrete stacks move to forks.
415+
"canary": True,
416+
"stack": "templates/fixture/stack.md",
417+
"answers": {
418+
"Project name": "echo",
419+
"Language": "Python",
420+
"Output format": "CLAUDE.md (inline model)",
421+
},
422+
"required": [
423+
"1. Project", "Commands", "Project structure",
424+
"Git", "Testing",
425+
"make test",
426+
"feat:",
427+
],
428+
429+
# [any] is the fixture's own placeholder; left in, the agent failed
430+
# to substitute the interview answers
431+
"forbidden": ["[any]", "[your project]", "[owner]", "[repo]"],
432+
},
411433
]
412434

413435
# -------------------------------------------------------------------------

‎tests/context-tiers.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
abstract 200K
99
backend 200K
1010
embedded 128K
11+
fixture 200K
1112
hypermedia 128K
1213
library 200K
1314
static 200K

0 commit comments

Comments
 (0)