ADR 0005: Auto-Generated Documentation

July 12, 2026 · View on GitHub

Status: Accepted
Authors: Provenant team Supersedes: None

Current contract owner: ../DOCUMENTATION_INDEX.md, ../HOW_TO_ADD_A_PARSER.md, and the xtask generator own the live documentation workflow. This ADR records the decision to keep a generated support matrix instead of maintaining that coverage manually.

Context

With 40+ package ecosystems and 136+ file formats to document, maintaining accurate parser documentation is a significant challenge:

  1. Scale Problem: Manual documentation for dozens of parsers is error-prone
  2. Staleness Risk: Documentation easily gets out of sync with code
  3. Consistency: Different contributors document parsers differently
  4. Discovery: Users need to find which formats are supported
  5. Maintenance Burden: Every parser addition requires manual doc updates

The Python ScanCode Toolkit solves this using a custom script (regen_package_docs.py) that extracts metadata from parser classes and generates reStructuredText documentation.

Question: How do we keep documentation accurate, comprehensive, and up-to-date as we add 40+ parsers?

Decision

Use a hybrid documentation approach: Auto-generate format tables from code metadata + manual architecture/guide documentation + Rust doc comments for API reference.

Documentation Strategy

┌─────────────────────────────────────────────────────────┐
│                 Documentation Sources                    │
└─────────────────────────────────────────────────────────┘
           │                    │                  │
           ▼                    ▼                  ▼
    ┌─────────────┐     ┌──────────────┐   ┌────────────┐
    │   Parser    │     │ Doc Comments │   │   Manual   │
    │  Metadata   │     │   (/// //!)  │   │ Markdown   │
    │   (code)    │     │              │   │   Files    │
    └──────┬──────┘     └──────┬───────┘   └──────┬─────┘
           │                   │                   │
           │                   │                   │
           ▼                   ▼                   ▼
    ┌─────────────┐     ┌──────────────┐   ┌────────────┐
    │ Pre-commit  │     │  cargo doc   │   │   GitHub   │
    │    Hook     │     │  (docs.rs)   │   │   README   │
    │ (generate)  │     │              │   │   /docs/   │
    └──────┬──────┘     └──────────────┘   └────────────┘


    ┌──────────────────┐
    │ SUPPORTED_       │
    │ FORMATS.md       │
    │ (auto-generated) │
    └──────────────────┘

Three Documentation Layers

1. Auto-Generated Format Table

Source: Registered parser metadata (descriptions, path patterns, package types, languages, docs URLs)

Output: docs/SUPPORTED_FORMATS.md

Generation: The xtask generator renders the Markdown table, and CI/pre-commit hooks verify that the checked-in file stays in sync

Example:

FormatPackage TypeFile PatternsStatus
package.jsonnpm**/package.json✅ Complete
Cargo.tomlcargo**/Cargo.toml✅ Complete
pom.xmlmaven**/pom.xml✅ Complete

Implementation (conceptual): parser metadata is declared close to the parser registration surface, and the generator renders SUPPORTED_FORMATS.md from that registered metadata rather than from hand-maintained Markdown.

Benefits:

  • Always accurate (generated from actual code)
  • Comprehensive (covers all parsers automatically)
  • Consistent format (same template for all)
  • No manual maintenance (automated in the Lefthook pre-commit hook)

2. Rust Doc Comments (API Reference)

Source: /// and //! comments in source code

Output: docs.rs API documentation (generated by cargo doc)

Target Audience: Rust developers using Provenant as a library

Example shape: Rust doc comments should explain supported inputs, important behavior, and one small doctest-sized usage example when the public API benefits from it.

Benefits:

  • Standard Rust documentation approach
  • Integrated with IDE tooltips (rust-analyzer)
  • Automatically published to docs.rs
  • Supports doc tests (examples are tested)
  • Searchable and linkable

3. Manual Markdown Documentation

Source: Manually maintained files in docs/ directory

Output: GitHub repository documentation

Target Audience: End users, contributors, architects

Structure:

docs/
├── ARCHITECTURE.md           # System design
├── HOW_TO_ADD_A_PARSER.md   # How to add parsers
├── TESTING_STRATEGY.md      # Testing philosophy and guidelines
├── adr/                     # Architectural decisions
│   ├── 0001-trait-based-parsers.md
│   └── ...
└── improvements/            # Beyond-parity features
    ├── alpine-parser.md
    └── ...

Benefits:

  • Explains "why" not just "what"
  • Provides context for design decisions
  • Documents trade-offs and alternatives
  • Guides contributors on conventions

Generation Workflow

Pre-Commit Hook

Lefthook owns the pre-commit behavior. When parser metadata changes, the hook runs the supported-formats generator and stages the regenerated file automatically.

Documentation Generator (Conceptual)

The generator iterates the registered parser metadata, renders a normalized Markdown table, and writes the result to docs/SUPPORTED_FORMATS.md.

Consequences

Benefits

  1. Documentation Drift Is Harder To Miss

    • Generated from registered metadata instead of hand-maintained tables
    • Pre-commit hooks and CI enforce updates
    • Parser metadata changes are easy to catch in review
  2. Consistency

    • Same format for all parsers
    • Template-driven generation
    • Uniform presentation
  3. Discoverability

    • Single source of truth (SUPPORTED_FORMATS.md)
    • Easy to search and filter
    • Clear status indicators
  4. Low Maintenance

    • No manual doc updates for format table
    • Contributors only write code
    • Automation handles the rest
  5. Multi-Audience

    • End users: README + SUPPORTED_FORMATS.md
    • API users: docs.rs documentation
    • Contributors: Architecture docs + ADRs

Trade-offs

  1. Build Complexity

    • Requires documentation generation tooling
    • Pre-commit tooling adds setup dependency
    • Acceptable: One-time setup, huge long-term benefit
  2. Partial Automation

    • Can't auto-generate architecture decisions or guides
    • Still need manual ADRs and improvement docs
    • Acceptable: Hybrid approach balances automation and flexibility
  3. Rust Doc Comments Required

    • Contributors must write /// comments
    • More verbose than Python docstrings
    • Acceptable: Standard Rust practice, kept as a contributor convention

Alternatives Considered

1. Fully Manual Documentation

Approach: write and maintain all format coverage documentation by hand.

Rejected because:

  • High maintenance burden (40+ parsers)
  • Prone to staleness (docs drift from code)
  • Inconsistent formatting (different contributors)
  • Easy to forget updating when adding parsers

2. Python-Style Registration System

Approach: use runtime metadata registration similar to Python class attributes.

Rejected because:

  • Not idiomatic Rust (prefer compile-time)
  • Requires runtime introspection
  • More complex than trait-based approach
  • Doesn't leverage Rust's type system

3. Macro-Based Registration

Approach: use proc macros to register parsers automatically.

Partial acceptance: This could work, but adds complexity.

Why not primary approach:

  • Proc macros add compile-time overhead
  • Harder to debug
  • Less explicit than trait methods
  • Can achieve same result with simpler build script

4. No Auto-Generation (Rust Doc Only)

Approach: Rely solely on cargo doc output, no separate SUPPORTED_FORMATS.md.

Rejected because:

  • Not user-friendly (API docs are developer-focused)
  • Requires users to browse docs.rs
  • No single-page format reference
  • Harder to search and filter

Python Reference Comparison

Python Approach:

  • Auto-generation: Manual script execution
  • Format: reStructuredText
  • Metadata source: Python class attributes

Our Rust Approach:

  • Auto-generation: Pre-commit hook
  • Format: Markdown
  • Metadata source: Registered parser metadata consumed by the xtask generator
  • Additional: cargo doc for API reference

References