docs(openspec): add Vale as a second static-tier engine - #71
Draft
thecodedrift wants to merge 6 commits into
Draft
docs(openspec): add Vale as a second static-tier engine#71thecodedrift wants to merge 6 commits into
thecodedrift wants to merge 6 commits into
Conversation
This was referenced Jul 28, 2026
…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
thecodedrift
force-pushed
the
openspec/add-vale-rule-engine
branch
from
July 29, 2026 19:04
4f6d941 to
ab995da
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