Skip to content

docs(agent): state where a runtime rule's fixtures go - #225

Merged
theCodeDrift merged 2 commits into
mainfrom
docs/runtime-fixture-shape
Aug 31, 2026
Merged

theCodeDrift merged 2 commits into
mainfrom
docs/runtime-fixture-shape

Conversation

@theCodeDrift

Copy link
Copy Markdown
Member

Recipe text plus a changeset. No behaviour change.

The gap

create-runtime-rule described a rule directory as captures/*.yml plus check.ts and stopped. An agent authoring a runtime rule was told nothing about .tests/. verify-rule reported runtime tests as "not run" without naming what it was not running.

So the fixture shape existed only inside the generator — which is the same "described in prose nowhere, implemented in one place" shape this whole alignment has been unpicking.

What is now stated

Cases live in .tests/pass/ and .tests/fail/, and a case is a directory whose path is the root the harness hands the check, with every match.file relative to it. So a case may hold as many files as it needs.

That last part is load-bearing, not cosmetic: a runtime rule exists because its evidence spans more than one file, so a layout allowing one file per case could not express the rules the tier is for.

And it was not academic. The generator's payload builder capped fixture path depth at 3 — which admits pass/case-1/input.ts and refuses pass/case-1/src/a.ts. The first cross-file fixture would have been rejected as a path-safety error: a security refusal for a legitimate test, which is about the most misleading error that shape of bug can produce. The cap had been written as a runaway guard and silently become a shape constraint; two different questions wanting two different numbers. They raised it to 8 and recorded which one it answers.

Bucket naming

pass/fail, matching Vale's, not valid/invalid.

valid/invalid are key names inside an ast-grep test YAML, and they are right for sg for exactly one reason: that file is handed to sg test verbatim. Nothing hands a runtime fixture to ast-grep, so reusing the word there would make it mean two things — the same collision captures/ already avoids by not being called matchers/.

Verification

1055 tests, build, and house style clean. Agreed with the cloud team as F1 and F2; their generator writes this shape, and their restore endpoint shares the derivation, so there is one implementation behind the statement rather than two that could disagree.

@theCodeDrift

Copy link
Copy Markdown
Member Author

@claude /review

@claude

claude Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Claude finished @theCodeDrift's task in 3m 26s —— View job


Review

Review mode: incremental — read 0 prior review thread(s) before reviewing. .prior-review.json holds no reviewThreads, reviews, or top-level comments (only the @claude /review trigger comment itself), so this is the first review of this PR — the whole diff was assessed.

  • Read .prior-review.json (no prior threads/reviews/comments)
  • Fetch diff with gh pr diff and read changed files
  • Review the two .txt recipe changes for accuracy/clarity
  • Review the changeset
  • Post final review

Scope: .changeset/runtime-fixture-shape.md (new), packages/cli/src/agent/create-runtime-rule.txt, packages/cli/src/agent/verify-rule.txt — a docs-only change (+34/-1), no runtime code touched.

Assessment: the added content is accurate and consistent with the codebase. Checked against:

  • packages/cli/src/rules/layout.ts / runtime/discover.ts — confirms .tests/ is RULE_TESTS_DIRECTORY, is excluded from the stray-module scan (so a .ts fixture file isn't refused), and directories under .taskless/rules/runtime/<id>/.tests/ are never enumerated as rules.
  • openspec/changes/generator-payload-alignment/specs/cli-runtime-rule-execution/spec.md — matches the "case is a directory, .tests/ not executed" framing.
  • create-sg-rule.txt / create-vale-rule.txt — confirms the pass/fail vs valid/invalid distinction is real and not a naming collision with existing conventions (sg's valid/invalid are YAML keys in one file; Vale's pass/fail are already files, not directories — the new text correctly flags that a runtime case being a directory is the actual departure worth calling out).
  • packages/cli/src/types/runtime-rule.ts — Match.file is genuinely "path RELATIVE to root", so the doc's claim about match.file being relative to the case directory is a consistent extrapolation of the existing harness contract (the PR body notes this was cross-checked with the team that owns the actual test-harness implementation, which lives outside this repo).

One finding posted inline (packages/cli/src/agent/create-runtime-rule.txt:34): the recipe's header still reads topic v1 even though this diff adds a genuinely new section (the whole .tests/ layout was previously undocumented). Every other recipe in packages/cli/src/agent/ bumps its topic vN on a material content change, and the version string is hand-maintained (no code reads or derives it), so it only reflects the change if someone remembers to bump it. Given this repo's own history of a stale dist/ serving an outdated topic version causing real harm, this seemed worth flagging even though it's non-blocking.

No other correctness, clarity, or convention issues found. verify-rule.txt's table row grew noticeably wider than its neighbors, but it's cosmetic and still parses fine.

Comment thread packages/cli/src/agent/create-runtime-rule.txt
theCodeDrift added a commit that referenced this pull request Aug 31, 2026
The recipe gained a whole section it never had — the `.tests/` layout, the
directory-per-case shape, and the bucket naming — while its header still
said v1. Every other recipe that changed materially bumped: create-sg-rule
is v4, create-vale-rule v3, improve-rule v4.

The number is maintained by hand, so nothing else would have caught it, and
a stale `topic vN` is exactly the failure CLAUDE.md records: an agent
followed a recipe from an old `dist/` and authored rules against outdated
guidance, missing the revision that documented the field it then got wrong.

Deliberately NOT bumping `verify-rule`, whose change in this branch names
the fixture buckets inside an existing row. The test there is whether acting
on the stale copy is wrong, not whether the text differs: an agent reading
the old verify-rule still learns runtime tests are not run locally, which
remains true. An agent reading the old create-runtime-rule learns nothing
about fixtures at all and invents a layout.

Found by the review on #225.
@theCodeDrift

Copy link
Copy Markdown
Member Author

Re: @claude[bot] — "a docs-only change (+34/-1), no runtime code touched…"
#225 (comment)

The inline topic vN finding was correct and is taken in 7f389fb. verify-rule is deliberately left at v2 — reasoning on the thread and in the commit.

— AI Coding Agent

`create-runtime-rule` described a rule directory as `captures/*.yml` plus
`check.ts` and stopped. An agent authoring a runtime rule was told nothing
about `.tests/` at all, and `verify-rule` reported runtime tests as "not
run" without naming what it was not running. The shape existed only inside
a generator.

Now stated in both, with the part that is load-bearing rather than
cosmetic: a case is a DIRECTORY whose path is the `root` the harness hands
the check, with every `match.file` relative to it, so a case may hold as
many files as it needs. A runtime rule exists because its evidence spans
more than one file — a layout allowing one file per case could not express
the rules the tier is for.

That distinction was not academic. The generator's payload builder capped
fixture path depth at 3, which admits `pass/case-1/input.ts` and refuses
`pass/case-1/src/a.ts`, so the first cross-file fixture would have been
rejected as a path-safety error: a security refusal for a legitimate test.
The cap was written as a runaway guard and had silently become a shape
constraint. They raised it to 8 and recorded which of the two it is.

Buckets are `pass`/`fail`, matching Vale's. `valid`/`invalid` are key names
inside an ast-grep test YAML and are right for `sg` for exactly one reason
— that file is handed to `sg test` verbatim. Nothing hands a runtime
fixture to ast-grep, so reusing the word there would make it mean two
things, the same collision `captures/` avoids by not being called
`matchers/`.

Agreed with the cloud team as F1 and F2; their generator writes this shape
and the restore endpoint shares the derivation.
The recipe gained a whole section it never had — the `.tests/` layout, the
directory-per-case shape, and the bucket naming — while its header still
said v1. Every other recipe that changed materially bumped: create-sg-rule
is v4, create-vale-rule v3, improve-rule v4.

The number is maintained by hand, so nothing else would have caught it, and
a stale `topic vN` is exactly the failure CLAUDE.md records: an agent
followed a recipe from an old `dist/` and authored rules against outdated
guidance, missing the revision that documented the field it then got wrong.

Deliberately NOT bumping `verify-rule`, whose change in this branch names
the fixture buckets inside an existing row. The test there is whether acting
on the stale copy is wrong, not whether the text differs: an agent reading
the old verify-rule still learns runtime tests are not run locally, which
remains true. An agent reading the old create-runtime-rule learns nothing
about fixtures at all and invents a layout.

Found by the review on #225.
@theCodeDrift
theCodeDrift force-pushed the docs/runtime-fixture-shape branch from 7f389fb to 8024f3e Compare August 31, 2026 20:13
@theCodeDrift
theCodeDrift merged commit f964061 into main Aug 31, 2026
2 checks passed
@theCodeDrift
theCodeDrift deleted the docs/runtime-fixture-shape branch August 31, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant