Skip to content

Contributing to sw2102-docs

This repo is the canonical documentation home for SectorWars 2102. It exists separately from the code repos (Sectorwars2102, sw2102-bang) so that design intent, system specs, and feature definitions can be reasoned about independently of any one implementation snapshot.

If you're new, read this file before editing or adding documentation.


When to add a doc here vs. in another repo

Add a doc to sw2102-docs when it describes:

  • How the game should work (rules, flows, balance, governance).
  • A system or subsystem that spans services or repos.
  • An API surface, data model, or operational concern that other contributors need to reference.
  • A definition or convention that should be authoritative.

Keep a doc in the source repo (e.g. Sectorwars2102/, sw2102-bang/) when it is:

  • A README explaining how to build, run, or develop that specific repo.
  • An inline code comment, module docstring, or implementation note.
  • A throwaway investigation or change log tied to a single PR.

Rule of thumb: if a doc would survive a full rewrite of the implementation, it belongs here.


Where does each section live and what belongs in it

Folder Purpose Examples
ARCHITECTURE/ System topology, services, deployment, dev environment. service inventory, container layout, environment matrix
DATA_MODELS/ Entities, schema, migrations, persistence rules. per-entity reference docs, migration policy
FEATURES/ What the game does, organized by player-visible concern. Only place implementation status lives. gameplay rules, economy, galaxy, planets
OPERATIONS/ Cross-cutting operational concerns. admin UI, player client, ARIA, i18n, multi-regional, realtime
SYSTEMS/ Prescriptive subsystem specs (one file per named subsystem). combat resolver, market pricing, galaxy generation, realtime bus
ADR/ Architecture Decision Records. one numbered file per significant architectural choice

Top-level files (README.md, CONTRIBUTING.md, GLOSSARY.md) are foundational/meta and apply across all sections.

If a doc doesn't fit any existing section, propose a new top-level section in your PR rather than burying it.


Status convention

Implementation status lives in FEATURES/ only, marked inline beside the feature, mechanic, or rule it describes. Use one of four markers:

Marker Meaning When to apply
✅ Shipped Implemented in the source repo and behaving as specified. The behaviour exists in Sectorwars2102 and matches the doc.
🚧 Partial Some of the behaviour is implemented; the rest is not. Code is present but incomplete, behind a flag, or with known gaps.
📐 Design-only Specified here but not yet built. The design is settled enough to document, but no production code exists.
🐛 Bug Implemented, but the live behaviour diverges from this spec. Live code disagrees with the spec, and the spec is the target.

All other folders (ARCHITECTURE/, DATA_MODELS/, OPERATIONS/, SYSTEMS/, ADR/) describe the target state. They do not carry status markers.

The REST API surface is intentionally not documented in this repo — the gameserver auto-publishes it at <api-host>/docs (Swagger), <api-host>/redoc, and <api-host>/openapi.json. WebSocket protocol design lives in SYSTEMS/realtime-bus.md.

If you find yourself wanting to track status outside FEATURES/, the right move is usually to add a feature entry that points at the system doc.


Phase tags

Every non-meta doc must carry one or more version tags in YAML frontmatter. The site uses these to power a four-mode reader filter. The full reader-facing vocabulary lives in tags.md; the decision record is ADR-0071.

The controlled vocabulary is exactly four values:

Tag Meaning
Live Shipped to the gameserver and verified by direct gameplay observation, recorded in FINDINGS.md within the last 90 days.
Current Shipped on main. Code path reachable end-to-end. Gameplay verification absent or stale.
Release Not yet shipped. Committed for 1.0 via a non-superseded Accepted ADR, the launch roadmap, or an explicit launch-commitment line. Design is settled.
Future Post-launch, aspirational, exploratory, or design-in-flight. Residual: anything not Live, Current, or Release.

Frontmatter

---
tags:
  - Current
  - Release
