-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ
Because "write the test first" is an instruction, and what you need is evidence. An agent asked to be test-driven will happily produce a test file and an implementation in one pass, describe the result as test-driven, and be perfectly sincere about it. Nothing in the output distinguishes that from a real cycle.
What makes the difference checkable is the ordering being recorded as it happens (the failure output, the command, the commit) and a separate pass with no memory of the session cross-checking that record against git history. The discipline is the same discipline a human follows. The addition is that it leaves a trail.
Partly, and optionally. spec-kit's task template includes test tasks marked OPTIONAL,
with a note to write them first, and you can make TDD mandatory through the project
constitution. That is the hook this extension plugs into: /speckit.tdd.setup proposes
the constitution principle, and /speckit.tdd.plan removes the optionality from the
task list and fixes the ordering.
What core spec-kit does not do is drive the per-behavior cycle, record the red, or check afterwards whether the tests would catch a bug. That is what this adds.
The bdd extension converts specs to Gherkin scenarios and scaffolds step definitions.
That is the outer loop's notation. This extension is the loop itself, plus the evidence
and the strength check.
They compose. If Gherkin scenarios already exist, /speckit.tdd.plan reads them as
outer-loop behaviors rather than deriving its own, and the loop drives the inner cycles
that make each scenario pass.
They cover different parts of the problem, and this one deliberately does not reimplement them:
| Extension | What it does | Relationship |
|---|---|---|
bdd, reqnroll-bdd
|
Gherkin scenarios and step definitions | Their scenarios become outer-loop behaviors |
spectest |
Generates test scaffolds from spec criteria | Generated scaffolds become list items; the loop still drives each red |
trace |
Requirement to test traceability matrix | Overlaps the audit's traceability section; either can corroborate the other |
test-coverage-drift-control |
Incremental coverage drift reports | Coverage is corroboration in the audit, never the verdict |
v-model |
Paired dev and test specs with traceability | Complementary: it governs the artifacts, this governs the loop |
golden-demo |
Behavioral drift oracle with fuzz vectors | Its oracle is a strong approval or property kind on the list |
qa, review, staff-review
|
Post-implementation review | They review the code; this one grades the tests |
The gap this fills is the loop discipline and the test-strength check. Nothing in the catalogue drives red-green-refactor per behavior or asks whether the tests would survive a mutant.
It changes where the time goes. The loop itself is not slower than writing code and tests together, because the same tests get written either way. What it adds is a suite run per cycle and a few seconds of reading the failure.
The real cost is the audit, especially mutation testing, which is why it is scoped to the
files the feature changed and why quick mode exists. A whole-repo mutation run belongs
in CI, not in a per-feature audit.
What it removes is the debugging session three weeks later where a green suite turned out to prove nothing.
No, and it is scoped when it runs. The audit mutates only the files the feature changed, reports the scope with the score so numbers stay comparable, and triages equivalent mutants rather than dumping the raw list.
Where the ecosystem has no mutation tool, the audit uses deliberate mutants instead: for the highest-risk behaviors, break the implementation in one small way, confirm a test fails, restore. Fewer samples, same question answered, and the report states how many behaviors were sampled so it cannot read as exhaustive.
Both, chosen per behavior. State-based testing with few doubles is the default for domain logic, calculations, and state machines, because those tests survive refactoring. Doubles at the boundary are right where the observable behavior is the call: sending an email, publishing an event, charging a card.
The extension takes a position on the limits rather than the school: never double the unit under test, never assert on a double's return value the test configured itself, do not double what you own and can construct cheaply, and inject time, randomness, network, and filesystem.
That is the case it plans for explicitly. A component the feature must change but which has no tests gets characterization behaviors first: tests that capture what the code does today, including behavior that looks wrong, as a baseline. They are verified with a deliberate mutant (so a vacuous baseline cannot slip through) and scheduled before the behaviors that change that component.
What it will not do is create a test framework where none exists. That is a feature's worth of work and its own decision, so it gets reported rather than done as a side effect.
Because a loop cannot grade itself. The session that wrote the tests knows what they were meant to assert, and fills in that intent automatically when reading them. The gaps that matter are exactly the ones that intent papers over.
Running /speckit.tdd.verify in a fresh session is the point. It reads what the tests say
rather than what they meant, and it will report that the audit was not independent if it
was run by the authoring session.
The same reasoning is why it never fixes what it finds. An auditor that edits the code it grades has no standing to grade it.
Because asking does not work at that point in the lifecycle. Spec Kit waits for a hook
only when its optional flag is false. An optional pre-hook prints its offer and the
same run carries straight on to implement every unchecked task, so by the time you read
the question the code is already written test-after. That is the exact failure the hook
exists to prevent, so before_implement is mandatory.
It stays your decision at a level that actually holds: set enabled: false on the hook
in .specify/extensions.yml and Spec Kit filters it out before it ever looks at the
flag. Then run /speckit.tdd.run when you want it.
No, and the mechanism is worth knowing because it is the only one Spec Kit honors.
/speckit.implement decides what to implement from the [X] checkboxes in tasks.md
and nothing else. So /speckit.tdd.plan writes each behavior id into the task text
([U3]), and /speckit.tdd.run ticks a task once every behavior it names is DONE.
What is left unticked is the work that never belonged in a red-green cycle: scaffolding,
configuration, wiring. /speckit.tdd.verify checks the coupling from the other side and
reports a task ticked against a behavior that is not DONE.
Yes. All four commands resolve their reference documents through Spec Kit's template
stack: .specify/templates/overrides/<name>.md first, then
.specify/presets/<preset-id>/templates/<name>.md, then the extension's own copy under
.specify/extensions/tdd/templates/. Drop a modified tdd-loop-playbook.md or
tdd-test-quality-rubric.md into either higher layer and every command reads yours
instead. The audit records which rubric it graded against in the report's standard:
field, so a verdict stays readable next to the standard that produced it.
It costs you the strongest evidence. The audit's PROVEN class needs git history to
corroborate that the test file changed with or before the source. A squashed branch loses
that ordering, so those behaviors are classified LIKELY instead: the cycle log records a
red, but nothing independent confirms it.
LIKELY is not a failure and does not block a pass. It caps the verdict at
PASS_WITH_GAPS, and the report says why.
No, and it is only applied with your explicit approval, because the constitution is your
document. But it is what makes the discipline hold in sessions where nobody remembers to
ask for tests, since /speckit.plan, /speckit.tasks, and /speckit.implement all read
it.
If an existing principle contradicts TDD, /speckit.tdd.setup presents both and asks
which governs rather than deciding for you.
All of them, because it does not know any of them. /speckit.tdd.setup detects the stack
from your manifests, scripts, CI config, and test layout, runs each candidate command to
prove it works, and writes them to a profile the other commands read.
That is a claim worth checking rather than believing, so Stack
Profiles drives the same behavior in
vitest, pytest, go test, JUnit, and cargo test side by side. The behavior text on the
test list is identical in all five. Three lines per cycle differ, and all three are quoted
from the runner rather than composed: the test reference, the red command, and the failure
output.
The test name inside the test file follows whatever your repository already does, because the loop imitates the exemplar test file recorded in the profile instead of imposing a convention.
Yes. /speckit.tdd.setup records one stack entry per ecosystem, each with its own working
directory and its own commands, and never averages two into one. You can also scope it to
a subtree: /speckit.tdd.setup packages/api.
Running the suite from the wrong directory is the most common cause of a false green in a
monorepo, which is why cwd is recorded per stack.
Partly. The commands read spec.md and plan.md to derive behaviors and to decide which
of a test or the code is wrong when they disagree, so a feature directory with a real
spec is what they are built for.
/speckit.tdd.setup is useful on its own in any repository. /speckit.tdd.verify branch
also works without a test list: it audits whatever the branch changed, with a weaker
verdict on ordering, which makes it a reasonable pre-pull-request check.
/speckit.tdd.plan raises it rather than skipping it. For a criterion too ambiguous to
test, it presents the two candidate tests that would contradict each other and asks which
is intended. For a criterion with no observable result at all ("the system is
maintainable"), it proposes a concrete proxy or removal from the test list, and records
the decision either way.
Silently dropping an untestable criterion is how a feature ends up green with a requirement nobody verified.
At green, one commit per cycle, with structural refactors as separate commits. It never commits on red, never pushes, never merges, and never commits to a shared branch.
Whether it commits at all follows your repository's convention. It checks for an existing
one and asks once if that is unclear, and --no-commit turns it off.
No. That is the single hardest rule in the extension. No loosened assertion, no widened
tolerance, no value check turned into a truthiness check, no skip, no narrowed filter, no
lowered threshold. When a test and the code disagree, spec.md decides which is wrong,
and correcting a genuinely wrong test is its own step with a stated reason, taken before
the implementation change.
The audit checks the branch diff for exactly these edits, and any of them is a FAIL
condition on its own.
No. The commands are Markdown prompts. They need a Spec Kit-aware assistant to resolve
and execute them, and the release zip has no runtime of its own. The one place a command
starts without you typing it is the before_implement hook, and that is Spec Kit
invoking /speckit.tdd.run inside your own session, not a background process.
If you approved the community catalog, specify extension update tdd. Otherwise re-run
the direct install with a newer release URL:
specify extension add tdd --from https://github.com/d0whc3r/spec-kit-tdd/releases/download/v1.1.1/tdd-1.1.1.zipYour specs/ tree and your profile are not touched.