Skip to content

Documentation Conventions

This guide explains how to keep documentation synchronized with the codebase and avoid disconnected code examples.

Problem: Disconnected Documentation

Documentation that contains pseudo-code or example snippets that don't match the actual implementation creates several problems:

  1. Misleading users who try to use the examples
  2. Maintenance burden when code changes but docs don't
  3. Loss of trust in documentation accuracy

Solution: Linked Documentation

We use several techniques to keep documentation synchronized with code.

1. Source Code References

Always include links to actual implementation when showing conceptual code:

!!! info "Conceptual Logic"
    The following illustrates the logic. For the actual implementation,
    see [`classify/classifier.py:87-150`](https://github.com/OpenAfterHours/rwa_calculator/blob/master/src/rwa_calc/engine/stages/classify/classifier.py#L87-L150).

Format for GitHub links:

https://github.com/OpenAfterHours/rwa_calculator/blob/master/src/rwa_calc/engine/stages/classify/classifier.py#L87-L150

2. Embedded Code Snippets

Use pymdownx.snippets to embed actual code from source files.

Syntax:

The snippet marker looks like scissors: two dashes, the digit 8, a less-than sign, and two more dashes (- - 8 < - -), followed by a quoted file path.

Pattern Description
Marker + "path/to/file.py" Include entire file
Marker + "path/to/file.py:10:50" Include lines 10-50

Path is relative to repository root. See pymdownx.snippets docs for full syntax.

Example - the actual snippets in retail.md look like:

See retail.md for working example
class ExposureClassifier:
    """
    Classify exposures by exposure class and approach.

    Implements ClassifierProtocol for:
    - Mapping counterparty types to exposure classes
    - Checking SME criteria (turnover thresholds)
    - Checking retail criteria (aggregate exposure thresholds)
    - Determining IRB eligibility based on permissions
    - Identifying specialised lending for slotting
    - Splitting exposures by calculation approach

    All operations use Polars LazyFrames for deferred execution.
    The classifier batches expressions into 4 .with_columns() calls
    to keep the query plan shallow (5 nodes instead of 21).
    """

    @cites("CRR Art. 112")
    @cites("CRR Art. 147")
    def classify(
        self,
        data: ResolvedHierarchyBundle,
        config: CalculationConfig,
        *,

3. Auto-generated API Documentation

Use mkdocstrings to generate documentation from docstrings:

::: rwa_calc.engine.classifier.ExposureClassifier
    options:
      show_root_heading: true
      members:
        - classify
      show_source: false

This automatically pulls docstrings and keeps them in sync with code.

4. Admonitions for Pseudo-code

When pseudo-code is necessary for conceptual explanation, mark it clearly:

!!! info "Conceptual Logic"
    The following is simplified pseudo-code to illustrate the concept.

```python
# This is conceptual - see actual implementation below
def simplified_example():
    pass
### 5. Collapsible Actual Code

Use collapsible sections to show lengthy actual code without cluttering the page:

??? example "See this working example from hierarchy/resolver.py"
    ```python
    class HierarchyResolver:
        """
        Resolve counterparty and exposure hierarchies.

        Implements HierarchyResolverProtocol for:
        - Building counterparty org hierarchy lookups
        - Inheriting ratings from parent entities
        - Resolving facility-to-exposure mappings
        - Aggregating lending group exposures for retail threshold

        All operations use Polars LazyFrames for deferred execution.
        """

        def resolve(
            self,
            data: RawDataBundle,
            config: CalculationConfig,
        ) -> ResolvedHierarchyBundle:
            """
            Resolve all hierarchies and return enriched data.

            Args:
                data: Raw data bundle from loader
                config: Calculation configuration

            Returns:
                ResolvedHierarchyBundle with hierarchy metadata added
            """
            errors: list[CalculationError] = []

            counterparty_lookup, cp_errors = self._build_counterparty_lookup(
                data.counterparties,
                data.org_mappings,
                data.ratings,
            )
    ```

### 6. Cross-Reference Convention

When a concept is explained in detail elsewhere, use a `> **Details:**` callout to link to the canonical source:

```markdown
> **Details:** See [Pipeline Architecture](../architecture/pipeline.md) for the full stage-by-stage walkthrough.

This pattern avoids duplicating content across multiple pages. Each concept should have one canonical location with full detail; other pages provide a brief (2-3 sentence) audience-appropriate summary and link to the canonical source.

Canonical locations for key concepts:

Concept Canonical Location
Pipeline architecture docs/architecture/pipeline.md
Design principles docs/architecture/design-principles.md
SA risk weights docs/specifications/crr/sa-risk-weights.md
IRB formulas docs/specifications/crr/firb-calculation.md + airb-calculation.md
CRM mechanics docs/specifications/crr/credit-risk-mitigation.md
Exposure classification docs/features/classification.md
Framework comparison docs/framework-comparison/key-differences.md
Coding conventions docs/development/code-style.md
Testing standards docs/development/testing.md

Best Practices

When Writing New Documentation

  1. Start with the actual code - Read the implementation first
  2. Use mkdocstrings for API docs - Let docstrings be the source of truth
  3. Link, don't copy - Use snippets rather than copying code
  4. Mark pseudo-code clearly - Use admonitions to indicate conceptual code

When Updating Code

  1. Check for documentation - Search for references to your function/class
  2. Update line numbers - Snippet references may need adjustment
  3. Update docstrings - mkdocstrings will pull these automatically
  4. Run docs locally - zensical serve to verify everything renders

Documentation Structure

Documentation Type Approach
API Reference Use module.Class for auto-generation
Conceptual Guides Pseudo-code with source links
Tutorials Embedded snippets from actual code
Examples Working code from test files

Available Tools

pymdownx.snippets

Configuration in zensical.toml:

[project.markdown_extensions.pymdownx.snippets]
base_path = ["."]
check_paths = false

mkdocstrings

Configuration in zensical.toml:

[project.plugins.mkdocstrings.handlers.python.options]
docstring_style = "google"
show_source = true
show_root_heading = true
members_order = "source"

Admonitions

Available types: note, info, tip, warning, danger, example

Checking Documentation

Before submitting changes:

  1. Run zensical serve locally
  2. Check that snippets render correctly
  3. Verify GitHub links point to correct lines
  4. Ensure mkdocstrings generates expected output

Migration Checklist

When finding disconnected code in documentation:

  • [ ] Identify the actual implementation
  • [ ] Add source code reference link
  • [ ] Convert to embedded snippet if appropriate
  • [ ] Add admonition if keeping conceptual code
  • [ ] Update line references after code changes