The core plans every contract step in authored order and runs it against the world the caller hands in; creating a fresh world per example is the adapter's lifecycle, never the core's.
Once the Vitest adapter creates a world, it awaits the optional after hook whether the steps pass or fail. A step failure stays the test's failure and an error from after is then discarded; when the steps pass, an error from after fails the test. A world factory that throws creates no world, so after does not run.
Duplicate step text within one example binds one handler, and every occurrence runs it; an occurrence that binds a slot to a different value is a conflicting re-binding, named at generation, and every occurrence runs with the first binding, because an example is one point.
A red step names itself before the assertion detail: the failure message leads with the step's natural reading — the Spec's own words with bound values inlined — and the original error is preserved, carried as cause when it cannot be re-messaged, and wrapped when the thrown value is not an error.
A missing or stale step handler is a compile-time refusal rather than a silent skip: the bindings type covers every step and only the steps, so spec-side drift fails the typecheck instead of the run.
The core contributes unspecified, the one outcome no Spec ever states, so an uncovered region of an example space has an honest answer rather than a manufactured one.
Given a contract whose given step repeats {occurrences: 2} times before one when step and one then step
Given the handler bound to the {failingPhase: "when"} step throws {thrown: "boom"}
When the bound plan runs against a fresh world
Then the run {outcome: "fails"}
Then the failure names the step in the Spec's own words as {failureLabel: "at step: When the cart is submitted"}
Then the failure preserves the original detail {detail: "boom"}
Given
a contract whose given step repeats {occurrences: 2} times before one when step and one then step
the handler bound to the {failingPhase: "when"} step throws {thrown: "boom"}
When
the bound plan runs against a fresh world
Then
the run {outcome: "fails"}
the failure names the step in the Spec's own words as {failureLabel: "at step: When the cart is submitted"}
the failure preserves the original detail {detail: "boom"}
Given a contract whose given step repeats {occurrences: 2} times before one when step and one then step
When the bound plan runs against a fresh world
Then the world records the handler trace {trace: "given 2 | given 2 | when | then"}
Then the run {outcome: "completes"}
Given
a contract whose given step repeats {occurrences: 2} times before one when step and one then step
When
the bound plan runs against a fresh world
Then
the world records the handler trace {trace: "given 2 | given 2 | when | then"}
the run {outcome: "completes"}
Given a contract whose given step repeats {occurrences:number} times before one when step and one then step
Given the handler bound to the {failingPhase:"given"|"when"|"then"} step throws {thrown:string}
When the bound plan runs against a fresh world
Then the world records the handler trace {trace:string}
Then the run {outcome:"completes"|"fails"}
Then the failure names the step in the Spec's own words as {failureLabel:string}
Then the failure preserves the original detail {detail:string}
Design
Ports and adapters. The runner accepts a generated contract, step handlers, and a caller-owned world. The Vitest adapter registers tests and creates each world before calling the runner. Framework dependencies point from the adapter toward the runner; the runner remains usable without a test framework. Step ordering and failure labels belong to the core, while test registration and world lifecycle belong to the adapter.
"at step: " + naturalReading + "\n" + originalMessage is the message expression; naturalReading is the rendered contract step and originalMessage is the original error message or the string form of a non-Error throw.
no citation recorded
Verification
Verifier bindings
spec:extraction.example-runner.red-step-naming · A red step names itself before the assertion detail · declared · example enabled · specs/extraction/example-runner.red-step-naming.sdp.md
External run evidence from test/self-hosting-extraction.test.ts
One query invocation shares its extracted graph and validation result (spec:extraction.build-pipeline.same-invocation)
passed
16.91 ms
executes the bound example against a fresh world
A prefix excludes its own tree and leaves a similar sibling standing (spec:extraction.excludes.segment-boundary)
passed
1.58 ms
executes the bound example against a fresh world
A Windows-drive absolute path is refused rather than normalized (spec:extraction.excludes.refused-path)
passed
1.08 ms
executes the bound example against a fresh world
A derived payload carries a schema version its consumer can read (spec:extraction.schema-versioning.declared-version)
passed
0.5 ms
executes the bound example against a fresh world
An unbound slot in a used step earns no step contract (spec:extraction.executable-contracts.concreteness-refusal)
passed
2.41 ms
executes the bound example against a fresh world
A second structured entry is named, never left silently inert (spec:extraction.executable-contracts.multi-entry-example)
passed
2.37 ms
executes the bound example against a fresh world
A case-only path collision withholds the whole contracts tree (spec:extraction.executable-contracts.case-colliding-path)
passed
0.95 ms
executes the bound example against a fresh world
A repeated step runs its one handler at each occurrence, in contract order (spec:extraction.example-runner.step-order)
passed
0.4 ms
executes the bound example against a fresh world
A red step names itself before the assertion detail (spec:extraction.example-runner.red-step-naming)
passed
0.45 ms
spec:extraction.example-runner.step-order · A repeated step runs its one handler at each occurrence, in contract order · declared · example enabled · specs/extraction/example-runner.step-order.sdp.md
test:protocol.example-runner-cleanup · the Vitest adapter cleans up a world whether its steps pass or fail · anchored · test anchor binding present · test/vitest-adapter.test.ts:19
External run evidence from test/vitest-adapter.test.ts
a contract whose given step repeats {occurrences:number} times before one when step and one then step
the handler bound to the {failingPhase:"given"|"when"|"then"} step throws {thrown:string}
When
the bound plan runs against a fresh world
Then
the world records the handler trace {trace:string}
the run {outcome:"completes"|"fails"}
the failure names the step in the Spec's own words as {failureLabel:string}
the failure preserves the original detail {detail:string}
Composing needs the script.
Design view
Requirement drawing
Requirement drawing for spec:extraction.example-runnerThe diagram as text
spec:extraction.example-runner: A bound example runs its contract steps against a fresh world · declared Spec
spec:extraction.example-runner.red-step-naming: A red step names itself before the assertion detail · declared Spec
spec:extraction.example-runner.step-order: A repeated step runs its one handler at each occurrence, in contract order · declared Spec
component:protocol.codegen: contracts and registrar output · anchored code · src/codegen/contracts.ts:633
component:protocol.runner: provider-neutral example execution · anchored code · src/runner/index.ts:99
component:protocol.testing: the generated registrar runtime · anchored code · src/testing/index.ts:38
impl:protocol.example-runner: plans and executes a bound example against the caller's world · anchored code · src/runner/index.ts:108
impl:protocol.example-runner-adapter: registers one test per example and owns the fresh world lifecycle · anchored code · src/adapters/vitest.ts:32
impl:protocol.example-testing-helpers: adapter-lifecycle and oracle-comparison helpers for bound examples · anchored code · src/testing/index.ts:50
impl:protocol.runnable-modules: derives and publishes runnable registrar modules from the graph · anchored code · src/codegen/contracts.ts:658
test:protocol.example-runner-cleanup: the Vitest adapter cleans up a world whether its steps pass or fail · anchored test binding · binding present · test/vitest-adapter.test.ts:19
test:protocol.example-runner.red-step-naming: the red-step point verifies the self-naming failure law · anchored test binding · binding present · test/self-hosting-extraction.test.ts:798
test:protocol.example-runner.step-order: the step-order point verifies contract order and the one handler per step · anchored test binding · binding present · test/self-hosting-extraction.test.ts:789
test:protocol.runnable-modules: verifies generated runnable-module registration and runtime semantics · anchored test binding · binding present · test/testing.test.ts:58
test:protocol.runnable-modules-generation: checks registrar generation, sibling paths and competing suite paths · anchored test binding · binding present · test/codegen.test.ts:22
test:protocol.runnable-modules-types: checks registrar skeletons and required authored adapters · anchored test binding · binding present · test/runnable-modules.typecheck.ts:5
component:protocol.adapters · external runtime and source adapters · src/adapters/vitest.ts:23 · role adapter · layer adapter · context protocol
component:protocol.runner · provider-neutral example execution · src/runner/index.ts:99 · role service · layer application · context protocol
impl:protocol.example-runner · plans and executes a bound example against the caller's world · src/runner/index.ts:108 · role service · component component:protocol.runner · layer application · context protocol
impl:protocol.example-runner-adapter · registers one test per example and owns the fresh world lifecycle · src/adapters/vitest.ts:32 · role adapter · component component:protocol.adapters · layer adapter · context protocol
Design reference: none
Verifier binding: present
spec:extraction.example-runner.red-step-naming · A red step names itself before the assertion detail · declared · specs/extraction/example-runner.red-step-naming.sdp.md · example enabled
spec:extraction.example-runner.step-order · A repeated step runs its one handler at each occurrence, in contract order · declared · specs/extraction/example-runner.step-order.sdp.md · example enabled
test:protocol.example-runner-cleanup · the Vitest adapter cleans up a world whether its steps pass or fail · anchored · test/vitest-adapter.test.ts:19 · test anchor