ADR Related Document Link Normalization + Mermaid Activation
SummaryResolve 2 defects discovered during Sprint 161 user visual verification: (1) Meta sidebar RelatedLinks rendered as <span> — not clickable (2) ADR body .md markdown links produce 404 on static export
Key Decisions
ID → URL conversion + span fallback pattern adopted
resolveAdrUrl(id, locale) helper returns null on pattern match failure → existing span preserved. Prevents 404 anchor creation
rehype plugin-based link normalization
Separated from parser.ts metadata extraction (extractOutgoingLinks) as a render-only transformation. Separation of concerns
Null byte placeholder pattern
Escaped pipe (\|) handling via \x00PIPE\x00 substitution → split → restore. No general text collision possible
CodeBlock → Mermaid early return branch
When extractLanguage yields 'mermaid', reuse existing <Mermaid> component (dynamic import, SSG-safe). Zero new implementation
Critic P2 data integrity resolution
sprint-67 related_adrs: [ADR-004, ADR-005] references non-existent ADRs → frontmatter removed
Goals
- Resolve 2 defects discovered during Sprint 161 user visual verification: (1) Meta sidebar RelatedLinks rendered as
<span>— not clickable (2) ADR body.mdmarkdown links produce 404 on static export - Resolve Sprint 161 Critic R2 P3 carry-over:
splitTableRowescaped pipe handling - Activate Mermaid code fence rendering in ADR — reuse existing Mermaid component
Decisions
- ID → URL conversion + span fallback pattern adopted:
resolveAdrUrl(id, locale)helper returns null on pattern match failure → existing span preserved. Prevents 404 anchor creation - rehype plugin-based link normalization: Separated from parser.ts metadata extraction (
extractOutgoingLinks) as a render-only transformation. Separation of concerns - Null byte placeholder pattern: Escaped pipe (
\|) handling via\x00PIPE\x00substitution → split → restore. No general text collision possible - CodeBlock → Mermaid early return branch: When
extractLanguageyields'mermaid', reuse existing<Mermaid>component (dynamic import, SSG-safe). Zero new implementation - Critic P2 data integrity resolution: sprint-67
related_adrs: [ADR-004, ADR-005]references non-existent ADRs → frontmatter removed
Implementation (single PR, branch feat/sprint-162-adr-links-mermaid, 5 commits)
| Phase | Owner | Change | Lines |
|---|---|---|---|
| A — RelatedLinks anchor conversion | architect | adr-meta-sidebar.tsx | +46 −6 |
| B — rehype link normalization | architect | rehype-adr-link-rewrite.ts new + markdown.ts + adr-detail-view.tsx | +90 −2 |
| C — escaped pipe handling | architect | parser.ts | +5 −1 |
| D — Mermaid activation | architect | code-block.tsx + sprint-160.md Mermaid diagram | +19 |
| Critic R1 P2 | architect | sprint-67.md KR+EN frontmatter | −2 |
Detailed Changes
- adr-meta-sidebar.tsx (+46 −6):
resolveAdrUrl(id, locale)helper — sprint-NNN →/adr/sprints/NNN/, ADR-NNN →/adr/permanent/NNN/, unsupported patterns → null.RelatedLinks<span>→<a>anchor conversion + unsupported ID span fallback (graceful degradation). locale prop added - rehype-adr-link-rewrite.ts (+75, new):
unist-util-visit-based rehype plugin. ADR body./sprint-NNN.md/./topics/SLUG.md/../adr-en/sprints/sprint-NNN.mdrelative paths → static export URL conversion - markdown.ts (+13 −1):
renderAdrMdx(source, locale)signature extended +[rehypeAdrLinkRewrite, { locale }]inserted into rehypePlugins chain (after rehypeSlug, before rehypeHighlight) - adr-detail-view.tsx (+2 −1): locale prop passed to
renderAdrMdx - parser.ts (+5 −1):
splitTableRow—\|escaped pipe replaced with null byte placeholder (\x00PIPE\x00) → split → restore - code-block.tsx (+8):
extractLanguageresult'mermaid'→<Mermaid chart={chartSource} />early return branch - docs/adr/sprints/sprint-160.md (+11): Phase A→F 6-step workflow Mermaid flowchart added
- docs/adr/sprints/sprint-67.md (−1): Non-existent
ADR-004,ADR-005references removed (Critic R1 P2) - docs/adr-en/sprints/sprint-67.md (−1): Same change
Verification
| Item | Result |
|---|---|
| tsc --noEmit | clean (0 errors) |
| npm run build | 247 pages static export success |
| check-adr-en-coverage --strict | 110/110 (100.0%) PASS |
| check-doc-refs | 287 files 0 broken refs |
Critic R1 (Codex, session 019e3ec2-5445-70d0-96e3-9d71fa8d8640) | P0/P1 0 items, P2 1 item (sprint-67 non-existent ADR) → resolved (commit 23002cd), P3 2 items → Sprint 163 carry-over |
| Critic R2 (Codex, R2-sprint162-20260519) | PASS. R1 P2 resolution confirmed, 0 new P0/P1/P2, P3 2 items (existing) |
Branch Discipline ✅ 30 sprints of consecutive compliance
- New branch
feat/sprint-162-adr-links-mermaid+ Squash merge pending - 0 direct commits to main, 0
--no-verifyuses
New Patterns
- ID → URL conversion + span fallback pattern —
resolveAdrUrlreturns null on pattern match failure → existing span preserved. Prevents 404 anchor creation - rehype plugin-based link normalization — Separated from parser.ts metadata extraction (
extractOutgoingLinks) as a render-only transformation. Separation of concerns - Null byte placeholder pattern —
\x00used for escaped pipe handling ensures no general text collision - CodeBlock → Mermaid early return branch — Reuses existing Mermaid component (dynamic import, SSG-safe). Zero new implementation
- Critic P2 → data integrity resolution — Critic detects frontmatter data issues, not code defects. Resolved via data correction rather than code modification
Related Documents
- sprint-161.md — Previous sprint, user visual verification defect discovery pattern inheritance
- sprint-160.md — Mermaid flowchart addition target