From 39d65020c9231856e11f302d6617a3487ee59a2e Mon Sep 17 00:00:00 2001 From: mintaka Date: Sun, 13 Sep 2026 16:25:24 -0400 Subject: [PATCH 1/6] docs(designs): scrub the private repo's former name and gate it (RIG-3756) Family 5 of the managed-boundary leak: the private repo's former proper name and live paths inside it, left behind when families 1-4 were scrubbed. The census that drove the earlier passes scoped itself to docs/ + AGENTS.md, so code and config were structurally invisible to it. Sweeping the tracked tree instead found the former name in apps/eng-docs and .moon/workspace.yml, and family 4 still alive in 11 files under tools/ and agent-image/. Records keep every technical claim; only the provenance descriptor changes. A path citation becomes the mechanism it establishes, so a reader with access can still find the source and a reader without one learns the design. The replacement vocabulary (prior art, out of tree, the fleet, managed-plane) all pre-existed in the corpus. The gate now scans for the former name too, but cannot do it whole-word: the word is ordinary English throughout go/ (a sealed sum type, a ciphertext sealed under a key, an egress-sealed agent). Measured over the tracked tree a whole-word scan flags 60 lines, every one legitimate -- a gate that is 100% false positives gets switched off. It matches only repo-shaped uses: a path inside the repo, its docsite host, its possessive, or the word followed by a repo noun. Tests pin both directions, including the three public names that carry the string and must never trip it. Code comments lose their migration narration outright rather than being reworded -- a public reader needs what the code does, not where it came from. Co-authored-by: Matt Wilkinson wip: resolve rebase conflicts --- .moon/workspace.yml | 7 +- apps/eng-docs/moon.yml | 2 +- apps/eng-docs/scripts/deploy.ts | 4 +- docs/designs/CONTRIBUTING.md | 6 +- .../agent/compass-agent-container-runtime.md | 2 +- .../agent/compass-forks-reversal/design.md | 22 +- .../compass-manager-comms-substrate/design.md | 2 +- .../ci/compass-agent-image-publish/design.md | 12 +- .../design.md | 2 +- .../infra/ci/compass-dogfood-e2e/design.md | 4 +- .../infra/ci/compass-dogfood-loop/design.md | 4 +- .../meta/compass-design-ledger/design.md | 2 +- .../repo/compass-design-docs-reorg/design.md | 12 +- docs/designs/repo/compass-eng-docs/design.md | 248 +++++++++--------- ...n-offline-redelivery-pre-settle-closure.md | 2 +- .../compass-mention-offline-redelivery.md | 2 +- .../design.md | 2 +- docs/designs/ui/compass-session-trace-diff.md | 4 +- .../design.md | 6 +- .../ui/compass-ux-foundation/design.md | 2 +- tools/agent-image-env-gate/env-check.ts | 2 +- tools/design-ledger-gate/moon.yml | 5 +- tools/orion-ref-gate/index.test.ts | 38 +++ tools/orion-ref-gate/index.ts | 52 +++- tools/renovate-preflight/moon.yml | 2 +- tools/renovate/bot-config.json5 | 2 +- tools/renovate/config.json5 | 10 +- tools/renovate/config.test.ts | 10 +- tools/renovate/moon.yml | 2 +- tools/renovate/package.json | 2 +- .../renovate/refresh-toolchain-hashes.test.ts | 3 +- tools/renovate/refresh-toolchain-hashes.ts | 6 +- 32 files changed, 267 insertions(+), 214 deletions(-) diff --git a/.moon/workspace.yml b/.moon/workspace.yml index 773d9d18a..608412e24 100644 --- a/.moon/workspace.yml +++ b/.moon/workspace.yml @@ -86,11 +86,10 @@ projects: stamp-gate: 'tools/stamp-gate' # The design-ledger gate: validates the Compass design-decision ledger # (docs/designs/DECISIONS.md), the per-record `Status:` headers, and - # dangling supersession/Record pointers (RIG-1187). Migrated from the sealed - # repo with the corpus it governs (RIG-1794). + # dangling supersession/Record pointers (RIG-1187). design-ledger-gate: 'tools/design-ledger-gate' # The orion-ref-gate boundary gate (RIG-2489): fail-closed scan that the PUBLIC - # compass repo carries no reference to the PRIVATE internal monorepo. Mirrors + # compass repo carries no out-of-tree reference the managed boundary forbids. Mirrors # design-ledger-gate; registered here so its check + typecheck + unit test run # in the moon-driven CI sweep — unregistered, moon never discovers it and the # boundary re-rots uncaught. @@ -138,7 +137,7 @@ projects: # silently inert (moon discovers projects only from this map) and the config # drift it fences ships uncaught. renovate: 'tools/renovate' - # The Renovate preflight probe (ported from the internal monorepo's preflight probe): + # The Renovate preflight probe: # checks the minted App token can see the repo before `bunx renovate` runs, # failing fast with a named diagnosis instead of Renovate's opaque # platform-unknown-error. Registered so its own typecheck + unit test gate. diff --git a/apps/eng-docs/moon.yml b/apps/eng-docs/moon.yml index 4c3b0baa2..d4c6d013a 100644 --- a/apps/eng-docs/moon.yml +++ b/apps/eng-docs/moon.yml @@ -5,7 +5,7 @@ # devenv toolchain on PATH. install/lint/format are inherited (bun tag → # root:install; biome + markdownlint are the root whole-repo sweep, which lints # the canonical docs/ sources — the generated src/content/docs/ mirror is -# gitignored and exempt). Public counterpart to sealed/apps/docs: no Cloudflare +# gitignored and exempt). Unlike the prior art's docs app: no Cloudflare # Access gate, no PostHog analytics. workspace: inheritedTasks: diff --git a/apps/eng-docs/scripts/deploy.ts b/apps/eng-docs/scripts/deploy.ts index 09d7904a8..31233abc9 100644 --- a/apps/eng-docs/scripts/deploy.ts +++ b/apps/eng-docs/scripts/deploy.ts @@ -5,8 +5,8 @@ // GitHub Actions workflow (RIG-1765). The engineering docsite lives on // Cloudflare Pages under the compass-eng-docs project. // -// Adapted from sealed apps/docs/scripts/deploy.ts — they share the same -// Cloudflare Pages deploy + PR-preview-comment shape and the three constants +// Shares the same Cloudflare Pages deploy + PR-preview-comment shape as the +// prior art, including the three constants // below (PROJECT_NAME, COMMENT_MARKER, SITE_LABEL). This docsite build gathers // the compass repo's markdown, so its preview comment also deep-links the .md // pages a PR changed (changedDocPages + commentBody's "Changed pages" section). diff --git a/docs/designs/CONTRIBUTING.md b/docs/designs/CONTRIBUTING.md index 9dea63760..8e6af9d53 100644 --- a/docs/designs/CONTRIBUTING.md +++ b/docs/designs/CONTRIBUTING.md @@ -7,7 +7,7 @@ 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 the records imported from the private `sealed` repo (new records should be +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. @@ -26,8 +26,8 @@ harmless. A dead `linear.app` URL is worse than no URL. ## 2. No `oss/compass/` path prefixes -The private repo vendored Compass under `oss/compass/`. This repo **is** that -tree, without the prefix. Cite paths relative to the repo root: +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.go` - `oss/compass/apps/ui/src/stub-data.ts` → `apps/ui/src/stub-data.ts` diff --git a/docs/designs/agent/compass-agent-container-runtime.md b/docs/designs/agent/compass-agent-container-runtime.md index 931aa4f9c..669e0412c 100644 --- a/docs/designs/agent/compass-agent-container-runtime.md +++ b/docs/designs/agent/compass-agent-container-runtime.md @@ -485,7 +485,7 @@ transcript-scoped, not container-scoped.) ### Spec impact — supersession, by citation -Per the sealed frozen-record convention, merged records are never edited; +Per the frozen-record convention, merged records are never edited; this record supersedes specific claims by citing them, and the **impl PR's living-spec update** carries the replacement into `docs/specs/product/compass.md`: diff --git a/docs/designs/agent/compass-forks-reversal/design.md b/docs/designs/agent/compass-forks-reversal/design.md index ab57b0995..1c975aad9 100644 --- a/docs/designs/agent/compass-forks-reversal/design.md +++ b/docs/designs/agent/compass-forks-reversal/design.md @@ -23,7 +23,7 @@ machinery that existed only to carry them. - **FROZEN (Matt, 2026-08-19): shared `RigelBuild/{devenv,nix2container,oh-my-pi}` repos + combined patch work.** Compass consumes the shared canonical fork - repos — one canonical fork per upstream. Sealed patches useful to both the + repos — one canonical fork per upstream. Patches useful to both the fleet and compass land in the shared repos, never duplicated. Do not relitigate; tasks execute it. - **Shared-repo patch ownership is disjoint (forge coordination, 2026-08-19).** @@ -133,7 +133,7 @@ is compass's review point — not a mechanical path swap. `moon.yml` check task carries `/forks/devenv/**` as an affected-detection input glob (`agent-image-env-gate/moon.yml:58`). -**The sealed patch is compass-specific and load-bearing.** All of it sits in +**The `containers.nix` patch is compass-specific and load-bearing.** All of it sits in `forks/devenv/src/modules/containers.nix`: - Per-container `user`/`group`/`homeDir` options (`containers.nix:373` — @@ -154,7 +154,7 @@ UPSTREAM (verified 2026-08-19 against `RigelBuild/devenv@afed7bf3` `src/modules/containers.nix`: `homeDir = "/env";` hardcoded in a module-scope `let`, `envContainerName = builtins.getEnv "DEVENV_CONTAINER"` present, no per-container identity options). The shared `RigelBuild/devenv` fork carries no -sealed diff for this and has no devenv consumer of its own. Per Matt's ruling, +diff for this and has no devenv consumer of its own. Per Matt's ruling, compass's `containers.nix` patch set therefore **lands INTO `RigelBuild/devenv` first** (harmless to other consumers, required by compass), and only then does compass repoint to `github:RigelBuild/devenv`. A naive repoint before the patch @@ -177,7 +177,7 @@ rationale. path:../forks/nix2container#skopeo-nix2container`. The env-gate also globs `/forks/nix2container/**` (`agent-image-env-gate/moon.yml:59`). -**The sealed patch is shared.** `forks/nix2container/default.nix:396-399` drops +**This patch is shared.** `forks/nix2container/default.nix:396-399` drops relocated copyToRoot paths from the initialized nix DB: ```nix @@ -216,9 +216,9 @@ merge and the rev were re-verified at source before this fold.) ### oh-my-pi **Consumer shape: no *build* consumer, one *tooling* consumer.** The tree is -plain upstream at tag `v17.1.8` with no sealed diff (`forks/README.md:151-155` — -"Sealed changes: NONE … verified byte-identical to `can1357/oh-my-pi` at -`v17.1.8`"); no compass image or app build consumes it (`forks/README.md:214`). +plain upstream at tag `v17.1.8` with no local diff at all — verified +byte-identical to `can1357/oh-my-pi` at `v17.1.8` — and no compass image or +app build consumes it. But it is **not** consumer-free: the store door's credential-denylist generator reads the subtree directly — `go/internal/store/gen_credential_keys.go:42` (`const schemaRelPath = "../../../forks/oh-my-pi/packages/coding-agent/src/config/settings-schema.ts"`), @@ -244,7 +244,7 @@ removes 5892 of the 7424 vendored files in one move. The one real consumer — the generator — should read the npm-installed schema the agent actually runs (`packages/compass-agent/node_modules/@oh-my-pi/pi-coding-agent/src/config/settings-schema.ts`, pinned at `packages/compass-agent/package.json:19`), so the denylist tracks the version -in production rather than a vendored snapshot. The sealed deltas catalogued in +in production rather than a vendored snapshot. The deltas catalogued in `forks/README.md:156-197` live in the monorepo fork and are `RigelBuild/oh-my-pi`'s concern, not compass's. Drop-vs-consume is a load-bearing Open Question (OQ1) — but the one real consumer wanting the npm @@ -272,7 +272,7 @@ this record does not require it. - **Compass-own fork repos** (`RigelBuild/compass-devenv` etc., or reviving the per-upstream Copybara spoke repos) — rejected. Matt ruled shared canonical repos: one fork per upstream, patch work combined. Two forks of the same - upstream would duplicate the sealed patches and re-create the divergence this + upstream would duplicate the patch work and re-create the divergence this reversal exists to end. Frozen; not relitigated here. - **Defer until the fleet's reversal fully lands** — rejected. Only the nix2container lane has a genuine cross-repo dependency (the shared @@ -304,7 +304,7 @@ Contribute compass's devenv patch set into `RigelBuild/devenv`, and confirm the nix2container shared fix has landed. - **L0a — land the `containers.nix` patch in `RigelBuild/devenv`.** Port the - full sealed diff from `forks/devenv/src/modules/containers.nix` (per-container + full diff from `forks/devenv/src/modules/containers.nix` (per-container `user`/`group`/`homeDir` options with upstream values as defaults, `containers.nix:373-389`; the `$HOME`-staging guard; the `imageEnv` DEVENV_-filter, `containers.nix:181`; the config-only `buildingContainer` @@ -342,7 +342,7 @@ nix2container shared fix has landed. Interfaces: -- Consumes: `forks/devenv/src/modules/containers.nix` (the sealed diff, source +- Consumes: `forks/devenv/src/modules/containers.nix` (the diff, source of truth for L0a); the shared nix-DB-drop fix on `RigelBuild/nix2container`. - Produces: `RigelBuild/devenv` `main` rev carrying the patch; `RigelBuild/nix2container` `master` rev carrying the shared fix. These two diff --git a/docs/designs/agent/compass-manager-comms-substrate/design.md b/docs/designs/agent/compass-manager-comms-substrate/design.md index 5098bbd78..8c3ce2113 100644 --- a/docs/designs/agent/compass-manager-comms-substrate/design.md +++ b/docs/designs/agent/compass-manager-comms-substrate/design.md @@ -292,7 +292,7 @@ DL-054 amendment). Every task below inherits these; task briefs do not restate them. -- **Two-repo split.** This record lives in `sealed` (design corpus); +- **Two-repo split.** This design corpus lives out of tree; implementation lands in `RigelBuild/compass`. All file:line citations below are into the compass clone. - **Additive-only proto changes.** New fields, new enum values, new RPCs, new diff --git a/docs/designs/infra/ci/compass-agent-image-publish/design.md b/docs/designs/infra/ci/compass-agent-image-publish/design.md index f95229c2a..a2188131b 100644 --- a/docs/designs/infra/ci/compass-agent-image-publish/design.md +++ b/docs/designs/infra/ci/compass-agent-image-publish/design.md @@ -8,10 +8,10 @@ Tracking: RIG-1690 (blocks compass-native RIG-1683/T2, RIG-1685/T4, RIG-1687/T6) > `agent-image/*`, `.github/workflows/*`, `forks/*`, `go/cmd/*`, `ci.yml`, > `devenv.nix`, `packages/compass-agent/*`, and `docs/architecture/*` citation > below is a path in that repo at HEAD `b3fc25311`, not this one (line numbers -> drift as the code evolves; resolve them against that commit). It lives in the -> sealed design corpus (`docs/designs/infra/ci/`) because that is where the wave's design +> drift as the code evolves; resolve them against that commit). It lives out of +> tree because that is where the wave's design > records freeze; the `docs/designs/ui/*` cross-references (e.g. DL-112) -> are paths in this (sealed) corpus. +> are paths in this corpus. > > **Superseded in part** (RIG-1746, Matt 2026-08-25): the *CI-placement* > decision below — a separate `.github/workflows/publish-agent-image.yml` @@ -517,11 +517,11 @@ Interfaces: ## Open Questions -- **[Resolved] Record placement.** This record lives in the sealed design - corpus (`docs/designs/infra/ci/`), the wave's canonical home for frozen +- **[Resolved] Record placement.** This record lives out of tree, + the wave's canonical home for frozen design records, beside the other `compass-*` records. T4 folds the durable operational content into the compass repo's `docs/architecture/build-and-ci.md` - once implemented; this record stays the design of record in sealed. + once implemented; this record stays the design of record out of tree. - **[Non-load-bearing] GA release tag.** RIG-1687 will likely want `:v` alongside `:git-`; T1's tag-list CLI makes that a no-redesign later add. Deferred to GA planning. diff --git a/docs/designs/infra/ci/compass-dogfood-e2e-steer-deliver-seam/design.md b/docs/designs/infra/ci/compass-dogfood-e2e-steer-deliver-seam/design.md index 1fb72df44..e2bf33775 100644 --- a/docs/designs/infra/ci/compass-dogfood-e2e-steer-deliver-seam/design.md +++ b/docs/designs/infra/ci/compass-dogfood-e2e-steer-deliver-seam/design.md @@ -278,7 +278,7 @@ In dependency order — T2 depends on T1, T3 on T1+T2. (window-scoped to each recipient's turn settle): peer-1 no `deliver`, spawner no `steer` for that id. -Note on ledgers: this record lives in the sealed platform design corpus +Note on ledgers: this record lives out of tree (`docs/designs/platform/`), which the design-ledger-gate governs only for the **product** corpus (`docs/designs/product/DECISIONS.md`). A platform record adds no DECISIONS row and declares no ledger delta, mirroring its frozen parent diff --git a/docs/designs/infra/ci/compass-dogfood-e2e/design.md b/docs/designs/infra/ci/compass-dogfood-e2e/design.md index 06368beb2..2c93196b5 100644 --- a/docs/designs/infra/ci/compass-dogfood-e2e/design.md +++ b/docs/designs/infra/ci/compass-dogfood-e2e/design.md @@ -11,7 +11,7 @@ Status: Draft > for the Dogfood milestone. The design targets the **`RigelBuild/compass`** > repo; every `go/*`, `proto/*`, `packages/*`, `apps/*`, and `devenv.nix:*` > citation below is a path in that repo at origin/main HEAD `abdb412c`, not -> this one. It lives in the sealed design corpus because that is where the +> this one. It lives out of tree because that is where the > wave's design records freeze. ## Problem / Intent @@ -45,7 +45,7 @@ messaging with @mention delivery, (5) teardown + resume from durable state — becomes the first scenario set authored on the harness and remains the concrete Dogfood acceptance gate. -Note on ledgers: this record lives in the sealed design corpus +Note on ledgers: this record lives out of tree (`docs/designs/platform/`), which the design-ledger-gate governs only for the **product** corpus (`docs/designs/product/DECISIONS.md`). A platform record adds no DECISIONS row and declares no ledger delta, so nothing here is diff --git a/docs/designs/infra/ci/compass-dogfood-loop/design.md b/docs/designs/infra/ci/compass-dogfood-loop/design.md index 5a98d2648..0a591ba60 100644 --- a/docs/designs/infra/ci/compass-dogfood-loop/design.md +++ b/docs/designs/infra/ci/compass-dogfood-loop/design.md @@ -8,7 +8,7 @@ Status: Active > end to end. The design targets the **`RigelBuild/compass`** repo (its > `devenv.nix`, `agent-image/`, and `go/cmd/*` binaries); every `devenv.nix:*`, > `agent-image/*`, and `go/cmd/*` citation below is a path in that repo at HEAD -> `21241f720`, not this one. It lives in the sealed design corpus because that is +> `21241f720`, not this one. It lives out of tree because that is > where the wave's design records freeze. ## Problem / Intent @@ -26,7 +26,7 @@ self-signed cert) and idles, and a real session is driven end to end (`CommsService.CreateAgent` → `CompassService.ProvisionAgentWorkspace` → `StartAgentSession`), so a real container spawns and runs an agent turn. -Note on ledgers: this record lives in the sealed design corpus +Note on ledgers: this record lives out of tree (`docs/designs/platform/`), which the design-ledger-gate governs only for the **product** corpus (`docs/designs/product/DECISIONS.md`). A platform record adds no DECISIONS row and declares no ledger delta, so nothing here is ledger-tracked; diff --git a/docs/designs/meta/compass-design-ledger/design.md b/docs/designs/meta/compass-design-ledger/design.md index aa88b6530..d67fc7400 100644 --- a/docs/designs/meta/compass-design-ledger/design.md +++ b/docs/designs/meta/compass-design-ledger/design.md @@ -203,7 +203,7 @@ fast-follow diff-aware core promotes it to gate-checked (merge-base compare). ### 4. The workflow rule — same-PR ledger flip + code-comment citation The ledger is the ONE living exception to freeze-on-merge, BY DESIGN. It -stays consistent with the freeze model the same way specs do — the sealed +stays consistent with the freeze model the same way specs do — the convention "update the matching `docs/specs/` doc *in the same PR* as the code" (`AGENTS.md:73-74`) extends to the ledger: **the PR that freezes a record also appends its new decision rows and flips any rows it supersedes.** diff --git a/docs/designs/repo/compass-design-docs-reorg/design.md b/docs/designs/repo/compass-design-docs-reorg/design.md index 2b727864f..a12967381 100644 --- a/docs/designs/repo/compass-design-docs-reorg/design.md +++ b/docs/designs/repo/compass-design-docs-reorg/design.md @@ -27,7 +27,7 @@ this record). Two problems: also collides with the fleet-wide sense of "platform" (the shared infrastructure layer), making it doubly ambiguous in a product repo. The bucket is an accident of migration: the eng-docs migration record itself asserted - "`platform/` — a sealed-monorepo domain — does not exist in compass" + "`platform/` — an out-of-tree domain — does not exist in compass" (`docs/designs/repo/compass-eng-docs/design.md:386-387`), yet 17 records now live there. @@ -205,7 +205,7 @@ docs/designs/platform/compass-renovate-migration.md"), `buf.gen.yaml:9`, `packages/compass-agent/src/transport/*` file comments, and gate/test fixtures (`tools/design-ledger-gate/index.test.ts`, `tools/orion-ref-gate/index.test.ts` — fixture strings, not live paths). Inside the corpus, 41 more `docs/designs/platform` -prose citations. Two cited paths are **already dead** (sealed-repo records that +prose citations. Two cited paths are **already dead** (out-of-tree records that never migrated, pre-existing rot, out of scope but noted): `buf.gen.yaml:9` (`docs/designs/platform/go-toolchain-default.md`) and `devenv.nix:208` (`docs/designs/platform/ci-toolchain-shared-defs.md`). @@ -486,8 +486,8 @@ the gate expansion it forces, and the migration strategy: *metadata* edits ride the same standard: Status-header normalization to the gate grammar (`index.ts:87`) for newly-governed records, and one-line corrections of a record's stale self-described location - (`compass-agent-image-publish.md:8-11,500-504` says it "lives in the sealed - design corpus") — location metadata and machine-checked headers, not + (`compass-agent-image-publish.md:8-11,500-504` says it "lives out of tree") + — location metadata and machine-checked headers, not decisions. ## Alternatives considered @@ -849,8 +849,8 @@ Interfaces: ### T9 — Post-move verification sweep Repo-wide grep proves zero live references to `docs/designs/platform/` (the -two pre-existing dead sealed citations `buf.gen.yaml:9` / `devenv.nix:208` are -re-pointed to prose or left with an explicit "sealed-private" annotation — +two pre-existing dead citations `buf.gen.yaml:9` / `devenv.nix:208` are +re-pointed to prose or left with an explicit "out-of-tree" annotation — executor's call, flagged in the PR) and that the only remaining `docs/designs/product/` paths are the T10-deferred native-family records and their Record cells. Docsite build renders every record; spot-check routes for diff --git a/docs/designs/repo/compass-eng-docs/design.md b/docs/designs/repo/compass-eng-docs/design.md index 6d04e0ea6..021b65f46 100644 --- a/docs/designs/repo/compass-eng-docs/design.md +++ b/docs/designs/repo/compass-eng-docs/design.md @@ -19,7 +19,7 @@ naming and `docs.compass.rigel.build` domain. This site takes 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 in sealed. +`docs/designs/repo/compass-eng-docs/design.md`, not out of tree. ## Problem / Intent @@ -28,16 +28,15 @@ 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 sealed's per-PR-preview UX, +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 -- **Public repo, public site — no access gate.** sealed's docsite is - "gated to the team via Cloudflare Access" - (`sealed/apps/docs/astro.config.mjs:9-10`: "to - sealed-docs.rigel.build via Cloudflare Pages, gated to the team via - Cloudflare Access"). The compass mirror deliberately drops the Access gate: +- **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_request` events @@ -53,8 +52,8 @@ re-based from Woodpecker onto GitHub Actions and with no Cloudflare Access gate. (`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 in `apps/eng-docs/package.json` following sealed's shape - (`sealed/apps/docs/package.json:13-19`). + sharp) go in `apps/eng-docs/package.json` following 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 :ci` on PRs and `moon run :ci` on main (`compass/.github/workflows/ci.yml:4`: "ONE JOB, NOT A MATRIX — the central @@ -74,10 +73,9 @@ re-based from Woodpecker onto GitHub Actions and with no Cloudflare Access gate. - **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 sealed - (`sealed/apps/docs/package.json:5`: "Content under src/content/docs/ is - generated by scripts/gather.ts … and is gitignored; edit the canonical - sources, not the generated copy"). +- **Generated content is gitignored.** As in the prior art: content under + `src/content/docs/` is generated by `scripts/gather.ts` and is gitignored; + edit the canonical sources, not the generated copy. - **markdownlint governs the canonical sources.** compass already lints all `*.md` with `ignores: ["forks/*/**"]` (`compass/.markdownlint-cli2.jsonc:8-10`); migrated records must pass it. @@ -89,42 +87,37 @@ re-based from Woodpecker onto GitHub Actions and with no Cloudflare Access gate. ## Approach -Mirror sealed's docsite mechanism — one Starlight app, a gather script that +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 sealed's docsite +### (a) The site: `apps/eng-docs`, a compass-adapted mirror of the prior art's docsite -sealed's shape, extracted at source this session: +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}}` with `src/content/docs/` + `src/sidebar.generated.ts` generated and gitignored. - **Gather** mirrors every tracked `*.md` (minus exclusions) into the content - collection, classified into nav sections. sealed's taxonomy - (`gather.ts:43-51`): `designs / specs / research / team / packages / infra / - contributing`. Its classifier keys `docs//…` to the matching section - and routes everything else to contributing/packages - (`gather.ts:94-123`). Exclusions come from the canonical - `.markdownlint-cli2.jsonc` `ignores` list — "the single source of truth" - (`gather.ts:126-137`, `parseExclusions` returns - `[...ignores, "oss/seal/**", "**/outputs/**"]`). + collection, classified into nav sections. The prior art's taxonomy: + `designs / specs / research / team / packages / infra / contributing`. Its + classifier keys `docs//…` to the matching section and routes + everything else to contributing/packages. Exclusions come from the canonical + `.markdownlint-cli2.jsonc` `ignores` list — "the single source of truth" — + its `parseExclusions` returns `[...ignores, "oss/seal/**", "**/outputs/**"]`. - **Per-page editUrl** — `editUrlFor` builds - `https://github.com/${REPO_SLUG}/edit/main/${sourcePath}` - (`gather.ts:203-205`), with `REPO_SLUG = "RigelBuild/compass"` - (`gather.ts:25`). + `https://github.com/${REPO_SLUG}/edit/main/${sourcePath}`, with + `REPO_SLUG = "RigelBuild/compass"`. - **Starlight config** — `pagefind: true`, generated `sidebar`, `editLink`, - `lastUpdated`, expressiveCode tokyo-night - (`astro.config.mjs:51-66`). + `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, - `moon.yml:18-25`), `build` (`bunx astro build`, deps `['gather']`, - `moon.yml:27-39`), `check` (`bunx astro check`, `moon.yml:43-52`), and - `deploy`/`deploy-preview` (`runInCI: false`, both `bun scripts/deploy.ts`, - `moon.yml:69-74`). + moon's affected graph rebuilds the site whenever any gathered doc changes), + `build` (`bunx astro build`, deps `['gather']`), `check` (`bunx astro + check`), and `deploy`/`deploy-preview` (`runInCI: false`, both + `bun scripts/deploy.ts`). The compass adaptation: @@ -137,13 +130,13 @@ The compass adaptation: - **`REPO_SLUG = "RigelBuild/compass"`**; editUrl points here. - **Exclusions**: compass's `.markdownlint-cli2.jsonc` `ignores` is `["forks/*/**"]` (`compass/.markdownlint-cli2.jsonc:10`); the gather adds - its own tree + `**/outputs/**` as sealed's does, and drops the + its own tree + `**/outputs/**` as the prior art's does, and drops the `oss/seal/**` special case (no such tree here). -- **`packagePath`'s `oss` special case drops** (`sealed gather.ts:78` +- **`packagePath`'s `oss` special case drops** (the prior art's `gather.ts` special-cases `apps|oss` two-segment package ids; compass keeps `apps` and gains nothing for `oss`, which does not exist here). -- **No Cloudflare Access, no PostHog identity inheritance** — sealed's - `cross_subdomain_cookie` PostHog block (`astro.config.mjs:26-46`) depends on +- **No Cloudflare Access, no PostHog identity inheritance** — the prior art's + `cross_subdomain_cookie` PostHog 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). @@ -154,31 +147,29 @@ The compass adaptation: 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 `/**/*.md` glob (mirroring - sealed), and `build`/`check` depend on it inside the one required + check.** `gather`'s inputs are the repo-wide `/**/*.md` glob (mirroring the + prior art), and `build`/`check` depend on it inside the one required `moon ci :ci` gate — so moon's affected graph triggers a full gather + `astro build` + `astro check` on ANY PR touching ANY `*.md`, not just docs PRs (a one-line README fix blocks on a full corpus build). Same tradeoff - sealed accepts for its one-job gate (`ci.yml:20-22`); named here, not free. + the prior art accepts for its one-job gate; named here, not free. The narrow alternative — scope `gather` inputs to `docs/**/*.md` + the - contributing files — is rejected to keep parity with sealed's glob and avoid + 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` -sealed's preview UX, at source: Woodpecker's Petrel policy fans out +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` (`sealed/ci/pipeline.ts:554-563`), both `runInCI: false` moon -tasks running `bun scripts/deploy.ts` (`sealed/apps/docs/moon.yml:69-74`). -`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", `deploy.ts:62-79`) — runs -`wrangler pages deploy dist --project-name=… --branch=… --commit-dirty=true` -(`deploy.ts:82-94`), parses the preview URL from wrangler output -(`deploy.ts:101-104`), and upserts a marker-keyed PR comment with the preview -link + changed-page deep links via the gh CLI (`deploy.ts:41`, -`COMMENT_MARKER = ""`). +`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 = ""`). The compass version keeps `deploy.ts` (adapted) and swaps the driver from Woodpecker to a dedicated GHA workflow, `.github/workflows/eng-docs-deploy.yml`: @@ -189,15 +180,15 @@ Woodpecker to a dedicated GHA workflow, `.github/workflows/eng-docs-deploy.yml`: PRs have no secrets and must not attempt a deploy (Global Constraints). - **Not part of `moon ci :ci`**: the deploy is CD, needs `CLOUDFLARE_API_TOKEN`/`CLOUDFLARE_ACCOUNT_ID` secrets, and must not red - the hermetic gate — the same split sealed makes (`runInCI: false`, - `moon.yml:63-68`: "CD (runInCI:false): the Petrel policy … fans these out - only when affected and gates the event"). The workflow runs + 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 runs `moon run compass-eng-docs:build` then `bun scripts/deploy.ts` (or `moon run compass-eng-docs:deploy` via `moon exec`-equivalent; the task keeps `runInCI: false` so the CI gate never runs it). -- **Env adaptation**: `deploy.ts` reads Woodpecker `CI_*` vars - (`deploy.ts:21-31`: `CI_PIPELINE_EVENT`, `CI_COMMIT_SOURCE_BRANCH`, - `CI_COMMIT_SHA`, `CI_REPO`, `CI_COMMIT_PULL_REQUEST`, `GH_TOKEN`). The +- **Env adaptation**: the prior art's `deploy.ts` reads Woodpecker `CI_*` 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 from `github.event.pull_request.number`, the commit SHA from an EXPLICIT @@ -215,9 +206,9 @@ Woodpecker to a dedicated GHA workflow, `.github/workflows/eng-docs-deploy.yml`: Pages keys deployments by `--branch`: the production branch is the alias, any other branch yields a preview deployment with its own stable URL (; - same model sealed relies on, `deploy.ts:33-34`). `cloudflare/wrangler-action` - exists but adds nothing over invoking wrangler from `deploy.ts` as sealed - does — rejected to keep one deploy code path across both repos' docsites. + same model the prior art relies on). `cloudflare/wrangler-action` + exists but adds nothing over invoking wrangler from `deploy.ts` as 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): @@ -229,7 +220,7 @@ 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 sealed's `runInCI: false` split). +PRs; deploys are event-gated CD (mirrors the prior art's `runInCI: false` split). ### (c) Sanitization / rewrite policy — the four classes @@ -239,9 +230,9 @@ Repeatable rules applied by the migration task and binding on future records: 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" - (`sealed/docs/designs/product/DECISIONS.md:37`, DL-001), and the v0.3 + (DL-001), and the v0.3 design record's §4.3 opens "Warden is the always-on security auditor" - (`sealed/docs/designs/product/compass.md:85-87` — the design record, not + (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 @@ -252,7 +243,7 @@ Repeatable rules applied by the migration task and binding on future records: (`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 sealed artifact. + dropped) when the referent is a private artifact out of tree. 2. **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 @@ -264,7 +255,7 @@ Repeatable rules applied by the migration task and binding on future records: `RIG-1234` mentions are untouched. Public readers see an opaque internal ticket ID — honest and harmless. 3. **`oss/compass/**` path rewrite.** *Strip the prefix.* 19 records cite - `oss/compass/` paths from sealed's vendored era; the public repo's + `oss/compass/` 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`) is `go/internal/runtime/image.go` @@ -285,15 +276,15 @@ Repeatable rules applied by the migration task and binding on future records: ### (d) Migration timing -Compass-record design PRs may be in flight in sealed against the old convention +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 sealed `main` at -branch-cut — no wave-1/wave-2 split. An individual sealed design PR still open -when the migration branch cuts is reconciled into that one PR rather than -deferred: the executor either lands it in sealed first and includes the merged +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 @@ -307,15 +298,15 @@ Q1–Q5 are all RULED (see Open Questions); T6 is dropped per Q5. ### T1 — Site scaffold + moon registration -Create `apps/eng-docs/` mirroring sealed's app shape, minus Access/PostHog, +Create `apps/eng-docs/` mirroring the prior art's app shape, minus Access/PostHog, and register the project. Interfaces: -- Consumes: `sealed/apps/docs/{astro.config.mjs,package.json,moon.yml,tsconfig.json,src/styles/custom.css,src/content.config.ts,.gitignore,public/favicon.svg}` as templates (read from the sealed clone; do not import at build time). +- 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` — `site` set per Q4's ruling (placeholder `https://compass-eng-docs.pages.dev` until the domain lands), `starlight({ title: "Compass Engineering Docs", pagefind: true, sidebar, editLink: {}, lastUpdated: true, tableOfContents: {...}, expressiveCode: {...} })`; NO `head` PostHog block, NO Access assumptions. - - `apps/eng-docs/package.json` — name `@compass/eng-docs`, scripts `{ gather, dev, build, preview, check }` as sealed's (`sealed/apps/docs/package.json:6-12`); deps `astro`, `@astrojs/starlight`, `@astrojs/check`, `github-slugger`, `sharp` via `catalog:` entries added to the root `package.json` `workspaces.catalog`. + - `apps/eng-docs/package.json` — name `@compass/eng-docs`, scripts `{ gather, dev, build, preview, check }` as the prior art's; deps `astro`, `@astrojs/starlight`, `@astrojs/check`, `github-slugger`, `sharp` via `catalog:` entries added to the root `package.json` `workspaces.catalog`. - `apps/eng-docs/moon.yml` — tasks `gather` (command `bun 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 a `ci` task depending on `['build', 'check']` so the project joins `moon ci :ci`. - `.moon/workspace.yml` — add `compass-eng-docs: 'apps/eng-docs'` under `projects`, same change (per `workspace.yml:41-47`'s silent-inert warning). - `apps/eng-docs/.gitignore` — `src/content/docs/`, `src/sidebar.generated.ts`, `dist/`, `.astro/`. @@ -327,13 +318,13 @@ Port `gather.ts` + `gather.test.ts` with the compass taxonomy. Interfaces: -- Consumes: `sealed/apps/docs/scripts/gather.ts` (491 lines) + `gather.test.ts` as the port source. +- Consumes: the prior art's `gather.ts` (491 lines) + `gather.test.ts` as the port source. - Produces: `apps/eng-docs/scripts/gather.ts` with: - - `const REPO_SLUG = "RigelBuild/compass"` (editUrl base, mirrors `sealed gather.ts:25,203-205`). - - `const DOMAINS = ["designs", "specs", "architecture"] as const` (replaces sealed's `["designs","specs","research","team"]`, `gather.ts:31`). - - `SECTIONS` in sidebar order: Designs, Specs, Architecture, Packages, Contributing (drops sealed's Research/Team/Infra, `gather.ts:43-51`). - - `packagePath` drops the `oss` arm (`sealed gather.ts:78`, keep the `apps` two-segment case). - - `parseExclusions` returns `[...ignores, "**/outputs/**"]` (drops `"oss/seal/**"`, `sealed gather.ts:131-137`); ignores read from `compass/.markdownlint-cli2.jsonc` (currently `["forks/*/**"]`). + - `const REPO_SLUG = "RigelBuild/compass"` (editUrl base, mirrors the prior art's `gather.ts`). + - `const DOMAINS = ["designs", "specs", "architecture"] as const` (replaces the prior art's `["designs","specs","research","team"]`). + - `SECTIONS` in sidebar order: Designs, Specs, Architecture, Packages, Contributing (drops the prior art's Research/Team/Infra). + - `packagePath` drops the `oss` arm (present in the prior art's `gather.ts`; keep the `apps` two-segment case). + - `parseExclusions` returns `[...ignores, "**/outputs/**"]` (drops `"oss/seal/**"` from the prior art's list); ignores read from `compass/.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 of `docs/designs/repo/x.md`, `go/README.md` → packages, exclusion of `forks/oh-my-pi/**`). @@ -345,11 +336,11 @@ Port `deploy.ts` to GHA env vars; add the CD workflow. Interfaces: -- Consumes: `sealed/apps/docs/scripts/deploy.ts` (495 lines) + `deploy.test.ts` as the port source; Cloudflare Direct Upload docs (cited in Approach (b)). +- Consumes: the prior art's `deploy.ts` (495 lines) + `deploy.test.ts` as the port source; Cloudflare Direct Upload docs (cited in Approach (b)). - Produces: `apps/eng-docs/scripts/deploy.ts` with: - `const PROJECT_NAME = "compass-eng-docs"` (Q4), `COMMENT_MARKER = ""`, `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 Woodpecker `CI_*` set (`sealed deploy.ts:21-31`). The recorded commit SHA is `PR_HEAD_SHA` on PRs (= `github.event.pull_request.head.sha`) and `GITHUB_SHA` on push; never `GITHUB_SHA` on 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 on `GITHUB_HEAD_REF` (`sealed deploy.ts:68-79`); `wranglerArgs`, `parsePreviewUrl`, `commentBody`, `changedDocPages`, escape/encode helpers port unchanged. + - `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 Woodpecker `CI_*` set (from the prior art's `deploy.ts`). The recorded commit SHA is `PR_HEAD_SHA` on PRs (= `github.event.pull_request.head.sha`) and `GITHUB_SHA` on push; never `GITHUB_SHA` on 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 on `GITHUB_HEAD_REF` (per the prior art's `deploy.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 }}` with `cancel-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 `.prototools` pins (reuse `ci.yml`'s pin-reading step, `ci.yml:154-196`), `moon run compass-eng-docs:build`, then `bun scripts/deploy.ts` with `env: { 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 }} }`. @@ -363,50 +354,50 @@ checklist for future records. Interfaces: -- Consumes: the sealed corpus enumerated this session — the 38 product design records (37 matching `sealed/docs/designs/product/compass-*` plus `sealed/docs/designs/product/compass.md`, the v0.3 base record whose name has no hyphen and so is not matched by the `compass-*` glob), `sealed/docs/designs/platform/compass-dogfood-loop/design.md`, `sealed/docs/specs/product/compass.md`, `sealed/docs/specs/product/README.md`. +- Consumes: the out-of-tree corpus enumerated this session — the 38 product design records (37 matching `docs/designs/product/compass-*` plus `docs/designs/product/compass.md`, the v0.3 base record whose name has no hyphen and so is not matched by the `compass-*` 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-](https://linear.app/…)` and the reference-definition `[SEA-]: https://linear.app/…` forms → `SEA-`; (2) `oss/compass/` prefix strip in paths/links/code spans; (3) link-to-private-record conversion for `seal-*.md` targets → 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 root `CONTRIBUTING.md`) stating the four rules as the standing policy for records authored here. - Test cycle: `bun test tools/docs-migrate` over 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): zero `linear.app` matches, zero `oss/compass` matches under `docs/designs/**` + `docs/specs/**`; `markdownlint-cli2` clean. -### T5 — Full-corpus migration + sealed-side removal (Q1/Q2/Q5 ruled) +### 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 sealed. compass is the source of truth going forward (Q2), so -design review continues here, not in sealed. +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 sealed `main` at - branch-cut — the 38 product design records, - `compass-dogfood-loop/design.md`, and both product specs. Any sealed design - PR still open at migration time is reconciled to compass rather than split - into a later wave (executor sequences: merge-in-sealed-first then migrate, or - re-target the PR to compass — both keep the corpus whole); the +- Consumes: T4's script output over the full corpus at the out-of-tree `main` + at 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/` — a sealed-monorepo domain — does not + product-process design; `platform/` — an out-of-tree domain — does not exist in compass, and repo-tooling records like THIS one live under `docs/designs/repo/`), `docs/specs/product/{compass.md,README.md}`, plus (Q1 ruled MOVE) `docs/designs/product/DECISIONS.md` + `tools/design-ledger-gate/**` (ported; - `PRODUCT_DIR` stays `docs/designs/product`, `index.ts:45`) + a + the gate's `PRODUCT_DIR` constant stays `docs/designs/product`) + a `design-ledger-gate` moon project registered in `.moon/workspace.yml` with a `ci` task. -- Produces (sealed PR, sequenced after the compass PR merges): delete the - migrated trees; leave `sealed/docs/designs/product/README.md` pointing at the - public repo; sealed's residual ledger keeps the seal-product rows - DL-045/DL-046 (Q1); sealed's gather needs no change (deleted files simply - stop being gathered). +- Produces (out-of-tree PR, sequenced after the compass PR merges): delete the + migrated trees; leave the out-of-tree `docs/designs/product/README.md` + pointing 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 :ci` green (docsite builds the full corpus; ledger gate green after the move); site renders the ledger and both spec - pages; sealed `moon run docs-site:build` green post-removal; + pages; the out-of-tree `moon run docs-site:build` green post-removal; `tools/docs-migrate/` deleted after the one-shot run. ### 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 sealed +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. @@ -415,12 +406,12 @@ Consumes), not deferred to a later wave. Interfaces: - Consumes: Q4 ruling (below) — project `compass-eng-docs`, custom domain - `eng.compass.rigel.build`, provisioned via sealed's Pulumi IaC lane. -- Produces: the `compass-eng-docs` Pages project via sealed's Pulumi IaC (sealed - precedent: the docsite got "its OWN Pages:Edit-scoped token once RIG-1119 - provisions the project", `sealed/ci/pipeline.ts:334-336`); repo secrets - `CLOUDFLARE_API_TOKEN` (Pages:Edit-scoped, least-privilege per - `pipeline.ts:321-324`) + `CLOUDFLARE_ACCOUNT_ID` on `RigelBuild/compass`; + `eng.compass.rigel.build`, provisioned via the fleet's Pulumi IaC lane. +- Produces: the `compass-eng-docs` Pages 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 secrets `CLOUDFLARE_API_TOKEN` + (Pages:Edit-scoped, least-privilege per the prior art) + `CLOUDFLARE_ACCOUNT_ID` + on `RigelBuild/compass`; production branch set to `main`. 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. @@ -431,7 +422,7 @@ Interfaces: - [ ] T2 — `gather.ts`/`gather.test.ts` ported to the compass taxonomy; this record renders. - [ ] T3 — `deploy.ts` on GHA env + `.github/workflows/eng-docs-deploy.yml` with the fork guard. - [ ] T4 — sanitization migration script + standing policy doc (Q3 ruled; classes final). -- [ ] T5 — full-corpus migration (all records, one PR) + sealed-side removal; ledger + ledger-gate moved to compass (Q1/Q2/Q5 ruled). +- [ ] 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). @@ -441,14 +432,13 @@ 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 in sealed?** The ledger is Compass-titled and - Compass-governed ("Compass design-decision ledger", - `sealed/docs/designs/product/DECISIONS.md:1`) and the gate hardcodes - `PRODUCT_DIR = "docs/designs/product"` - (`sealed/tools/design-ledger-gate/index.ts:45`), so it follows the corpus. + 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 its + `design-ledger-gate` tool), 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, `DECISIONS.md:197-198`) stay behind in a small sealed-side residual + DL-046) stay behind in a small out-of-tree residual ledger next to the seal records they cite. `gather.ts` is 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 @@ -460,22 +450,22 @@ earlier. T5 and T7 execute against these rulings; T6 is dropped (Q5). 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 sealed?** **RULED (Matt): SOURCE OF + 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 sealed (T5 deletes the sealed - trees): several ACTIVE non-compass sealed records cite INTO the compass + 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.md` at ~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 sealed's own `gather.ts` renders no 404 — only the human/agent + zero), so the out-of-tree `gather.ts` renders 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 sealed-side + and record name in the prose still name the target) plus the out-of-tree `README.md` pointer T5 already leaves at `docs/designs/product/`; a per-file pointer stub is not worth the churn. - **Q3 — Warden/Cotal cross-product references: hold-and-omit vs @@ -493,23 +483,23 @@ earlier. T5 and T7 execute against these rulings; T6 is dropped (Q5). 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 (sealed's pipeline knows only - `sealed-docs` + the marketing site, `sealed/ci/pipeline.ts:333-343`). + 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-docs` project + a - Pages:Edit-scoped token via sealed's existing Pulumi IaC lane (the RIG-1119 - precedent, `pipeline.ts:334-336`), production branch `main`; custom domain + Pages:Edit-scoped token via the fleet's existing Pulumi IaC lane (the RIG-1119 + precedent), production branch `main`; custom domain `eng.compass.rigel.build` (Matt ruled). The `docs.compass` naming and `docs.compass.rigel.build` domain are deliberately RESERVED for the future user-facing product docsite (a separate site), so this engineering docs site takes the `eng.` subdomain. Until the domain lands the site ships - on `compass-eng-docs.pages.dev`. Analytics (PostHog snippet, minus sealed's + on `compass-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 sealed design PR still open at migration time - is reconciled to compass by T5 (merge-in-sealed-first then migrate, or + 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. diff --git a/docs/designs/server/compass-mention-offline-redelivery-pre-settle-closure.md b/docs/designs/server/compass-mention-offline-redelivery-pre-settle-closure.md index dd397dd28..b8a191ee5 100644 --- a/docs/designs/server/compass-mention-offline-redelivery-pre-settle-closure.md +++ b/docs/designs/server/compass-mention-offline-redelivery-pre-settle-closure.md @@ -5,7 +5,7 @@ Status: Draft Tracker: RIG-2490. Sibling follow-up to: `compass-mention-offline-redelivery.md` (RIG-1641) — per -the sealed frozen-record convention this record ADDS a sibling; the merged +the frozen-record convention this record ADDS a sibling; the merged RIG-1641 record is never edited in place. All file+line grounding below was verified against the working tree this run (jj workspace off main `48d4a7cd`). diff --git a/docs/designs/server/compass-mention-offline-redelivery.md b/docs/designs/server/compass-mention-offline-redelivery.md index 9361f90c1..3d6b36a93 100644 --- a/docs/designs/server/compass-mention-offline-redelivery.md +++ b/docs/designs/server/compass-mention-offline-redelivery.md @@ -15,7 +15,7 @@ of this record). DL-071/DL-073 stay Active — this record amends the frozen OQ-3 offline clause by citation, it does not reverse the steer-only precedence or the control-op shapes. -> **Amends `compass-notification-delivery` (frozen).** Per the sealed +> **Amends `compass-notification-delivery` (frozen).** Per the frozen-record > convention a later change ADDS a record (sibling precedent: > `compass-sidebar-pins-unreachable-amendment`, > `compass-server-ownership-layer-amendment`); the frozen record is never diff --git a/docs/designs/server/compass-server-ownership-layer-amendment/design.md b/docs/designs/server/compass-server-ownership-layer-amendment/design.md index d8f42ebdf..3c0889ea4 100644 --- a/docs/designs/server/compass-server-ownership-layer-amendment/design.md +++ b/docs/designs/server/compass-server-ownership-layer-amendment/design.md @@ -5,7 +5,7 @@ Tracker: SEA > **Extends #995 (frozen).** This record is a sibling amendment to > `docs/designs/server/compass-server-ownership-layer/design.md` (merged in -> #995). The merged record is frozen; per sealed convention a later change ADDS +> #995). The merged record is frozen; per the frozen-record convention a later change ADDS > a record. This amendment reconciles #995's forge-shaped proto type family to > the single canonical `compass.v1` family frozen by > `docs/designs/server/compass-issue-model/design.md` (#1018). diff --git a/docs/designs/ui/compass-session-trace-diff.md b/docs/designs/ui/compass-session-trace-diff.md index 9567a604f..7d4cc886b 100644 --- a/docs/designs/ui/compass-session-trace-diff.md +++ b/docs/designs/ui/compass-session-trace-diff.md @@ -78,8 +78,8 @@ decisions, all three forks from the brief: use a diff library. `apps/ui/package.json:7-11` carries three runtime deps (`@compass/client`, `@tauri-apps/api`, `solid-js`); this adds one, `diff` (jsdiff) — verified resolvable from the workspace registry at -`9.0.0` (`bun pm view diff version`), so the offline-leaning workspace (sealed -monorepo, LAN registry) is not a blocker. jsdiff ships a battle-tested Myers +`9.0.0` (`bun pm view diff version`), so an offline-leaning workspace +(LAN registry) is not a blocker. jsdiff ships a battle-tested Myers O(ND) implementation: **linear space** (no `m×n` table), but O((m+n)·D) *time* in the edit distance D. The hand-rolled table's load-bearing risk was **memory** — `FileDiff` holds whole-file texts (`session-events.ts:22-27`) with diff --git a/docs/designs/ui/compass-sidebar-pins-unreachable-amendment/design.md b/docs/designs/ui/compass-sidebar-pins-unreachable-amendment/design.md index c8d60fc5e..12d863f6f 100644 --- a/docs/designs/ui/compass-sidebar-pins-unreachable-amendment/design.md +++ b/docs/designs/ui/compass-sidebar-pins-unreachable-amendment/design.md @@ -15,12 +15,12 @@ escape hatch is needed in the PR body. > **Amends `compass-sidebar-pins` (frozen).** This record is a sibling > amendment to `docs/designs/ui/compass-sidebar-pins/design.md` (RIG-1632, -> DL-096). The merged record is frozen; per sealed convention a later change +> DL-096). The merged record is frozen; per the frozen-record convention a later change > ADDS a record. This amendment supersedes the frozen record's §T2 > unresolvable-pin filtering and §T3 fluctuation-coercion clauses per Matt's > ruling of 2026-08-02 (PR #98's review medium). All file+line grounding below -> was verified against the working trees this run: the frozen record in the -> sealed repo, the shipped implementation in the compass repo +> was verified against the working trees this run: the frozen record out of +> tree, the shipped implementation in the compass repo > (`apps/ui/src/…`, post-merge #98). ## Problem / Intent diff --git a/docs/designs/ui/compass-ux-foundation/design.md b/docs/designs/ui/compass-ux-foundation/design.md index ae20224ce..4e860ee67 100644 --- a/docs/designs/ui/compass-ux-foundation/design.md +++ b/docs/designs/ui/compass-ux-foundation/design.md @@ -2,7 +2,7 @@ Status: Draft Linear: RIG-1663 -Supersedes: the pre-freeze draft of this record (sealed PR #1075; its +Supersedes: the pre-freeze draft of this record (an out-of-tree PR; its DL-114..122 block never shipped) That pre-freeze draft was authored against a *provisional* brand identity; the diff --git a/tools/agent-image-env-gate/env-check.ts b/tools/agent-image-env-gate/env-check.ts index 72a081a1f..583c29a2f 100644 --- a/tools/agent-image-env-gate/env-check.ts +++ b/tools/agent-image-env-gate/env-check.ts @@ -18,7 +18,7 @@ // the initialized nix DB — non-reproducible bloat and phantom DB entries. Two // such vars exist (`DEVENV_PROFILE`, a 266-path dev profile; `DEVENV_TASK_FILE`, // the tasks.json), each neutralized consumer-side in agent-image/devenv.nix -// (mkForce to a non-store placeholder, gated on isBuilding, as the internal monorepo ships it). +// (mkForce to a non-store placeholder, gated on isBuilding). // This gate is the regression backstop for that // neutralization, plus a build-host-home leak check that catches a builder path // baked into ANY key (a non-reproducible-across-hosts defect). Both invariants diff --git a/tools/design-ledger-gate/moon.yml b/tools/design-ledger-gate/moon.yml index 9355e8810..6ef131e62 100644 --- a/tools/design-ledger-gate/moon.yml +++ b/tools/design-ledger-gate/moon.yml @@ -8,11 +8,10 @@ # whole-repo tasks on the root project (/moon.yml), so this leaf has no own # bun.lock and never runs its own install. # -# Migrated from the sealed repo (RIG-1794): the Compass design corpus + ledger -# now live here, so the gate that governs them lives here too. Compass CI is a +# Compass CI is a # single moon-driven `CI` job (.github/workflows/ci.yml runs `moon run :ci`), # so the `ci` aggregate below is swept automatically — no separate meta.ts -# wiring (unlike sealed's Woodpecker pipeline). +# wiring (unlike the prior art's Woodpecker pipeline). layer: 'tool' language: 'typescript' tags: ['bun', 'ci-group.bun'] diff --git a/tools/orion-ref-gate/index.test.ts b/tools/orion-ref-gate/index.test.ts index a07406f62..e65f0881b 100644 --- a/tools/orion-ref-gate/index.test.ts +++ b/tools/orion-ref-gate/index.test.ts @@ -50,6 +50,44 @@ describe("lineHasToken — whole-word, case-insensitive", () => { }); }); +describe("lineHasToken — the former name, matched only in repo-shaped uses", () => { + test("a path inside the private repo is a reference", () => { + expect(lineHasToken("See `sealed/ci/pipeline.ts:554` for the job")).toBe( + true, + ); + }); + test("its possessive, docsite host, and repo-noun uses are references", () => { + expect(lineHasToken("following sealed's shape")).toBe(true); + expect(lineHasToken("deployed to sealed-docs.rigel.build")).toBe(true); + expect(lineHasToken("this record lives in the sealed design corpus")).toBe( + true, + ); + expect(lineHasToken("per sealed convention a later change ADDS")).toBe( + true, + ); + }); + // The word is ordinary English throughout go/: a whole-word scan flags 60 + // tracked lines, every one legitimate. These pin the narrowing that keeps + // the gate usable. + test("the English engineering word is not a reference", () => { + expect(lineHasToken("Frame is a sealed sum type")).toBe(false); + expect(lineHasToken("the row was sealed under a known key")).toBe(false); + expect(lineHasToken("an egress-sealed agent holds no server token")).toBe( + false, + ); + expect(lineHasToken("gochecksumtype for sealed-interface sum types")).toBe( + false, + ); + }); + test("genuinely public names carrying the string are not references", () => { + expect(lineHasToken("github.com/sealedsecurity/compass/go")).toBe(false); + expect(lineHasToken("Sealed Security Inc → Rigel AI Software Inc")).toBe( + false, + ); + expect(lineHasToken("ci.sealedsecurity.com")).toBe(false); + }); +}); + describe("isCarveOut", () => { test("the gate's own source is carved out", () => { expect(isCarveOut("tools/orion-ref-gate/index.ts")).toBe(true); diff --git a/tools/orion-ref-gate/index.ts b/tools/orion-ref-gate/index.ts index a77d181fa..742ee1693 100644 --- a/tools/orion-ref-gate/index.ts +++ b/tools/orion-ref-gate/index.ts @@ -43,9 +43,30 @@ import { $ } from "bun"; -/** The private monorepo's token. Whole-word, case-insensitive. */ +/** + * The private repo's current name. Whole-word, case-insensitive: a bare + * `orion` in this repo is always the private repo. + */ export const PRIVATE_TOKEN = "orion"; +/** + * The private repo's FORMER name, which imported records still carry. It + * cannot be scanned whole-word like the current one: `sealed` is also ordinary + * English this codebase uses constantly — a sealed sum type, a ciphertext + * sealed under a key, an egress-sealed agent. Measured over the tracked tree, + * a whole-word scan flags 60 lines, every one of them legitimate; a gate that + * is 100% false positives gets switched off. + * + * So match only the shapes that name the REPO: a path inside it, its docsite + * host, its possessive, or the word followed by a repo-ish noun. + */ +export const LEGACY_NAME_PATTERNS: readonly RegExp[] = [ + /\bsealed\/[a-z]/i, + /\bsealed-docs\b/i, + /\bsealed's\b/i, + /\bsealed (repo|monorepo|design corpus|platform|convention|PR #)/i, +]; + /** * Repo-relative path prefixes never scanned. A reference under one of these is * either a generated copy (eng-docs / bun.lock) or this gate's own description @@ -97,13 +118,15 @@ export function isCarveOut(path: string): boolean { } /** - * Whole-word, case-insensitive match for the private token in one line. The - * gate's own compound name (`orion-ref-gate`) is not a private-repo reference, - * so a bare `orion` immediately followed by `-ref-gate` does not count. + * Case-insensitive match for a private-repo reference in one line: the current + * name whole-word, or one of the former name's repo-shaped patterns. The + * gate's own compound name (`orion-ref-gate`) is not a reference, so a bare + * `orion` immediately followed by `-ref-gate` does not count. */ export function lineHasToken(text: string): boolean { const stripped = text.replace(/orion-ref-gate/gi, ""); - return new RegExp(`\\b${PRIVATE_TOKEN}\\b`, "i").test(stripped); + if (new RegExp(`\\b${PRIVATE_TOKEN}\\b`, "i").test(stripped)) return true; + return LEGACY_NAME_PATTERNS.some((re) => re.test(stripped)); } /** @@ -167,15 +190,20 @@ export async function runOnce(deps: Deps): Promise { } /** - * `git grep -nwI -i ` over tracked files. `git grep` exits 0 with - * matches, 1 on no match (a legitimately clean, empty result), and >=2 on a - * real error (e.g. not a git work tree). We must distinguish the last from the - * clean case: swallowing it would make the gate report clean on a broken scan — - * fail-OPEN, the exact false-green a fail-closed gate exists to stop. Exit >=2 - * throws, so runOnce's catch returns exit 2. + * `git grep -nEI` for either name over tracked files. The regex is a coarse + * pre-filter — `lineHasToken` makes the real decision, so this only has to be + * a superset of it. `sealed` is matched bare here and narrowed there. + * + * `git grep` exits 0 with matches, 1 on no match (a legitimately clean, empty + * result), and >=2 on a real error (e.g. not a git work tree). We must + * distinguish the last from the clean case: swallowing it would make the gate + * report clean on a broken scan — fail-OPEN, the exact false-green a + * fail-closed gate exists to stop. Exit >=2 throws, so runOnce's catch + * returns exit 2. */ async function gitGrep(): Promise { - const res = await $`git grep -nwiI ${PRIVATE_TOKEN}`.nothrow().quiet(); + const pattern = `\\b(${PRIVATE_TOKEN}|sealed)`; + const res = await $`git grep -nEiI ${pattern}`.nothrow().quiet(); if (res.exitCode >= 2) throw new Error( `git grep exited ${res.exitCode}: ${res.stderr.toString().trim()}`, diff --git a/tools/renovate-preflight/moon.yml b/tools/renovate-preflight/moon.yml index 9d728941f..af96eb42f 100644 --- a/tools/renovate-preflight/moon.yml +++ b/tools/renovate-preflight/moon.yml @@ -8,7 +8,7 @@ # affected graph — this project carries only the code + its unit gate. Compass # CI is a single moon-driven `CI` job (.github/workflows/ci.yml runs # `moon run :ci`), which sweeps the tasks below automatically — no separate -# meta.ts wiring (unlike the internal monorepo's CI/CD pipeline). install/lint/format +# meta.ts wiring (unlike the prior art's CI/CD pipeline). install/lint/format # inherited via the `bun` tag (.moon/tasks/tag-bun.yml). layer: 'tool' language: 'typescript' diff --git a/tools/renovate/bot-config.json5 b/tools/renovate/bot-config.json5 index e19bda76c..b35b0112f 100644 --- a/tools/renovate/bot-config.json5 +++ b/tools/renovate/bot-config.json5 @@ -28,7 +28,7 @@ // NOT pinned here: Renovate autodetects it from the per-run installation // token, so an explicit value could only ever be a stale or malformed copy of // what the token already carries. Omitting gitAuthor is the correct App-auth - // posture (unlike the internal monorepo, which authenticates as a bot USER via a PAT and so + // posture (unlike the prior art, which authenticates as a bot USER via a PAT and so // must name that user). One consequence: this drops the App-slug paste-back // step from the RIG-2432 provisioning runbook — nothing to fill in post-registration. onboarding: false, // config already committed; no onboarding PR diff --git a/tools/renovate/config.json5 b/tools/renovate/config.json5 index cceb7dd2a..4e44621f7 100644 --- a/tools/renovate/config.json5 +++ b/tools/renovate/config.json5 @@ -62,9 +62,9 @@ labels: ["dependencies"], // Explicit allowlist for the current stack. `github-actions` is present here - // (unlike the internal monorepo, whose meta jobs moved off GHA): compass runs all CI on GitHub + // (unlike the prior art, whose meta jobs moved off GHA): compass runs all CI on GitHub // Actions and keeps every workflow `uses:` SHA-pinned — see the github-actions - // manager rationale below. Dropped vs the internal monorepo: `cargo`/`rust-toolchain` (no Rust), + // manager rationale below. Dropped because compass has none: `cargo`/`rust-toolchain` (no Rust), // `woodpecker` (no Woodpecker), and `nix`. Compass now DOES carry a root // flake (flake.nix/flake.lock, added for the distribution flake + gtk4/OTel // work), but the nix manager stays off deliberately: the flake's nixpkgs is @@ -356,7 +356,7 @@ // (`{ version = "1.26.6"; }`, version-only — hashes come from go-overlay) and // DERIVES the `go_X_Y_Z` overlay attr name in devenv.nix:30-31 via // lib.replaceStrings. So devenv.nix contains no literal `go_X_Y_Z` string to - // regex (the internal monorepo tracked devenv.nix; compass tracks go.nix instead). The + // regex (the prior art tracked devenv.nix; compass tracks go.nix instead). The // version is dotted in go.nix, so there is NO dots↔underscores gymnastics — // capture it straight for the golang-version datasource, and devenv.nix picks // it up automatically at eval time. A go bump rewrites go.nix and no hash @@ -458,7 +458,7 @@ // Un-group them so each language pin opens its OWN branch and PR. Because // compass's go manager now ALSO targets a file under this glob // (tools/toolchain/versions/go.nix), this one rule un-groups all four pins — - // the internal monorepo's separate go un-group rule (its go lived in devenv.nix, off-glob) is + // the prior art's separate go un-group rule (its go lived in devenv.nix, off-glob) is // NOT needed here. matchFileNames: ["tools/toolchain/versions/*.nix"], groupName: null, @@ -638,7 +638,7 @@ matchDepNames: ["cachix/devenv-nixpkgs"], groupName: "devenv nixpkgs channel", // DAILY, aligned to the same before-4am-ET window the daily cron lands in - // (see `timezone` above). This is a deliberate compass divergence from the internal monorepo, + // (see `timezone` above). This is a deliberate compass divergence from the prior art, // whose rule schedules weekly (`before 4am on monday`) to bound `rolling`'s // near-daily churn — Matt's ruling for compass: nixpkgs tracks daily too. schedule: ["before 4am"], diff --git a/tools/renovate/config.test.ts b/tools/renovate/config.test.ts index 40add9e94..f719f18d1 100644 --- a/tools/renovate/config.test.ts +++ b/tools/renovate/config.test.ts @@ -8,10 +8,9 @@ import config from "./config.json5"; // module does no I/O at import (main() is behind import.meta.main). import { FOD_ENTRIES } from "./refresh-fod-hashes.ts"; -// Guard suite for compass's self-hosted Renovate config (RIG-2432). Ported from -// the internal monorepo's config.test.ts and adapted to compass's config + -// ecosystems (bun catalog, devenv-nixpkgs channel, toolchain pins, gomod, GitHub -// Actions; no rust/pulumi/woodpecker). The .json5 configs load via Bun's loader. +// Guard suite for compass's self-hosted Renovate config (RIG-2432). Covers compass's +// config + ecosystems (bun catalog, devenv-nixpkgs channel, toolchain pins, gomod, +// GitHub Actions; no rust/pulumi/woodpecker). The .json5 configs load via Bun's loader. type PostUpgradeTasks = { commands?: string[]; @@ -503,7 +502,8 @@ describe("tools/renovate devenv nixpkgs lockstep", () => { // Branch-mode lockstep task over the files the script writes: devenv.lock + // package.json (biome catalog) + bun.lock (steps 2/4/5), flake.nix + flake.lock - // (step 6), and agent-image/entrypoint.nix (the FOD outputHash). + // (step 6), and agent-image/entrypoint.nix (the FOD outputHash). compass has + // NO committed inner-rev guard file. // The FOD refresh is required: a channel bump moves pkgs.bun (the FOD builder) // and, when the biome pin moves, re-resolves the bun.lock closure — either can diff --git a/tools/renovate/moon.yml b/tools/renovate/moon.yml index 15ed86d6f..58485ee50 100644 --- a/tools/renovate/moon.yml +++ b/tools/renovate/moon.yml @@ -1,7 +1,7 @@ # yaml-language-server: $schema=https://moonrepo.dev/schemas/project.json # # renovate (RIG-2432) — self-hosted Renovate config + lockstep postUpgradeTask -# scripts for compass, ported from the internal monorepo's renovate config. A bun/TypeScript +# scripts for compass. A bun/TypeScript # package; a hoisted root-workspace member (`bun` tag): install is inherited via # .moon/tasks/tag-bun.yml (the shared root install) and lint/format are whole-repo # tasks on the root project (/moon.yml), so this leaf has no own bun.lock and diff --git a/tools/renovate/package.json b/tools/renovate/package.json index a25468302..811a2e8f2 100644 --- a/tools/renovate/package.json +++ b/tools/renovate/package.json @@ -2,7 +2,7 @@ "name": "@compass/renovate", "private": true, "type": "module", - "description": "Self-hosted Renovate config + lockstep postUpgradeTask scripts for compass (RIG-2432): repo config, bot config, toolchain-hash + devenv-nixpkgs relock scripts, and the config guard suite. Ported from the internal monorepo's renovate config, adapted to compass's tools/* layout, ecosystems, and GitHub Actions runner.", + "description": "Self-hosted Renovate config + lockstep postUpgradeTask scripts for compass (RIG-2432): repo config, bot config, toolchain-hash + devenv-nixpkgs relock scripts, and the config guard suite.", "module": "config.json5", "devDependencies": { "@types/bun": "catalog:", diff --git a/tools/renovate/refresh-toolchain-hashes.test.ts b/tools/renovate/refresh-toolchain-hashes.test.ts index f0fcbd498..3679198e1 100644 --- a/tools/renovate/refresh-toolchain-hashes.test.ts +++ b/tools/renovate/refresh-toolchain-hashes.test.ts @@ -6,8 +6,7 @@ import { dirname, join } from "node:path"; import { $ } from "bun"; import { readVersion, rewriteHash } from "./refresh-toolchain-hashes.ts"; -// Regression test for tools/renovate/refresh-toolchain-hashes.ts (RIG-2432, -// ported from the internal monorepo's test). +// Regression test for tools/renovate/refresh-toolchain-hashes.ts (RIG-2432). // // The bug this guards against: the script's path constants are all // repo-root-relative (the pin files), but the gate `git diff --quiet "$base_ref" diff --git a/tools/renovate/refresh-toolchain-hashes.ts b/tools/renovate/refresh-toolchain-hashes.ts index 300d6a19f..6692c89a3 100755 --- a/tools/renovate/refresh-toolchain-hashes.ts +++ b/tools/renovate/refresh-toolchain-hashes.ts @@ -13,9 +13,9 @@ // bump re-prefetches bun.nix alone. Requires nix (nix-command) on PATH, provided // by the runner; run via bun. -// bun/TypeScript port of the internal monorepo's refresh-toolchain-hashes -// (RIG-2432), scoped to compass's three vendored binary toolchains. Every -// observable behaviour is preserved 1:1. +// Scoped to compass's three vendored binary toolchains (bun, node, moon). A +// per-file self-gate, per-leg hash refresh that fails loud on a missing marker / +// hash line, and idempotence. import { $ } from "bun"; From 80f2103fa04b5aa8dc82aebf6b14a16717d80048 Mon Sep 17 00:00:00 2001 From: mintaka Date: Sun, 13 Sep 2026 16:06:36 -0400 Subject: [PATCH 2/6] docs(ledger): correct the DL-241 forge toolset count to twelve (RIG-3774) DL-241 recorded ten tools and enumerated ten; createForgeTools ships twelve. The transition pair (forge_transition_issue_state, forge_transition_pull_request_state) arrived with DL-342 / RIG-3331 and the row was never refreshed. The row's own closing line makes the count load-bearing for future toolset-refresh rows, so a refresh diffing against 'ten' would start from a wrong base. Amended in place per Matt. Also retires the row's ratified subscribe caveat: both arms persist now (EnsureAgentForgeSubscription / DeleteAgentForgeSubscription), so they are no longer CodeUnimplemented stubs. The stale caveat was also shipping to agents at runtime. SUBSCRIBE_RULE told every model the subscribe calls 'return unimplemented' and 'should not be relied on yet', steering agents off a working feature; it now describes what a subscription does. Record tasks T1/T2 are checked, its counts and the ForgeCallRequest arm range (2-11 plus 14-15) corrected. Co-authored-by: Matt Wilkinson --- docs/designs/DECISIONS.md | 2 +- .../agent/compass-agent-forge-tools/design.md | 47 +++++++++++-------- packages/compass-agent/src/forge.ts | 4 +- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/docs/designs/DECISIONS.md b/docs/designs/DECISIONS.md index 75dfd6ca4..3a38eb287 100644 --- a/docs/designs/DECISIONS.md +++ b/docs/designs/DECISIONS.md @@ -220,7 +220,7 @@ check enforces the mechanical half. Full rationale: | DL-210 | Forge integration testing adds two live-contract tiers above the DL-174 hermetic pyramid: (1) a hermetic golden-fixture replay leg (committed `go/internal/forge/testdata/` fixtures replayed through the stub RoundTripper, an untagged Go test riding moon affected-detection on every forge-affected PR + the main/nightly sweep, no `ci.yml` project enumeration) and (2) a `//go:build livegithub` live-credentials oracle (same scenarios against a throwaway `RigelBuild/compass-forge-testbed` + a Linear test team under test-only bot PATs ≠ the `server_only` production secrets), REQUIRED on forge-affected PRs + nightly, covering GitHub and Linear co-equally (the GitHub-only F1 reviewer≠author 422→APPROVE headline; Linear's PR/review family is `ErrUnsupported`, not a scenario). This is a NEW secret-bearing per-PR CI step — a standalone decision, NOT an amendment: D2's full-stack deterministic tier (`compass-dogfood-e2e/design.md:815-830`) stays secret-free and unchanged; a forward pointer next to D2 records the carve-out. Fork-PR secret safety: the same-repo-head-guarded step goes vacuously green on fork heads (GitHub withholds secrets there); accepted, with the push-to-main run + a maintainer same-repo re-push convention as the catch (0 forks today) | Active (Matt, 2026-08-18) | [forge integration testing §Approach](server/compass-forge-integration-testing/design.md#approach) | | DL-226 | A message owed to an OFFLINE channel agent member is never silently stranded: the server wakes the member by RESUMING its most recent session (a system-authorized internal sibling of the public resume path, via a new `LatestSessionForAccount` read; fresh start only for a never-started agent; per-agent singleflight + not-live pre-check as cost control — agent-triggered starts are a core product capability, and `StartAgentSession`'s adminOnly PUBLIC door is untouched). Durability split: a mentioned member outside the sweep set (unsubscribed, non-home, non-mandatory) gets a durable owed-mention row `(agent_account_id, message_id)` written at the settle edge before the wake and swept subscription-independently on session start AS A STEER (D5 mention→steer preserved; steer-only precedence intact), cleared on the frozen message_id ack; a subscribed/home/mandatory member gets no owed row — the D2 cursor sweep is its durable backstop and the wake (both the mention arm and the plain-deliver arm) is pure latency. Broadcast mentions (`@everyone`/`@agents`) wake too; N-start amplification accepted. The residual pre-settle window is accepted for MVP (RIG-2490). Amends D5/OQ-3's offline clause by citation | Active (Matt, 2026-08-21); residual pre-settle window closed by DL-240 (RIG-2490, 2026-08-23) | [mention offline redelivery §Decisions](server/compass-mention-offline-redelivery.md#decisions-ruled-by-matt-2026-08-21) | | DL-240 | The RIG-1641 OQ-5 residual pre-settle mention-loss window (a mention to an offline out-of-sweep-set member, lost when a crash or bus overrun drops `MessagePosted` before the settle-edge `routeMentions` pass) is closed by a per-message delivery marker, NOT a high-water cursor: a nullable `messages.mentions_routed_at BIGINT` (unix ms) set by the consumer after the settle-edge pass, with a recovery scan at consumer start + the `Lagged()` overrun re-subscribe reading `WHERE mentions_routed_at IS NULL` (skipping message_ids in `c.held`), replaying the ONE shared `routeMentions` body, then marking. The killed cursor could advance past a LOWER in-flight seq (`messages.seq` is `BIGSERIAL` assigned at INSERT but the bus event publishes post-commit, `comms.go:361-375`) whose crash-dropped event then stranded the mention forever — a new silent loss the marker cannot express. Seed-forward on first deploy (no historical backfill; compass pre-live). Extends DL-226's no-loss invariant from the settle edge back to the message-post commit; DL-226's wake+owed-mention mechanism is unchanged | Active (Matt, 2026-08-23) | [mention offline pre-settle closure §Resolved decisions](server/compass-mention-offline-redelivery-pre-settle-closure.md#resolved-decisions) | -| DL-241 | The agent forge native toolset is ten single-purpose tools, one per `ForgeCallRequest` arm (`forge_get_issue`, `forge_get_pull_request`, `forge_list_issues`, `forge_comment_on_issue`, `forge_comment_on_pull_request`, `forge_submit_review`, `forge_create_issue`, `forge_create_pull_request`, `forge_subscribe`, `forge_unsubscribe`), each a native `AgentTool` over a thin `ForgeBroker` on the `RunnerTransport.forge()` seam; `forge_subscribe`/`forge_unsubscribe` ship the complete surface now but return the server's in-band `unimplemented` until the poll-driver lane lands the `agent_forge_subscriptions` writer (DL-163). Multi-forge is exposed: every tool takes an optional forge selector (`forge_provider` + optional `forge_host`, unset = the configured default GitHub forge, DL-202) so an agent targets Linear (issues-only, `repo` = team key, DL-051; PR/review arms return in-band `unimplemented`) as well as GitHub. Mirrors DL-212's comms-toolset count row; the tool-count claim is load-bearing for future toolset-refresh rows | Active (Matt, 2026-08-24) | [forge tools §Tool set and shape](agent/compass-agent-forge-tools/design.md#tool-set-and-shape--ten-native-tools-one-per-arm) | +| DL-241 | The agent forge native toolset is twelve single-purpose tools, one per `ForgeCallRequest` arm (`forge_get_issue`, `forge_get_pull_request`, `forge_list_issues`, `forge_comment_on_issue`, `forge_comment_on_pull_request`, `forge_submit_review`, `forge_create_issue`, `forge_create_pull_request`, `forge_transition_issue_state`, `forge_transition_pull_request_state`, `forge_subscribe`, `forge_unsubscribe`), each a native `AgentTool` over a thin `ForgeBroker` on the `RunnerTransport.forge()` seam. Multi-forge is exposed: every tool takes an optional forge selector (`forge_provider` + optional `forge_host`, unset = the configured default GitHub forge, DL-202) so an agent targets Linear (issues-only, `repo` = team key, DL-051; PR/review arms return in-band `unimplemented`) as well as GitHub. Mirrors DL-212's comms-toolset count row; the tool-count claim is load-bearing for future toolset-refresh rows. Amended 2026-09-13: the count was ten at ratification; the transition pair arrived with DL-342 (RIG-3331) and the original row was not refreshed. The ratified caveat that `forge_subscribe`/`forge_unsubscribe` return in-band `unimplemented` until the DL-163 writer lands is also retired — both arms persist (`EnsureAgentForgeSubscription` / `DeleteAgentForgeSubscription`) and `forge_subscribe` returns a real subscription id | Active (Matt, 2026-08-24; amended Matt, 2026-09-13) | [forge tools §Tool set and shape](agent/compass-agent-forge-tools/design.md#tool-set-and-shape--twelve-native-tools-one-per-arm) | | DL-291 | Agents and client UIs address channels and topics by NAME, not id — request-input channel/topic fields on the agent tool surface are name-typed, resolved viewer-scoped at the service edge (`ChannelByNameForViewer`: miss ≡ invisible ≡ merged `not_found`; a multi-hit errors `invalid_argument`, never auto-picks); response/stored/event fields stay id-typed. Extends DL-269/DL-270 from accounts to channels + topics. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](agent/compass-agent-peer-dm/design.md#ledger-delta) | | DL-292 | Steer/deliver control ops denormalize the source channel name + topic name (server-resolved at wrap in `deliverOp`/`steerOp`, the `from_handle` pattern; a name-resolve miss degrades like a handle miss, never blocks delivery); the agent renders `Channel › topic :` and must name both on every post — `comms_post_message` has NO home-channel default and never auto-picks a reply target. The dogfood reply-mis-routing fix (RIG-2956 T0). Proto: `DeliverControl.channel_name = 5`, `SteerControl.topic_name = 4`/`channel_name = 5`. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](agent/compass-agent-peer-dm/design.md#ledger-delta) | | DL-293 | Creating a topic requires `create_topic: true` on the post, in every channel including DMs (`PostMessageRequest.create_topic = 6`; `TopicRef.Create` gates the store name path) — amends DL-098's topic get-or-create clause (the Zulip threading model stays live; only auto-mint-on-miss is gated). A gated miss errors in-band `not_found`, never mints and never drops the message. Escape hatch (Matt): may revert for DMs only if it proves a blocker. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](agent/compass-agent-peer-dm/design.md#ledger-delta) | diff --git a/docs/designs/agent/compass-agent-forge-tools/design.md b/docs/designs/agent/compass-agent-forge-tools/design.md index c88113ed3..fa1256ce3 100644 --- a/docs/designs/agent/compass-agent-forge-tools/design.md +++ b/docs/designs/agent/compass-agent-forge-tools/design.md @@ -4,7 +4,7 @@ Status: Active Design for the TypeScript agent-side leg of the forge surface: a `forge()` method on the frozen `RunnerTransport` seam plus a native tool set (`forge.ts`) -that exposes all ten `ForgeCallRequest` arms to the containerized first-party +that exposes all twelve `ForgeCallRequest` arms to the containerized first-party agent, one tool per arm (the two subscription arms ship now but return the server's in-band `unimplemented` until the `agent_forge_subscriptions` store writer lands), with a @@ -49,7 +49,7 @@ But the agent cannot reach any of it: `RunnerTransport` (`packages/compass-agent/src/transport/index.ts`) exposes `comms()` and `lifecycle()` and no `forge()`, and no `forge.ts` exists (comms ships five tools, lifecycle two, forge zero). This record designs the missing TS leg — -the transport method, the `ForgeBroker`, the ten native tools (the two +the transport method, the `ForgeBroker`, the twelve native tools (the two subscription tools built now over the stub arms) with their multi-forge selector and per-tool prompt guidance, and the `cli.ts` wiring — and nothing else. @@ -58,7 +58,7 @@ else. ### Decisions (pre-resolved by Matt — not reopened below) -1. **Full surface: all ten `ForgeCallRequest` arms become tools.** Every arm +1. **Full surface: all twelve `ForgeCallRequest` arms become tools.** Every arm the wire carries ships as an agent tool in this record — the eight arms `ExecuteForgeCallAsAccount` dispatches for real PLUS `subscribe`/ `unsubscribe`. No partial MVP subset, no hidden arms. @@ -67,7 +67,9 @@ else. precedent. Names: `forge_get_issue`, `forge_get_pull_request`, `forge_comment_on_issue`, `forge_comment_on_pull_request`, `forge_submit_review`, `forge_create_issue`, `forge_create_pull_request`, - `forge_list_issues`, `forge_subscribe`, `forge_unsubscribe`. + `forge_list_issues`, `forge_transition_issue_state`, + `forge_transition_pull_request_state`, `forge_subscribe`, + `forge_unsubscribe`. 3. **`forge_subscribe`/`forge_unsubscribe` ship NOW, returning the server's in-band `unimplemented` until the writer lands.** The backend arms are `CodeUnimplemented` stubs (`go/server/forge.go`) pending the @@ -79,6 +81,12 @@ else. `unimplemented`, with the per-tool guidance saying "not yet wired") until the writer lands, at which point they light up with no contract rework and no re-registration. + **Landed since (2026-09-13): the writer is in, so this caveat is spent.** + `subscribeForge` calls `store.EnsureAgentForgeSubscription` and returns a + real subscription id; `unsubscribeForge` calls + `store.DeleteAgentForgeSubscription` (both in `go/server/forge.go`). The + two arms are no longer `CodeUnimplemented`, and the per-tool "not yet + wired" guidance no longer describes them. 4. **V1 is multi-forge: the `ForgeRef` selector is exposed on every tool.** The wave needs GitHub AND Linear (it files Linear issues and opens GitHub PRs), and the substrate resolves a per-provider coordinate end to end @@ -118,7 +126,7 @@ else. - **The proto carrier and its generated TS types exist.** `proto/compass/v1/agent_gateway.proto` `rpc Forge(ForgeCallRequest) returns (ForgeCallResult)` on `AgentGateway`; `ForgeCallRequest` carries `call_id`, - the ten-arm `call` oneof (arms 2–11), an optional `ForgeRef forge` (unset = + the twelve-arm `call` oneof (arms 2–11 plus 14–15), an optional `ForgeRef forge` (unset = configured default GitHub forge, DL-202), and `client_request_id` (create arms only, DL-206). `ForgeCallResult` retypes the domain arms to canonical `compass.v1.Issue`/`PullRequest` (DL-069/DL-092) plus `CommentRef`/`ReviewRef` @@ -162,9 +170,9 @@ else. customTools→state.tools→`#withNatives` path. Forge adds one broker and one spread to that list. -### Tool set and shape — ten native tools, one per arm +### Tool set and shape — twelve native tools, one per arm -All ten tools live in one new `packages/compass-agent/src/forge.ts`, +All twelve tools live in one new `packages/compass-agent/src/forge.ts`, authored as OMP `AgentTool`s with arktype parameters, closing over a `ForgeBroker`. Approval levels follow the comms precedent (`comms.ts`: mutations `approval: "write"`, reads `approval: "read"`; the container runs @@ -509,7 +517,7 @@ returns its result; `idempotencyKey` is nonce-prefixed, stable per broker, distinct across brokers. `direnv exec . moon run compass-agent:test` red first, then green; biome clean. -### T2 — Agent: `createForgeTools` (ten tools) + `cli.ts` wiring + prompt guidance +### T2 — Agent: `createForgeTools` (twelve tools) + `cli.ts` wiring + prompt guidance In `packages/compass-agent/src/forge.ts` (same file, tool half): @@ -546,7 +554,7 @@ const forgeSelector = type({ }); // EVERY tool schema below also spreads `...forgeSelector` (elided in each body // for brevity — the eight non-subscription sketches show only their arm-specific -// fields). An implementer adds `...forgeSelector,` to all ten object literals. +// fields). An implementer adds `...forgeSelector,` to all twelve object literals. export const getIssueParameters = type({ repo: /* non-blank */ "Repository as / (GitHub) or team key (Linear)", issue_number: type("1 <= number.integer"), @@ -623,7 +631,7 @@ implementer must copy that bound, not the literal `/* non-blank */` comment. Every schema also spreads `...forgeSelector` (shown once above, elided in each body for brevity): the optional `forge_provider`/`forge_host` pair is on all -ten tools. When either is set, `execute` builds +twelve tools. When either is set, `execute` builds `create(ForgeRefSchema, { provider: , host: forge_host ?? "" })` and sets `ForgeCallRequest.forge`; when both are unset it leaves `forge` nil (the default-GitHub path). The string enum maps to the generated @@ -688,7 +696,7 @@ const nativeTools = [ is unchanged. **Interfaces:** `createForgeTools(broker: ForgeBroker): AgentTool[]`; the -ten exported parameter schemas above (the shared `forgeSelector` spread +twelve exported parameter schemas above (the shared `forgeSelector` spread into each); `function forgeFailure(result: ForgeCallResult, toolName: string, expected: string): Error` (module-private, mirroring `lifecycleFailure`, plus the `retry_after_ms` suffix). @@ -714,12 +722,12 @@ compass-agent:test` + `compass-agent:lint` green. ## Tasks -- [ ] T1 — Transport + broker: `forge()` member on `RunnerTransport` + +- [x] T1 — Transport + broker: `forge()` member on `RunnerTransport` + one-line `createUnixSocketTransport` delegation; `ForgeTransport` + `ForgeBroker` (nonce-scoped `idempotencyKey`) in new `forge.ts`; `compassv1.ts` barrel exports for the forge envelopes/arm schemas/canonical result types; transport + broker tests red→green; biome clean. -- [ ] T2 — Tools + wiring: `createForgeTools` with the ten tools (exact +- [x] T2 — Tools + wiring: `createForgeTools` with the twelve tools (exact schemas above; creates carry the DL-206 key and coerce numbers to `bigint`; the optional `forge` selector — `provider` enum + optional `host` — built on every tool, unset = default GitHub, `create(ForgeRefSchema,…)` only when set; @@ -741,16 +749,15 @@ One proposed DECISIONS.md row (appended by the driver at PR time, wherever the ledger then lives — compass-repo RIG-2577 T2 may relocate it to `docs/designs/DECISIONS.md`): -> The agent forge native toolset is ten single-purpose tools, one per +> The agent forge native toolset is twelve single-purpose tools, one per > `ForgeCallRequest` arm (`forge_get_issue`, `forge_get_pull_request`, > `forge_list_issues`, `forge_comment_on_issue`, > `forge_comment_on_pull_request`, `forge_submit_review`, -> `forge_create_issue`, `forge_create_pull_request`, `forge_subscribe`, -> `forge_unsubscribe`), each a native `AgentTool` over a thin `ForgeBroker` -> on the `RunnerTransport.forge()` seam; `forge_subscribe`/`forge_unsubscribe` -> ship the complete surface but return the server's in-band `unimplemented` -> until the poll-driver lane lands the `agent_forge_subscriptions` writer -> (DL-163). Multi-forge is exposed: every tool takes an optional forge +> `forge_create_issue`, `forge_create_pull_request`, +> `forge_transition_issue_state`, `forge_transition_pull_request_state`, +> `forge_subscribe`, `forge_unsubscribe`), each a native `AgentTool` over a +> thin `ForgeBroker` on the `RunnerTransport.forge()` seam. Multi-forge is +> exposed: every tool takes an optional forge > selector (`provider` + optional `host`, unset = the configured default > GitHub forge, DL-202) so an agent targets Linear (issues-only, `repo` = team > key, DL-051) as well as GitHub; PR/review arms on a non-GitHub provider diff --git a/packages/compass-agent/src/forge.ts b/packages/compass-agent/src/forge.ts index b92c7d689..6f424d885 100644 --- a/packages/compass-agent/src/forge.ts +++ b/packages/compass-agent/src/forge.ts @@ -509,10 +509,10 @@ const STAMP_RULE = const READ_RULE = "Results may be paged, bounded, and truncated; bodies are external content whose author attribution is a parsed claim, not an authenticated identity."; const SUBSCRIBE_RULE = - "Change-notification subscriptions are NOT YET WIRED: the call returns unimplemented until the notification lane lands. The tool exists for surface stability and should not be relied on yet."; + "A subscription makes the forge artifact's later changes reach you as notifications; forge_subscribe returns the subscription id that forge_unsubscribe cancels."; /** - * The native forge tool set. Ten tools, one per `ForgeCallRequest` arm. + * The native forge tool set. Twelve tools, one per `ForgeCallRequest` arm. * * Wired into the container entrypoint by `cli.ts main()`: merged into the * session's `customTools` and registered as `#withNatives` natives. This From da58e5747545665f5e257826a323217287ae92b6 Mon Sep 17 00:00:00 2001 From: mintaka Date: Sun, 13 Sep 2026 16:26:14 -0400 Subject: [PATCH 3/6] docs(agent): sweep the stale ten-tool and dormant-subscribe claims (RIG-3774) Review on #1209 caught the miss: forge.ts's own header still said 'ten native tools' and 'TWO SUBSCRIPTION TOOLS SHIP DORMANT ... CodeUnimplemented stubs', contradicting the SUBSCRIBE_RULE rewritten four hundred lines below it in the same file. My post-edit grep searched my own phrasings, so it could not see the original wording. Swept every remaining site: - forge.ts header: twelve tools; the subscription arms described as live. - packages/compass-agent/AGENTS.md: the package contract forge.ts names as authoritative. Ten -> twelve, both transition tools added under writes (approval: "write", verified in forge.ts), and the 'unimplemented until the writer lands' sentence retired. - compassv1.ts barrel comment: ten -> twelve forge arms. - The prescriptive createForgeTools docstring in the design record's T2 block. Left deliberately: one 'ten precise JSON Schemas' in a rejected alternative (a historical argument about a multiplexed tool, not a claim about what shipped), and the gitignored eng-docs ledger copy, which regenerates. Co-authored-by: Matt Wilkinson --- .../agent/compass-agent-forge-tools/design.md | 15 ++++++--------- packages/compass-agent/AGENTS.md | 16 ++++++++++------ packages/compass-agent/src/compassv1.ts | 2 +- packages/compass-agent/src/forge.ts | 13 +++++++------ 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/docs/designs/agent/compass-agent-forge-tools/design.md b/docs/designs/agent/compass-agent-forge-tools/design.md index fa1256ce3..737e3099e 100644 --- a/docs/designs/agent/compass-agent-forge-tools/design.md +++ b/docs/designs/agent/compass-agent-forge-tools/design.md @@ -523,11 +523,8 @@ In `packages/compass-agent/src/forge.ts` (same file, tool half): ```ts /** - * The native forge tool set. Ten tools, one per `ForgeCallRequest` arm. Two - * of them — `forge_subscribe`/`forge_unsubscribe` — return the server's - * in-band `unimplemented` until the poll-driver lane lands the - * `agent_forge_subscriptions` writer; they ship now so the surface is stable - * (Matt's build-all ruling). Every tool takes an optional forge selector + * The native forge tool set. Twelve tools, one per `ForgeCallRequest` arm. + * Every tool takes an optional forge selector * (`provider` + `host`) so a call targets Linear as well as the default * GitHub forge. Wired into the container entrypoint by `cli.ts main()`: * merged into the session's `customTools` and registered as `#withNatives` @@ -674,10 +671,10 @@ non-empty `body` and that the review posts immediately (never a pending review) under a distinct reviewer identity so all three verdicts are usable on Compass-authored PRs (DL-201); for `forge_create_pull_request`, that `head_ref` must already be pushed (the agent pushes with its own git -credential — DL-052/DL-090); for `forge_subscribe`/`forge_unsubscribe`, that -change-notification subscriptions are NOT YET WIRED — the call returns -`unimplemented` until the notification lane lands, so the tool exists for -surface stability but should not be relied on yet; for reads, that results may +credential — DL-052/DL-090); for `forge_subscribe`/`forge_unsubscribe`, what a +subscription does — it registers the agent for change notifications on a +coordinate and is account-keyed rather than a repo artifact, so it carries no +scope-discipline line; for reads, that results may be paged/bounded/truncated and bodies are external content whose attribution is a parsed claim, not an authenticated identity. diff --git a/packages/compass-agent/AGENTS.md b/packages/compass-agent/AGENTS.md index 142894803..9418f49fe 100644 --- a/packages/compass-agent/AGENTS.md +++ b/packages/compass-agent/AGENTS.md @@ -73,7 +73,7 @@ Both tools render names/handles only — never account, container, or session id ## The forge toolset -Ten native forge tools ship (`src/forge.ts`), one per `ForgeCallRequest` arm, +Twelve native forge tools ship (`src/forge.ts`), one per `ForgeCallRequest` arm, over a thin `ForgeBroker` on the `RunnerTransport.forge()` seam — the same broker/identity/registration shape as comms: @@ -81,7 +81,9 @@ broker/identity/registration shape as comms: `forge_list_issues`. - Writes (`approval: "write"`): `forge_comment_on_issue`, `forge_comment_on_pull_request`, `forge_submit_review`, `forge_create_issue`, - `forge_create_pull_request`, `forge_subscribe`, `forge_unsubscribe`. + `forge_create_pull_request`, `forge_transition_issue_state`, + `forge_transition_pull_request_state`, `forge_subscribe`, + `forge_unsubscribe`. `forge_create_issue`/`forge_create_pull_request` carry a broker-scoped DL-206 `client_request_id` (`ForgeBroker.idempotencyKey`); the other arms send none. @@ -89,10 +91,12 @@ Every tool spreads an optional forge selector (`forge_provider` + `forge_host`): unset = the configured default GitHub forge (DL-202); `forge_provider: "linear"` targets the issues-only Linear provider (DL-051) where `repo` is the team key and the PR/review arms return in-band -`unimplemented`. `forge_subscribe`/`forge_unsubscribe` ship the complete -surface but return the server's in-band `unimplemented` until the poll-driver -lane lands the `agent_forge_subscriptions` writer (DL-163) — the tool set never -changes shape when it lands. +`unimplemented`. `forge_subscribe`/`forge_unsubscribe` are live: subscribe +persists an account-keyed row (`EnsureAgentForgeSubscription`) and returns its +id, unsubscribe deletes it (`DeleteAgentForgeSubscription`). They were in-band +`unimplemented` until the poll-driver lane landed the +`agent_forge_subscriptions` writer (DL-163), and the tool set did not change +shape when it did. **The forge surface is prompt-contained, not authz-contained.** Unlike comms (channel membership), the substrate ships no scope rejection (A8): one forge diff --git a/packages/compass-agent/src/compassv1.ts b/packages/compass-agent/src/compassv1.ts index 905667804..007a5a399 100644 --- a/packages/compass-agent/src/compassv1.ts +++ b/packages/compass-agent/src/compassv1.ts @@ -22,7 +22,7 @@ export { type BoardCallResult, BoardCallResultSchema, // The agent-initiated forge call envelopes (internal-only AgentGateway gen). Request - // carries `call_id`, a oneof over the ten forge arms, an optional `ForgeRef`, and a + // carries `call_id`, a oneof over the twelve forge arms, an optional `ForgeRef`, and a // `client_request_id` (create arms); Result retypes to canonical Issue/PullRequest/etc // plus an in-band `error` arm carrying `retry_after_ms`. Reused as RelayForgeCall payloads. CommentOnIssueRequestSchema, diff --git a/packages/compass-agent/src/forge.ts b/packages/compass-agent/src/forge.ts index 6f424d885..c5a834605 100644 --- a/packages/compass-agent/src/forge.ts +++ b/packages/compass-agent/src/forge.ts @@ -1,6 +1,6 @@ -// The agent's forge surface: a thin broker over the Runner transport, plus the ten native -// tools to read and write forge artifacts — issues, PRs, comments, reviews, and -// change-notification subscriptions (design compass-agent-forge-tools T1 + T2). +// The agent's forge surface: a thin broker over the Runner transport, plus the twelve native +// tools to read and write forge artifacts — issues, PRs, comments, reviews, state +// transitions, and change-notification subscriptions (design compass-agent-forge-tools T1 + T2). // Mirrors comms.ts / lifecycle.ts: `AgentGateway.Forge` is a Connect unary over the // per-container Unix socket, so a result is the awaited return value — no pending map, no @@ -19,9 +19,10 @@ // prompt-level: every artifact-write tool's description carries the scope-discipline line, and // the DL-050 attribution trail is the only audit. -// TWO SUBSCRIPTION TOOLS SHIP DORMANT: `forge_subscribe`/`forge_unsubscribe` are built now -// though the server arms are `CodeUnimplemented` stubs until the poll-driver lands — the tools -// render the in-band `unimplemented` cleanly, so the surface never changes shape when it lands. +// THE SUBSCRIPTION ARMS ARE LIVE: `forge_subscribe` persists an account-keyed row +// (`EnsureAgentForgeSubscription`) and returns its id; `forge_unsubscribe` deletes it. Both +// were `CodeUnimplemented` until the poll-driver landed the writer — the surface did not +// change shape when it did, as designed. // The schema builder rides the SDK's own schema stack via its `/ark` compat facade — one // there is no two-copy mismatch to catch. From e9d0bda0715ec6af4df5a9ac461983bd4e518d97 Mon Sep 17 00:00:00 2001 From: mintaka Date: Sun, 13 Sep 2026 18:01:11 -0400 Subject: [PATCH 4/6] test(compass-agent): floor the config-passthrough suite timeout to 60s (RIG-3783) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every test in cli.config-passthrough.test.ts does real filesystem work (mkdir + writeFile fixtures, then a buildFleetSettings/main read over both config layers). Under the parallel pre-push gate that I/O outruns bun's implicit 5s per-test default and flakes — measured 5423ms on the fleet-overlay test. This is the same starvation RIG-3609 fixed for the afterEach; the buildFleetSettings block and its ~19 siblings never got the same treatment. A file-wide setDefaultTimeout(60_000) covers the whole class in one line; the (g) probes keep their explicit 130_000 (an explicit per-test timeout still overrides the default). No production behavior change. --- .../src/cli.config-passthrough.test.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/compass-agent/src/cli.config-passthrough.test.ts b/packages/compass-agent/src/cli.config-passthrough.test.ts index 4689f06a7..562fbe74b 100644 --- a/packages/compass-agent/src/cli.config-passthrough.test.ts +++ b/packages/compass-agent/src/cli.config-passthrough.test.ts @@ -26,7 +26,14 @@ // real one. Every fixture is a real tempdir, torn down after each test; no // timers, no sleeps, no retries — deterministic FS fixtures only. -import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { + afterEach, + beforeEach, + describe, + expect, + setDefaultTimeout, + test, +} from "bun:test"; import { lstatSync, mkdirSync, @@ -63,6 +70,12 @@ function scratch(): string { return dir; } +// Every test does real FS work; under the parallel pre-push gate that I/O +// outruns bun's implicit 5s default and flakes (the starvation RIG-3609 fixed +// for the afterEach). This file-wide floor covers the whole class; the (g) +// probes' explicit 130_000 still overrides it. +setDefaultTimeout(60_000); + let savedHome: string | undefined; beforeEach(() => { savedHome = process.env.HOME; From 837280acd39d0b7f56b4e6b2842166789617d28b Mon Sep 17 00:00:00 2001 From: mintaka Date: Sun, 13 Sep 2026 18:48:28 -0400 Subject: [PATCH 5/6] fix(orion-ref-gate): close the former-name false-negative hole (RIG-3756) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review findings on PR #1216, both mediums on the gate rather than the scrub. The narrow pattern set missed two citation shapes, and both are shapes this scrub removed BY HAND — so the standing backstop would not have caught its own regression: - the space form, `sealed apps/docs/scripts/deploy.ts`, which is the most natural way to cite a file in another repo - the hyphenated repo-noun, `sealed-monorepo` / `sealed-repo` / `sealed-private` The space-form arm anchors on a source-file extension rather than on any slash-bearing token. A looser form false-positives on ordinary English, which carries slashes too: "values sealed and/or rotated" and "sealed in transit/at rest" both match a bare `sealed\s+\S*/`. Validated at 15/15 engineering-word negatives and 9/9 leak shapes; zero hits over the tracked tree. The module header contradicted the code after the two-name change, still reading "orion ONLY / a single blunt token beats a clever regex" while the former name is matched by exactly such a narrowing set. Rewritten to state both names and why the asymmetry is deliberate: blunt where the token is unambiguous, narrow where it collides with English. Also drops `\b` from the git grep pre-filter. It is a GNU extension, not base POSIX ERE, and a toolchain change that made git treat it literally would match nothing and exit 1 — a legitimately-clean signal — so the gate would fail OPEN. The pre-filter only has to be a superset; lineHasToken owns the boundary. Verified superset: 174 unanchored vs 168 anchored lines. Tests 26 -> 29. Mutation-tested: removing the two arms turns 29 pass/0 fail into 26 pass/3 fail. Co-authored-by: Matt Wilkinson --- tools/orion-ref-gate/index.test.ts | 22 ++++++++++++ tools/orion-ref-gate/index.ts | 54 +++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/tools/orion-ref-gate/index.test.ts b/tools/orion-ref-gate/index.test.ts index e65f0881b..52608a9a5 100644 --- a/tools/orion-ref-gate/index.test.ts +++ b/tools/orion-ref-gate/index.test.ts @@ -56,6 +56,28 @@ describe("lineHasToken — the former name, matched only in repo-shaped uses", ( true, ); }); + // The space form, not the slash form: citing a file in another repo by + // ` ` is the most natural shape, and every one of these is a + // line this scrub removed by hand — so the gate has to catch its own + // regression, not just the form that happened to be written with a slash. + test("a space-separated path or bare filename citation is a reference", () => { + expect( + lineHasToken("Adapted from sealed apps/docs/scripts/deploy.ts"), + ).toBe(true); + expect(lineHasToken("mirrors `sealed gather.ts:25,203-205`")).toBe(true); + expect(lineHasToken("ported from sealed flake.nix")).toBe(true); + }); + // Prose carries slashes too, so the space form anchors on a source-file + // extension rather than on any slash-bearing token. + test("slash-bearing English prose is not a reference", () => { + expect(lineHasToken("values sealed and/or rotated")).toBe(false); + expect(lineHasToken("rows sealed in transit/at rest")).toBe(false); + }); + test("a hyphenated repo-noun is a reference", () => { + expect(lineHasToken("a sealed-monorepo domain")).toBe(true); + expect(lineHasToken("sealed-repo records")).toBe(true); + expect(lineHasToken('the "sealed-private" annotation')).toBe(true); + }); test("its possessive, docsite host, and repo-noun uses are references", () => { expect(lineHasToken("following sealed's shape")).toBe(true); expect(lineHasToken("deployed to sealed-docs.rigel.build")).toBe(true); diff --git a/tools/orion-ref-gate/index.ts b/tools/orion-ref-gate/index.ts index 742ee1693..ef721acb2 100644 --- a/tools/orion-ref-gate/index.ts +++ b/tools/orion-ref-gate/index.ts @@ -9,15 +9,26 @@ // sweep removed the existing references; this gate keeps the boundary from // silently re-rotting, the same way design-ledger-gate keeps the ledger honest. // -// SCOPE: orion ONLY. This gate scans for one token and does not double as a -// general brand-token gate; other one-time cleanups that are not being re-added -// need no standing scan here. +// SCOPE: the private repo's two names ONLY — the current one and the former +// one imported records still carry. This gate does not double as a general +// brand-token gate; other one-time cleanups that are not being re-added need +// no standing scan here. // -// What counts as a reference: the whole-word token `orion` (any case), which -// catches the repo name, `RigelBuild/orion`, an `orion ` citation, and -// "ported from orion" provenance prose alike. The scan is deliberately blunt — -// a single blunt token with a small, explicit allowlist beats a clever regex -// that tries to tell a "good" orion from a "bad" one. +// What counts as a reference, and why the two names differ: +// - `orion` (current) is scanned WHOLE-WORD, any case — the repo name, +// `RigelBuild/orion`, an `orion ` citation, and "ported from orion" +// provenance prose alike. A bare `orion` in this repo is always the repo, +// so a blunt token with a small explicit allowlist is the right shape. +// - `sealed` (former) CANNOT be scanned that way: it is also ordinary +// English this codebase uses constantly (a sealed sum type, a ciphertext +// sealed under a key, an egress-sealed agent), and it is in the public +// company name. A whole-word scan measures 60 tracked lines, all +// legitimate. So it is matched only in repo-SHAPED uses — +// LEGACY_NAME_PATTERNS, whose docstring carries the tradeoff. +// +// The asymmetry is deliberate: blunt where the token is unambiguous, narrow +// where it collides with English. A gate that is all false positives on one of +// its tokens gets switched off, which protects neither. // // CARVE-OUTS (never scanned): // - tools/orion-ref-gate/** this gate's own source + fixtures name the token @@ -57,12 +68,19 @@ export const PRIVATE_TOKEN = "orion"; * a whole-word scan flags 60 lines, every one of them legitimate; a gate that * is 100% false positives gets switched off. * - * So match only the shapes that name the REPO: a path inside it, its docsite - * host, its possessive, or the word followed by a repo-ish noun. + * So match only the shapes that name the REPO: a path inside it (slash- or + * space-separated), its docsite host, its possessive, or the word followed by + * a repo-ish noun (spaced or hyphenated). + * + * The space-form arm requires the cited token to END in a source-file + * extension. A looser `sealed\s+\S*\/` matches ordinary prose, because English + * carries slashes too — "values sealed and/or rotated" and "sealed in + * transit/at rest" both false-positive without the extension anchor. */ export const LEGACY_NAME_PATTERNS: readonly RegExp[] = [ /\bsealed\/[a-z]/i, - /\bsealed-docs\b/i, + /\bsealed\s+[\w.-]+(?:\/[\w.-]+)*\.(?:ts|tsx|js|jsx|go|nix|md|json5?|ya?ml|toml|sh|py|rs|lock)\b/i, + /\bsealed-(?:repo|monorepo|docs|private)\b/i, /\bsealed's\b/i, /\bsealed (repo|monorepo|design corpus|platform|convention|PR #)/i, ]; @@ -190,9 +208,10 @@ export async function runOnce(deps: Deps): Promise { } /** - * `git grep -nEI` for either name over tracked files. The regex is a coarse - * pre-filter — `lineHasToken` makes the real decision, so this only has to be - * a superset of it. `sealed` is matched bare here and narrowed there. + * `git grep -nEI` for either name over tracked files, unanchored. The regex is + * a coarse pre-filter — `lineHasToken` makes the real decision, so this only + * has to be a superset of it. Both names are matched bare here and narrowed + * there. * * `git grep` exits 0 with matches, 1 on no match (a legitimately clean, empty * result), and >=2 on a real error (e.g. not a git work tree). We must @@ -202,7 +221,12 @@ export async function runOnce(deps: Deps): Promise { * returns exit 2. */ async function gitGrep(): Promise { - const pattern = `\\b(${PRIVATE_TOKEN}|sealed)`; + // No `\b` here: it is a GNU extension, not base POSIX ERE. If a toolchain + // change ever made git treat it literally, the pre-filter would match + // nothing and git grep would exit 1 — a legitimately-clean signal — so the + // gate would fail OPEN. The pre-filter only has to be a superset; + // lineHasToken owns the word boundary. + const pattern = `(${PRIVATE_TOKEN}|sealed)`; const res = await $`git grep -nEiI ${pattern}`.nothrow().quiet(); if (res.exitCode >= 2) throw new Error( From 18663ca56780978731eedbb3c09b87f3eda8854b Mon Sep 17 00:00:00 2001 From: mintaka Date: Sun, 13 Sep 2026 19:09:24 -0400 Subject: [PATCH 6/6] docs(orion-ref-gate): cite the pattern the prose examples fail under (RIG-3756) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review round 2 on PR #1216: high 0, medium 0, low 2. This closes the one low that was a real defect; the other is explicitly informational (the reviewer adjudicated the extension-anchor narrowing as correct and recommended no change). The docstring justified the extension anchor by naming `sealed\s+\S*\/`, then attributed two false positives to it. Only the first actually fails under that pattern: in "rows sealed in transit/at rest" the `\S*` stops at the space before "in", so no slash is adjacent to the token run. Both examples fail under the DEPLOYED arm with its extension anchor stripped, which is the pattern the argument is really about — I had probed the deployed arm and then written up a different regex. A maintainer testing the cited one would find it does not hold and might conclude the anchor is unnecessary. Now names the anchor-stripped arm, and records the trade it buys: a directory-only citation and an off-list extension are missed, deliberately, because broadening to a bare `sealed /` puts those prose hits back and an all-false-positive gate gets switched off. Also makes the whole-word measurement exact. It read "flags 60 lines"; the count outside this gate's own carve-out is 59. A published number that drifts is worse than a stated magnitude, so it now gives the magnitude and scopes the exact figure to its measurement. Verified every claim the docstring now makes: both prose examples clean under the deployed arm, both documented misses confirmed, all three citation shapes still caught. Tests 29 pass / 0 fail; gate clean; root:ci rc=0. Co-authored-by: Matt Wilkinson --- tools/orion-ref-gate/index.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/orion-ref-gate/index.ts b/tools/orion-ref-gate/index.ts index ef721acb2..9ed8e16e9 100644 --- a/tools/orion-ref-gate/index.ts +++ b/tools/orion-ref-gate/index.ts @@ -64,18 +64,24 @@ export const PRIVATE_TOKEN = "orion"; * The private repo's FORMER name, which imported records still carry. It * cannot be scanned whole-word like the current one: `sealed` is also ordinary * English this codebase uses constantly — a sealed sum type, a ciphertext - * sealed under a key, an egress-sealed agent. Measured over the tracked tree, - * a whole-word scan flags 60 lines, every one of them legitimate; a gate that - * is 100% false positives gets switched off. + * sealed under a key, an egress-sealed agent. A whole-word scan of the tracked + * tree flags dozens of lines (59 outside this gate's own carve-out when the + * scan was widened), every one of them legitimate; a gate that is 100% false + * positives gets switched off. * * So match only the shapes that name the REPO: a path inside it (slash- or * space-separated), its docsite host, its possessive, or the word followed by * a repo-ish noun (spaced or hyphenated). * * The space-form arm requires the cited token to END in a source-file - * extension. A looser `sealed\s+\S*\/` matches ordinary prose, because English - * carries slashes too — "values sealed and/or rotated" and "sealed in - * transit/at rest" both false-positive without the extension anchor. + * extension. Drop that anchor and the same arm matches ordinary prose, because + * English carries slashes too: "values sealed and/or rotated" and "rows sealed + * in transit/at rest" both false-positive once the extension is optional. + * + * It therefore misses a directory-only citation ("sealed apps/docs/") and an + * extension outside the list. That is the accepted trade: broadening to a bare + * `sealed /` re-introduces those prose hits, and an all-false- + * positive gate gets switched off, which protects nothing. */ export const LEGACY_NAME_PATTERNS: readonly RegExp[] = [ /\bsealed\/[a-z]/i,