---
  • Listed in maturity order: Live, Current, Release, Future. The linter autofixes order.
  • TitleCase in YAML, lowercase in data-version attributes.
  • One to three tags per page. A page that needs all four is split rather than tagged — the split pattern is the same one already used to separate Launch end-state from Current shipped-state pages.
  • Meta files (this file, README.md, GLOSSARY.md, CLAUDE.md, AISPEC.md, FINDINGS.md, DECISIONS.md, tags.md) carry no version tag and are always visible.

Per-section markers

A page may serve multiple lanes by tagging the divergent sections inline. Canonical syntax on a heading:

## Stellar engineering {.version-tag data-version="future"}

For non-heading content (tables, paragraphs) wrap in a div:

<div class="version-tag" data-version="future" markdown>

| Param | Value |
|-------|------:|
| ... | ... |

</div>

Multi-value: a section that serves more than one lane uses space-separated tokens, e.g. data-version="current release".

Unmarked prose inherits the page's frontmatter tags. You only mark sections that diverge from the page's primary lane.

How the runtime filter chooses what to show

Mode selection is cumulative — the active lane plus everything more mature than it:

Selected mode Shows sections tagged…
Live Live only
Current Live + Current
Release Live + Current + Release
Future all four

This means a section tagged Current is visible whenever the reader is in Current, Release, or Future modes. It is hidden only when the reader is in Live mode. Authors do not need to think about cumulative semantics when tagging — tag with the strict, lowest-maturity lane the section represents; the runtime adds the rest.

Composition with the four inline status markers

The ✅ 🚧 📐 🐛 inline markers (described above) live only in FEATURES/ and describe code-vs-spec drift at the sentence/bullet granularity. The four version tags describe release-timeline bucket at the page/section granularity. They are orthogonal but constrained:

Tag \ Marker 🚧 📐 🐛
Live OK warn error warn
Current OK OK error OK
Release warn OK OK warn
Future error error OK error

Promotion of a Current section to Live requires an entry in the FINDINGS.md Gameplay verifications table. ADRs are tagged by the maturity of the decision's implementation, not by ADR status — Proposed ADRs are Future, Accepted ones inherit the maturity of their shipped (or not yet shipped) code.

Tooling

  • python scripts/tags/scan_tags.py [<path>] — repo-state report.
  • python scripts/tags/lint_tags.py [--fix] — 17 numbered rules. Wired into pre-commit and the Cloudflare build.
  • python scripts/tags/gen_page_tags.py — MkDocs hook that emits the page-tag JSON map consumed by the topbar filter JS.

tags_allowed in mkdocs.yml enforces the vocabulary at build time — adding a tag outside the list fails the build. Adding a new tag requires team agreement, an ADR update, and coordinated changes to mkdocs.yml, tags.md, lint_tags.py, and the JS filter constants.


Filename and folder rules

  • Content files: lowercase-with-hyphens, .md extension. Example: first-login.md, combat-resolver.md.
  • Top-level reference docs: ALL_CAPS, .md extension. Example: CLAUDE.md, CONTRIBUTING.md, GLOSSARY.md, README.md, AISPEC.md, FINDINGS.md. These sit at the repo root or as section indexes and are loaded as primary navigation. The ALL_CAPS signals "load this first." Build artifacts produced by the doc system (e.g. tags.md, generated by mkdocs-material) follow lowercase-with-hyphens — they aren't hand-edited reference docs.
  • Top-level folders: ALL CAPS. Example: FEATURES/, OPERATIONS/.
  • Subfolders: lowercase. Example: FEATURES/gameplay/, FEATURES/economy/.
  • Index files: every section folder has its own README.md acting as the index for that area.
  • No spaces, no underscores in filenames.

