Add the Flaky Test Detector: find flaky tests by reading them, fix what you approve - #22
Merged
Merged
Conversation
The spec derives from brds/flaky-test-detector.md: six prioritized user stories, 30 acceptance scenarios, 14 edge cases, 48 functional requirements, 11 key entities, and 12 measurable criteria, plus the Constraints, Dependencies, and Out of Scope sections the plan's Constitution Check will need. The BRD's eight open questions are settled in Clarifications rather than passed downstream. Two were settled restrictively on purpose: no verification run after a fix, because an agent allowed to run the suite it just edited is an agent that can iterate until green; and no numeric cap on candidates, because a cap decides for the developer which flakiness matters. A clarify session settled five more, each closing a gap the BRD did not reach: - FR-031a — re-confirm the recorded evidence before editing. A plan can sit for days, and applying a stale row edits code the analysis never saw. - FR-029a — a narrowed re-run must name the pending rows it would drop. The scope argument and whole-file replacement together were a silent data-loss path through someone's afternoon of triage. - FR-026a — reasons live in an outcomes section keyed by candidate id. The obligation to record one existed; a place to put it did not. - FR-032a — new test-support files are allowed, since a mock with nowhere to live is a fix that never lands, but a change reaching past the approved row is declared rather than folded into the diff. - FR-033a — the consumer project's constitution binds fix selection, and it is theirs, never Spectra's. Where a guardrail rules out the only remedy the row stays open with the rule named; where no constitution exists the agent says so and proceeds on merit. Two departures from the BRD are recorded in Assumptions: per-candidate evidence is a MUST rather than a SHOULD, because resuming in a later session is worthless without it, and FR-015 writes down the confidence rubric the BRD required to exist but never stated. Quality checklist passes 16/16, unchanged by the clarify session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…gument Phase 0 and Phase 1 for the sixth command. The full artifact set rather than the folded plan.md that specs 012-017 use: those were changes to existing commands, and every new agent here — 001, 002, 003, 008 — carries research, data model, contracts, and quickstart. research.md records twelve decisions with the alternative each one beat. The two that shaped everything else: Suite discovery and file parsing stay in prose. Both look like code problems, and a script for either would break Principle III and the Markdown-only guarantee the published package makes. Prose also degrades better — an agent meeting an unfamiliar framework can still recognize it by convention, and the mandatory coverage statement forces it to say what it could not classify. The analysis file is a parse contract, not a document. That is what settles Principle VIII. VIII shapes deliverables, and VII already names this category — a command writing to .specify/ is writing context for another command, here this same command's next run. But the argument that actually decides it only became clear in Phase 1: VIII's honour-don't-repair rule would oblige the command to accept an override as authored, so an override renaming ## Tasks or reordering the columns would not restyle the output, it would make the file unreadable to the run that has to resume from it. Templates are right for documents whose shape is taste; they are wrong for a file two runs must agree on. contracts/analysis-file.md pins the structure instead, and defines "unparseable" by structure rather than content so that deleting a row or rewording a fix stays a legitimate edit. Constitution Check passes 8/8 with Complexity Tracking empty. One item is recorded there anyway: this command's write scope is wider than any existing Spectra command's, because it edits files the user wrote. Four independent limits keep that bounded rather than one — test-only edits, the prohibited-remedy list, a surviving row as authorization, and nothing ever committed. Extension classification is MINOR, 1.10.0 to 1.11.0, catalog channel only. VERSION stays put, no tag. The census baselines are verified: 14 available and 32 planned today, moving to 15 and 31. Flagged for whoever implements this: it is the first Spectra command that modifies files it did not create, in a project it did not author. The constitution says nothing about that, and this plan deliberately does not invent a principle — the limits live in the spec. If a second such agent appears, they should be lifted rather than copied. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hat you approve Spectra's sixth command, and the first that edits code the user wrote. Finding a flaky test conventionally means instrumenting CI, collecting hundreds of runs, and computing a score — pipeline work, a results store, and weeks before the first answer. The causes are already in the source: an unconditional sleep before an assertion, an un-awaited async call, state one test leaves for another, a live network call, an unseeded random value, an assertion against the real clock. The agent reads the suite and names them on the day you install it. Because it edits tests, the limits matter more than the detection. Four of them, each independent, so no single misjudgment is enough to do damage. It never executes anything — not the suite, not a build, not an install, and not to verify a fix it just applied. That last exclusion is the one an agent would grant itself: given the ability to run the tests it just edited, it can iterate until green, and iterating until green is how a test ends up asserting nothing. A fix removes the cause. Deleting an assertion, loosening one until it always passes, skipping the test, marking it expected-to-fail, adding a retry, or lengthening a sleep are named and forbidden. An item it cannot fix that way stays open with a reason. Edits stay in test and test-support files. It may create a helper where a fix needs one — a mock with nowhere to live is a fix that never lands — but never production source and never a new dependency. Where the real remedy is in the application, it records what would change and where. Nothing is committed. The working-tree diff is the last checkpoint before any of it becomes permanent. Two gates with pruning in between: it reports, asks before writing the plan, then asks again before touching code, and works only the rows still in the file. The list is written to .specify/memory/flaky-test-analysis.md and outlives the session — every run reads it first and branches on its state. Unfinished work resumes without re-analysing and without discarding the developer's pruning; a completed list is not replaced without asking; a file it cannot parse is never overwritten silently. Progress is written after each individual fix, so an interrupted session leaves a file that is exactly true. Confidence is High/Medium/Low over the strength of the evidence, not a failure rate — with no run history there is no denominator, so no percentage or score is emitted. The consumer project's own constitution binds which fixes are allowed. No template is registered for the analysis file. Principle VIII shapes deliverables; Principle VII already places a .specify/ write in the category of context for another command, and here that command is this one's next run. The deciding argument is narrower: the file's structure is a parse contract, and VIII's honour-don't-repair rule would oblige the command to accept an override that renamed ## Tasks — which would not restyle the output, it would make the file unreadable to the run that has to resume from it. Extension 1.10.0 -> 1.11.0, catalog channel only. VERSION untouched, no tag. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Summary
Spectra's sixth command,
speckit.spectra.flaky-test-detector, and the first that edits code the userwrote.
Finding a flaky test conventionally means instrumenting CI, collecting hundreds of runs, and computing a
score — pipeline changes, a results store, and weeks of waiting before the first answer. The causes are
already sitting in the source: an unconditional sleep before an assertion, an un-awaited async call, state
one test leaves behind for another, a live network call, an unseeded random value, an assertion against
the real clock. This agent reads the suite and names them on the day you install it. No CI integration, no
results store, no run history.
Because it edits tests, the limits matter more than the detection. Four of them, each independent, so no
single misjudgment is enough to cause damage:
Two gates, with pruning in between. The run reports a ranked table — test, file, confidence, concrete
fix — and stops. On a go-ahead it writes
.specify/memory/flaky-test-analysis.md: a run summary, one[ ]row per candidate, the evidence behind each, and what it could not examine. The developer deletesthe rows they disagree with. On a second go-ahead it works what is left, one item at a time.
The list outlives the session. Every run reads that file first and branches on its state: unfinished
work resumes without re-analysing and without discarding the pruning, a completed list is not replaced
without asking, and a file it cannot parse is never overwritten silently. Progress is written after each
individual fix, so an interrupted session leaves a file that is exactly true rather than one claiming
nothing happened. Before a run scoped to one suite replaces a broader plan, it names the pending items
that would be dropped.
Confidence is High/Medium/Low over the strength of the evidence, not a failure rate — with no run
history there is no denominator, so no percentage, score, or flakiness index is ever emitted. The
consumer project's own constitution binds which fixes are allowed: where a guardrail rules out the only
remedy, the item is left open with that rule named.
No template is registered for the analysis file. Principle VIII shapes deliverables; Principle VII
already places a
.specify/write in the category of context for another command, and here that commandis this one's next run. The deciding argument is narrower than the category, though: the file's structure
is a parse contract, and VIII's honour-don't-repair rule would oblige the command to accept an
override that renamed
## Tasks— which would not restyle the output, it would make the file unreadableto the run that has to resume from it. Reasoning recorded in
specs/018-flaky-test-detector/research.md(R-002) and the plan's Constitution Check.
Spec, plan, research, data model, contracts, quickstart, and tasks:
specs/018-flaky-test-detector/. Derived frombrds/flaky-test-detector.md(BRD-008), whichdeliberately scopes down the QE Practice reference document — that one specifies the execution-telemetry
version of this capability, and remains a separate, later product.
Testing
python3 -m unittest discover -s tests→ 752 tests, OK (was 696), including a new 56-assertiontests/test_flaky_test_detector_flow.pycovering the refusals, both gates, the prohibited-remedy list,the write scope, the four state branches, the honesty rules, and the guardrail binding.
regressions: softening the prohibited-remedy list, removing the no-verification clause, and permitting
production edits each produced a failure; reverting restored green.
references neither
ghnorgit— unlikecreate-prandreview-pr, it gates on no binary at all.python3 tools/generate_agent_docs.py --check→ 46 agents, 6 prose blocks, roster and manifestagree.
python3 tools/build_package.py→ idempotent (identical hash across consecutive builds); the packagedzip carries
spectra/commands/flaky-test-detector.mdand a manifest reading1.11.0.specify extension add --dev: registers asspeckit-spectra-flaky-test-detector, andspecify extension info spectralists six commands.Release
Extension 1.10.0 → 1.11.0 (minor: a command is added; none renamed or removed, and no existing
command's behaviour changes). Manifest,
catalog.json(5 → 6 commands), changelog, generated regions,landing page, and
spectra.zipare in sync. The roster entry moves from under-development to availablewith its command recorded, and carries a hand-authored prose block. The CLI channel is untouched — no
tag,
VERSIONunchanged (Principle VI).Blocked / not covered
Nothing blocked. Not verified end-to-end by an agent run: the command is a prompt, so the enforceable
surface is its text plus the tests on it. The eleven behavioural scenarios in
specs/018-flaky-test-detector/quickstart.mdstill need a human pass in a real project — the four worththe time are the diff-level safety check, checkpointing across an interruption, the stale-plan guard, and
the refusals, none of which a unit test can replace. A scratch suite with six planted patterns and two
deliberately stable control tests is described in that quickstart for the purpose.
Also worth a reviewer's attention: this is the first Spectra command that modifies files it did not
create, in a project it did not author. The constitution says nothing about that category today, and this
change deliberately does not invent a principle — the limits live in the spec. If a second such agent
appears, they should be lifted into the constitution rather than copied.
🤖 Generated with Claude Code