Reference Generation Sample
Purpose: Reference document: Reference Generation Sample Detail Level: Full reference
Product area canonical values
Section titled “Product area canonical values”Invariant: The product-area tag uses one of 7 canonical values. Each value represents a reader-facing documentation section, not a source module.
Rationale: Without canonical values, organic drift (e.g., Generator vs Generators) produces inconsistent grouping in generated documentation and fragmented product area pages.
| Value | Reader Question | Covers |
|---|---|---|
| Annotation | How do I annotate code? | Scanning, extraction, tag parsing, dual-source |
| Configuration | How do I configure the tool? | Config loading, presets, resolution |
| Generation | How does code become docs? | Codecs, generators, rendering, diagrams |
| Validation | How is the workflow enforced? | FSM, DoD, anti-patterns, process guard, lint |
| DataAPI | How do I query process state? | Process state API, stubs, context assembly, CLI |
| CoreTypes | What foundational types exist? | Result monad, error factories, string utils |
| Process | How does the session workflow work? | Session lifecycle, handoffs, conventions |
ADR category canonical values
Section titled “ADR category canonical values”Invariant: The adr-category tag uses one of 4 values.
Rationale: Unbounded category values prevent meaningful grouping of architecture decisions and make cross-cutting queries unreliable.
| Value | Purpose |
|---|---|
| architecture | System structure, component design, data flow |
| process | Workflow, conventions, annotation rules |
| testing | Test strategy, verification approach |
| documentation | Documentation generation, content structure |
FSM status values and protection levels
Section titled “FSM status values and protection levels”Invariant: Pattern status uses exactly 4 values with defined protection levels. These are enforced by Process Guard at commit time.
Rationale: Without protection levels, active specs accumulate scope creep and completed specs get silently modified, undermining delivery process integrity.
| Status | Protection | Can Add Deliverables | Allowed Actions |
|---|---|---|---|
| roadmap | None | Yes | Full editing |
| active | Scope-locked | No | Edit existing deliverables only |
| completed | Hard-locked | No | Requires unlock-reason tag |
| deferred | None | Yes | Full editing |
Valid FSM transitions
Section titled “Valid FSM transitions”Invariant: Only these transitions are valid. All others are rejected by Process Guard.
Rationale: Allowing arbitrary transitions (e.g., roadmap to completed) bypasses the active phase where scope-lock and deliverable tracking provide quality assurance. Completed is a terminal state. Modifications require @libar-docs-unlock-reason escape hatch.
| From | To | Trigger |
|---|---|---|
| roadmap | active | Start work |
| roadmap | deferred | Postpone |
| active | completed | All deliverables done |
| active | roadmap | Blocked/regressed |
| deferred | roadmap | Resume planning |
Tag format types
Section titled “Tag format types”Invariant: Every tag has one of 6 format types that determines how its value is parsed.
Rationale: Without explicit format types, parsers must guess value structure, leading to silent data corruption when CSV values are treated as single strings or numbers are treated as text.
| Format | Parsing | Example |
|---|---|---|
| flag | Boolean presence, no value | @libar-docs-core |
| value | Simple string | @libar-docs-pattern MyPattern |
| enum | Constrained to predefined list | @libar-docs-status completed |
| csv | Comma-separated values | @libar-docs-uses A, B, C |
| number | Numeric value | @libar-docs-phase 15 |
| quoted-value | Preserves spaces | @libar-docs-brief:‘Multi word’ |
Source ownership
Section titled “Source ownership”Invariant: Relationship tags have defined ownership by source type. Anti-pattern detection enforces these boundaries.
Rationale: Cross-domain tag placement (e.g., runtime dependencies in Gherkin) creates conflicting sources of truth and breaks the dual-source architecture ownership model.
| Tag | Correct Source | Wrong Source | Rationale |
|---|---|---|---|
| uses | TypeScript | Feature files | TS owns runtime dependencies |
| depends-on | Feature files | TypeScript | Gherkin owns planning dependencies |
| quarter | Feature files | TypeScript | Gherkin owns timeline metadata |
| team | Feature files | TypeScript | Gherkin owns ownership metadata |
Quarter format convention
Section titled “Quarter format convention”Invariant: The quarter tag uses YYYY-QN format (e.g., 2026-Q1). ISO-year-first sorting works lexicographically.
Rationale: Non-standard formats (e.g., Q1-2026) break lexicographic sorting, which roadmap generation and timeline queries depend on for correct ordering.
Canonical phase definitions (6-phase USDP standard)
Section titled “Canonical phase definitions (6-phase USDP standard)”Invariant: The default workflow defines exactly 6 phases in fixed order. These are the canonical phase names and ordinals used by all generated documentation.
Rationale: Ad-hoc phase names and ordering produce inconsistent roadmap grouping across packages and make cross-package progress tracking impossible.
| Order | Phase | Purpose |
|---|---|---|
| 1 | Inception | Problem framing, scope definition |
| 2 | Elaboration | Design decisions, architecture exploration |
| 3 | Session | Planning and design session work |
| 4 | Construction | Implementation, testing, integration |
| 5 | Validation | Verification, acceptance criteria confirmation |
| 6 | Retrospective | Review, lessons learned, documentation |
Deliverable status canonical values
Section titled “Deliverable status canonical values”Invariant: Deliverable status (distinct from pattern FSM status) uses exactly 6 values, enforced by Zod schema at parse time.
Rationale: Freeform status strings bypass Zod validation and break DoD checks, which rely on terminal status classification to determine pattern completeness.
| Value | Meaning |
|---|---|
| complete | Work is done |
| in-progress | Work is ongoing |
| pending | Work has not started |
| deferred | Work postponed |
| superseded | Replaced by another |
| n/a | Not applicable |
Configuration Components
Section titled “Configuration Components”Scoped architecture diagram showing component relationships:
graph TB
subgraph config["Config"]
DeliveryProcessFactory("DeliveryProcessFactory")
DefineConfig[/"DefineConfig"/]
end
ConfigBasedWorkflowDefinition["ConfigBasedWorkflowDefinition"]
ProcessGuardTesting["ProcessGuardTesting"]
subgraph related["Related"]
AntiPatternDetector["AntiPatternDetector"]:::neighbor
ConfigurationTypes["ConfigurationTypes"]:::neighbor
RegexBuilders["RegexBuilders"]:::neighbor
ProjectConfigTypes["ProjectConfigTypes"]:::neighbor
ConfigurationPresets["ConfigurationPresets"]:::neighbor
ProcessGuardLinter["ProcessGuardLinter"]:::neighbor
PhaseStateMachineValidation["PhaseStateMachineValidation"]:::neighbor
MvpWorkflowImplementation["MvpWorkflowImplementation"]:::neighbor
end
DeliveryProcessFactory -->|uses| ConfigurationTypes
DeliveryProcessFactory -->|uses| ConfigurationPresets
DeliveryProcessFactory -->|uses| RegexBuilders
DefineConfig -->|uses| ProjectConfigTypes
ConfigBasedWorkflowDefinition -.->|depends on| MvpWorkflowImplementation
ProcessGuardTesting -.->|depends on| PhaseStateMachineValidation
ProcessGuardTesting -.->|depends on| AntiPatternDetector
ProcessGuardTesting ..->|implements| ProcessGuardLinter
RegexBuilders -->|uses| ConfigurationTypes
ProjectConfigTypes -->|uses| ConfigurationTypes
ProjectConfigTypes -->|uses| ConfigurationPresets
ConfigurationPresets -->|uses| ConfigurationTypes
classDef neighbor stroke-dasharray: 5 5
Generation Pipeline
Section titled “Generation Pipeline”Temporal flow of the documentation generation pipeline:
sequenceDiagram
participant CLI
participant Orchestrator
participant Scanner
participant Extractor
participant Transformer
participant Codec
participant Renderer
CLI ->> Orchestrator: generate(config)
Orchestrator ->> Scanner: scanPatterns(globs)
Scanner -->> Orchestrator: TypeScript ASTs
Orchestrator ->> Scanner: scanGherkinFiles(globs)
Scanner -->> Orchestrator: Gherkin documents
Orchestrator ->> Extractor: extractPatterns(files)
Extractor -->> Orchestrator: ExtractedPattern[]
Orchestrator ->> Extractor: extractFromGherkin(docs)
Extractor -->> Orchestrator: ExtractedPattern[]
Orchestrator ->> Orchestrator: mergePatterns(ts, gherkin)
Orchestrator ->> Transformer: transformToMasterDataset(patterns)
Transformer -->> Orchestrator: MasterDataset
Orchestrator ->> Codec: codec.decode(dataset)
Codec -->> Orchestrator: RenderableDocument
Orchestrator ->> Renderer: render(document)
Renderer -->> Orchestrator: markdown string
Generator Class Model
Section titled “Generator Class Model”Scoped architecture diagram showing component relationships:
classDiagram
class SourceMapper {
<<infrastructure>>
}
class Documentation_Generation_Orchestrator {
<<service>>
}
class TransformDataset {
<<service>>
}
class DecisionDocGenerator {
<<service>>
}
class MasterDataset
class Pattern_Scanner
class GherkinASTParser
class ShapeExtractor
class DecisionDocCodec
class PatternRelationshipModel
SourceMapper ..> DecisionDocCodec : depends on
SourceMapper ..> ShapeExtractor : depends on
SourceMapper ..> GherkinASTParser : depends on
Documentation_Generation_Orchestrator ..> Pattern_Scanner : uses
TransformDataset ..> MasterDataset : uses
TransformDataset ..|> PatternRelationshipModel : implements
DecisionDocGenerator ..> DecisionDocCodec : depends on
DecisionDocGenerator ..> SourceMapper : depends on
Delivery Lifecycle FSM
Section titled “Delivery Lifecycle FSM”FSM lifecycle showing valid state transitions and protection levels:
stateDiagram-v2
[*] --> roadmap
roadmap --> active : Start work
roadmap --> deferred : Postpone
roadmap --> roadmap : Stay in planning
active --> completed : All deliverables done
active --> roadmap : Blocked / regressed
completed --> [*]
deferred --> roadmap : Resume planning
note right of roadmap
Protection: none
end note
note right of active
Protection: scope-locked
end note
note right of completed
Protection: hard-locked
end note
note right of deferred
Protection: none
end note
Scanning & Extraction Boundary
Section titled “Scanning & Extraction Boundary”Scoped architecture diagram showing component relationships:
C4Context
title Scanning & Extraction Boundary
Boundary(extractor, "Extractor") {
System(GherkinExtractor, "GherkinExtractor")
System(DualSourceExtractor, "DualSourceExtractor")
System(Document_Extractor, "Document Extractor")
}
Boundary(scanner, "Scanner") {
System(Pattern_Scanner, "Pattern Scanner")
System(GherkinScanner, "GherkinScanner")
System(GherkinASTParser, "GherkinASTParser")
System(TypeScript_AST_Parser, "TypeScript AST Parser")
}
System_Ext(DocDirectiveSchema, "DocDirectiveSchema")
System_Ext(GherkinRulesSupport, "GherkinRulesSupport")
Rel(GherkinScanner, GherkinASTParser, "uses")
Rel(GherkinScanner, GherkinRulesSupport, "implements")
Rel(GherkinASTParser, GherkinRulesSupport, "implements")
Rel(TypeScript_AST_Parser, DocDirectiveSchema, "uses")
Rel(GherkinExtractor, GherkinASTParser, "uses")
Rel(GherkinExtractor, GherkinRulesSupport, "implements")
Rel(DualSourceExtractor, GherkinExtractor, "uses")
Rel(DualSourceExtractor, GherkinScanner, "uses")
Rel(Document_Extractor, Pattern_Scanner, "uses")
Domain Layer Overview
Section titled “Domain Layer Overview”Scoped architecture diagram showing component relationships:
graph LR
subgraph api["Api"]
MasterDataset[/"MasterDataset"/]
PatternHelpers["PatternHelpers"]
ArchQueriesImpl("ArchQueriesImpl")
end
subgraph config["Config"]
ConfigurationTypes["ConfigurationTypes"]
ProjectConfigTypes["ProjectConfigTypes"]
ConfigurationPresets["ConfigurationPresets"]
end
subgraph taxonomy["Taxonomy"]
TagRegistryBuilder("TagRegistryBuilder")
end
subgraph validation["Validation"]
FSMTransitions[/"FSMTransitions"/]
FSMStates[/"FSMStates"/]
end
subgraph related["Related"]
ProcessStateAPI["ProcessStateAPI"]:::neighbor
TypeScriptTaxonomyImplementation["TypeScriptTaxonomyImplementation"]:::neighbor
PhaseStateMachineValidation["PhaseStateMachineValidation"]:::neighbor
DataAPIOutputShaping["DataAPIOutputShaping"]:::neighbor
DataAPIArchitectureQueries["DataAPIArchitectureQueries"]:::neighbor
end
TagRegistryBuilder ..->|implements| TypeScriptTaxonomyImplementation
ProjectConfigTypes -->|uses| ConfigurationTypes
ProjectConfigTypes -->|uses| ConfigurationPresets
ConfigurationPresets -->|uses| ConfigurationTypes
PatternHelpers ..->|implements| DataAPIOutputShaping
ArchQueriesImpl -->|uses| ProcessStateAPI
ArchQueriesImpl -->|uses| MasterDataset
ArchQueriesImpl ..->|implements| DataAPIArchitectureQueries
FSMTransitions ..->|implements| PhaseStateMachineValidation
FSMStates ..->|implements| PhaseStateMachineValidation
ProcessStateAPI -->|uses| MasterDataset
ProcessStateAPI ..->|implements| PhaseStateMachineValidation
DataAPIArchitectureQueries -.->|depends on| DataAPIOutputShaping
classDef neighbor stroke-dasharray: 5 5
API Types
Section titled “API Types”SectionBlock (type)
Section titled “SectionBlock (type)”type SectionBlock = | HeadingBlock | ParagraphBlock | SeparatorBlock | TableBlock | ListBlock | CodeBlock | MermaidBlock | CollapsibleBlock | LinkOutBlock;normalizeStatus (function)
Section titled “normalizeStatus (function)”/** * Normalize any status string to a display bucket * * Maps status values to three canonical display states: * - "completed": completed * - "active": active * - "planned": roadmap, deferred, planned, or any unknown value * * Per PDR-005: deferred items are treated as planned (not actively worked on) * * @param status - Raw status from pattern (case-insensitive) * @returns "completed" | "active" | "planned" * * @example * ```typescript * normalizeStatus("completed") // → "completed" * normalizeStatus("active") // → "active" * normalizeStatus("roadmap") // → "planned" * normalizeStatus("deferred") // → "planned" * normalizeStatus(undefined) // → "planned" * ``` */function normalizeStatus(status: string | undefined): NormalizedStatus;| Parameter | Type | Description |
|---|---|---|
| status | Raw status from pattern (case-insensitive) |
Returns: “completed” | “active” | “planned”
DELIVERABLE_STATUS_VALUES (const)
Section titled “DELIVERABLE_STATUS_VALUES (const)”/** * Canonical deliverable status values * * These are the ONLY accepted values for the Status column in * Gherkin Background deliverable tables. Values are lowercased * at extraction time before schema validation. * * - complete: Work is done * - in-progress: Work is ongoing * - pending: Work hasn't started * - deferred: Work postponed * - superseded: Replaced by another deliverable * - n/a: Not applicable * */DELIVERABLE_STATUS_VALUES = [ 'complete', 'in-progress', 'pending', 'deferred', 'superseded', 'n/a',] as constCategoryDefinition (interface)
Section titled “CategoryDefinition (interface)”interface CategoryDefinition { /** Category tag name without prefix (e.g., "core", "api", "ddd", "saga") */ readonly tag: string; /** Human-readable domain name for display (e.g., "Strategic DDD", "Event Sourcing") */ readonly domain: string; /** Display order priority - lower values appear first in sorted output */ readonly priority: number; /** Brief description of the category's purpose and typical patterns */ readonly description: string; /** Alternative tag names that map to this category (e.g., "es" for "event-sourcing") */ readonly aliases: readonly string[];}| Property | Description |
|---|---|
| tag | Category tag name without prefix (e.g., “core”, “api”, “ddd”, “saga”) |
| domain | Human-readable domain name for display (e.g., “Strategic DDD”, “Event Sourcing”) |
| priority | Display order priority - lower values appear first in sorted output |
| description | Brief description of the category’s purpose and typical patterns |
| aliases | Alternative tag names that map to this category (e.g., “es” for “event-sourcing”) |
Behavior Specifications
Section titled “Behavior Specifications”DeliveryProcessFactory
Section titled “DeliveryProcessFactory”View DeliveryProcessFactory source
Delivery Process Factory
Section titled “Delivery Process Factory”Main factory function for creating configured delivery process instances. Supports presets, custom configuration, and configuration overrides.
When to Use
Section titled “When to Use”- At application startup to create a configured instance
- When switching between different tag prefixes
- When customizing the taxonomy for a specific project
DefineConfig
Section titled “DefineConfig”Define Config
Section titled “Define Config”Identity function for type-safe project configuration.
Follows the Vite/Vitest defineConfig() convention:
returns the input unchanged, providing only TypeScript type checking.
Validation happens later at load time via Zod schema in loadProjectConfig().
When to Use
Section titled “When to Use”In delivery-process.config.ts at project root:
import { defineConfig } from '@libar-dev/delivery-process/config';
export default defineConfig({ preset: 'ddd-es-cqrs', sources: { typescript: ['src/** /*.ts'] },});ADR005CodecBasedMarkdownRendering
Section titled “ADR005CodecBasedMarkdownRendering”View ADR005CodecBasedMarkdownRendering source
Context: The documentation generator needs to transform structured pattern data (MasterDataset) into markdown files. The initial approach used direct string concatenation in generator functions, mixing data selection, formatting logic, and output assembly in a single pass. This made generators hard to test, difficult to compose, and impossible to render the same data in different formats (e.g., full docs vs compact AI context).
Decision: Adopt a codec architecture inspired by serialization codecs (encode/decode). Each document type has a codec that decodes a MasterDataset into a RenderableDocument — an intermediate representation of sections, headings, tables, paragraphs, and code blocks. A separate renderer transforms the RenderableDocument into markdown. This separates data selection (what to include) from formatting (how it looks) from serialization (markdown syntax).
Consequences: | Type | Impact | | Positive | Codecs are pure functions: dataset in, document out — trivially testable | | Positive | RenderableDocument is an inspectable IR — tests assert on structure, not strings | | Positive | Composable via CompositeCodec — reference docs assemble from child codecs | | Positive | Same dataset can produce different outputs (full doc, compact doc, AI context) | | Negative | Extra abstraction layer between data and output | | Negative | RenderableDocument vocabulary must cover all needed output patterns |
Benefits: | Benefit | Before (String Concat) | After (Codec) | | Testability | Assert on markdown strings | Assert on typed section blocks | | Composability | Copy-paste between generators | CompositeCodec assembles children | | Format variants | Duplicate generator logic | Same codec, different renderer | | Progressive disclosure | Manual heading management | Heading depth auto-calculated |
Codecs implement a decode-only contract (2 scenarios)
Codecs implement a decode-only contract
Section titled “Codecs implement a decode-only contract”Invariant: Every codec is a pure function that accepts a MasterDataset and returns a RenderableDocument. Codecs do not perform side effects, do not write files, and do not access the filesystem. The codec contract is decode-only because the transformation is one-directional: structured data becomes a document, never the reverse.
Rationale: Pure functions are deterministic and trivially testable. For the same MasterDataset, a codec always produces the same RenderableDocument. This makes snapshot testing reliable and enables codec output comparison across versions.
Codec call signature:
interface DocumentCodec { decode(dataset: MasterDataset): RenderableDocument; }Verified by:
- Codec produces deterministic output
- Codec has no side effects
RenderableDocument is a typed intermediate representation (2 scenarios)
RenderableDocument is a typed intermediate representation
Section titled “RenderableDocument is a typed intermediate representation”Invariant: RenderableDocument contains a title, an ordered array of SectionBlock elements, and an optional record of additional files. Each SectionBlock is a discriminated union: heading, paragraph, table, code, list, separator, or metaRow. The renderer consumes this IR without needing to know which codec produced it.
Rationale: A typed IR decouples codecs from rendering. Codecs express intent (“this is a table with these rows”) and the renderer handles syntax (“pipe-delimited markdown with separator row”). This means switching output format (e.g., HTML instead of markdown) requires only a new renderer, not changes to every codec.
Section block types:
| Block Type | Purpose | Markdown Output |
|---|---|---|
| heading | Section title with depth | ## Title (depth-adjusted) |
| paragraph | Prose text | Plain text with blank lines |
| table | Structured data | Pipe-delimited table |
| code | Code sample with language | Fenced code block |
| list | Ordered or unordered items | - item or 1. item |
| separator | Visual break between sections | --- |
| metaRow | Key-value metadata | Key: Value |
Verified by:
- All block types render to markdown
- Unknown block type is rejected
CompositeCodec assembles documents from child codecs (2 scenarios)
CompositeCodec assembles documents from child codecs
Section titled “CompositeCodec assembles documents from child codecs”Invariant: CompositeCodec accepts an array of child codecs and produces a single RenderableDocument by concatenating their sections. Child codec order determines section order in the output. Separators are inserted between children by default.
Rationale: Reference documents combine content from multiple domains (patterns, conventions, shapes, diagrams). Rather than building a monolithic codec that knows about all content types, CompositeCodec lets each domain own its codec and composes them declaratively.
Composition example:
const referenceDoc = CompositeCodec.create({ title: 'Architecture Reference', codecs: [ behaviorCodec, // patterns with rules conventionCodec, // decision records shapeCodec, // type definitions diagramCodec, // mermaid diagrams ], });Verified by:
- Child sections appear in codec array order
- Empty children are skipped without separators
ADR content comes from both Feature description and Rule prefixes (3 scenarios)
ADR content comes from both Feature description and Rule prefixes
Section titled “ADR content comes from both Feature description and Rule prefixes”Invariant: ADR structured content (Context, Decision, Consequences) can appear in two locations within a feature file. Both sources must be rendered. Silently dropping either source causes content loss.
Rationale: Early ADRs used name prefixes like “Context - …” and “Decision - …” on Rule blocks to structure content. Later ADRs placed Context, Decision, and Consequences as bold-annotated prose in the Feature description, reserving Rule: blocks for invariants and design rules. Both conventions are valid. The ADR codec must handle both because the codebase contains ADRs authored in each style. The Feature description lives in pattern.directive.description. If the codec only renders Rules (via partitionRulesByPrefix), then Feature description content is silently dropped — no error, no warning. This caused confusion across two repos where ADR content appeared in the feature file but was missing from generated docs. The fix renders pattern.directive.description in buildSingleAdrDocument between the Overview metadata table and the partitioned Rules section, using renderFeatureDescription() which walks content linearly and handles prose, tables, and DocStrings with correct interleaving.
| Source | Location | Example | Rendered Via |
|---|---|---|---|
| Rule prefix | Rule: Context - … | ADR-001 (taxonomy) | partitionRulesByPrefix() |
| Feature description | Context: prose in Feature block | ADR-005 (codec rendering) | renderFeatureDescription() |
Verified by:
- Feature description content is rendered
- Rule prefix content is rendered
- Both sources combine in single ADR
The markdown renderer is codec-agnostic (2 scenarios)
The markdown renderer is codec-agnostic
Section titled “The markdown renderer is codec-agnostic”Invariant: The renderer accepts any RenderableDocument regardless of which codec produced it. Rendering depends only on block types, not on document origin. This enables testing codecs and renderers independently.
Rationale: If the renderer knew about specific codecs, adding a new codec would require renderer changes. By operating purely on the SectionBlock discriminated union, the renderer is closed for modification but open for extension via new block types.
Verified by:
- Same renderer handles different codec outputs
- Renderer and codec are tested independently
ADR001TaxonomyCanonicalValues
Section titled “ADR001TaxonomyCanonicalValues”View ADR001TaxonomyCanonicalValues source
Context: The annotation system requires well-defined canonical values for taxonomy tags, FSM status lifecycle, and source ownership rules. Without canonical values, organic growth produces drift (Generator vs Generators, Process vs DeliveryProcess) and inconsistent grouping in generated documentation.
Decision: Define canonical values for all taxonomy enums, FSM states with protection levels, valid transitions, tag format types, and source ownership rules. These are the durable constants of the delivery process.
Consequences: | Type | Impact | | Positive | Generated docs group into coherent sections | | Positive | FSM enforcement has clear, auditable state definitions | | Positive | Source ownership prevents cross-domain tag confusion | | Negative | Migration effort for existing specs with non-canonical values |
Product area canonical values
Product area canonical values
Section titled “Product area canonical values”Invariant: The product-area tag uses one of 7 canonical values. Each value represents a reader-facing documentation section, not a source module.
Rationale: Without canonical values, organic drift (e.g., Generator vs Generators) produces inconsistent grouping in generated documentation and fragmented product area pages.
| Value | Reader Question | Covers |
|---|---|---|
| Annotation | How do I annotate code? | Scanning, extraction, tag parsing, dual-source |
| Configuration | How do I configure the tool? | Config loading, presets, resolution |
| Generation | How does code become docs? | Codecs, generators, rendering, diagrams |
| Validation | How is the workflow enforced? | FSM, DoD, anti-patterns, process guard, lint |
| DataAPI | How do I query process state? | Process state API, stubs, context assembly, CLI |
| CoreTypes | What foundational types exist? | Result monad, error factories, string utils |
| Process | How does the session workflow work? | Session lifecycle, handoffs, conventions |
ADR category canonical values
ADR category canonical values
Section titled “ADR category canonical values”Invariant: The adr-category tag uses one of 4 values.
Rationale: Unbounded category values prevent meaningful grouping of architecture decisions and make cross-cutting queries unreliable.
| Value | Purpose |
|---|---|
| architecture | System structure, component design, data flow |
| process | Workflow, conventions, annotation rules |
| testing | Test strategy, verification approach |
| documentation | Documentation generation, content structure |
FSM status values and protection levels
FSM status values and protection levels
Section titled “FSM status values and protection levels”Invariant: Pattern status uses exactly 4 values with defined protection levels. These are enforced by Process Guard at commit time.
Rationale: Without protection levels, active specs accumulate scope creep and completed specs get silently modified, undermining delivery process integrity.
| Status | Protection | Can Add Deliverables | Allowed Actions |
|---|---|---|---|
| roadmap | None | Yes | Full editing |
| active | Scope-locked | No | Edit existing deliverables only |
| completed | Hard-locked | No | Requires unlock-reason tag |
| deferred | None | Yes | Full editing |
Valid FSM transitions
Valid FSM transitions
Section titled “Valid FSM transitions”Invariant: Only these transitions are valid. All others are rejected by Process Guard.
Rationale: Allowing arbitrary transitions (e.g., roadmap to completed) bypasses the active phase where scope-lock and deliverable tracking provide quality assurance. Completed is a terminal state. Modifications require @libar-docs-unlock-reason escape hatch.
| From | To | Trigger |
|---|---|---|
| roadmap | active | Start work |
| roadmap | deferred | Postpone |
| active | completed | All deliverables done |
| active | roadmap | Blocked/regressed |
| deferred | roadmap | Resume planning |
Tag format types
Tag format types
Section titled “Tag format types”Invariant: Every tag has one of 6 format types that determines how its value is parsed.
Rationale: Without explicit format types, parsers must guess value structure, leading to silent data corruption when CSV values are treated as single strings or numbers are treated as text.
| Format | Parsing | Example |
|---|---|---|
| flag | Boolean presence, no value | @libar-docs-core |
| value | Simple string | @libar-docs-pattern MyPattern |
| enum | Constrained to predefined list | @libar-docs-status completed |
| csv | Comma-separated values | @libar-docs-uses A, B, C |
| number | Numeric value | @libar-docs-phase 15 |
| quoted-value | Preserves spaces | @libar-docs-brief:‘Multi word’ |
Source ownership
Source ownership
Section titled “Source ownership”Invariant: Relationship tags have defined ownership by source type. Anti-pattern detection enforces these boundaries.
Rationale: Cross-domain tag placement (e.g., runtime dependencies in Gherkin) creates conflicting sources of truth and breaks the dual-source architecture ownership model.
| Tag | Correct Source | Wrong Source | Rationale |
|---|---|---|---|
| uses | TypeScript | Feature files | TS owns runtime dependencies |
| depends-on | Feature files | TypeScript | Gherkin owns planning dependencies |
| quarter | Feature files | TypeScript | Gherkin owns timeline metadata |
| team | Feature files | TypeScript | Gherkin owns ownership metadata |
Quarter format convention
Quarter format convention
Section titled “Quarter format convention”Invariant: The quarter tag uses YYYY-QN format (e.g., 2026-Q1). ISO-year-first sorting works lexicographically.
Rationale: Non-standard formats (e.g., Q1-2026) break lexicographic sorting, which roadmap generation and timeline queries depend on for correct ordering.
Canonical phase definitions (6-phase USDP standard)
Canonical phase definitions (6-phase USDP standard)
Section titled “Canonical phase definitions (6-phase USDP standard)”Invariant: The default workflow defines exactly 6 phases in fixed order. These are the canonical phase names and ordinals used by all generated documentation.
Rationale: Ad-hoc phase names and ordering produce inconsistent roadmap grouping across packages and make cross-package progress tracking impossible.
| Order | Phase | Purpose |
|---|---|---|
| 1 | Inception | Problem framing, scope definition |
| 2 | Elaboration | Design decisions, architecture exploration |
| 3 | Session | Planning and design session work |
| 4 | Construction | Implementation, testing, integration |
| 5 | Validation | Verification, acceptance criteria confirmation |
| 6 | Retrospective | Review, lessons learned, documentation |
Deliverable status canonical values (1 scenarios)
Deliverable status canonical values
Section titled “Deliverable status canonical values”Invariant: Deliverable status (distinct from pattern FSM status) uses exactly 6 values, enforced by Zod schema at parse time.
Rationale: Freeform status strings bypass Zod validation and break DoD checks, which rely on terminal status classification to determine pattern completeness.
| Value | Meaning |
|---|---|
| complete | Work is done |
| in-progress | Work is ongoing |
| pending | Work has not started |
| deferred | Work postponed |
| superseded | Replaced by another |
| n/a | Not applicable |
Verified by:
- Canonical values are enforced
ConfigBasedWorkflowDefinition
Section titled “ConfigBasedWorkflowDefinition”View ConfigBasedWorkflowDefinition source
Problem:
Every pnpm process:query and pnpm docs:* invocation prints:
Failed to load default workflow (6-phase-standard): Workflow file not found
The loadDefaultWorkflow() function resolves to catalogue/workflows/
which does not exist. The directory was deleted during monorepo extraction.
The system already degrades gracefully (workflow = undefined), but the
warning is noise for both human CLI use and future hook consumers (HUD).
The old 6-phase-standard.json conflated three concerns:
- Taxonomy vocabulary (status names) — already in
src/taxonomy/ - FSM behavior (transitions) — already in
src/validation/fsm/ - Workflow structure (phases) — orphaned, no proper home
Solution:
Inline the default workflow as a constant in workflow-loader.ts, built
from canonical taxonomy values. Make loadDefaultWorkflow() synchronous.
Preserve loadWorkflowFromPath() for custom --workflow <file> overrides.
The workflow definition uses only the 4 canonical statuses from ADR-001
(roadmap, active, completed, deferred) — not the stale 5-status set from
the deleted JSON (which included non-canonical implemented and partial).
Phase definitions (Inception, Elaboration, Session, Construction, Validation, Retrospective) move from a missing JSON file to an inline constant, making the default workflow always available without file I/O.
Design Decisions (DS-1, 2026-02-15):
| ID | Decision | Rationale | | DD-1 | Inline constant in workflow-loader.ts, not preset integration | Minimal correct fix, zero type regression risk. Preset integration deferred. | | DD-2 | Constant satisfies existing WorkflowConfig type | Reuse createLoadedWorkflow() from workflow-config.ts. No new types needed. | | DD-3 | Remove dead code: getCatalogueWorkflowsPath, loadWorkflowConfig, DEFAULT_WORKFLOW_NAME | Dead since monorepo extraction. Public API break is safe (function always threw). | | DD-4 | loadDefaultWorkflow() returns LoadedWorkflow synchronously | Infallible constant needs no async or error handling. | | DD-5 | Amend ADR-001 with canonical phase definitions | Phase names are canonical values; fits existing governance in ADR-001. |
Default workflow is built from an inline constant (2 scenarios)
Default workflow is built from an inline constant
Section titled “Default workflow is built from an inline constant”Invariant: loadDefaultWorkflow() returns a LoadedWorkflow without file system access. It cannot fail. The default workflow constant uses only canonical status values from src/taxonomy/status-values.ts.
Rationale: The file-based loading path (catalogue/workflows/) has been dead code since monorepo extraction. Both callers (orchestrator, process-api) already handle the failure gracefully, proving the system works without it. Making the function synchronous and infallible removes the try-catch ceremony and the warning noise.
| Step | Change | Impact |
|---|---|---|
| Add DEFAULT_WORKFLOW_CONFIG constant | WorkflowConfig literal with 4 statuses, 6 phases | New code in workflow-loader.ts |
| Change loadDefaultWorkflow() to sync | Returns createLoadedWorkflow(DEFAULT_WORKFLOW_CONFIG) | Signature: Promise to sync |
| Remove dead code paths | Delete getCatalogueWorkflowsPath, loadWorkflowConfig, DEFAULT_WORKFLOW_NAME, dead imports | workflow-loader.ts cleanup |
| Remove loadWorkflowConfig from public API | Update src/config/index.ts exports | Breaking change (safe: function always threw) |
| Update orchestrator call site | Remove await and try-catch (lines 410-418) | orchestrator.ts |
| Update process-api call site | Remove await and try-catch (lines 549-555) | process-api.ts |
Verified by:
-
Default workflow loads without warning
-
Workflow constant uses canonical statuses only
-
Workflow constant uses canonical statuses only
Implementation approach:
Custom workflow files still work via --workflow flag (1 scenarios)
Custom workflow files still work via —workflow flag
Section titled “Custom workflow files still work via —workflow flag”Invariant: loadWorkflowFromPath() remains available for projects that need custom workflow definitions. The --workflow <file> CLI flag and workflowPath config field continue to work.
Rationale: The inline default replaces file-based default loading, not file-based custom loading. Projects may define custom phases or additional statuses via JSON files.
Verified by:
- Custom workflow file overrides default
FSM validation and Process Guard are not affected
FSM validation and Process Guard are not affected
Section titled “FSM validation and Process Guard are not affected”Invariant: The FSM transition matrix, protection levels, and Process Guard rules remain hardcoded in src/validation/fsm/ and src/lint/process-guard/. They do not read from LoadedWorkflow.
Rationale: FSM and workflow are separate concerns. FSM enforces status transitions (4-state model from PDR-005). Workflow defines phase structure (6-phase USDP). The workflow JSON declared transitionsTo on its statuses, but no code ever read those values — the FSM uses its own VALID_TRANSITIONS constant. This separation is correct and intentional. Blast radius analysis confirmed zero workflow imports in: - src/validation/fsm/ (4 files) - src/lint/process-guard/ (5 files) - src/taxonomy/ (all files)
Workflow as a configurable preset field is deferred
Workflow as a configurable preset field is deferred
Section titled “Workflow as a configurable preset field is deferred”Invariant: The inline default workflow constant is the only workflow source until preset integration is implemented. No preset or project config field exposes workflow customization.
Rationale: Coupling workflow into the preset/config system before the inline fix ships would widen the blast radius and risk type regressions across all config consumers. Adding workflow as a field on DeliveryProcessConfig (presets) and DeliveryProcessProjectConfig (project config) is a natural next step but NOT required for the MVP fix. The inline constant in workflow-loader.ts resolves the warning. Moving workflow into the preset/config system enables: - Different presets with different default phases (e.g., 3-phase generic) - Per-project phase customization in delivery-process.config.ts - Phase definitions appearing in generated documentation See ideation artifact for design options: delivery-process/ideations/2026-02-15-workflow-config-and-fsm-extensibility.feature
ProcessGuardTesting
Section titled “ProcessGuardTesting”View ProcessGuardTesting source
Pure validation functions for enforcing delivery process rules per PDR-005. All validation follows the Decider pattern: (state, changes, options) => result.
Problem:
- Completed specs modified without explicit unlock reason
- Invalid status transitions bypass FSM rules
- Active specs expand scope unexpectedly with new deliverables
- Changes occur outside session boundaries
Solution:
- checkProtectionLevel() enforces unlock-reason for completed (hard) files
- checkStatusTransitions() validates transitions against FSM matrix
- checkScopeCreep() prevents deliverable addition to active (scope) specs
- checkSessionScope() warns about files outside session scope
- checkSessionExcluded() errors on explicitly excluded files
Completed files require unlock-reason to modify (4 scenarios)
Completed files require unlock-reason to modify
Section titled “Completed files require unlock-reason to modify”Invariant: A completed spec file cannot be modified unless it carries an @libar-docs-unlock-reason tag.
Rationale: Completed work represents validated, shipped functionality — accidental modification risks regression.
Verified by:
- Completed file with unlock-reason passes validation
- Completed file without unlock-reason fails validation
- Protection levels and unlock requirement
- File transitioning to completed does not require unlock-reason
Status transitions must follow PDR-005 FSM (2 scenarios)
Status transitions must follow PDR-005 FSM
Section titled “Status transitions must follow PDR-005 FSM”Invariant: Status changes must follow the directed graph: roadmap->active->completed, roadmap<->deferred, active->roadmap.
Rationale: The FSM prevents skipping required stages (e.g., roadmap->completed bypasses implementation).
Verified by:
- Valid transitions pass validation
- Invalid transitions fail validation
Active specs cannot add new deliverables (6 scenarios)
Active specs cannot add new deliverables
Section titled “Active specs cannot add new deliverables”Invariant: A spec in active status cannot have deliverables added that were not present when it entered active.
Rationale: Scope-locking active work prevents mid-sprint scope creep that derails delivery commitments.
Verified by:
- Active spec with no deliverable changes passes
- Active spec adding deliverable fails validation
- Roadmap spec can add deliverables freely
- Removing deliverable produces warning
- Deliverable status change does not trigger scope-creep
- Multiple deliverable status changes pass validation
Files outside active session scope trigger warnings (4 scenarios)
Files outside active session scope trigger warnings
Section titled “Files outside active session scope trigger warnings”Invariant: Files modified outside the active session’s declared scope produce a session-scope warning.
Rationale: Session scoping keeps focus on planned work and makes accidental cross-cutting changes visible.
Verified by:
- File in session scope passes validation
- File outside session scope triggers warning
- No active session means all files in scope
- ignoreSession flag suppresses session warnings
Explicitly excluded files trigger errors (3 scenarios)
Explicitly excluded files trigger errors
Section titled “Explicitly excluded files trigger errors”Invariant: Files explicitly excluded from a session cannot be modified, producing a session-excluded error.
Rationale: Exclusion is stronger than scope — it marks files that must NOT be touched during this session.
Verified by:
- Excluded file triggers error
- Non-excluded file passes validation
- ignoreSession flag suppresses excluded errors
Multiple rules validate independently (3 scenarios)
Multiple rules validate independently
Section titled “Multiple rules validate independently”Invariant: Each validation rule evaluates independently — a single file can produce violations from multiple rules.
Rationale: Independent evaluation ensures no rule masks another, giving complete diagnostic output.
Verified by:
- Multiple violations from different rules
- Strict mode promotes warnings to errors
- Clean change produces empty violations