Agentic AI Atlasby a5c.ai
OverviewWikiGraphFor AgentsEdgesSearchWorkspace
/
GitHubDocsDiscord
iiRecord
Agentic AI Atlas · WP-RN-08 record: t3code intake naming rules — the no-double-rename gate
page:docs-specs-platform-gaps-phase0-no-double-renamea5c.ai
Search record views/
Record · tabs

Available views

II.Record viewspp. 1 - 1
overviewarticlejsongraph
II.
Page JSON

page:docs-specs-platform-gaps-phase0-no-double-rename

Structured · live

WP-RN-08 record: t3code intake naming rules — the no-double-rename gate json

Inspect the normalized record payload exactly as the atlas UI reads it.

File · wiki/docs/specs/platform-gaps/phase0/no-double-rename.mdCluster · wiki
Record JSON
{
  "id": "page:docs-specs-platform-gaps-phase0-no-double-rename",
  "_kind": "Page",
  "_file": "wiki/docs/specs/platform-gaps/phase0/no-double-rename.md",
  "_cluster": "wiki",
  "attributes": {
    "nodeKind": "Page",
    "sourcePath": "docs/specs/platform-gaps/phase0/no-double-rename.md",
    "sourceKind": "repo-docs",
    "title": "WP-RN-08 record: t3code intake naming rules — the no-double-rename gate",
    "displayName": "WP-RN-08 record: t3code intake naming rules — the no-double-rename gate",
    "slug": "docs/specs/platform-gaps/phase0/no-double-rename",
    "articlePath": "wiki/docs/specs/platform-gaps/phase0/no-double-rename.md",
    "article": "\n# WP-RN-08 record: t3code intake naming rules — the no-double-rename gate\n\nExecuted 2026-09-28 on branch `phase0/hard-split-registry-guards` of `a5c-ai/fabric`. Spec: `docs/specs/platform-gaps/15-private-isolation-rename.md` \"WP-RN-08\", §3.3 (the migrated-unit table, binding), §3.1/§3.2 (name matrix), §5 interaction rules 1, 2 and 4; intent `00-intent.md` D17–D21 and acceptance criterion 7; roadmap `50-roadmap-workpackages.md` (WP-RN-08 blocks WP-T3-01; M0 exit criterion 4: \"the no-double-rename gate trips on a fixture `@t3code/x` manifest\"). Builds on WP-RN-04 (`publish-guards.md`: the `publish-isolation` CI job and the single scope constant) and the scope re-lock (`scope-relock.md`). The public repository `a5c-ai/babysitter` was never written to (`gh api repos/a5c-ai/babysitter --jq .pushed_at` stayed `2026-09-16T19:59:50Z`; only GET calls were issued), nothing was published, no infrastructure changed.\n\n## What the gate checks\n\n`scripts/ci/no-double-rename.cjs` (CommonJS, Node ≥ 22, no dependencies; runs before `npm ci`) scans every workspace `package.json` (root `workspaces` globs) plus every `package.json` up to four path segments deep under `packages/`, `apps/` and `infra/` — so a unit dropped into a spec 15 §3.3 directory without a `workspaces` entry is still seen, and `apps/commander` (not a workspace) is covered. The private scope is the single constant in the root `package.json` `fabric` block (`scripts/lib/registry-pin.cjs`); the name matrix is parsed from spec 15 itself by `scripts/lib/rename-spec.cjs` (§2 rejected scopes, §3.1 43 rows including the expanded hooks template row with `genty` → `agent-runtime`, §3.2 8 renamable workspaces + the 8-shell retirement row, §3.3 10 migrated units), so the gate cannot drift from the spec text.\n\n\"New unit\" = a manifest whose `name` is not in the baseline inventory. Findings (exit 1), each printed as `<manifest>:<line of \"name\">: [rule] message`:\n\n| Rule | Trips when |\n|---|---|\n| `t3code-scope-name` | `name` matches `@t3code/*` |\n| `t3-prefix-name` | `name` is `t3-*` (bare) or `@<scope>/t3-*` |\n| `upstream-t3code-name` | `name` is one t3code's own manifests carry in the pinned snapshot: `@t3tools/*`, `t3`, `t3code-*`, `effect-acp`, `effect-codex-app-server` (the snapshot's real names are `@t3tools/contracts`, `effect-acp`, `effect-codex-app-server`, `@t3tools/ssh`, `@t3tools/tailscale`, `@t3tools/client-runtime`, `t3`, `@t3tools/web`, `@t3tools/desktop`, `t3code-relay` — none of them is `@t3code/*`, so the spec's pattern alone would not have caught a verbatim import) |\n| `legacy-scope-new-unit` | a NEW unit carries `@a5c-ai/*`; the spec 15 §3.2 retirement list (T-27, 8 shells) is exempt |\n| `foreign-scope-new-unit` | a NEW unit is in any scope other than `@fabricstack` (the message names a spec 15 §2 rejected scope when it is one) |\n| `unscoped-new-unit` | a NEW unit has no scope |\n| `private-scope-name-not-in-spec` | a `@fabricstack/*` name is not in the §3.1/§3.2 new-name column or the §3.3 table (an interim name such as `@fabricstack/effect-acp`) |\n| `spec-directory-wrong-name` | a manifest sits in a §3.1/§3.2/§3.3 target directory but carries another name — e.g. `packages/catalog` holding `@a5c-ai/atlas`, the \"move now, rename later\" double rename; retirement-listed names are excepted |\n| `retirement-list-drift` | the `RETIRED_UNITS` constant in the script no longer equals the spec 15 §3.2 retirement row (the constant is kept so a reviewer sees the list; the spec text is authoritative) |\n\nNotices (never failing): a baseline package found at a directory other than its baselined one; a manifest without a `name`. There is no waiver annotation: the only way past the gate is a manifest that carries a spec 15 name in a spec 15 directory, or a reviewed baseline change.\n\n## Baseline generation\n\n`scripts/ci/fixtures/no-double-rename/baseline-packages.json` is written by `node scripts/ci/no-double-rename.cjs --write-baseline` from the tree: 59 entries `{ name, dir }` sorted by directory — the 43 `@a5c-ai/*` publishables, the 15 `@a5c-ai/*` private workspaces (8 renamable + 7 retired shells + `@a5c-ai/genty-web-app`, i.e. the whole §3.2 column) and `a5c-commander`. `scripts/ci/no-double-rename.test.mjs` pins the file to the tree (regenerating in memory must equal the file) and asserts that the baseline name set equals spec 15's current-name column exactly, so any inventory change is a deliberate, reviewed diff and the spec's \"confirmed from the live inventory\" claim stays mechanically true. Migrated units are never added to the baseline: they pass because they carry a §3.3 name, not because they are known.\n\n## Fixtures (red, then green)\n\nUnder `scripts/ci/fixtures/no-double-rename/` (self-contained roots with the `fabric` block, consumed by `--self-test` and by the node:test suite):\n\n| Fixture | Manifest | Result |\n|---|---|---|\n| `negative/t3code-scope` | `packages/x` = `@t3code/x` | `packages/x/package.json:2: [t3code-scope-name] @t3code/x is a t3code-scoped name; migrated units land only as @fabricstack/<spec 15 §3.3 name>` (+ `foreign-scope-new-unit`), exit 1 — **WP-RN-08 AC2 / M0 exit criterion 4** |\n| `negative/t3-prefix` | `packages/t3-x` = `t3-x` | `[t3-prefix-name]`, exit 1 |\n| `negative/legacy-scope-new-unit` | `packages/new-unit` = `@a5c-ai/new-unit` (public) | `[legacy-scope-new-unit]`, exit 1 |\n| `negative/rejected-scope` | `packages/x` under the spec 15 §2 rejected scope proposal | `[foreign-scope-new-unit] ... is a rejected scope (spec 15 §2)`, exit 1 |\n| `negative/upstream-name` | `packages/contracts` = `@t3tools/contracts`, `packages/acp` = `effect-acp`, `infra/relay` = `t3code-relay` | `[upstream-t3code-name]` + `[spec-directory-wrong-name]` on all three, exit 1 |\n| `negative/old-name-in-spec-dir` | `packages/catalog` = `@a5c-ai/atlas` | `[spec-directory-wrong-name] packages/catalog is the spec 15 directory of @fabricstack/catalog but the manifest is named @a5c-ai/atlas`, exit 1 |\n| `negative/interim-private-name` | `packages/acp` = `@fabricstack/effect-acp` (pinned to AR) | `[private-scope-name-not-in-spec]` + `[spec-directory-wrong-name]`, exit 1 |\n| `positive/migrated-unit` | `packages/contracts` = `@fabricstack/contracts`, `apps/environment` = `@fabricstack/environment` (bin `environment-server`), both pinned to AR | 0 findings |\n| `positive/baseline-unchanged` | `packages/atlas` = `@a5c-ai/atlas` | 0 findings |\n\n`node scripts/ci/no-double-rename.cjs --self-test` → every negative trips with a `file:line` on the `\"name\"` line, both positives pass, then `ok   repository scan — 59 manifest(s), 0 findings, 0 notice(s), 0 new unit(s)` and `no-double-rename self-test: 10/10 assertions passed (7 negative, 2 positive fixtures; retirement list: 8 units)`, exit 0. The node:test suite (`npm run test:no-double-rename`, 16 tests) additionally proves on synthetic roots that a rename in place (`packages/atlas` → `@fabricstack/catalog`), a move with the new name, and a §3.3 birth (`packages/contracts` = `@fabricstack/contracts`, `infra/relay` = `@fabricstack/relay`) pass, that every other birth name trips, that retirement-listed shells stay exempt with an empty baseline, that a manifest without a `workspaces` entry is scanned, and that the CLI exits 1 with `packages/x/package.json:2: [t3code-scope-name] @t3code/x ...` on the AC2 fixture.\n\n## Spec 10 naming check (AC1)\n\n`scripts/ci/check-spec10-names.cjs` parses spec 15 §3.3 into the canonical set and asserts `docs/specs/platform-gaps/10-t3code-migration.md` references migrated units only by those `@fabricstack/…` names: violations are `t3code-scope-name`, `t3-prefix-name` (a `t3-*` token quoted as code and not a path), `upstream-t3code-name` (`@t3tools/*`, `t3code-*`), `legacy-scope-name` (`@a5c-ai/<x>` where `<x>` is not a §3.1/§3.2 current name — existing fabric units may be cited by their current name under interaction rule 3), `rejected-scope-name` (any spec 15 §2 rejected scope), `interim-private-name` (`@fabricstack/<x>` outside §3.1/§3.2/§3.3), and `missing-migrated-name` / `missing-migrated-dir` (each of the ten §3.3 names and directories must appear). The allow-rule is explicit and narrow, and every allowed hit is printed as a notice: the glob forms `@t3code/*`, `t3-*`, `@a5c-ai/*` (spec 10 restating the rule), a `t3-`/`t3code-` token inside a path segment (`t3:docs/internals/t3-connect.md`, `research/t3code-architecture.md`), and a forbidden name inside a code span immediately preceded on the same line by \"upstream name\" or \"upstream package\" (the provenance form). A bare hyphenated token outside a code span is prose (`the four/five t3code-blind actions`, spec 10 §4.3) and is not a name.\n\nResult on the binding text: **0 violations, 12 notices** (lines 18 and 237: the three rule-statement globs; lines 5, 206, 236, 475: upstream path citations; line 214: `@a5c-ai/comm-adapter`, an existing fabric unit in the §7 consumer inventory). All ten §3.3 names and all ten directories are present. **No change to spec 10 was needed**; its final text already references only §3.3 names. `--self-test` first proves `scripts/ci/fixtures/no-double-rename/spec10/negative.md` trips all eight rules (25 violations) and exercises all three allow forms as notices, then checks the real spec 10: `check-spec10-names self-test: passed (10 §3.3 names checked)`.\n\n## CI wiring and intake documents\n\n- `.github/workflows/ci.yml`, job `publish-isolation` (WP-RN-04's guard job), new step \"No-double-rename gate and spec-10 naming check (WP-RN-08)\": `node scripts/ci/no-double-rename.cjs --self-test`, `node scripts/ci/check-spec10-names.cjs --self-test`, `npm run test:no-double-rename`. js-yaml loads the file; job list unchanged (`public-push-guard, publish-isolation, docs-quality, test, gateway-node-engine, workspace-coverage, observer-dashboard`).\n- Root `package.json`: `\"test:no-double-rename\": \"node --test scripts/ci/no-double-rename.test.mjs\"`. `test:publish-guards` runs a single file and was left untouched.\n- `.github/PULL_REQUEST_TEMPLATE/upstream-intake.md` and `docs/UPSTREAM-INTAKE.md` §10 now carry the naming rules: a unit entering fabric lands only as `@fabricstack/<spec 15 §3.3 name>` in the §3.3 directory, pinned to Artifact Registry; never `@t3code/*`, `t3-*`, the upstream t3code names, `@a5c-ai/*` or any other scope for a new unit; the gate enforces it and has no waiver.\n\n## Acceptance criteria\n\n| AC | Status |\n|---|---|\n| (1) spec 10's final text references `@fabricstack/{contracts,acp,codex-protocol,ssh,tailscale,environment,client-runtime,console-web,console-desktop,relay}` and no interim names | **Done, mechanically**: `check-spec10-names.cjs` → 0 violations; runs in CI so the Gate-B cross-check cannot regress |\n| (2) the CI assertion trips on a fixture `@t3code/x` manifest | **Done**: `negative/t3code-scope`, `packages/x/package.json:2: [t3code-scope-name]`, exit 1; asserted by `--self-test` and by the node:test suite |\n| (3) the first real landed fork (T-01/T-02 output) passes the gate un-waived | **Not yet exercisable** — no fork has landed (Phase 0 has no migrated unit). Owned by WP-T3-01 AC3 and WP-T3-02 AC5 (roadmap M2 exit criterion 1). The gate is in place for them, see below |\n\n## How WP-T3-01 / WP-T3-02 pass it un-waived\n\n1. Each landed unit's `package.json` is born with the §3.3 name and in the §3.3 directory (`@fabricstack/contracts` at `packages/contracts`, `@fabricstack/acp` at `packages/acp`, …, `@fabricstack/relay` at `infra/relay`), with `publishConfig.registry` = the Artifact Registry URL (guard G1) and, for the three `(private)` rows, `private: true`. Upstream names (`@t3tools/contracts`, `effect-acp`, `t3code-relay`, `t3`) may appear only in `UPSTREAM.json`, `LICENSE-THIRD-PARTY` and provenance headers — never in a `name` field.\n2. The baseline is not touched: a migrated unit passes because its name is in spec 15, not because it is baselined. If `--write-baseline` shows a diff in a migration PR, something landed under a non-spec name.\n3. The intake PR fills the \"Naming rules\" checklist of the template and cites `node scripts/ci/no-double-rename.cjs` output (`0 findings`) as test evidence; the `publish-isolation` job is the mechanical proof. There is no allow annotation or environment flag that relaxes the gate.\n4. If spec 15 §3.3 changes at Gate B, the spec text is edited first and the gate follows automatically (it parses the table); `check-spec10-names.cjs` then tells spec 10 which references to update.\n\n## Gates run (from `C:/work/fabric`)\n\n- Orchestrator gate, verbatim: `node scripts/ci/no-double-rename.cjs --self-test && echo NDR-PASS` → `... no-double-rename self-test: 10/10 assertions passed (7 negative, 2 positive fixtures; retirement list: 8 units)` then `NDR-PASS`.\n- `npm run test:no-double-rename` → `# tests 16 / # pass 16 / # fail 0`.\n- `node scripts/ci/check-spec10-names.cjs --self-test` → passed (fixture: 25 violations across all 8 rules; spec 10: 0 violations, 12 notices).\n- `npm run test:publish-guards` → 17/17; `node scripts/ci/publish-isolation-guard.cjs --self-test` → repository scan clean (122 files — it now also sees the new fixture manifests — 0 findings, 8 legacy-train notices).\n- `node scripts/ci/public-push-guard.cjs` → 214 files, 0 findings, 0 suppressed; `npm run guard:packages` → package-integrity guard passed; `node --test scripts/__tests__/publishable-packages.test.mjs` → 7/7 (still 43 `@a5c-ai/*` publishables).\n- js-yaml loads `ci.yml`; `node scripts/docs-style-check.cjs` and `npx markdownlint-cli2` clean on every edited document.\n\n## Commits (branch `phase0/hard-split-registry-guards`, pushed)\n\nSee `git log --oneline -- scripts/ci/no-double-rename.cjs docs/specs/platform-gaps/phase0/no-double-rename.md`; the SHAs are recorded in the WP output.\n",
    "documents": []
  },
  "outgoingEdges": [],
  "incomingEdges": [
    {
      "from": "page:docs",
      "to": "page:docs-specs-platform-gaps-phase0-no-double-rename",
      "kind": "contains_page"
    }
  ]
}

Shortcuts

Back to overview
Open graph tab