-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Context
The reference codec system (createReferenceCodec) composes documents from three content sources: conventions, shapes, and behaviors. Convention content is extracted from decision records tagged with @libar-docs-convention.
Problem: parseBusinessRuleAnnotations() in helpers.ts already extracts code examples (including """mermaid""" blocks) into annotations.codeExamples as SectionBlock[]. However, extractConventionRuleContent() in convention-extractor.ts discards this data because ConventionRuleContent has no codeExamples field.
Evidence: ADR-006 (Process Guard) contains two mermaid diagrams (stateDiagram-v2 and flowchart LR) in convention-tagged Rule blocks. The generated PROCESS-GUARD-REFERENCE.md shows empty gaps where these diagrams should appear — only the surrounding narrative text survives.
Data flow showing the loss point
Rule description with """mermaid ... """
│
├─ Path A: ADR/Decision Doc Codec
│ └─ parseDescriptionWithDocStrings() → code(content, "mermaid") ✅ preserved
│
└─ Path B: Convention Extractor → Reference Codec
├─ parseBusinessRuleAnnotations()
│ ├─ codeExamples: [code("stateDiagram-v2\n...", "mermaid")] ✅ extracted
│ └─ remainingContent: "The FSM enforces..."
│
└─ extractConventionRuleContent()
├─ narrative = remainingContent
└─ codeExamples → DISCARDED ← loss point
Proposed Changes
1. Add codeExamples to ConventionRuleContent (convention-extractor.ts)
import type { SectionBlock } from '../schema.js';
export interface ConventionRuleContent {
// ...existing fields...
/** Code examples extracted from DocStrings in the rule description (includes mermaid diagrams) */
readonly codeExamples?: readonly SectionBlock[];
}Wire in extractConventionRuleContent():
function extractConventionRuleContent(rule: BusinessRule): ConventionRuleContent {
const annotations = parseBusinessRuleAnnotations(rule.description);
const tables = extractTablesFromDescription(rule.description);
return {
ruleName: rule.name,
...(annotations.invariant !== undefined && { invariant: annotations.invariant }),
...(annotations.rationale !== undefined && { rationale: annotations.rationale }),
...(annotations.verifiedBy !== undefined && { verifiedBy: annotations.verifiedBy }),
tables,
narrative: annotations.remainingContent ?? '',
...(annotations.codeExamples && annotations.codeExamples.length > 0 && {
codeExamples: annotations.codeExamples,
}),
};
}2. Emit code/mermaid blocks in buildConventionSections() (reference.ts)
Import mermaid from schema, then render codeExamples after tables:
import {
// ...existing imports...
mermaid,
} from '../schema.js';
// In buildConventionSections(), after table rendering, before separator:
if (rule.codeExamples && detailLevel !== 'summary') {
for (const example of rule.codeExamples) {
if (example.type === 'code' && 'language' in example && example.language === 'mermaid') {
sections.push(mermaid((example as { content: string }).content));
} else {
sections.push(example);
}
}
}Note: parseBusinessRuleAnnotations produces code(content, "mermaid") (CodeBlock with language: "mermaid"). We convert these to mermaid() blocks (MermaidBlock) for semantic correctness — both render identically as ```mermaid ``` but MermaidBlock is the canonical type for programmatic consumers (e.g., future SVG rendering per #16).
3. Test scenarios
Convention extractor (convention-extractor.feature):
Rule: Code examples in rule descriptions are preserved
@happy-path
Scenario: Mermaid diagram in rule description is extracted as code example
Given a pattern with convention "fsm-rules" and rule description:
"""
The FSM enforces valid state transitions.
"""mermaid
stateDiagram-v2
[*] --> roadmap
roadmap --> active
"""
"""
When extracting conventions for tag "fsm-rules"
Then the first rule has 1 code example
And the code example has language "mermaid"Reference codec (reference-codec.feature):
Rule: Convention code examples render as mermaid blocks
@happy-path
Scenario: Convention with mermaid content produces mermaid block in output
Given a reference config with convention tags "fsm-rules" and behavior tags ""
And a MasterDataset with a convention pattern with a mermaid diagram
When decoding at detail level "detailed"
Then the document contains a mermaid block
@happy-path
Scenario: Summary level omits code examples
Given a reference config with convention tags "fsm-rules" and behavior tags ""
And a MasterDataset with a convention pattern with a mermaid diagram
When decoding at detail level "summary"
Then the document does not contain a mermaid blockVerification
After implementation:
pnpm test— all existing + new tests passpnpm docs:reference— regenerate reference docs- Check
docs-generated/docs/PROCESS-GUARD-REFERENCE.md— the "FSM Diagram" section should now contain thestateDiagram-v2mermaid block, and the "Architecture" section should contain theflowchart LRdiagram
Why This Matters
This is a prerequisite for generating rich architecture overview documents in the consuming monorepo. The reference codec is the right vehicle for composing multi-diagram architecture docs (convention narrative + mermaid diagrams + TypeScript shapes), but currently silently drops all diagram content from convention sources.
Once this is in place, a new reference config (12th entry) can produce architecture overview documents with interleaved mermaid diagrams and explanatory copy — similar to what currently requires hand-maintained PR descriptions.
Related
- Evaluate beautiful-mermaid for SVG/ASCII diagram rendering #16 (beautiful-mermaid for SVG rendering — would benefit from semantic
MermaidBlocktypes) CodecDrivenReferenceGenerationspec (the reference codec architecture this extends)