diff --git a/.changeset/vale-recipe-regex-and-fixtures.md b/.changeset/vale-recipe-regex-and-fixtures.md new file mode 100644 index 00000000..220bb018 --- /dev/null +++ b/.changeset/vale-recipe-regex-and-fixtures.md @@ -0,0 +1,7 @@ +--- +"@taskless/cli": patch +--- + +`agent create-vale-rule` (topic v13) corrects two claims that cost rule authors work. Vale patterns are not RE2-only: Vale compiles with Go's `regexp` and falls back to `regexp2`, so lookahead, lookbehind and backreferences work, and the recipe no longer tells you to split a rule that one pattern expresses. Two silent limits are measured and documented alongside it: a backreference does nothing as a `swap` key, and the implicit word boundary on `tokens`/`swap` lands after a trailing lookahead, so that lookahead has to peek at a non-word character. `check` on a rule's `.tests/fail` bucket is a supported way to read a rendered message, because `.taskless/` is excluded from the whole-project walk only; when that bucket comes back empty, the recipe now sends you to the rule's own config, specifically a `[.taskless/**]` matcher, before the pattern. + +`verify` carried the same imprecision and now states both halves: a `[.taskless/**]` matcher is unnecessary on a whole-project check, AND it silences the rule on a path you name, such as the rule's own fixture bucket. It was previously described as acting only under a bare `vale` invocation, which read as harmless. `agent update` (topic v10) is corrected to match. diff --git a/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/.openspec.yaml b/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/.openspec.yaml new file mode 100644 index 00000000..1b9acb7f --- /dev/null +++ b/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-22 diff --git a/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/proposal.md b/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/proposal.md new file mode 100644 index 00000000..6a07c81a --- /dev/null +++ b/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/proposal.md @@ -0,0 +1,55 @@ +## Why + +taskless/cli#370 and #371 corrected the recipe and the `verify` advisory: a +`[.taskless/**]` matcher is not harmless. `check` excludes `.taskless/` from a +_whole-project walk_ only, so the matcher does nothing there — but on a path +named explicitly, such as the rule's own `.tests/fail` bucket, the matcher is +live and silences the rule. That is the shape that reproduces "`test` says the +fixture fired, `check` on the same fixture says nothing". + +The recipe, the `update` ledger and the advisory string now all say both halves. +The standing spec does not. `cli-vale-rule-engine` still reads "`check` excludes +that tree before Vale runs, so the matcher acts only under a bare `vale` +invocation", and its scenario still requires `verify` to "report that `check` +already excludes that tree" — the exact imprecise phrasing the code no longer +ships. The spec is the source of truth for this capability, so leaving it +disagreeing with the advisory it describes is how the next author reproduces +#370 from the spec instead of the recipe. + +This change carries no code. The implementation already landed in this PR; the +spec is what is behind. + +## What Changes + +- **`cli-vale-rule-engine`** — the advisory bullet and the + `.taskless/**` scenario state both halves of the behaviour: unnecessary on a + whole-project check, AND silencing on a named path. The scenario also gains + the `check`-notices half that the other advisory scenarios already carry, so + the two advisory paths are specified alike. + +No requirement is added or removed, and no behaviour changes: this is the spec +catching up to an advisory string and a recipe that already shipped. + +## Capabilities + +### New Capabilities + +None. + +### Modified Capabilities + +- `cli-vale-rule-engine`: "A rule's Vale config is validated against a schema + before it is assembled" — the `.taskless/**` advisory bullet and its scenario + are restated to match the shipped advisory. + +## Impact + +Documentation only. No source file, test, or public surface changes. The bump +stays `patch` and rides the existing changeset for this PR; no second changeset +is added. + +## Delivery shape + +**Single PR.** The spec correction is two edits inside one requirement and +belongs with the code change that made the standing text wrong, which is this +PR. It is the tip, so the change is archived here. diff --git a/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/specs/cli-vale-rule-engine/spec.md b/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/specs/cli-vale-rule-engine/spec.md new file mode 100644 index 00000000..841a7d69 --- /dev/null +++ b/openspec/changes/archive/2026-09-22-vale-taskless-matcher-spec/specs/cli-vale-rule-engine/spec.md @@ -0,0 +1,84 @@ +## MODIFIED Requirements + +### Requirement: A rule's Vale config is validated against a schema before it is assembled + +The system SHALL parse each rule's `.vale.ini` into an ordered, lossless AST and validate that AST against a schema keyed by the rule's directory id, before the config is assembled into the run config and when the rule is verified. Validation SHALL be performed on the parsed structure, never by matching the file's text. + +The schema SHALL reject a config that: + +- assigns any property above its first matcher (`StylesPath`, `MinAlertLevel`, or anything else; Vale ignores such a line with a `W101` warning and the rule verifies clean while enabled nowhere) +- declares a matcher without a `tskl) rule = ` breadcrumb naming this rule +- assigns a key other than `.` (a `