Skip to content

Gherkin Patterns Guide

Practical patterns for writing Gherkin specs that work with delivery-process generators.

Tag Reference: Run npx generate-tag-taxonomy -o TAG_TAXONOMY.md -f for the complete tag list. See TAXONOMY.md for concepts.


Roadmap specs define planned work with Problem/Solution descriptions and a Background deliverables table.

@libar-docs-pattern:ProcessGuardLinter
@libar-docs-status:roadmap
@libar-docs-phase:99
Feature: Process Guard Linter
**Problem:**
During planning and implementation sessions, accidental modifications occur:
- Specs outside the intended scope get modified in bulk
- Completed/approved work gets inadvertently changed
**Solution:**
Implement a Decider-based linter that:
1. Derives process state from existing file annotations
2. Validates proposed changes against derived state
3. Enforces file protection levels per PDR-005
Background: Deliverables
Given the following deliverables:
| Deliverable | Status | Location |
| State derivation | Pending | src/lint/process-guard/derive.ts |
| Git diff change detection | Pending | src/lint/process-guard/detect.ts |
| CLI integration | Pending | src/cli/lint-process.ts |

Key elements:

  • @libar-docs-pattern:Name - Unique identifier (required)
  • @libar-docs-status:roadmap - FSM state
  • **Problem:** / **Solution:** - Extracted by generators
  • Background deliverables table - Tracks implementation progress

Use Rule: to group related scenarios under a business constraint.

Rule: Status transitions must follow PDR-005 FSM
@happy-path
Scenario Outline: Valid transitions pass validation
Given a file with status "<from>"
When the status changes to "<to>"
Then validation passes
Examples:
| from | to |
| roadmap | active |
| roadmap | deferred |
| active | completed |
| deferred | roadmap |
@edge-case
Scenario Outline: Invalid transitions fail validation
Given a file with status "<from>"
When the status changes to "<to>"
Then validation fails with "invalid-status-transition"
Examples:
| from | to |
| roadmap | completed |
| deferred | active |
| completed | roadmap |

Rules provide semantic grouping - generators extract them for business rules documentation.

When the same pattern applies with different inputs, use Scenario Outline with an Examples table.

Scenario Outline: Protection levels by status
Given a file with status "<status>"
When checking protection level
Then protection is "<protection>"
And unlock required is "<unlock>"
Examples:
| status | protection | unlock |
| roadmap | none | no |
| active | scope | no |
| completed | hard | yes |
| deferred | none | no |

Test features focus on behavior verification with section dividers for organization.

@behavior @scanner-core
@libar-docs-pattern:ScannerCore
Feature: Scanner Core Integration
The scanPatterns function orchestrates file discovery and AST parsing.
**Problem:**
- Need to scan codebases for documentation directives efficiently
- Files without @libar-docs opt-in should be skipped
**Solution:**
- Two-phase filtering: quick regex check, then file opt-in validation
- Result monad pattern captures errors without failing entire scan
Background:
Given a scanner integration context with temp directory
# ==========================================================================
# Basic Scanning
# ==========================================================================
@happy-path
Scenario: Scan files and extract directives
Given a file "src/auth.ts" with content:
"""
/** @libar-docs */
/** @libar-docs-core */
export function authenticate() {}
"""
When scanning with pattern "src/**/*.ts"
Then the scan should succeed with 1 file
# ==========================================================================
# Error Handling
# ==========================================================================
@error-handling
Scenario: Collect errors for files that fail to parse
Given a file "src/valid.ts" with valid content
And a file "src/invalid.ts" with syntax errors
When scanning with pattern "src/**/*.ts"
Then the scan should succeed with 1 file
And the scan should have 1 error

