HL β TFW-27 / Phase B: Link Resolution & Dynamic Navigation¶
Date: 2026-04-08 Author: Coordinator Status: π HL_DRAFT Parent HL: HL-TFW-27 RESEARCH: RES-TFW-27 β all hypotheses resolved
1. Vision¶
The TFW documentation site builds successfully but has two systemic problems: (1) ~31 broken internal links where .tfw/ source files reference siblings via relative paths that don't survive the sourceβoutput path mapping, and (2) a hardcoded nav: section in mkdocs.yml that needs manual updates every time a knowledge topic, workflow, or task is added.
Phase B makes the docs site self-healing and self-organizing. The link rewriter fixes all broken cross-references automatically at build time. The literate-nav integration generates navigation from the filesystem. After this phase, adding a new task or knowledge file requires zero manual nav/link maintenance β mkdocs build --strict passes clean.
Impact: The documentation site becomes a reliable, low-maintenance knowledge surface. Every reference to a TFW entity becomes a clickable link. Navigation reflects the actual project structure without manual curation. --strict mode ensures no silent breakage.
"I added a new knowledge topic file. Rebuilt the docs. The nav updated automatically, all cross-references resolved, and strict mode passed. I didn't touch mkdocs.yml or gen_docs.py."
2. Current State (As-Is)¶
| Aspect | Current State |
|---|---|
| Broken links | ~31 internal links broken. .tfw/README.md links to conventions.md (sibling) β resolves as /conventions.md in output, but actual output is /reference/conventions/. README.md links to .tfw/README.md β becomes /concepts/philosophy/ |
| Bare task IDs | [TFW-18](../../TFW-18__knowledge_consolidation/HL-TFW-18__knowledge_consolidation.md) in text is plain text, not a link. Only [HL TFW-18](../../TFW-18__knowledge_consolidation/HL__PhaseB__knowledge_quality.md), [TS TFW-18](../../TFW-18__knowledge_consolidation/TS__PhaseB__knowledge_quality.md) resolve (artifact-prefixed) |
| HTML anchors | D1, [TD-72](../../../reference/tech-debt.md), P3 link to section headers (#architecture-decisions) but not to individual rows. No deep linking to specific items |
| Navigation | Hardcoded nav: in mkdocs.yml (43 lines). Adding a knowledge topic requires editing mkdocs.yml. Task nav auto-generated via gen_docs.py section index, but still listed under hardcoded nav: entry |
| Strict mode | mkdocs build --strict fails due to absolute link warnings |
| Reference resolvers | 6 working resolvers (artifact refs, phase refs, HL-dash, TD-N, D-N, backtick paths). Missing: bare task ID, markdown link rewriting |
3. Target State (To-Be)¶
| Aspect | To-Be |
|---|---|
| Broken links | 0 broken internal links. Markdown link rewriter maps source-relative paths to output-relative paths at build time |
| Bare task IDs | [TFW-18](../../TFW-18__knowledge_consolidation/HL-TFW-18__knowledge_consolidation.md) β clickable link to task HL. Works anywhere in text |
| HTML anchors | id="d1", id="td-72", id="p3", id="f6" on table rows in KNOWLEDGE.md and TECH_DEBT.md. Deep-linkable: /knowledge-index/#d1 |
| Navigation | Dynamic via mkdocs-literate-nav. SUMMARY.md auto-generated by gen_docs.py. Static sections (Home, Getting Started, Concepts) defined in code. Dynamic sections (Knowledge, Tasks, Workflows, Templates) from filesystem scan |
| Strict mode | mkdocs build --strict passes clean |
| Reference resolvers | 8 resolvers total (existing 6 + bare task ID + markdown link rewriter) |
3.1 Result Visualization¶
Link rewriter pipeline (build time):
Source file: .tfw/README.md
Contains: [conventions.md](conventions.md) β sibling link
Mapped to output: concepts/philosophy.md
Link rewriter:
1. Resolve relative to SOURCE: .tfw/conventions.md
2. Look up in Source Manifest: .tfw/conventions.md β reference/conventions.md
3. Compute relative from OUTPUT: concepts/philosophy.md β ../reference/conventions.md
4. Rewrite: [conventions.md](../reference/conventions/)
Result: [conventions.md](../reference/conventions/) β
valid
HTML anchors on table rows:
KNOWLEDGE.md source: Output:
| [D1](../../../knowledge-index.md#architecture-decisions) | Use .tfw/ as core | ... β <tr id="d1">| [D1](#d1) | Use .tfw/ as core | ...
| P3 | Traces over code | ... β <tr id="p3">| [P3](#p3) | Traces over code | ...
Deep link: /knowledge-index/#d1 β
Dynamic navigation (literate-nav):
gen_docs.py generates SUMMARY.md: mkdocs-literate-nav renders:
* [Home](index.md) Home
* [Getting Started](getting-started.md) Getting Started
* Concepts Concepts
* [Philosophy](concepts/philosophy) β Philosophy
* Knowledge Knowledge
* [Index](knowledge-index.md) β Index
* Topics β Topics
* [Convention](knowledge/...) β β Convention (auto)
* [Constraint](knowledge/...) β β Constraint (auto)
* [Philosophy](knowledge/...) β β Philosophy (auto)
* [Process](knowledge/...) β β Process (auto)
* Reference Reference
* [Conventions](reference/...) β Conventions
* [Glossary](reference/...) β Glossary
* Workflows β Workflows
* [plan](reference/workflows/...) β β plan (auto)
* [handoff](reference/workflows..) β β handoff (auto)
* ... β β ...
* Tasks Tasks
* [Index](tasks/index.md) β Index (with status)
* [TFW-1](../../TFW-1__formalize_success_criteria/) ... β [TFW-1](../../TFW-1__formalize_success_criteria/) (auto)
* ... β ...
4. Deliverables¶
4 features in gen_docs.py (~120 LOC) + config changes:
| # | Feature | File | LOC | TDs Fixed |
|---|---|---|---|---|
| 1 | Bare task ID resolver | gen_docs.py |
~15 | β |
| 2 | Markdown link rewriter | gen_docs.py |
~50 | TD-72, TD-74 |
| 3 | HTML anchors on table rows | gen_docs.py |
~30 | β |
| 4 | literate-nav SUMMARY.md generation | gen_docs.py |
~25 | TD-69, TD-70, TD-71 |
| 5 | Add literate-nav + section-index deps | requirements.txt |
2 lines | β |
| 6 | Remove hardcoded nav, add literate-nav plugin | mkdocs.yml |
~10 lines change | TD-69 |
Budget: 0 new files, 3 modifications. ~120 LOC. Limits: max 14 files, max 8 new, max 1200 LOC.
5. Detailed Feature Descriptions¶
Feature 1: Bare Task ID Resolver¶
What: Resolve standalone [TFW-18](../../TFW-18__knowledge_consolidation/HL-TFW-18__knowledge_consolidation.md) (without artifact prefix) to the task's HL page.
Current behavior: Only [HL TFW-18](../../TFW-18__knowledge_consolidation/HL__PhaseB__knowledge_quality.md), [TS TFW-18](../../TFW-18__knowledge_consolidation/TS__PhaseB__knowledge_quality.md) resolve. Plain [TFW-18](../../TFW-18__knowledge_consolidation/HL-TFW-18__knowledge_consolidation.md) stays as text.
New behavior: [TFW-18](../../TFW-18__knowledge_consolidation/HL-TFW-18__knowledge_consolidation.md) β [TFW-18](/tasks/TFW-18__knowledge_consolidation/HL-TFW-18__knowledge_consolidation/)
Regex: (?<!\[)(?<!\w)\bTFW-\d+\b(?!\])(?!__) β must not match inside existing links, and must not match folder names (TFW-18__...).
Order: Run AFTER artifact resolver (so [HL TFW-18](../../TFW-18__knowledge_consolidation/HL__PhaseB__knowledge_quality.md) gets resolved first, then remaining bare [TFW-18](../../TFW-18__knowledge_consolidation/HL-TFW-18__knowledge_consolidation.md)).
Feature 2: Markdown Link Rewriter¶
What: Fix [text](relative.md) links that break when source files are mapped to different output paths.
How:
1. Build a path map from STATIC_SOURCES + GLOB_SOURCES: {source_path β output_path}
2. For each page being processed, when encountering a markdown link [text](target.md):
a. Resolve target.md relative to the SOURCE file path
b. Look up the resolved path in the path map
c. If found, compute the relative path from the CURRENT OUTPUT to the TARGET OUTPUT
d. Rewrite the link
3. Leave external links (http/https) and anchor-only links (#) unchanged
Critical: Must handle both .md links and directory-URL links. Must not break already-resolved links from reference resolvers.
Feature 3: HTML Anchors on Table Rows¶
What: Add id="..." attributes to table rows containing entity IDs (D{N}, TD-{N}, P{N}, F{N}, S{N}).
How: Post-process table lines. When a row starts with | [D1](../../../knowledge-index.md#architecture-decisions) or | [TD-72](../../../reference/tech-debt.md), inject an HTML anchor prefix.
Target files: KNOWLEDGE.md β knowledge-index.md, TECH_DEBT.md β reference/tech-debt.md. Applied during copy_with_frontmatter.
Result: /knowledge-index/#d1, /reference/tech-debt/#td-72 become valid deep links.
Feature 4: literate-nav SUMMARY.md¶
What: Generate a SUMMARY.md file via mkdocs_gen_files.Nav() that mkdocs-literate-nav uses for navigation.
How:
1. Static nav items defined in code (Home, Getting Started, Concepts, Reference)
2. Dynamic sections: scan the output pages already generated by gen_docs.py
3. Write SUMMARY.md via mkdocs_gen_files.open("SUMMARY.md", "w")
4. Remove nav: from mkdocs.yml, add literate-nav plugin
Nav structure: Matches current mkdocs.yml nav: but with dynamic Knowledge topics, Workflows, Templates, and Tasks.
6. Definition of Done (DoD)¶
- β
1.
mkdocs build --strictpasses clean (0 warnings, 0 errors) - β
2. Bare
[TFW-18](../../TFW-18__knowledge_consolidation/HL-TFW-18__knowledge_consolidation.md)in text β clickable link to task HL - β
3. All
.tfw/sibling links resolve correctly (e.g.,conventions.mdin.tfw/README.mdβ/reference/conventions/) - β
4. README.md links to
.tfw/README.mdresolve to/concepts/philosophy/ - β
5.
D1,[TD-72](../../../reference/tech-debt.md),P3deep-linkable via anchors - β
6. Navigation auto-generated: adding a file to
knowledge/or.tfw/workflows/shows up in nav without editing mkdocs.yml - β 7. Existing reference resolvers still work (regression test)
- β
8. Hardcoded
nav:removed from mkdocs.yml
7. Definition of Failure (DoF)¶
- β 1. Link rewriter breaks existing valid links (regression)
- β 2. literate-nav produces different nav structure than current hardcoded nav (unexpected section order)
- β 3. HTML anchors break table rendering in MkDocs
- β 4. Bare task ID resolver matches inside folder names or existing links (false positives)
8. Risks¶
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| Link rewriter doesn't handle all edge cases (anchors, query params, external URLs) | Medium | Medium | Unit tests for each edge case. External URLs explicitly skipped |
| literate-nav section order differs from current nav | Low | Low | Define static sections first in code, verify against current nav |
| HTML anchor injection breaks markdown table parsing | Medium | Medium | Test with pymdownx.superfences + tables extension. Fallback: use heading anchors instead of row anchors |
| Bare task ID regex matches too broadly | Low | Medium | Negative lookaheads for __, [, existing links. Unit test with known false-positive patterns |
9. Principles¶
- Resolvers are additive β new resolvers must not break existing 6 resolvers
- Links are relative β rewriter generates relative paths, not absolute, enabling strict mode
- Nav follows filesystem β no separate nav manifest. Directory structure = navigation structure
- Order matters β resolvers run in specific order: specific β general (artifact refs β bare task IDs)
10. RESEARCH Case¶
RESEARCH already completed at master HL level (RES-TFW-27). All hypotheses resolved: - H1: No artifact graph needed (rejected) - H2: literate-nav confirmed - H3: Broken links = two categories (sibling + READMEβ.tfw/) - R3: P{N} auto-resolution rejected (double semantics) - R4: Backtick-only path resolution confirmed
No additional Phase B research needed. Scope is fully specified by RES conclusions.
11. Strategic Session Insights¶
Human-Only Test: Would this insight be unknown without the user saying it?
No new strategic insights in Phase B β this phase is purely technical, fully specified by RES.
HL β TFW-27 / Phase B: Link Resolution & Dynamic Navigation | 2026-04-08