Compass engineering docs site
Status: Active
Design record for making Compass build-in-the-open: relocate the Compass design
records + product specs into this PUBLIC repo (RigelBuild/compass) and
stand up a public Astro Starlight engineering docs site with production
deploy on push:main and a per-PR Cloudflare Pages preview, driven by GitHub
Actions. Matt’s intent, verbatim: “build in the open — people can look through
and see how we built Compass using all of these practices. I’m OK with exposing
more than most products would.”
This site is the engineering docs — the design records, specs, and
architecture that document how Compass is built. It is deliberately named apart
from the future user-facing product docsite (the end-user product
documentation), which is a separate site that reserves the docs.compass
naming and docs.compass.rigel.build domain. This site takes
eng.compass.rigel.build.
This record is itself the first artifact under the new convention: it is
authored in RigelBuild/compass at
docs/designs/repo/compass-eng-docs/design.md, not out of tree.
Problem / Intent
Section titled “Problem / Intent”The Compass design corpus (39 records + the living spec) lives out of tree,
invisible to the public the product is being
built in the open for; the public RigelBuild/compass repo has no docsite
and no docs/designs/ tree (only docs/architecture/build-and-ci.md, verified
this session). Move the Compass records + specs here and publish them on a
public Starlight engineering docs site with the prior art’s per-PR-preview UX,
re-based from Woodpecker onto GitHub Actions and with no Cloudflare Access gate.
Global Constraints
Section titled “Global Constraints”- Public repo, public site — no access gate. The prior art’s docsite is gated to the team via Cloudflare Access — its Astro config deploys the built site to a team-only host fronted by Cloudflare Access. The compass mirror deliberately drops the Access gate: the site is public. Nothing in the docsite build, deploy, or content may assume an authenticated reader.
- Fork-PR secret hygiene. The repo is public, so
pull_requestevents from forks run WITHOUT repository secrets — and GitHub forcesGITHUB_TOKENread-only on a forkpull_requestregardless of the workflowpermissions:block. The preview-deploy job MUST guard on same-repo PRs (github.event.pull_request.head.repo.full_name == github.repository). Fork PRs therefore get the build/check gate but STRUCTURALLY cannot preview (no secrets to reach Cloudflare, a read-only token that would 403 the comment upsert) — not a deliberate reduced-service tier but an unavoidable consequence. - Toolchain pins. bun
1.3.13, node24.18.0, moon2.4.2(compass/.prototools:6-8). New shared JS deps ride the root catalog (compass/package.json:5: “pins shared dependency versions via the catalog”); app runtime deps (astro, @astrojs/starlight, github-slugger, sharp) go inapps/eng-docs/package.jsonfollowing the prior art’s shape (its docs app declares these same runtime deps). - One CI job, no matrix. compass CI is deliberately a single job running
moon ci :cion PRs andmoon run :cion main (compass/.github/workflows/ci.yml:4: “ONE JOB, NOT A MATRIX — the central structural decision”;:281-292). The docsite’s build/check tasks join that gate as a new moon project; only the DEPLOY (CD, secret-bearing) is a separate workflow. - moon projects are an explicit map. “moon discovers projects from this
explicit map” (
compass/.moon/workspace.yml:37-38); the newapps/eng-docsproject MUST be registered in.moon/workspace.ymlin the same change that adds the tree, or its CI tasks silently gate nothing (workspace.yml:41-47: “Aforks/<name>/moon.ymlwith no entry below is silently inert”). - Sanitization policy is repeatable rules, not a blind copy. The four content classes below (§Approach — Sanitization policy) govern every migrated record AND every future record authored here. No per-file ad-hoc judgment outside those rules.
- Security sections are kept. Matt ruled that the 13 records carrying threat-model / security-boundary / egress sections are fine to expose. Do not strip or soften them.
- Generated content is gitignored. As in the prior art: content under
src/content/docs/is generated byscripts/gather.tsand is gitignored; edit the canonical sources, not the generated copy. - markdownlint governs the canonical sources. compass already lints all
*.mdwithignores: ["forks/*/**"](compass/.markdownlint-cli2.jsonc:8-10); migrated records must pass it. - Hygiene-rule carve-out for design records. compass
AGENTS.md:55-58bans “planning metadata (issue IDs, phase numbers)” in source. Design records are historical records, not source: SEA-#### identifiers survive as plain-text provenance (see sanitization class 2). The AGENTS.md hygiene paragraph gains one sentence scoping itself to code, in the migration PR.
Approach
Section titled “Approach”Mirror the prior art’s docsite mechanism — one Starlight app, a gather script that
mirrors the repo’s reviewed markdown into a gitignored content collection, a
generated sidebar, per-page GitHub editUrl, pagefind search, and a
deploy script that pushes dist/ to Cloudflare Pages and upserts a preview-URL
PR comment — with two deliberate divergences: CI is GitHub Actions, not
Woodpecker, and the site is public with no Access gate.
(a) The site: apps/eng-docs, a compass-adapted mirror of the prior art’s docsite
Section titled “(a) The site: apps/eng-docs, a compass-adapted mirror of the prior art’s docsite”The prior art’s shape, extracted at source this session:
- App layout —
apps/eng-docs/{astro.config.mjs,package.json,moon.yml, tsconfig.json,src/,public/,scripts/{gather.ts,deploy.ts}}withsrc/content/docs/+src/sidebar.generated.tsgenerated and gitignored. - Gather mirrors every tracked
*.md(minus exclusions) into the content collection, classified into nav sections. The prior art’s taxonomy:designs / specs / research / team / packages / infra / contributing. Its classifier keysdocs/<domain>/…to the matching section and routes everything else to contributing/packages. Exclusions come from the canonical.markdownlint-cli2.jsoncignoreslist — “the single source of truth” — itsparseExclusionsreturns[...ignores, "oss/seal/**", "**/outputs/**"]. - Per-page editUrl —
editUrlForbuildshttps://github.com/${REPO_SLUG}/edit/main/${sourcePath}, withREPO_SLUG = "RigelBuild/compass". - Starlight config —
pagefind: true, generatedsidebar,editLink,lastUpdated, expressiveCode tokyo-night. - moon tasks —
gather(inputs/**/*.md+ the markdownlint config, so moon’s affected graph rebuilds the site whenever any gathered doc changes),build(bunx astro build, deps['gather']),check(bunx astro check), anddeploy/deploy-preview(runInCI: false, bothbun scripts/deploy.ts).
The compass adaptation:
- Sections:
Designs,Specs,Contributing,Packages— compass has nodocs/research/ordocs/team/orinfra/tree (top level verified this session:go/ packages/ apps/ proto/ tools/ forks/ docs/ agent-image/).docs/architecture/classifies under Designs? No — it keeps its ownArchitecturesection (adocs/domain like the others); the DOMAINS list becomes["designs", "specs", "architecture"]. REPO_SLUG = "RigelBuild/compass"; editUrl points here.- Exclusions: compass’s
.markdownlint-cli2.jsoncignoresis["forks/*/**"](compass/.markdownlint-cli2.jsonc:10); the gather adds its own tree +**/outputs/**as the prior art’s does, and drops theoss/seal/**special case (no such tree here). packagePath’sossspecial case drops (the prior art’sgather.tsspecial-casesapps|osstwo-segment package ids; compass keepsappsand gains nothing foross, which does not exist here).- No Cloudflare Access, no PostHog identity inheritance — the prior art’s
cross_subdomain_cookiePostHog block depends on the Access-identified apex; the compass site ships either no analytics or a plain PostHog snippet (Open Question Q4 covers the domain; analytics rides the same decision). - moon registration:
compass-eng-docs: 'apps/eng-docs'added to.moon/workspace.ymlprojects. Itsbuild+checktasks joinmoon ci :ciautomatically (“a new project with acitask is picked up the moment it is registered — no matrix entry to forget”,ci.yml:16-18), so a docs-affecting PR builds the site as part of the one CI job at zero workflow churn. - Accepted cost — any markdown edit rebuilds the site in the required
check.
gather’s inputs are the repo-wide/**/*.mdglob (mirroring the prior art), andbuild/checkdepend on it inside the one requiredmoon ci :cigate — so moon’s affected graph triggers a full gather +astro build+astro checkon ANY PR touching ANY*.md, not just docs PRs (a one-line README fix blocks on a full corpus build). Same tradeoff the prior art accepts for its one-job gate; named here, not free. The narrow alternative — scopegatherinputs todocs/**/*.md+ the contributing files — is rejected to keep parity with the prior art’s glob and avoid a package-README doc link silently going stale un-rebuilt.
(b) Per-PR preview: a GHA workflow doing wrangler pages deploy
Section titled “(b) Per-PR preview: a GHA workflow doing wrangler pages deploy”The prior art’s preview UX, at source: Woodpecker’s Petrel policy fans out
docs-site:deploy on push:main and docs-site:deploy-preview on
pull_request, both runInCI: false moon tasks running
bun scripts/deploy.ts. deploy.ts picks the Pages --branch from the
event — production is the "main" alias, a PR deploys under its SOURCE branch
and refuses to fall back (“Never fall back to a target branch on a PR — that
would risk deploying a preview over production”) — runs
wrangler pages deploy dist --project-name=… --branch=… --commit-dirty=true,
parses the preview URL from wrangler output, and upserts a marker-keyed PR
comment with the preview link + changed-page deep links via the gh CLI
(COMMENT_MARKER = "<!-- docs-preview -->").
The compass version keeps deploy.ts (adapted) and swaps the driver from
Woodpecker to a dedicated GHA workflow, .github/workflows/eng-docs-deploy.yml:
- Triggers:
push: branches: [main](production) andpull_request(preview). The deploy job guardsif: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository— fork PRs have no secrets and must not attempt a deploy (Global Constraints). - Not part of
moon ci :ci: the deploy is CD, needsCLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_IDsecrets, and must not red the hermetic gate — the same split the prior art makes (runInCI: false: “CD (runInCI:false): the Petrel policy … fans these out only when affected and gates the event”). The workflow runsmoon run compass-eng-docs:buildthenbun scripts/deploy.ts(ormoon run compass-eng-docs:deployviamoon exec-equivalent; the task keepsrunInCI: falseso the CI gate never runs it). - Env adaptation: the prior art’s
deploy.tsreads WoodpeckerCI_*vars (CI_PIPELINE_EVENT,CI_COMMIT_SOURCE_BRANCH,CI_COMMIT_SHA,CI_REPO,CI_COMMIT_PULL_REQUEST,GH_TOKEN). The compass copy reads the GHA equivalents:GITHUB_EVENT_NAME,GITHUB_HEAD_REF,GITHUB_REPOSITORY, PR number fromgithub.event.pull_request.number, the commit SHA from an EXPLICITPR_HEAD_SHA(=github.event.pull_request.head.sha) on PRs — NOTGITHUB_SHA, which on apull_requestevent is the ephemeral MERGE commit (refs/pull/N/merge), absent from the PR branch and unlinkable (GITHUB_SHAis correct only onpush), and the workflow’sGITHUB_TOKEN(withpermissions: pull-requests: writefor the comment;contents: readotherwise). TheDeployEnvinterface is renamed to those keys — a fork of the script, not a shim layer. - Cloudflare mechanism: Direct Upload via wrangler — the documented CI
pattern (“you can set up a GitHub Action to automate your subsequent
deployments with Wrangler”,
https://developers.cloudflare.com/pages/how-to/use-direct-upload-with-continuous-integration/).
Pages keys deployments by
--branch: the production branch is the alias, any other branch yields a preview deployment with its own stable URL (https://developers.cloudflare.com/pages/configuration/preview-deployments/; same model the prior art relies on).cloudflare/wrangler-actionexists but adds nothing over invoking wrangler fromdeploy.tsas the prior art does — rejected to keep one deploy code path across both repos’ docsites.
Alternative considered — Cloudflare Pages GitHub integration (Pages builds
the site itself on every push; automatic previews, zero workflow):
rejected. The build would run outside moon (no toolchain pins, no affected
graph, a second build definition drifting from apps/eng-docs/moon.yml), the
gather step’s repo-wide markdown walk would need replicating in Pages’ build
config, and there is no seam for the changed-pages PR comment deploy.ts
provides. Direct Upload keeps the build in the one pinned toolchain.
Alternative considered — docsite deploy inside moon ci :ci: rejected;
the CI job is the hermetic required check and must stay secret-free for fork
PRs; deploys are event-gated CD (mirrors the prior art’s runInCI: false split).
(c) Sanitization / rewrite policy — the four classes
Section titled “(c) Sanitization / rewrite policy — the four classes”Repeatable rules applied by the migration task and binding on future records:
- Cross-product references (Warden, Cotal). Contextualize-and-keep.
Warden is a designed Compass component, not a foreign product: the ledger’s
first row reads “Compass is an agent development environment: named
workstream agents supervised by a Dispatcher, gated by a Warden”
(DL-001), and the v0.3
design record’s §4.3 opens “Warden is the always-on security auditor”
(the v0.3 design record, not
the living spec, whose Warden mentions are thin and scattered). Stripping
it would gut the
corpus. What stays PRIVATE is seal-the-product internals: records whose
subject is seal (
seal-restructure.md,seal-config-path-collision.md) do not migrate; compass records that LINK to them convert the link to plain text (“the seal restructure record, private”). Cotal is external Apache-2.0 OSS cited as a dependency (compass-0.4/design.md:25-27: “Cotal (Apache-2.0, NATS/JetStream)”) — keep verbatim. Rule of thumb: a reference is kept when the referent is a Compass component or public OSS; it is de-linked (kept as prose, link dropped) when the referent is a private artifact out of tree. - Private tracker links (SEA-####, linear.app). Keep the ID, strip the
link. ~50 distinct SEA IDs are load-bearing provenance (records cite each
other through them); a dead
linear.app/rigelbuild/...URL is worse than no URL. Rewrite BOTH link forms to plainRIG-1234: the inline[RIG-1234](https://linear.app/…)AND the reference-definition[RIG-1234]: https://linear.app/…(^\[.+\]:\s*https://linear\.app/) — the corpus’s one live URL is the latter form (compass-0.4/design.md:207), which an inline-only regex would miss. BareRIG-1234mentions are untouched. Public readers see an opaque internal ticket ID — honest and harmless. oss/compass/**path rewrite. Strip the prefix. 19 records citeoss/compass/<path>paths from the prior art’s vendored era; the public repo’s layout is the same tree without the prefix — e.g.oss/compass/go/internal/runtime/image.go(compass-agent-container-runtime.md:54) isgo/internal/runtime/image.gohere,oss/compass/apps/ui/src/stub-data.ts(compass-ade-shell/design.md:16) isapps/ui/src/stub-data.ts(top-levelgo/ packages/ apps/ proto/confirmed this session against the compass root). Mechanical rewrite:oss/compass/→ `` (empty) in code spans, links, and prose paths; a bareoss/compass(the vendored root itself, no trailing path — including quoted workspace literals like["oss/seal", "oss/compass"]) →compass, since that root no longer exists in the published tree and the repo itself now IS that tree. One special case: self-referential internal-repo claims (e.g.compass-0.4/design.md:201-203: “this is an internal design record, not a publishedoss/compass/artifact”) get a one-line editorial bracket noting the record now IS published — never silent rewording of frozen prose.- Threat-model / security-boundary / egress sections. Keep, verbatim. Matt’s explicit ruling; 13 records carry them. Not blockers, not edited.
(d) Migration timing
Section titled “(d) Migration timing”Compass-record design PRs may be in flight out of tree against the old convention
at migration time (as of this session’s open-PR list: #1096
(docs/designs/platform/compass-dogfood-e2e/design.md), #1095 (edits a
product compass record), #1087 (platform compass-agent GHCR record), plus
#1089 and #1075 (compass-ux)). Q5 ruled all-at-once, so the
migration is a SINGLE PR carrying the full corpus at the out-of-tree main at
branch-cut — no wave-1/wave-2 split. An individual out-of-tree design PR still
open when the migration branch cuts is reconciled into that one PR rather than
deferred: the executor either lands it out of tree first and includes the merged
record, or re-targets it to compass. This is coherent with Q2 (compass is the
source of truth): review continues in the public repo, so migrating a
still-under-review record does not strand its threads — they simply continue
here. New Compass records started AFTER this record merges are authored in
compass directly (Q2).
Executable by an implementing agent; every task carries its own test cycle. Q1–Q5 are all RULED (see Open Questions); T6 is dropped per Q5.
T1 — Site scaffold + moon registration
Section titled “T1 — Site scaffold + moon registration”Create apps/eng-docs/ mirroring the prior art’s app shape, minus Access/PostHog,
and register the project.
Interfaces:
- Consumes: the prior art’s docs app files as templates — its
astro.config.mjs,package.json,moon.yml,tsconfig.json,src/styles/custom.css,src/content.config.ts,.gitignore,public/favicon.svg(read from the out-of-tree clone; do not import at build time). - Produces:
apps/eng-docs/astro.config.mjs—siteset per Q4’s ruling (placeholderhttps://compass-eng-docs.pages.devuntil the domain lands),starlight({ title: "Compass Engineering Docs", pagefind: true, sidebar, editLink: {}, lastUpdated: true, tableOfContents: {...}, expressiveCode: {...} }); NOheadPostHog block, NO Access assumptions.apps/eng-docs/package.json— name@compass/eng-docs, scripts{ gather, dev, build, preview, check }as the prior art’s; depsastro,@astrojs/starlight,@astrojs/check,github-slugger,sharpviacatalog:entries added to the rootpackage.jsonworkspaces.catalog.apps/eng-docs/moon.yml— tasksgather(commandbun scripts/gather.ts, inputs['scripts/gather.ts', '/**/*.md', '/.markdownlint-cli2.jsonc'], outputs['src/content/docs', 'src/sidebar.generated.ts']),build(bunx astro build, deps['gather'], outputs['dist']),check(bunx astro check, deps['gather']),deploy+deploy-preview(bun scripts/deploy.ts, deps['build'],options.runInCI: false), and acitask depending on['build', 'check']so the project joinsmoon ci :ci..moon/workspace.yml— addcompass-eng-docs: 'apps/eng-docs'underprojects, same change (perworkspace.yml:41-47’s silent-inert warning).apps/eng-docs/.gitignore—src/content/docs/,src/sidebar.generated.ts,dist/,.astro/.
- Test cycle:
moon run compass-eng-docs:buildandmoon run compass-eng-docs:checkgreen locally;moon query projectslistscompass-eng-docs; a scratch PR shows the CI job picking the project up via the affected graph.
T2 — Gather script adapted to the compass layout
Section titled “T2 — Gather script adapted to the compass layout”Port gather.ts + gather.test.ts with the compass taxonomy.
Interfaces:
- Consumes: the prior art’s
gather.ts(491 lines) +gather.test.tsas the port source. - Produces:
apps/eng-docs/scripts/gather.tswith:const REPO_SLUG = "RigelBuild/compass"(editUrl base, mirrors the prior art’sgather.ts).const DOMAINS = ["designs", "specs", "architecture"] as const(replaces the prior art’s["designs","specs","research","team"]).SECTIONSin sidebar order: Designs, Specs, Architecture, Packages, Contributing (drops the prior art’s Research/Team/Infra).packagePathdrops theossarm (present in the prior art’sgather.ts; keep theappstwo-segment case).parseExclusionsreturns[...ignores, "**/outputs/**"](drops"oss/seal/**"from the prior art’s list); ignores read fromcompass/.markdownlint-cli2.jsonc(currently["forks/*/**"]).CONTRIBUTING_FILES= compass’s root convention files:README.md,AGENTS.md,CONTRIBUTING.md,forks/README.md.- Everything else (frontmatter injection, H1 strip, link rewriting, sidebar generation, index page) ports unchanged.
- Produces:
apps/eng-docs/scripts/gather.test.ts— the ported unit suite with fixtures updated to compass paths (classification ofdocs/designs/repo/x.md,go/README.md→ packages, exclusion offorks/oh-my-pi/**). - Test cycle:
bun test apps/eng-docs/scripts/gather.test.tsgreen;moon run compass-eng-docs:gatherthenmoon run compass-eng-docs:buildrenders this record at/designs/repo/compass-eng-docs/design/with a working editUrl.
T3 — Deploy script + GHA workflow
Section titled “T3 — Deploy script + GHA workflow”Port deploy.ts to GHA env vars; add the CD workflow.
Interfaces:
- Consumes: the prior art’s
deploy.ts(495 lines) +deploy.test.tsas the port source; Cloudflare Direct Upload docs (cited in Approach (b)). - Produces:
apps/eng-docs/scripts/deploy.tswith:const PROJECT_NAME = "compass-eng-docs"(Q4),COMMENT_MARKER = "<!-- compass-eng-docs-preview -->",SITE_LABEL = "Compass engineering docs".interface DeployEnv { GITHUB_EVENT_NAME?; GITHUB_HEAD_REF?; GITHUB_SHA?; PR_HEAD_SHA?; GITHUB_REPOSITORY?; PR_NUMBER?; GH_TOKEN?; CLOUDFLARE_API_TOKEN?; CLOUDFLARE_ACCOUNT_ID? }— replaces the WoodpeckerCI_*set (from the prior art’sdeploy.ts). The recorded commit SHA isPR_HEAD_SHAon PRs (=github.event.pull_request.head.sha) andGITHUB_SHAon push; neverGITHUB_SHAon a PR (it is the merge commit, not the branch head).isPullRequest(env)→env.GITHUB_EVENT_NAME === "pull_request";deployBranch(env)keeps the refuse-to-fall-back invariant onGITHUB_HEAD_REF(per the prior art’sdeploy.ts);wranglerArgs,parsePreviewUrl,commentBody,changedDocPages, escape/encode helpers port unchanged.
- Produces:
.github/workflows/eng-docs-deploy.yml:on: { push: { branches: [main] }, pull_request: {} };permissions: { contents: read, pull-requests: write };concurrency: eng-docs-deploy-${{ github.ref }}withcancel-in-progress: true.- One job
deploy,if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository(fork guard); steps: checkout, setup-bun/node/moon from.prototoolspins (reuseci.yml’s pin-reading step,ci.yml:154-196),moon run compass-eng-docs:build, thenbun scripts/deploy.tswithenv: { CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}, CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}, GH_TOKEN: ${{ github.token }}, PR_NUMBER: ${{ github.event.pull_request.number }}, PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} }.
- Produces:
apps/eng-docs/scripts/deploy.test.ts— ported pure-function suite (branch selection, fork of the env mapping, comment body, URL parse). - Test cycle:
bun test apps/eng-docs/scripts/deploy.test.tsgreen; after Q4’s project exists, a scratch PR shows the preview comment with a live*.pages.devURL, and a merge to main updates production.
T4 — Sanitization rewrite pass (Q3 ruled; policy classes final)
Section titled “T4 — Sanitization rewrite pass (Q3 ruled; policy classes final)”Encode the four-class policy as a one-shot migration script + a documented checklist for future records.
Interfaces:
- Consumes: the out-of-tree corpus enumerated this session — the 38 product design records (37 matching
docs/designs/product/compass-*plusdocs/designs/product/compass.md, the v0.3 base record whose name has no hyphen and so is not matched by thecompass-*glob),docs/designs/platform/compass-dogfood-loop/design.md,docs/specs/product/compass.md,docs/specs/product/README.md. - Produces:
tools/docs-migrate/migrate.ts(one-shot, deleted at the end of the migration) applying, per file: (1) linear.app link strip — BOTH the inline[SEA-<n>](https://linear.app/…)and the reference-definition[SEA-<n>]: https://linear.app/…forms →SEA-<n>; (2)oss/compass/prefix strip in paths/links/code spans; (3) link-to-private-record conversion forseal-*.mdtargets → plain prose; (4) NO edits to security sections. Emits a per-file diff summary for review. Editorial brackets (the self-referential internal-record claims, Approach (c) class 3) are applied by hand in the same PR, listed in the PR body. - Produces:
docs/designs/CONTRIBUTING.md(or a section in rootCONTRIBUTING.md) stating the four rules as the standing policy for records authored here. - Test cycle:
bun test tools/docs-migrateover fixture snippets for each class (including the reference-definition link form); post-run grep gates (authoritative over the rewrite regexes — the run fails if any form slipped): zerolinear.appmatches, zerooss/compassmatches underdocs/designs/**+docs/specs/**;markdownlint-cli2clean.
T5 — Full-corpus migration + out-of-tree removal (Q1/Q2/Q5 ruled)
Section titled “T5 — Full-corpus migration + out-of-tree removal (Q1/Q2/Q5 ruled)”Land the whole Compass corpus in compass in a single PR (Q5: all at once); remove it from the out-of-tree source. compass is the source of truth going forward (Q2), so design review continues here, not out of tree.
Interfaces:
- Consumes: T4’s script output over the full corpus at the out-of-tree
mainat branch-cut — the 38 product design records,compass-dogfood-loop/design.md, and both product specs. Any out-of-tree design PR still open at migration time is reconciled to compass rather than split into a later wave (executor sequences: merge-out-of-tree-first then migrate, or re-target the PR to compass — both keep the corpus whole); the wave-1/wave-2 split is dropped per Q5. - Produces (compass PR):
docs/designs/product/**(the 38 product records),docs/designs/product/compass-dogfood-loop/design.md(a Compass product-process design;platform/— an out-of-tree domain — does not exist in compass, and repo-tooling records like THIS one live underdocs/designs/repo/),docs/specs/product/{compass.md,README.md}, plus (Q1 ruled MOVE)docs/designs/product/DECISIONS.md+tools/design-ledger-gate/**(ported; the gate’sPRODUCT_DIRconstant staysdocs/designs/product) + adesign-ledger-gatemoon project registered in.moon/workspace.ymlwith acitask. - Produces (out-of-tree PR, sequenced after the compass PR merges): delete the
migrated trees; leave the out-of-tree
docs/designs/product/README.mdpointing at the public repo; the out-of-tree residual ledger keeps the seal-product rows DL-045/DL-046 (Q1); the out-of-tree gather needs no change (deleted files simply stop being gathered). - Test cycle: compass
moon run :cigreen (docsite builds the full corpus; ledger gate green after the move); site renders the ledger and both spec pages; the out-of-treemoon run docs-site:buildgreen post-removal;tools/docs-migrate/deleted after the one-shot run.
T6 — Wave-2 straggler sweep — DROPPED (Q5 ruled all at once)
Section titled “T6 — Wave-2 straggler sweep — DROPPED (Q5 ruled all at once)”Q5 ruled “all at once”, so there is no separate wave-2 sweep: T5 migrates the
whole corpus in one PR and deletes tools/docs-migrate/ at the end. Any out-of-tree
design PR still open at migration time is reconciled to compass by T5 (see T5
Consumes), not deferred to a later wave.
T7 — Cloudflare Pages project provisioning (Q4 ruled)
Section titled “T7 — Cloudflare Pages project provisioning (Q4 ruled)”Interfaces:
- Consumes: Q4 ruling (below) — project
compass-eng-docs, custom domaineng.compass.rigel.build, provisioned via the fleet’s Pulumi IaC lane. - Produces: the
compass-eng-docsPages project via the fleet’s Pulumi IaC (prior-art precedent: the docsite got its OWN Pages:Edit-scoped token once RIG-1119 provisioned the project); repo secretsCLOUDFLARE_API_TOKEN(Pages:Edit-scoped, least-privilege per the prior art) +CLOUDFLARE_ACCOUNT_IDonRigelBuild/compass; production branch set tomain. NOTE: creating the Pages project + seeding the two repo secrets is an operator step (not agent-executable). - Test cycle: T3’s scratch-PR preview + main production deploy succeed end to end.
- T1 —
apps/eng-docsscaffold +compass-eng-docsmoon registration; build/check green inmoon ci :ci. - T2 —
gather.ts/gather.test.tsported to the compass taxonomy; this record renders. - T3 —
deploy.tson GHA env +.github/workflows/eng-docs-deploy.ymlwith the fork guard. - T4 — sanitization migration script + standing policy doc (Q3 ruled; classes final).
- T5 — full-corpus migration (all records, one PR) + out-of-tree removal; ledger + ledger-gate moved to compass (Q1/Q2/Q5 ruled).
- T6 — DROPPED: Q5 ruled all-at-once; wave-2 sweep folded into T5.
- T7 — Cloudflare Pages
compass-eng-docs+eng.compass.rigel.build+ secrets provisioned via Pulumi (Q4 ruled).
Open Questions
Section titled “Open Questions”Batched for Matt — ALL RULED (below): Q1/Q2/Q4/Q5 ruled 2026-08-05, Q3 ruled earlier. T5 and T7 execute against these rulings; T6 is dropped (Q5).
- Q1 — Does the design-ledger + ledger-gate + gather tooling move to
compass, or stay out of tree? The ledger is Compass-titled and
Compass-governed (its ledger is titled “Compass design-decision ledger”) and
the gate hardcodes
PRODUCT_DIR = "docs/designs/product"(in itsdesign-ledger-gatetool), so it follows the corpus. RULED (Matt): MOVE ledger + ledger-gate to compass (the gate ports with its path constant unchanged); the two seal-product rows (DL-045, DL-046) stay behind in a small out-of-tree residual ledger next to the seal records they cite.gather.tsis NOT shared — each repo keeps its own copy (they already diverge on taxonomy); no extraction. Verified the cut is edge-clean: DL-045/DL-046 are the ONLY rows under the## Sealheading, neither supersedes nor is superseded by any row, and they are the only rows whose Record link points at aseal-*.mdfile — so moving DL-001..DL-128 minus DL-045/046 to compass severs zero supersession edges and leaves zero dangling Record links; the gate’s dangling-pointer check stays green after the split (DL-046’s prose mentions “the Compass Warden security model” but that is not a ledger EDGE). Q1 is the most defensible choice, not the weakest. - Q2 — Is compass the SOURCE OF TRUTH for Compass records going forward, or
a published mirror gathered from out of tree? RULED (Matt): SOURCE OF
TRUTH. A mirror leaves every design PR on a non-public surface, defeating
build-in-the-open (readers see outputs, not the review process); it also
needs a cross-repo sync job that can silently drift. Authoring here means
the design PRs, review threads, and preview links are all public — the
point of the exercise. This record dogfoods the ruling.
Named consequence of moving the corpus out of tree (T5 deletes the out-of-tree
trees): several ACTIVE non-compass out-of-tree records cite INTO the compass
corpus by bare
file:line/§ anchor (verified:sea-1023-acp-session.md,sea-1115-agent-provisioning-cotal.md,platform/go-toolchain-default.mdat ~40 refs,platform/repo-structure-reorg.md, others) whose lane is seal/agent/platform, so they do NOT migrate. Mitigating: these are bare-prose citations, NOT Markdown hyperlinks (a link-form grep returns zero), so the out-of-treegather.tsrenders no 404 — only the human/agent grounding value is severed. Recommendation: leave-as-historical (the SEA ID and record name in the prose still name the target) plus the out-of-treeREADME.mdpointer T5 already leaves atdocs/designs/product/; a per-file pointer stub is not worth the churn. - Q3 — Warden/Cotal cross-product references: hold-and-omit vs
contextualize-and-keep? RULED (Matt): contextualize-and-keep for both.
Warden is a designed Compass component (DL-001; v0.3 design record §4.3) and
Cotal is public Apache-2.0 OSS. Matt ruled the seal-the-product detail that
rides along in the kept Warden sections is a non-issue — “Seal is already
OSS, the wasm setup is public” — so §6.5’s seal WASM-agent-loop internals
and DL-046’s seal-crate restructure stay verbatim, with no scrub sub-rule.
He likewise ruled internal fleet/agent handles, the
mattuser name, and theCo-Authored-By: sealcommit trailers are non-issues (“fleet handles, matt, seal i don’t care about”) — so the policy adds NO internal-identifier scrub class. The two records whose SUBJECT is seal-the-product (seal-restructure.md,seal-config-path-collision.md) still do not migrate — out of the Compass corpus — and compass records linking to them de-link to plain prose (class 1). - Q4 — Cloudflare Pages project + custom domain: does one exist, who
provisions? No compass Pages project exists (the prior art’s pipeline knows
only its own docsite + the marketing site).
RULED (Matt): provision a new
compass-eng-docsproject + a Pages:Edit-scoped token via the fleet’s existing Pulumi IaC lane (the RIG-1119 precedent), production branchmain; custom domaineng.compass.rigel.build(Matt ruled). Thedocs.compassnaming anddocs.compass.rigel.builddomain are deliberately RESERVED for the future user-facing product docsite (a separate site), so this engineering docs site takes theeng.subdomain. Until the domain lands the site ships oncompass-eng-docs.pages.dev. Analytics (PostHog snippet, minus the prior art’s Access-cookie inheritance) rides the domain decision. - Q5 — Migration scope: all 39 at once vs settled-now + in-flight-after freeze? RULED (Matt): all at once — migrate the full corpus in one PR, no two-wave split (supersedes the wave recommendation). Coherent with Q2: because compass is the source of truth, design review continues in the public repo, so the “strands review threads” cost the two-wave split was meant to avoid is instead accepted — any out-of-tree design PR still open at migration time is reconciled to compass by T5 (merge-out-of-tree-first then migrate, or re-target to compass — executor sequences), not deferred to a later wave. T6 is therefore dropped.