Planned Taskless Rules - #168
Open
thecodedrift wants to merge 7 commits into
Open
Conversation
Seven rules mined from CLAUDE.md, the .conventions styleguides, and the posthog conventions — the places this repo already states its rules in prose. Each one is verified and tested locally; `check` reports two real findings, both READMEs telling external consumers to run `pnpm dlx`. sg: no-index-imports relative imports ending in /index no-pii-in-telemetry PII in capture/identify/groupIdentify prefer-do-rpc `as DurableObjectStub<T>` casts no-regex-over-build-output a test function that reads dist/ and regexes it no-pull-request-branches-filter a branches: filter under pull_request: vale: docs-npx-cli pnpm invocations in READMEs no-hedging simply / obviously / of course Also backfills tests for the pre-existing no-eval rule, which was failing `verify` for a missing test file, and puts every rule's `language:` on ast-grep's own spelling. The install churn — the rules/ partition, taskless.json, the embedded SKILL.md — was already in the tree and is carried along rather than authored here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cEN93Acyp4zBwP3oDnyy1
Member
Author
|
|
A sweep of merged-PR review threads and the OSS Linear backlog turned up OSS-49, which names two planned GitHub Actions rules and records that a prior onboarding pass stalled on whether ast-grep handles YAML. It does, so both are buildable locally rather than runtime-tier. Adds pr-workflow-ready-for-review, and renames the branches-filter rule to the pr-workflow-* name OSS-49 already uses for the pair. One finding on the real workflows: stack-breadcrumb.yml names types: [opened, reopened, edited, closed] with no ready_for_review. That is a question rather than a defect — it reacts to PR metadata, not to readiness — and is left for review to settle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cEN93Acyp4zBwP3oDnyy1
OSS-28 specifies the house writing style as Vale rules. This adds the two that can be expressed cleanly, scoped to READMEs rather than the whole repository: broadening is a separate decision with roughly 2200 findings attached. no-em-dashes needs `nonword: true`, which the snippet in OSS-28 does not carry. Measured: without it the rule parses, passes verify, and does not fire, because Vale wraps every token in word boundaries and an em dash is non-word on both sides. no-blocklist-phrases drops the `landed on` token OSS-28 proposed. Measured firing on "the plane landed on time", which is the literal sense the issue says to protect; `we landed` already covers "we landed on the second option", so the broader token earned nothing. Not included: the "not X, Y" antithesis rule. OSS-28 is undecided on how to express it and calls it a heuristic, so it wants a human judgement this pass cannot make. 24 findings in READMEs, all em dashes, left unfixed pending a call on whether to rewrite the prose or relax the level. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cEN93Acyp4zBwP3oDnyy1
Brings the nine READMEs in line with no-em-dashes, which this branch scopes to `**/README.md`. Twenty-four instances, rewritten as a period, comma, colon, or parentheses per the rule's own message rather than mechanically swapped for one substitute. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cEN93Acyp4zBwP3oDnyy1
docs-npx-cli says docs use `npx @taskless/cli`, the normalized invocation for external consumers. Two README blocks offered `pnpm dlx` alongside it, which is the same claim the rule exists to prevent, so the alternative is removed rather than annotated. Annotating was measured and is not available here: a rule scoped to `raw` reads the unparsed document, so Vale's `<!-- vale Rule = NO -->` directive is inert for it. That scope is what lets the rule see fenced blocks at all, and every command in a README lives in one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cEN93Acyp4zBwP3oDnyy1
The most repeated finding in the merged-PR review threads: a comment that cites a version or a claim the code moved out from under it. On #161 alone, five threads — "we pin 3.17.1" left behind after VALE_VERSION went to 3.18.0, a comment naming .rmd as plaintext after the diff moved it to markup, a block still framing 3.18.0 as "the known incoming bump" after it shipped. Same shape on #155 and #157. The rule flags the construction rather than the stale number, which is the half a static check can see. Vale reads .ts in its comments-only tier, so it lints the comment text and never the code. Zero findings on packages/cli/src today, because #161 fixed them all. Reach verified separately by planting a forecast comment in a real source file: fixtures run under an isolating config, so a passing test does not prove the matcher glob reaches anything. Also ignores .taskless/ in eslint and prettier. A rule about source comments needs .ts fixtures, Vale decides its comments-only tier by extension, and those files belong to no tsconfig — so lint-staged failed the commit on "not found by the project service". Rule fixtures are inputs written to be flagged; verify and test are what keep them honest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cEN93Acyp4zBwP3oDnyy1
pr-workflow-ready-for-review flagged this as the only finding on the repo, and it is a real gap rather than the intended exception. `ready_for_review` is not in the default event set, so a draft marked ready fired nothing here: the breadcrumb went on describing the PR as a draft until some later event happened to run. The existing comment says tree SHAPE only, which is still true — `synchronize` stays out because a head push never changes membership. A draft becoming ready does change the stack, so it is named explicitly and the comment now says why. `taskless check` is clean at 12 rules. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cEN93Acyp4zBwP3oDnyy1
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.
Stack (root → tip):
Ten rules for our own repository, mined from the places we already state our conventions in prose:
CLAUDE.md, the two.conventionsstyleguides, and the PostHog notes. Nothing here is settled — the point of landing it is to have somewhere concrete to argue about what we actually want enforced.docs-npx-clipnpm dlx @taskless/cli/pnpm cliin any READMEno-em-dashesno-blocklist-phrasesload-bearing)no-hedgingno-index-imports/indexno-pii-in-telemetryemail/displayName/etc. incapture(),identify(),groupIdentify()no-regex-over-build-outputdist/and then regexes itpr-workflow-no-branches-filterbranches:filter under apull_request:triggerpr-workflow-ready-for-reviewpull_request:types:list that omitsready_for_reviewprefer-do-rpc… as DurableObjectStub<T>castsThe two
docs-npx-clifindings —README.md:37andpackages/cli/README.md:17— are left unfixed on purpose, so the PR demonstrates a rule catching something rather than only asserting it would.The two Vale house-style rules come from the dogfooding issue (#104 / OSS-28), scoped to
**/README.md. Widening them is #169, because repo-wide they are roughly 2300 findings. Two corrections to that issue's spec, both measured and both in the rule files:no-em-dashesneedsnonword: trueor it silently never fires, and the proposedlanded ontoken fires on "the plane landed on time" and was dropped.The 24 em-dash findings in READMEs are unfixed. Rewriting them is an editorial pass on user-facing prose, so it wants a decision rather than a default: rewrite the prose, or drop the rule to
warninguntil someone does.The two
pr-workflow-*rules come from OSS-49, which names both and records that an earlier onboarding pass stalled on whether ast-grep handles YAML. It does —Yamlis one of its 26 languages — so both build locally instead of needing a login.pr-workflow-ready-for-reviewreports one finding, and it is a question rather than a defect:stack-breadcrumb.ymlnamestypes: [opened, reopened, edited, closed]with noready_for_review. It reacts to PR metadata rather than to readiness, so omitting it may well be correct. Settling that is part of what this PR is for.Where the rules are narrower than the conventions
Three are worth arguing about specifically, because each is a deliberate retreat from what the styleguide actually says:
no-index-importsis not "no barrel imports." Tellingfrom "../wizard"(a directory barrel) fromfrom "./ask"(a file) needs filesystem resolution, which is a cross-file question and therefore runtime-tier. The rule catches only the explicit/indexform, which meanspackages/cli/src/commands/init.ts:16is a real violation that nothing in this PR flags.no-regex-over-build-outputscopes to the enclosing function, not the file. Scoped to the file it fired three times onpackages/cli/test/prompts.test.ts, where a helper deliberately regexes hand-written source and the same file separately loads a built artifact. That helper is correct and the styleguide says so.prefer-do-rpchas no instances in this repository — no octokit, no Durable Objects. Its tests are synthetic and it is carried from the shared styleguide as a pre-emptive rule. Reasonable to drop it here and keep it wherever the DO code actually lives.Two conventions could not be expressed at all while logged out, both for the same reason — they need the cross-file graph: "a type reachable from an exported signature must itself be exported" (the
declaration: truetrap) and "a hand-written type must not duplicate a library type."Where to start
The two Vale
.vale.inifiles. Scoping is the decision most likely to be wrong and the least visible in a diff: both rules are restricted to READMEs, both exclude**/test/fixtures/**(they were firing on CLI test inputs), anddocs-npx-clideliberately does not coverCLAUDE.md, which documents the localpnpm clipath on purpose.docs-npx-clialso carriesscope: [raw, code, text]. Without it the rule passes every fixture and catches nothing real, because every command in a README is in a code span or a fenced block.Carried along
The
rules/engine partition,taskless.json, the embeddedSKILL.md, and theno-evalmove were already in the working tree from the install. Also backfilled: tests forno-eval, which had been failingverifyfor a missing test file, and every rule'slanguage:is now on ast-grep's own spelling rather than lowercase.Refs #165
Refs #166
Refs #167