Repository navigation
feat(agent): fixtures come from real code and pass the repo's linters - #504
Merged
Merged
Conversation
The authoring recipes said fixtures should be "drawn from real code where you can" and nothing else, so an agent could hand a team a `valid:` case their own ESLint config rejects. A user reported exactly that: placeholder types and nested chains in the passing bucket, read as Taskless endorsing code they would send back in review. One shared passage, `%(FIXTURE_SOURCES)s`, now sits in every recipe where the agent writes fixtures (create-sg-rule, create-vale-rule, create-runtime-rule, improve-rule --anonymous): copy cases from the repo before inventing them and say which were invented, read the linters `detect --json` reports and write passing cases they would accept, and vary a case only where the rule looks. The two recipes that submit cases to the generator carry the same bar in a sentence. `verify` is unchanged.
… from real code The first end-to-end trial showed three gaps in the fixture passage. "Copy before you invent" left nothing to copy for the failing bucket of a rule that forbids something, so every failing case counted as invented. Running a linter on a fixture invites a loop that improves nothing about the rule, and here it could not even work: eslint ignores `.taskless/` and answers with an "ignored file" warning that reads as a pass. And step 6's awaited-generic case asked for code the repository may never write. Failing cases now come from the nearest real code with only the flagged construct changed, borrowing names from elsewhere where needed. Linters are read and applied to every case as source, never run. The awaited generic case is asked for only where the repository awaits that callee with a type argument.
`{ email }` is a `shorthand_property_identifier`, not a `pair`, so the
rule never saw it, and this repository writes shorthand wherever a name
allows (`distinctId`, `ghOwner`). The old fixtures were invented in the
`posthog.capture({...})` shape from the docs and could not show it.
Found by re-authoring the fixtures under the new recipe passage, twice,
by agents that were not told about the gap. The fixtures are now copied
from real call sites, and the failing cases are real calls with only the
key changed. The rule on main fails the new shorthand case; the repo
itself has no hits.
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.
A user reviewed a rule an agent wrote with Taskless. The rule was correct, but its
valid:fixtures usedRecord<string, never>and deeply nested call chains, and broke their own ESLint config. In their words, "the safer code fails while the bad code passes." People read fixtures as examples of the codebase's style, so a technically correct fixture the team would reject in review costs the rule their trust. The recipes allowed it: they asked for fixtures "drawn from real code where you can" and said nothing else.What changes
A shared passage,
%(FIXTURE_SOURCES)s(src/prompts/recipes.ts), rendered into every recipe where the agent writes fixtures:create-sg-rule,create-vale-rule,create-runtime-rule, andimprove-rule --anonymous. It tells the agent to:detect --jsonreports that cover the rule's language, and writes cases those linters would accept as source. It never runs a linter or formatter on a fixture: fixing what a tool says about a fixture is an endless loop that improves nothing about the rule.With
mechanics: falseit names no command.create-sg-rulestep 6 asks for anawait f<T>(...)failing case only for a callee the repository actually awaits with a type argument, instead of for every rule that keys on a callee.create-remote-ruleandimprove-rulehold the cases and references they send to the generator to the same standard.verifyis unchanged. Fixture style is the recipe's job, not a gate.no-pii-in-telemetrynow catches{ email }. See the trial below.Topic versions are bumped on all six recipes. The change includes a
patchchangeset. The OpenSpec changefixture-qualityadds one requirement tocli-agent-authoringand is archived in this PR. All 19 existing scenarios survive the archive, which adds 10 new ones.Trial (task 4.3)
I asked agents to re-author
no-pii-in-telemetryfrom scratch by following the built recipe. It is the closest analog in this repository to the user's metric rule: a rule about which keys may appear inside a telemetry call..taskless/), and the awaited-generic instruction conflicted with writing idiomatic code.telemetry.ts,report.tsandinfo.ts.{ email }is ashorthand_property_identifier, not apair, so the rule never matched it. The old fixtures were invented in theposthog.capture({...})shape from the docs and could not show this.mainfails the new shorthand case, the new rule passes all 8 cases, andcheckfinds no hits in the repository.Delivery shape
Single PR. The change is recipe prose, one shared variable and its tests, and one rule fix. None of it is unsafe to ship on its own.
Verification
pnpm typecheck,pnpm lint, andpnpm --filter @taskless/cli test(126 files, 2296 tests) all pass.prompts.test.tscover the shared passage in every fixture-writing recipe, the detect command when a CLI is available, and no command with mechanics off.