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-versionattributes. - 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,
.mdextension. Example:first-login.md,combat-resolver.md. - Top-level reference docs: ALL_CAPS,
.mdextension. 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.mdacting as the index for that area. - No spaces, no underscores in filenames.
The docs/ directory is symlinks-only¶
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 thenavinmkdocs.yml:ln -s ../NEWSECTION docs/NEWSECTION # run from the repo root - The
check-docs-symlinks.shguard (wired into the pre-commit hook) fails the commit if any non-symlink turns up underdocs/. Run it any time with./scripts/check-docs-symlinks.sh.
Cross-linking rules¶
- Use repo-relative paths. From
OPERATIONS/realtime.mdtoSYSTEMS/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
mainif you must, but prefer prose ("seeservices/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
Sectorwars2102orsw2102-bang. - Section folder's
README.mdindex 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:
- Read the root
README.mdto understand the layout. - Skim
GLOSSARY.mdso the vocabulary clicks. - Read this file (
CONTRIBUTING.md) end-to-end. - Read the
README.mdindex of whichever section you're touching. - Open one or two existing docs in the same section to match tone and structure.
- 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.