Authoring design records in Compass
Compass is a public repository. Design records under docs/designs/ are
published verbatim to the engineering-docs site, so a record must carry no dead
private-repo artifacts and must never expose a colleague’s security analysis in
a form they did not intend to publish.
These five rules are the standing policy for every design record authored here going forward. Rules 1-4 match the sanitization the one-shot migration applied to records imported from out of tree (new records should be written this way from the start so they need no migration); rule 5 governs what happens to a record’s inbound links when another record is deleted.
1. Tracker IDs stay as plain-text provenance
Section titled “1. Tracker IDs stay as plain-text provenance”Keep SEA-#### issue references as bare plain text — they are load-bearing
provenance (records cite each other through them). Do not wrap them in a
linear.app link, in either form:
- inline:
[RIG-1234](https://linear.app/…)— writeRIG-1234 - reference-definition: a trailing
[RIG-1234]: https://linear.app/…line — drop the definition; keep the bareRIG-1234in the prose
A public reader sees an opaque internal ticket ID, which is honest and
harmless. A dead linear.app URL is worse than no URL.
2. No oss/compass/ path prefixes
Section titled “2. No oss/compass/ path prefixes”Some imported records cite Compass paths under an oss/compass/ prefix. This
repo is that tree, without the prefix. Cite paths relative to the repo root:
oss/compass/go/internal/runtime/image.go→go/internal/runtime/image.gooss/compass/apps/ui/src/stub-data.ts→apps/ui/src/stub-data.ts
3. De-link private records to prose
Section titled “3. De-link private records to prose”Records whose subject is seal-the-product (seal-*.md) are not published
here. When a Compass record references one, keep the reference as prose and drop
the link wrapper:
[the seal restructure record](https://github.com/RigelBuild/compass/blob/main/docs/designs/seal-restructure.md)→the seal restructure record
Cross-product references that name a Compass component (e.g. Warden) or public OSS (e.g. Cotal, Apache-2.0) are kept as written.
4. Never edit another author’s security sections
Section titled “4. Never edit another author’s security sections”Threat-model, security-boundary, and egress sections are kept verbatim. Do not restructure, summarize, or “sanitize” a section under a heading matching threat-model / security / egress (including security-boundary) that you did not author. If a section needs a change, raise it with its author rather than editing it in-place.
5. Freeze protects decision content, not links — fix inbound links on deletion
Section titled “5. Freeze protects decision content, not links — fix inbound links on deletion”The freeze convention (a later change adds a new record, never rewrites one)
protects a record’s decision content. It does not freeze a
record’s links to other records: a link whose target no longer exists is rot,
not content. So when a record is deleted or superseded, re-point or de-link its
inbound references from surviving records in the same PR — even from a frozen
Active/Historical record — pointing them at the successor record, the new
home for the carried-over rationale, or the decision files, or dropping the link
wrapper to prose (rule 3) when nothing replaces the target. A dead ](https://github.com/RigelBuild/compass/blob/main/docs/designs/path)
link degrades on the docsite to a bare GitHub blob URL into a deleted path, which
is exactly the “published record cites something that no longer exists” artifact
rule 1 forbids for tracker IDs. This is a link-integrity edit, not a
decision-content rewrite, so it is not a freeze violation; leave the record’s
decisions, prose, and security sections (rule 4) untouched.
The same link-integrity requirement covers each decision file’s record link:
the gate resolves every decision’s record regardless of its status, so a
Retired or Superseded by decision whose record is deleted still gets its
record re-pointed (to the successor, the new home for the rationale, or the
design-ledger record) in the same PR. A retracted decision’s link is held to the
same standard as a live one’s.
6. The bucket taxonomy
Section titled “6. The bucket taxonomy”Design records live under one of eight top-level buckets in docs/designs/. The
bucket names the record’s concern; pick the one that fits and place the record
there.
ui/— the product’s visible surfaces: shell, board, sidebar, keyboard, rendering, the design system, and the native/desktop shell family.agent/— agent behavior and lifecycle: config, comms, session, spawn, transport, prompts, the ask contract, the agent container.server/— server-side domain model and write paths: the ownership layer, forge, threading/issue model, notification and mention delivery.meta/— process and method records governing the corpus and the product’s engineering posture: architecture lineage, the design ledger itself, test strategy, scope gates.infra/— runtime and CI/testing infrastructure, sub-grouped asinfra/runtime/andinfra/ci/.observability/— telemetry for the product and its agents: OTel export, agent-loop traces, trace continuity.repo/— repository tooling and the dependency/library decisions that govern the build (Effect adoption, Renovate, proto drop, the eng-docs site).platform/— deployment platforms and runner hosting: macOS runners, runner containerization, stack supervision, model routing.
Layout
Section titled “Layout”The layout rule is <bucket>/[<subgroup>/]<name>/design.md: a record is a
<name>/design.md directory (which may own supporting .md files beside its
design.md), optionally nested one subgroup deep under a bucket (as infra/
is). A flat <name>.md belongs at a bucket root. Add a subgroup when a bucket
outgrows flat scanning; until then records sit directly under their bucket.
The design-ledger-gate governs every bucket
Section titled “The design-ledger-gate governs every bucket”tools/design-ledger-gate scans every governed bucket (the taxonomy buckets
above) and every .md beneath one, at any depth, supporting files included: a
record Status: header, when present, must have valid grammar, and a PR that
touches a governed record must either add or change a decision file
(docs/designs/decisions/<area>/DL-NNN.md) or declare a Ledger-impact: line
in its description. Decision files stay scoped to product decisions; the
gate governing a record is independent of whether that record has a decision
file. File layout and keys are in decisions/README.md.
Moving a record is not a freeze violation
Section titled “Moving a record is not a freeze violation”A move changes a record’s path and its link graph, not one word of its
decisions — so it is a link-integrity edit under rule 5, not a decision-content
rewrite, and the freeze does not forbid it. When a record moves, re-point every
inbound reference to it (other records’ links, decision files’ record links, and
code/config/doc citations) in the same PR, exactly as rule 5 requires on
deletion — a move leaves the same dangling-link rot a deletion would. Two narrow
metadata edits ride the same standard and are likewise not freeze violations:
normalizing a newly-governed record’s Status: header to the gate grammar, and
a one-line correction of a record’s stale self-described location.
7. Claim design-ledger IDs
Section titled “7. Claim design-ledger IDs”New decision files MUST get IDs from the shared counter, not from a guessed
next number. Concurrent PRs can otherwise claim the same ID. The reconcile
workflow marks claimed IDs as landed after merge. Set DL_CLAIM_TOKEN before
running:
bun tools/dl-claim --ref RIG-1234 --lane feature/design-recordUse --count N to claim more than one ID. Name each new decision file after its
printed ID, docs/designs/decisions/<area>/DL-NNN.md, in the same PR as the
record.
Failure handling, the token, and rotation are in tools/dl-claim/README.md.