docs(openspec): add Vale as a second static-tier engine - #71
Draft
thecodedrift wants to merge 7 commits into
Draft
docs(openspec): add Vale as a second static-tier engine#71thecodedrift wants to merge 7 commits into
thecodedrift wants to merge 7 commits into
Conversation
This was referenced Jul 28, 2026
thecodedrift
force-pushed
the
openspec/add-vale-rule-engine
branch
3 times, most recently
from
August 3, 2026 23:16
12dded7 to
c452427
Compare
thecodedrift
added a commit
that referenced
this pull request
Aug 4, 2026
A spec-only proposal is its own tip until its implementation is stacked on top, so the gate demanded it archive a change nobody had built yet. #70, #71, and #72 have failed this check on every run since July 28 for exactly that reason — weeks of red on PRs that were never merge-eligible, which is how a team learns to stop reading red. A draft cannot merge, so skipping it costs nothing: no unarchived change can reach `main` either way. `ready_for_review` is added to the trigger types because the default set (opened/synchronize/reopened) does not include it — without that, a draft could be marked ready and merged on a green that was never re-evaluated. That event is what preserves the guarantee. The tip rule is unchanged for PRs that are ready for review.
…ngine Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LdEhGzeQfSGJM3nKKNj7Bp
The ingest writer hardcodes .taskless/rules, so 0004 would relayout existing rules under sg/ while the next `rule create` wrote back into a directory no engine dispatches from. The API carries no engine discriminator, so an engine-less payload is ast-grep by definition — the default is permanent, matching what the migration does to the same rules on disk. An unrecognized engine fails loudly instead, since filing a Vale rule under sg/ surfaces as a broken rule rather than version skew. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDv57zHq7abms3RReSQw6q
…solution Three additions to the Vale change: The engine-selection knowledge topic ships here rather than as a follow-on, since it names the engine directories this change creates. Written engine-shaped, kept distinct from route's authoring destination and from trust tier — sg and vale are both static-tier, and conflating those axes is what the platform's binary classifier got wrong. Legacy .taskless/rules/ stays dispatchable alongside sg/rules/, so a producer can keep using the pre-migration layout and its rules keep running. That decouples this release from any consumer's. Vale's binary resolves the way findSgBinary already does — resolve the platform package from our own module context and exec beside it, no lifecycle script. That code exists because the upstream postinstall hardlink breaks under pnpm dlx, leaving a placeholder text file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDv57zHq7abms3RReSQw6q
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDv57zHq7abms3RReSQw6q
An OpenSpec change has to land complete in one PR — the archive gate requires a tip PR to leave openspec/changes/ empty — and this one had grown to 44 tasks across ten groups. The layout half moved to partition-rules-by-engine. What stays is the engine and the knowledge about it: the Vale runner and its scoping model, fixture verify, findings mapping, concurrent multi-engine orchestration, and the engine-selection topic. 22 tasks. The topic stays here rather than with the layout because it names sg/vale/runtime as things an agent can actually choose between, which is only true once Vale executes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDv57zHq7abms3RReSQw6q
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDv57zHq7abms3RReSQw6q
Every one of these PRs carried skip-changeset while it was spec-only, which becomes wrong the moment implementation lands. Stating the impact in the proposal means the tip PR needs a changeset written, not a label kept. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDv57zHq7abms3RReSQw6q
thecodedrift
force-pushed
the
openspec/add-vale-rule-engine
branch
from
August 6, 2026 02:51
c452427 to
7b4d143
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rescoped. This change previously carried the layout, the migration, the engine, and the knowledge topic together — 44 tasks across ten groups. Since an OpenSpec change has to land complete in a single PR, that could never merge. The layout and migration moved to #73; what remains here is 22 tasks across 4 groups.
Makes the scaffolded
.taskless/vale/directory actually execute, and adds the knowledge an agent needs to decide when a rule belongs there at all.Vale runs as a second static-tier engine: resolve its binary, run
vale --config .taskless/vale/.vale.ini --output=JSON --no-exitover the target paths, and map findings into the sharedCheckResult, stripping therules.check-name prefix and normalizing severity. Static-tier is a verified property rather than an assumption — Vale's Tengoscriptsandbox exposes onlytext/math/fmt, withos/io/execreporting "module not found", so a Vale rule cannot reach the host. Trust therefore equals ast-grep's, and a subprocess timeout bounds a runaway loop.Per-rule scoping lives in
.vale.inimatchers —[<glob>] rules.<name> = YES/NO, where enables union across matchers and a disable wins regardless of order (all verified). Because one rule's scoping can scatter across several matchers, each Taskless-owned matcher carries atskl)-namespaced breadcrumb naming its owning rule; Vale accepts and silently drops unknown keys, so they ride inside the config rather than in a sidecar. Verify uses per-rulepass//fail/fixture directories with an isolating.vale.inigenerated at verify time, mirroring ast-grep'svalid/invalid.With two static engines,
checkruns them concurrently and merges into one result set, and an unavailable engine is reported without aborting the others.The engine-selection topic ships here rather than with the layout, because it names
sg/vale/runtimeas things an agent can actually choose between — only true once Vale executes. Two constraints are written into the spec because they are the failure modes: engine selection is a different axis fromroute's authoring destination, and a different axis from trust tier, sincesgandvaleare both static-tier and onlyruntimeinvolves login, reconcile, and signing. Ambiguity defaults tosg, stated as a property — the default names an engine known to be available — so it stays correct wherever a route can be withheld or a binary missing.stack: openspec-archivedwill be red until the change is implemented and archived. That is expected: archiving now would delete the spec before anything is built against it.Where this sits
Each change is independently landable: one OpenSpec change, one PR, archived on merge. The archive gate requires it — a tip PR must leave
openspec/changes/empty — so nothing here is stacked and none of these depend on a shared branch.vale/directory it scaffolds) and #72 (needs a binary to resolve)Only #71 has prerequisites. The other three can land in any order.
#70 and #71 are coupled by exactly one line: whichever lands second adds the engine-selection topic to
TOPICS. Ordering between them doesn't matter.Downstream, the generator's decision router (TSKL-279) needs a published release containing #70 and #71. It consumes a normal release — no prerelease, no path dependency — so it waits without blocking anything here.
Fixes OSS-21