Skip to content

feat(rules): generate and improve rules through the v2 API (0.12.0, stack 2/5) - #412

Open
thecodedrift wants to merge 1 commit into
openspec/cli-v2-rule-apifrom
openspec/cli-v2-rule-api-generation
Open

thecodedrift wants to merge 1 commit into
openspec/cli-v2-rule-apifrom
openspec/cli-v2-rule-api-generation

Conversation

@thecodedrift

@thecodedrift thecodedrift commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Stack (root → tip):

Stack 2/5 of the v2 rule API migration. It merges down into #411, which reaches main once, carrying the whole stack. See #411 for why.

What changes

  • rule create / rule improve use v2 generation (rules/generate.ts). The CLI submits, polls by requestId, then fetches each produced rule's head by ruleId. The head is fetched without revision=, so a Free plan is never refused for a rule it just generated. Every rule is verified before any is written, so one bad rule leaves the tree untouched.
  • Every served file is checked against its signature before it's written (rules/verify-delivery.ts). The served revisionId must match the one polling reported, and a runtime set's signature must equal its check.ts entry. Anything else refuses the whole rule.
  • A served set replaces its rule directory, .tests/ included (the rules team confirmed fixtures always ship). Parent directories are created as files are written.
  • BREAKING for --json consumers: rule create --json prints requestId plus rules (the rule ids, which are directory names), and no longer prints ruleId, which always held the request id. rule improve's input ruleId is the directory name. 404 rule_not_found becomes RULE_NOT_FOUND.
  • A request that ends failed or unsupported prints the server's error as given, with control characters stripped.
  • Recipes: create-remote-rule, improve-rule, rule-meta, and the rule index now say the rule id is the directory name and is never the request id. Each topic version is bumped.
  • Removed: the v1 request, poll, and iterate client calls, and their test.

The v1 single-content writers stay until slice 5, because the v1 repair inside check still calls them until slice 3 removes it.

Tests

The command-level tests now drive the real command against a stubbed v2 server (test/support/v2-server.ts), which signs served sets with the CLI's own hash. The #280 envelope guard now covers a tampered served rule. New tests cover:

  • a revision mismatch
  • directory replacement, including stale fixtures
  • a sanitized failed error
  • RULE_NOT_FOUND on improve
  • 12 verifier refusals

pnpm typecheck, pnpm lint, and the full suite (110 files, 1,852 tests) pass.

Refs TSKL-307

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Open OpenSpec Contains unresolved OpenSpec changes. All openspec changes must eventually reach an archive state.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant