One .sdp.gherkin file carries exactly one behavior Spec as its Feature and zero or more example Specs as ordinary Scenarios, with one canonical carrier surface per Spec ID.
A .sdp.gherkin file uses Gherkin's English dialect, by default or under # language: en; any other # language: header refuses the file at that line with extract/gherkin-grammar.
A Feature and each ordinary Scenario carry exactly one @spec.<dotted-id> tag, with the Spec id's spec: prefix omitted, one @altitude.<value> tag taking epic, feature or story, and one @readiness.<value> tag taking idea, scoped, defined or ready.
A .sdp.gherkin carrier holds only behavior and example Specs; the Markdown and TypeScript carriers remain lawful for the other kinds, under spec:decisions.carrier-universality.
A relation tag is a head, a dot and a full Spec id, as in @depends-on.spec:carrier.slot-notation, and the heads @refines., @depends-on., @constrained-by., @decided-by. and @verifies. declare refines, dependsOn, constrainedBy, decidedBy and verifies; an ordinary Scenario defaults refines and verifies to its Feature unless it explicitly declares that relation type.
@exercises.<key> on an ordinary Scenario names a rule key of the Spec it verifies, and it and a Rule title key follow spec:model.rule-keys; @kind., @pack, @pack. and @supersedes. are refused.
A tag whose head, compared case-insensitively, is implemented, has-verifier, hasVerifier, observed, claim, status, lifecycle, workflow or architect, followed by the end of the tag, . or -, is refused, so the carrier authors no delivery fact, claim, lifecycle state or workflow status.
A tag whose head has a unique nearest reserved head, within one edit of a reserved head of at most five letters or two edits of a longer one, is refused, and the refusal suggests that head only when its suggested form is lawful; every other tag, @wip included, is decoration and authors no graph state.
A keyed Feature or ordinary Scenario description line has the form - <key>: <value> with a nonempty value; actor, problem, outcome, value and description occur at most once and populate Intent, risk and assumption repeat in Intent, criterion repeats in Verification, and verification-mode occurs at most once with manual, reviewed, contract or executable.
An unknown description key or a heading-shaped description line is refused at its physical source line, despite blanks and comments; remaining non-heading prose is narrative, lawful only as free prose on the typed prose owners named by the prose-ownership decision, spec:decisions.prose-ownership, and never a new field or a parser within a parser.
Trailing title-only Rule blocks populate behavior rules in source order, and a Rule title may open with a rule key marker, [#key] and a space; a Rule carrying tags, description, or positionally nested children is refused.
At most one @example-space pseudo-scenario supplies the parent vocabulary without producing a Spec node, while each ordinary Scenario supplies exactly one bound example point.
An ordinary Scenario and an @example-space pseudo-scenario must each carry at least one step; a step-less Scenario is refused at its Scenario line without inventing a complete-GWT rule.
Gherkin steps reuse the Protocol-owned slot notation; conjunctions inherit the preceding phase, and outlines, backgrounds, star steps, doc strings, data tables, and leading conjunctions are refused.
A step of an ordinary Scenario or of the @example-space pseudo-scenario may open its text with a step key marker, [#key] and a space, after its keyword, And included, under spec:carrier.step-keys.
Independent semantic Gherkin findings accumulate in physical source order up to a hard cap of 100; any semantic finding excludes the entire invalid carrier from the graph while healthy sibling files survive.
Gherkin is a canonical authoring carrier rather than a Cucumber execution path; generated contracts and resolving code-side anchors remain the execution and delivery-fact boundary.
Packs follow the Pack syntax ruling, spec:decisions.pack-markdown-carrier; this carrier neither admits a Gherkin Pack surface nor reopens the Pack Markdown envelope.
Universality is a generated Gherkin-shaped read projection of any Spec, never an authored .sdp.gherkin in an authored tree and never round-trip parity.
Given the Gherkin fixture corpus {probe: "authored-fact"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 1} findings
Then the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 1}
Then the graph omits the Spec {absentId: "spec:fixture.authored-fact"}
Given
the Gherkin fixture corpus {probe: "authored-fact"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 1} findings
the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 1}
the graph omits the Spec {absentId: "spec:fixture.authored-fact"}
Given the Gherkin fixture corpus {probe: "parity"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 0} findings
Then the graph for {parityLeft: "twin.sdp.md"} equals the graph for {parityRight: "twin.sdp.gherkin"}
Then the contracts for {parityLeft: "twin.sdp.md"} equal the contracts for {parityRight: "twin.sdp.gherkin"}
Given
the Gherkin fixture corpus {probe: "parity"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 0} findings
the graph for {parityLeft: "twin.sdp.md"} equals the graph for {parityRight: "twin.sdp.gherkin"}
the contracts for {parityLeft: "twin.sdp.md"} equal the contracts for {parityRight: "twin.sdp.gherkin"}
Given the Gherkin fixture corpus {probe: "description-location-refusal"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 1} findings
Then the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 6}
Then the graph omits the Spec {absentId: "spec:fixture.desc-loc-refusal"}
Given
the Gherkin fixture corpus {probe: "description-location-refusal"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 1} findings
the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 6}
the graph omits the Spec {absentId: "spec:fixture.desc-loc-refusal"}
Given the Gherkin fixture corpus {probe: "duplicate-surface"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 2} findings
Then the report contains finding {findingId: "extract/duplicate-id"}
Then the graph omits the Spec {absentId: "spec:fixture.surface-duplicate"}
Then no graph edge names the absent Spec {absentId: "spec:fixture.surface-duplicate"}
Then the graph contains the Spec {specId: "spec:fixture.surface-sibling"} with kind {specKind: "example"}
Given
the Gherkin fixture corpus {probe: "duplicate-surface"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 2} findings
the report contains finding {findingId: "extract/duplicate-id"}
the graph omits the Spec {absentId: "spec:fixture.surface-duplicate"}
no graph edge names the absent Spec {absentId: "spec:fixture.surface-duplicate"}
the graph contains the Spec {specId: "spec:fixture.surface-sibling"} with kind {specKind: "example"}
Given the Gherkin fixture corpus {probe: "example-space"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 0} findings
Then the graph contains exactly {specCount: 2} Specs
Then the parent example space contains {spaceStep: "Given a cart containing {item:string}"}
Then the graph omits the Spec {absentId: "spec:fixture.example-space"}
Given
the Gherkin fixture corpus {probe: "example-space"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 0} findings
the graph contains exactly {specCount: 2} Specs
the parent example space contains {spaceStep: "Given a cart containing {item:string}"}
the graph omits the Spec {absentId: "spec:fixture.example-space"}
Given the Gherkin fixture corpus {probe: "malformed-relation"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 1} findings
Then the first finding is {findingId: "extract/invalid-id"} at line {line: 4}
Then the graph omits the Spec {absentId: "spec:fixture.malformed-relation"}
Given
the Gherkin fixture corpus {probe: "malformed-relation"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 1} findings
the first finding is {findingId: "extract/invalid-id"} at line {line: 4}
the graph omits the Spec {absentId: "spec:fixture.malformed-relation"}
Given the Gherkin fixture corpus {probe: "missing-id"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 1} findings
Then the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 3}
Then the graph omits the Spec {absentId: "spec:fixture.missing-id"}
Given
the Gherkin fixture corpus {probe: "missing-id"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 1} findings
the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 3}
the graph omits the Spec {absentId: "spec:fixture.missing-id"}
Given the Gherkin fixture corpus {probe: "multi-finding"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 4} findings
Then the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 1}
Then the graph contains exactly {specCount: 1} Specs
Then the graph omits the Spec {absentId: "spec:fixture.invalid-parent"}
Then no graph edge names the absent Spec {absentId: "spec:fixture.invalid-child"}
Then the graph contains the Spec {specId: "spec:fixture.healthy-sibling"} with kind {specKind: "behavior"}
Given
the Gherkin fixture corpus {probe: "multi-finding"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 4} findings
the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 1}
the graph contains exactly {specCount: 1} Specs
the graph omits the Spec {absentId: "spec:fixture.invalid-parent"}
no graph edge names the absent Spec {absentId: "spec:fixture.invalid-child"}
the graph contains the Spec {specId: "spec:fixture.healthy-sibling"} with kind {specKind: "behavior"}
Given the Gherkin fixture corpus {probe: "parent-child"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 0} findings
Then the graph contains exactly {specCount: 2} Specs
Then the graph contains the Spec {specId: "spec:fixture.gherkin-parent"} with kind {specKind: "behavior"}
Then the graph contains the child Spec {childId: "spec:fixture.gherkin-child"} with kind {specKind: "example"}
Then the child Spec {childId: "spec:fixture.gherkin-child"} declares {relationType: "refines"} to {relationTarget: "spec:fixture.gherkin-parent"}
Then the child Spec {childId: "spec:fixture.gherkin-child"} declares the additional relation {relationType: "verifies"} to {relationTarget: "spec:fixture.gherkin-parent"}
Given
the Gherkin fixture corpus {probe: "parent-child"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 0} findings
the graph contains exactly {specCount: 2} Specs
the graph contains the Spec {specId: "spec:fixture.gherkin-parent"} with kind {specKind: "behavior"}
the graph contains the child Spec {childId: "spec:fixture.gherkin-child"} with kind {specKind: "example"}
the child Spec {childId: "spec:fixture.gherkin-child"} declares {relationType: "refines"} to {relationTarget: "spec:fixture.gherkin-parent"}
the child Spec {childId: "spec:fixture.gherkin-child"} declares the additional relation {relationType: "verifies"} to {relationTarget: "spec:fixture.gherkin-parent"}
Given the Gherkin fixture corpus {probe: "step-less"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 1} findings
Then the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 5}
Then the graph omits the Spec {absentId: "spec:fixture.step-less"}
Given
the Gherkin fixture corpus {probe: "step-less"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 1} findings
the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 5}
the graph omits the Spec {absentId: "spec:fixture.step-less"}
Given the Gherkin fixture corpus {probe: "unbound-ready"}
When the fixture corpus is extracted and validated
Then validation reports {findingCount: 3} findings
Then the report contains finding {findingId: "honesty/readiness-floor"}
Then the graph contains the Spec {specId: "spec:fixture.unbound-ready"} with kind {specKind: "example"}
Given
the Gherkin fixture corpus {probe: "unbound-ready"}
When
the fixture corpus is extracted and validated
Then
validation reports {findingCount: 3} findings
the report contains finding {findingId: "honesty/readiness-floor"}
the graph contains the Spec {specId: "spec:fixture.unbound-ready"} with kind {specKind: "example"}
Given the Gherkin fixture corpus {probe: "unknown-tag"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 1} findings
Then the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 1}
Then the first finding message contains {messageText: "did you mean"}
Then the graph omits the Spec {absentId: "spec:fixture.unknown-tag"}
Given
the Gherkin fixture corpus {probe: "unknown-tag"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 1} findings
the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 1}
the first finding message contains {messageText: "did you mean"}
the graph omits the Spec {absentId: "spec:fixture.unknown-tag"}
Given the Gherkin fixture corpus {probe: "unsupported-construct"}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount: 1} findings
Then the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 7}
Then the graph omits the Spec {absentId: "spec:fixture.outline"}
Given
the Gherkin fixture corpus {probe: "unsupported-construct"}
When
the fixture corpus is extracted and validated
Then
extraction reports {findingCount: 1} findings
the first finding is {findingId: "extract/gherkin-grammar"} at line {line: 7}
the graph omits the Spec {absentId: "spec:fixture.outline"}
Given the Gherkin fixture corpus {probe:string}
When the fixture corpus is extracted and validated
Then extraction reports {findingCount:number} findings
Then validation reports {findingCount:number} findings
Then the first finding is {findingId:string} at line {line:number}
Then the first finding message contains {messageText:string}
Then the report contains finding {findingId:string}
Then the graph contains exactly {specCount:number} Specs
Then the graph contains the Spec {specId:string} with kind {specKind:"behavior"|"example"}
Then the graph contains the child Spec {childId:string} with kind {specKind:"behavior"|"example"}
Then the child Spec {childId:string} declares {relationType:string} to {relationTarget:string}
Then the child Spec {childId:string} declares the additional relation {relationType:string} to {relationTarget:string}
Then the graph omits the Spec {absentId:string}
Then no graph edge names the absent Spec {absentId:string}
Then the parent example space contains {spaceStep:string}
Then the graph for {parityLeft:string} equals the graph for {parityRight:string}
Then the contracts for {parityLeft:string} equal the contracts for {parityRight:string}
the reserved heads are spec, altitude, readiness, refines, depends-on, constrained-by, decided-by, verifies, exercises, kind, pack, supersedes and example-space; the near-miss refusal measures a tag head against them.
spec:carrier.gherkin-authoring.multi-finding-bounded · Multiple findings exclude one carrier and keep a healthy sibling · declared · example enabled · specs/carrier/gherkin-authoring.multi-finding-bounded.sdp.md
spec:carrier.gherkin-authoring.unbound-ready-refused · A Gherkin example with an unbound used slot fails its stated readiness floor · declared · example enabled · specs/carrier/gherkin-authoring.unbound-ready-refused.sdp.md
extraction reports {findingCount:number} findings
validation reports {findingCount:number} findings
the first finding is {findingId:string} at line {line:number}
the first finding message contains {messageText:string}
the report contains finding {findingId:string}
the graph contains exactly {specCount:number} Specs
the graph contains the Spec {specId:string} with kind {specKind:"behavior"|"example"}
the graph contains the child Spec {childId:string} with kind {specKind:"behavior"|"example"}
the child Spec {childId:string} declares {relationType:string} to {relationTarget:string}
the child Spec {childId:string} declares the additional relation {relationType:string} to {relationTarget:string}
the graph omits the Spec {absentId:string}
no graph edge names the absent Spec {absentId:string}
the parent example space contains {spaceStep:string}
the graph for {parityLeft:string} equals the graph for {parityRight:string}
the contracts for {parityLeft:string} equal the contracts for {parityRight:string}
Composing needs the script.
Design view
Requirement drawing
Requirement drawing for spec:carrier.gherkin-authoringThe diagram as text
spec:carrier.gherkin-authoring: Gherkin authoring enters the one graph · declared Spec
spec:carrier.gherkin-authoring.authored-fact-refused: An authored delivery fact lookalike is refused · declared Spec
spec:carrier.gherkin-authoring.contract-parity: Markdown and Gherkin twins derive equal graphs and contracts · declared Spec
spec:carrier.gherkin-authoring.description-location-refused: A bad description key reports its physical source line · declared Spec
spec:carrier.gherkin-authoring.duplicate-surface-refused: Duplicate Markdown and Gherkin surfaces are both excluded · declared Spec
spec:carrier.gherkin-authoring.example-space-extraction: The pseudo-scenario supplies example space without a node · declared Spec
spec:carrier.gherkin-authoring.malformed-relation-refused: A malformed relation target is refused · declared Spec
spec:carrier.gherkin-authoring.missing-id-refused: A Feature without identity is refused · declared Spec
spec:carrier.gherkin-authoring.multi-finding-bounded: Multiple findings exclude one carrier and keep a healthy sibling · declared Spec
spec:carrier.gherkin-authoring.parent-child-extraction: A Feature and Scenario enter the graph as parent and child · declared Spec
spec:carrier.gherkin-authoring.step-less-scenario-refused: A step-less Scenario is refused at its Scenario line · declared Spec
spec:carrier.gherkin-authoring.unbound-ready-refused: A Gherkin example with an unbound used slot fails its stated readiness floor · declared Spec
spec:carrier.gherkin-authoring.unknown-tag-refused: A graph-aware tag near miss is refused · declared Spec
spec:carrier.gherkin-authoring.unsupported-construct-refused: A Scenario Outline is refused · declared Spec
spec:carrier.markdown-authoring: Markdown authoring enters the one graph · declared Spec
spec:validation.kind-evidence: Each kind carries its own evidence · declared Spec
impl:protocol.gherkin-authoring: reifies Gherkin behavior and example authoring into the one carrier path · anchored code · src/extract/gherkin.ts:1323
impl:protocol.gherkin-kind-policy: shared Gherkin kind-refusal and loss explanations · anchored code · src/extract/gherkin-kind-honesty.ts:6
test:protocol.gherkin-authoring.authored-fact-refused: the authored-fact-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:363
test:protocol.gherkin-authoring.contract-parity: the contract-parity point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:388
test:protocol.gherkin-authoring.description-location-refused: the description-location-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:656
test:protocol.gherkin-authoring.duplicate-surface-refused: the duplicate-surface-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:396
test:protocol.gherkin-authoring.example-space-extraction: the example-space-extraction point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:439
test:protocol.gherkin-authoring.malformed-relation-refused: the malformed-relation-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:481
test:protocol.gherkin-authoring.missing-id-refused: the missing-id-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:509
test:protocol.gherkin-authoring.multi-finding-bounded: the multi-finding-bounded point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:714
test:protocol.gherkin-authoring.parent-child-extraction: the parent-child-extraction point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:534
test:protocol.gherkin-authoring.step-less-scenario-refused: the step-less-scenario-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:686
test:protocol.gherkin-authoring.unbound-ready-refused: the unbound-ready-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:588
test:protocol.gherkin-authoring.unknown-tag-refused: the unknown-tag-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:596
test:protocol.gherkin-authoring.unsupported-construct-refused: the unsupported-construct-refused point verifies the Gherkin carrier contract · anchored test binding · binding present · test/self-hosting-carrier-gherkin.test.ts:626
In order, first, Gherkin remains an honest canonical per-ID option only for behavior (Feature) and example (ordinary Scenario); the other six kinds stay Markdown because a Gherkin mapping would lie against the kind-evidence table — workflow has no distinct Gherkin root and Feature mapping erases the kind; rule collides with Rule: already consumed as inline behavior.rules; constraint needs machine-readable targets a Scenario cannot own; model needs keyed terms; decision needs context/decision/rationale/consequences (and supersedes) that Feature structure cannot distinguish; contract shares the behavior family row but Feature cannot structurally mark the kind. Second, rich content is ruled by physical form: Feature and Scenario description prose (keyed description bullets and remaining non-heading prose) is lawful only as free prose on the prose owners the prose-ownership law (MD-19) names — narrative or description on the typed owner — never a new field and never a parser-within-a-parser beyond enumerated constructs; Gherkin DocStrings and DataTables remain refused. Third, "universal" means per-ID carriers plus a generated Gherkin-shaped READ projection of any Spec (visibly generated, disposable, lossy commentary allowed for refused kinds), not one default authored carrier for everything and not a lossless codec. Fourth, the corpus default does not flip: Markdown remains the default Spec carrier; a default flip is refused before full honest round-trip exists. Fifth, Packs are out of this ruling; the Pack syntax ruling (MD-25) remains the Pack carrier law.
A behavior or example Spec ID may select a graph-aware Gherkin carrier as a lawful canonical per-ID option. Markdown remains the default, each ID has exactly one canonical surface with no mixing, and Gherkin derives the existing graph shape and executes only through generated contracts plus anchored code-side handlers. Its syntax maps onto the existing envelope, sections, relations, and notation; it creates no parallel lifecycle status or tag registry.
A Pack's Markdown carrier is a .sdp.md file routed by the pack: envelope id namespace, closed to id · specs · modelRefs, with the H1 as title and remaining prose as framing; the TypeScript pack() builder stays a lawful per-ID option and the import source.
Canonical graph-aware Gherkin Specs use the .sdp.gherkin suffix. Discovery is suffix-only: .sdp.gherkin files are Gherkin carriers, and bare .feature files are not. Bare .feature remains non-canonical territory for import sources, foreign corpora, and historical lineage, never a second live canonical surface. This ruling does not change which Spec kinds may choose Gherkin, does not flip the default carrier away from Markdown, and does not admit dual-suffix discovery or content sniffing.
Runtime
component:protocol.extract · the carrier and source pipeline · src/extract/index.ts:192 · layer application · context protocol
Uses
component:protocol.graph · the one graph and its semantic decisions · src/graph/schema.ts:34 · layer domain · context protocol
component:protocol.model · the authored contracts and stable ids · src/model/anchors.ts:100 · layer domain · context protocol
impl:protocol.gherkin-authoring · reifies Gherkin behavior and example authoring into the one carrier path · src/extract/gherkin.ts:1323 · role extractor · component component:protocol.extract · layer application · context protocol
impl:protocol.gherkin-kind-policy · shared Gherkin kind-refusal and loss explanations · src/extract/gherkin-kind-honesty.ts:6 · role decider · component component:protocol.extract · layer application · context protocol
spec:carrier.gherkin-authoring.multi-finding-bounded · Multiple findings exclude one carrier and keep a healthy sibling · declared · specs/carrier/gherkin-authoring.multi-finding-bounded.sdp.md · example enabled
spec:carrier.gherkin-authoring.unbound-ready-refused · A Gherkin example with an unbound used slot fails its stated readiness floor · declared · specs/carrier/gherkin-authoring.unbound-ready-refused.sdp.md · example enabled