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:
- Misleading users who try to use the examples
- Maintenance burden when code changes but docs don't
- 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¶
- Start with the actual code - Read the implementation first
- Use mkdocstrings for API docs - Let docstrings be the source of truth
- Link, don't copy - Use snippets rather than copying code
- Mark pseudo-code clearly - Use admonitions to indicate conceptual code
When Updating Code¶
- Check for documentation - Search for references to your function/class
- Update line numbers - Snippet references may need adjustment
- Update docstrings - mkdocstrings will pull these automatically
- Run docs locally -
zensical serveto 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:
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:
- Run
zensical servelocally - Check that snippets render correctly
- Verify GitHub links point to correct lines
- 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