# How the documentation is organised This page is for people **writing** OasisLMF documentation. It records how the docs are structured, built and published, and the rules to follow when adding a page, so that decisions already taken don't have to be rediscovered. ## Ownership: each repository documents its own code **Every code repository owns the documentation for its own code, in-repo, next to that code. One thin orchestrator aggregates them into the published site.** ``` OasisLMF/docs/ MDK, pytools, CLI, the financial module, modelling methodology, correlation, disaggregation, the kernel component reference OasisPlatform/docs/ platform, deployment, distributed execution, REST API ODS_Tools/docs/ OED loading and validation, the settings schemas ODS_OpenExposureData/ the OED standard } spec-generated reference ODS_OpenResultsData/ the ORD standard } OasisModels/docs/ worked, end-to-end model examples GenerateDocs orchestrator: pins each repository to a ref, builds each one, resolves cross-references between them, and publishes the combined site to oasislmf.github.io ``` Why this shape: - **It kills drift.** Conceptual pages sit beside the code, so a behaviour change and its documentation travel in the same pull request and the same review. - **One source of truth per topic.** The orchestrator holds no prose; it only assembles. - **Versioned.** The orchestrator pins refs, so each published build maps to real releases and the site can offer a version selector. - **Lower barrier.** Documentation lives where contributors already are. The trade-off, accepted deliberately: contributors must know which repository owns a page. If you are unsure, the owner is whichever repository contains the code the page describes. ktools is being decommissioned and does **not** own documentation. Its component docs were drained into this repository and rewritten against the `oasislmf/pytools` implementations; ktools is a content source, not a documentation home. ## Content model: Diátaxis Four modes, and **never two on the same page**: | Mode | Purpose | Examples here | Maintained as | |------|---------|---------------|---------------| | **Tutorials** | Learning by doing | "Run your first analysis" | Hand-written, ideally executable | | **How-to** | Task recipes | "Generate Oasis files", "Configure distributed execution" | Hand-written | | **Reference** | Dry facts | Python API, CLI options, settings schemas, stream formats | **Generated** where possible (autoapi, argparse, schema) | | **Explanation** | Understanding | Financial module, sampling, correlation, disaggregation | Hand-written, **co-located with the algorithms** | The reference layer is largely automatable, which frees effort for the explanation layer — where both the value and the drift risk concentrate. Each audience gets a landing page: analysts and end users, model developers, platform operators, and contributors. ## Tooling In place: | Concern | Choice | Why | |---------|--------|-----| | Engine | Sphinx | Already in use; the right tool | | Theme | Furo | Branded (Oasis colours, Raleway) | | Authoring | MyST Markdown alongside reStructuredText | Lower barrier; both compile, so migration is incremental | | API reference | `sphinx-autoapi`, **scoped per subsystem** | AST-based, so no heavy imports; avoids a whole-package dump | | Landing pages | `sphinx-design` cards and grids | Per-audience entry points | | Executable docs | `myst-nb` | Tutorials run at build time, so they cannot silently rot | | Copy buttons | `sphinx-copybutton` | Contributor experience | | Cross-repo links | `sphinx.ext.intersphinx`, driven by the orchestrator | See the note below | Agreed but **not yet implemented** — worth knowing before you assume a safety net exists: - **`linkcheck` in CI.** Dead external links build perfectly cleanly. There is no job running it today. - **Docstring-coverage gate** (e.g. `interrogate`), to keep the generated reference honest as the autoapi scope widens. - **Mermaid diagrams.** Diagrams-as-text would diff cleanly and avoid stale binary assets, but the extension is not configured. - **A render check.** See the first gotcha below: "builds clean" is not "renders clean". ## Authoring rules and traps These are concrete, recurring problems found while building these docs. Where a rule exists it is because something broke. 1. **Do not use `.. contents::`.** Furo renders its own "On this page" sidebar, and a docutils `.. contents::` directive becomes a red error box visible to readers. 2. **"Builds clean" is not "renders clean".** That `.. contents::` failure produced **exit 0 and no Sphinx warning** — the theme injects the error into the HTML, not the build log. When you change something structural, look at the built page. 3. **Cross-repository references need the orchestrator.** An `{external+...}` role only resolves when the orchestrator supplies the inventories, and an unresolved one does not degrade to plain text — Sphinx drops the link text and silently mangles the sentence. For prose a reader must follow, either route the target through a per-build-mode substitution in `conf.py` or write an ordinary link; the orchestrator rewrites in-site URLs to page-relative either way. 4. **Google-style docstrings: mind the colon.** In a `Returns:` block napoleon treats everything before the first colon on the first line as the return *type*. A named return (`intervals (np.ndarray): …`) therefore turns the name into a type and emits a cross-reference; write the description first instead. 5. **Docstrings are RST.** Bare indented code or algorithm sketches need a `::` literal block; lists need a blank line before them; `*args`-style text and identifiers ending in an underscore (`numpy.str_`) must be inline literals or they are read as markup. 6. **Never paste code.** Use `literalinclude` or an executable notebook cell, so samples come from sources that are actually run. 7. **Keep the build at zero warnings.** Every component currently builds clean, standalone and aggregated. That is only useful as a gate if it stays true.