Section comments (# ===) improve readability in large feature files.


Use for data that applies to all scenarios - deliverables, definitions, etc.

Background: Deliverables
Given the following deliverables:
| Deliverable | Status | Location | Tests |
| Category types | Done | src/types.ts | Yes |
| Validation logic | Pending | src/validate.ts | Yes |

Use for scenario-specific test inputs.

Scenario: Session file defines modification scope
Given a session file with in-scope specs:
| spec | intent |
| mvp-workflow-implementation | modify |
| short-form-tag-migration | review |
When deriving process state
Then "mvp-workflow-implementation" is modifiable

Use """typescript for code blocks. Essential when content contains pipes or special characters.

Scenario: Extract directive from TypeScript
Given a file with content:
"""typescript
/** @libar-docs */
/**
* @libar-docs-core
* Authentication utilities
*/
export function authenticate() {}
"""
When scanning the file
Then directive should have tag "@libar-docs-core"

These tags are recognized by the extractor and appear in generated documentation:

TagPurpose
@acceptance-criteriaRequired for DoD validation of completed patterns
@happy-pathPrimary success scenario
@validationInput validation, constraint checks
@business-ruleBusiness invariant verification
@business-failureExpected business failure scenario
@compensationCompensating action scenario
@idempotencyIdempotency verification
@expirationExpiration/timeout behavior
@workflow-stateWorkflow state transition scenario

These tags are not extracted by generators but are used by convention for organizing feature files:

TagPurpose
@edge-caseBoundary conditions, unusual inputs
@error-handlingError recovery, graceful degradation
@integrationCross-component behavior
@pocProof of concept, experimental

Combine scenario-level tags with feature-level tags for filtering:

@behavior @scanner-core
@libar-docs-pattern:ScannerCore
Feature: Scanner Core Integration

Feature files serve dual purposes: executable specs and documentation source. Content in the Feature description section appears in generated docs.

Prefer code stubs over DocStrings for complex examples. Feature files should reference code, not duplicate it.

ApproachWhen to Use
DocStrings ("""typescript)Brief examples (5-10 lines), current/target state comparison
Code stub referenceComplex APIs, interfaces, full implementations

Instead of large DocStrings:

Rule: Reservations use atomic claim
See `@libar-dev/platform-core/src/reservations/reserve.ts` for API.

Code stubs are annotated TypeScript files with throw new Error("not yet implemented").

For features that define business constraints, use Rule: blocks with structured descriptions:

Rule: Reservations prevent race conditions
**Invariant:** Only one reservation can exist for a given key at a time.
**Rationale:** Check-then-create patterns have TOCTOU vulnerabilities.
**Verified by:** Concurrent reservations, Expired reservation cleanup
@acceptance-criteria @happy-path
Scenario: Concurrent reservations
...
ElementPurposeExtracted By
**Invariant:**Business constraint (what must be true)Business Rules generator
**Rationale:**Business justification (why it exists)Business Rules generator
**Verified by:**Comma-separated scenario namesMultiple codecs (Business Rules, Reference)

Note: Rule blocks are optional. Use them when the feature defines business invariants that benefit from structured documentation.

Choose headers that fit your pattern:

StructureHeadersBest For
Problem/Solution**Problem:**, **Solution:**Pain point → fix
Value-First**Business Value:**, **How It Works:**TDD-style, Gherkin spirit
Context/Approach**Context:**, **Approach:**Technical patterns

The Problem/Solution pattern is the dominant style in this codebase.

Content TypeSyntaxAppears in Docs
Plain textRegular paragraphsYes
Bold/emphasis**bold**, *italic*Yes
TablesMarkdown pipe tablesYes
Lists- item or 1. itemYes
DocStrings"""typescript"""Yes (code block)
Comments# commentNo (ignored)

Prefer DocStrings over code fences for portability:

# Preferred - DocStrings with language hint
Given the following code:
"""typescript
const x = 1;
"""
# Avoid - markdown fences in descriptions may not render consistently

Tag values cannot contain spaces. Use hyphens:

InvalidValid
@unlock-reason:Fix for issue@unlock-reason:Fix-for-issue
@libar-docs-pattern:My Pattern@libar-docs-pattern:MyPattern

For values with spaces, use the quoted-value format where supported:

@libar-docs-usecase "When handling command failures"

ElementUse ForExample Location
Background DataTableDeliverables, shared reference datadelivery-process/specs/process-guard-linter.feature
Rule:Group scenarios by business constrainttests/features/validation/*.feature
Scenario OutlineSame pattern with variationstests/features/validation/fsm-validator.feature
DocString """Code examples, content with pipestests/features/behavior/scanner-*.feature
Section comments #Organize large feature filesMost test features
lint-stepsCatch vitest-cucumber traps staticallyVALIDATION.md — lint-steps

DocumentPurpose
ANNOTATION-GUIDE.mdAnnotation mechanics and tag reference
TAXONOMY.mdTag taxonomy concepts and API
CONFIGURATION.mdPreset and tag prefix configuration
VALIDATION.mdFull validation tool suite and CI setup