Documentation Style Guide

Writing and formatting conventions for all EMMA documentation. Pages that deviate from this guide require an explicit exemption comment.

Audience and tone

  • Write for an engineering and scientific audience: model authors, benchmark contributors, downstream evaluators, and reviewers.

  • Use short paragraphs (three sentences or fewer) and bullets for lists.

  • No em-dashes (U+2014). Use commas, semicolons, colons, or rewrite the sentence.

  • Avoid LLM-voice phrasings: “it’s worth noting”, “importantly”, “this allows us to”, “as we can see”, “deep dive”. State the fact directly.

  • Define every acronym on first use, on every page that uses it. RF, I/Q, AoA, DoA, OOD, CSI, SEI, ULA, URA, SNR, NMSE, SI-SDR, BLEU, FM, and similar count as acronyms.

Heading conventions

  • Use ## See Also (title-case “See Also”, always two words) for the cross-link section at the bottom of every concept and reference page. Do not use “Where to look next”, “Further reading”, or any other variant.

  • Reserve ## for major page sections. Use ### for subsections, #### for sub-subsections.

  • Do not skip heading levels.

Pre-implementation admonition

Every page that describes an API surface (class, method, config field, schema, CLI command) and does not have a corresponding code implementation carries this admonition at the top, immediately after the page title:

:::{warning}
**Pre-implementation.** This page describes proposed contracts. Class signatures, parameter types, schema fields, and behavior are subject to change before code lands. Once implementation exists, content here will be regenerated from docstrings or sourced from running tests.
:::

Rules:

  • Place the admonition before any module summary or introductory prose.

  • Do not add it to docs/index.md (which carries its own pre-launch warning), docs/glossary.md, docs/STYLE.md, or docs/PRINCIPLES.md.

  • Pure conceptual pages without specific API claims do not require it.

  • Section index pages (getting-started/index.md, how-to/index.md, etc.) carry a shorter form adapted to README/index format (a :::{warning} callout, not a code block).

Version and maturity labels

EMMA ships across versions. Every task, dataset, schema, class, and CLI command carries two labels: a version badge (when it ships) and a maturity label (its contract state). Use the exact vocabulary below. No other variants.

Version badges

Render version as an HTML span using the badge classes defined in docs/_static/custom.css:

Markup

Meaning

<span class="badge badge-live">v0.1</span>

ships at launch (live)

<span class="badge">v0.2</span>

planned for v0.2

<span class="badge">v1</span>

planned for v1

<span class="badge">v2</span>

planned for v2

badge-live is the emerald “live” accent; plain badge is the neutral future-version style.

Maturity labels

Use these inline-code labels in tables and admonitions to state the contract state. No other variants.

Label

Meaning

planned

Named roadmap item; no contract yet.

proposed-contract

Intended API, schema, or recipe shape. May still change before code lands.

implemented

Code exists; examples are runnable.

verified

Implementation has contract tests or golden validation.

deprecated

Still present but scheduled for removal; use the replacement instead.

Until src/emma/ lands, every API/schema surface is proposed-contract; datasets and tasks whose recipe is fully specified are proposed-contract, otherwise planned. See Reference / Maturity Matrix for the per-feature status table.

Code-span linking rule

Every code span in prose that has an API reference entry must link to that entry’s anchor. Examples:

  • {ref}`FrozenBackbone <class-emma-tasks-frozenbackbone>`

  • {ref}`MeanAngularError <class-emma-metrics-meanangularerror>`

  • {ref}`DatasetRecipe <class-emma-schemas-datasetrecipe>`

This applies in concept pages, how-to guides, and cross-links in reference pages. It does not apply inside code blocks.

API anchor format

  • Class / ABC / Protocol: class-emma-<module>-<lowercased-classname>

    • Example: class-emma-tasks-frozenbackbone, class-emma-metrics-meanangularerror, class-emma-schemas-datasetrecipe

  • Method on a class: method-emma-<module>-<lowercased-classname>-<methodname>

    • Example: method-emma-tasks-task-score, method-emma-harness-evaluator-run

These mirror what sphinx.ext.autodoc emits, so swapping hand-written stubs for generated pages is mechanical. Every anchor used in prose must also appear as a heading anchor (class-emma-...) or (method-emma-...) on the API page, and must have an entry in _code_links.json.

Enum vs string in Python examples

Framework-owned closed choices (task pillars, OOD axes, splits, environments, submission modes, metric directions, target domains) use StrEnum members in Python code:

# Correct
task = TaskRegistry.get(TaskID.E_LOC_AOA, version=ReleaseVersion.V0_1)
evaluator = Evaluator(protocol=OODProtocol.LEAVE_ONE_ENVIRONMENT_OUT)

YAML and recipe configs may use the enum string value because Pydantic deserializes it at validation time:

# Correct in YAML
task: E_LOC_AOA
protocol: leave_one_environment_out

Open plugin registry names (for example a custom RealCaptureAdapter name) stay as plain strings because they resolve through the registry, not a closed enum.

Section index exemptions

Section index pages (*/index.md) are exempt from the ## See Also requirement because their job is navigation, not instruction. They carry audience framing (Who should read this, Before you start, What this section is not) instead.

Reference and catalog sub-pages that enumerate rather than instruct (for example per-dataset recipe pages under datasets/) are also exempt from ## See Also. They carry a one-line pointer to their parent section.

Reference table conventions

Reference-surface tables (the kind that document a contract or enumerate tasks, metrics, schemas, datasets, or plugin slots) follow these rules.

Column headers carry the canonical field name. Use ID, Pillar, OOD axis, Metric, ABC, Version, Maturity, Domain. Do not use #, Item, or ad-hoc names. The header is the contract.

One row, one entity. Every row describes a single thing of the same kind. Do not mix tasks and metrics in the same table.

Every code identifier links. Class, ABC, method, enum, and field names in cells use {ref} links to their canonical anchor. Plain backticks are reserved for shell commands and inline literals with no API surface.

Enum cells show the member. When a row references an enum member, include the member name (for example LEAVE_ONE_ENVIRONMENT_OUT) so a reader can wire the contract directly.

Version and maturity get their own columns. Do not bury the ship version or contract state in prose; render them as the badge and inline-code label in dedicated columns.

Footnotes and admonitions for caveats. When a row has a caveat (“continuity column, excluded from aggregate”, “subject to change at v0”, “depends on rfgen feature not yet shipped”), put the caveat in a :::{note} directly below the table or as a numbered footnote. Do not stuff prose into a structured column.

Example task table:

| ID | Task | Metric | OOD axis | Domain | Version | Maturity |
|----|------|--------|----------|--------|---------|----------|
| `E-LOC-AOA` | Angle-of-arrival / DoA | {ref}`MeanAngularError <class-emma-metrics-meanangularerror>` | `LEAVE_ONE_ENVIRONMENT_OUT` | `POSITIONING` | <span class="badge badge-live">v0.1</span> | `proposed-contract` |

References section

Every page that makes a scientific or load-bearing claim ends with a ## References section listing the canonical sources cited on that page, before ## See Also if both are present. Each entry is specific enough to verify:

  • paper: Author(s), "Title", Venue, Year, DOI: <doi> or arXiv:<id> plus equation or section number where applicable.

  • standard: Body <number>, <revision-year> plus section number.

  • library: distribution >= <minimum-version> plus the function or class path.

Unverifiable citations carry a (verify) note rather than a guessed identifier. The master reading list lives in Background / Literature.