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, ordocs/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 |
|---|---|
|
ships at launch (live) |
|
planned for v0.2 |
|
planned for v1 |
|
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 |
|---|---|
|
Named roadmap item; no contract yet. |
|
Intended API, schema, or recipe shape. May still change before code lands. |
|
Code exists; examples are runnable. |
|
Implementation has contract tests or golden validation. |
|
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.
Cross-link placement¶
Place
## See Alsoat the bottom of every concept and reference page.Include 3 to 6 links; prefer links to concrete reference pages over general index pages.
Format each entry as a bullet:
- [Page title](relative/path.md): one-sentence description.
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.