All real Markdown lives at the repo root (ADR/, FEATURES/, GLOSSARY.md, …) so it reads as plain Markdown when browsing the repo. MkDocs, however, forbids its docs_dir from being the repo root, so docs/ exists purely as a build root: every entry in it is a symlink pointing back up to the real file (docs/ADR -> ../ADR). Nothing in docs/ is a real file, and editing either path edits the same bytes.

Consequences for contributors:

  • Never create a real file or directory under docs/. Content placed only there is invisible from the repo root and silently diverges. Edit the top-level copy instead.
  • When you add a new top-level section or top-level doc, add a matching symlink in docs/ so it appears on the site, and add it to the nav in mkdocs.yml:
    ln -s ../NEWSECTION docs/NEWSECTION    # run from the repo root
    
  • The check-docs-symlinks.sh guard (wired into the pre-commit hook) fails the commit if any non-symlink turns up under docs/. Run it any time with ./scripts/check-docs-symlinks.sh.

Cross-linking rules

  • Use repo-relative paths. From OPERATIONS/realtime.md to SYSTEMS/realtime-bus.md, write ../SYSTEMS/realtime-bus.md.
  • Do not use absolute filesystem paths.
  • Do not link to external commit SHAs in the source repos; link to a path under the source repo's main if you must, but prefer prose ("see services/gameserver/src/services/combat_service.py") so the reference survives a refactor.
  • When citing source files, use the repo-relative path within the source repo (e.g. services/gameserver/src/models/ship.py). These citations describe where the target code should live, not necessarily what is committed today.
  • When a term is defined in GLOSSARY.md, link to it on first use in a doc rather than redefining it.

Writing style

Prescriptive voice for non-FEATURES docs. Describe how the system should work, not how it currently works or used to work. "The combat resolver returns a CombatResult containing..." — not "The combat resolver was rewritten in 2024 and now returns...".

Inline status for FEATURES. When a feature doc covers behaviour that isn't fully shipped, mark each section, table row, or bullet with the appropriate status emoji. Do not bury status in a "current state" footer.

No historical narrative. Avoid:

  • "Previously, X..."
  • "We removed Y..."
  • "This used to be Z, but now..."
  • "Legacy behaviour..."
  • "Deprecated in favour of..."

If something has been removed or replaced, the doc simply describes the target state without referencing the prior one. ADRs (ADR/) are the place for "we decided X over Y" reasoning, not feature or system docs.

Concrete, specific, terse. Tables and bullets where they fit. Numbers where they're known. Code paths where they apply. Avoid marketing language.

No redundant prose. If a table conveys it, skip the paragraph. If GLOSSARY.md defines it, link rather than redefine.


Reviewing a doc PR

Use this checklist before approving:

  • File path matches naming conventions (lowercase-with-hyphens, correct folder casing).
  • The doc lives in the right section per the table above.
  • Voice is prescriptive (or, in FEATURES/, prescriptive with inline status).
  • No "previously / used to / legacy / removed" language.
  • Status markers (if FEATURES/) are present where behaviour is not fully shipped.
  • Cross-links are repo-relative and resolve.
  • Source-file citations point at plausible paths under Sectorwars2102 or sw2102-bang.
  • Section folder's README.md index is updated if a new file was added.
  • Glossary terms are linked rather than redefined.
  • No emojis except the four status markers in FEATURES/.

Contributor onboarding

A short path for someone who has just cloned the repo:

  1. Read the root README.md to understand the layout.
  2. Skim GLOSSARY.md so the vocabulary clicks.
  3. Read this file (CONTRIBUTING.md) end-to-end.
  4. Read the README.md index of whichever section you're touching.
  5. Open one or two existing docs in the same section to match tone and structure.
  6. Make your edit; run through the review checklist above before opening a PR.

If your change crosses sections (for example, a new feature spec plus a system doc plus a data-model entry), open a single PR that updates all of them together — readers should not encounter half-applied changes.

For substantive architectural choices, open an ADR under ADR/ in the same PR. See ADR/README.md for when an ADR is warranted and the template to follow.