II.
Page overview
Reference · livepage:docs-specs-platform-gaps-phase0-scope-relock
Scope re-lock record: `@agentfabric` → `@fabricstack` (spec 15 §2, owner decision) overview
Inspect the raw attributes, linked wiki pages, and inbound or outbound graph edges for page:docs-specs-platform-gaps-phase0-scope-relock.
Attributes
nodeKind
Page
sourcePath
docs/specs/platform-gaps/phase0/scope-relock.md
sourceKind
repo-docs
title
Scope re-lock record: `@agentfabric` → `@fabricstack` (spec 15 §2, owner decision)
displayName
Scope re-lock record: `@agentfabric` → `@fabricstack` (spec 15 §2, owner decision)
slug
docs/specs/platform-gaps/phase0/scope-relock
articlePath
wiki/docs/specs/platform-gaps/phase0/scope-relock.md
article
# Scope re-lock record: `@agentfabric` → `@fabricstack` (spec 15 §2, owner decision)
Executed 2026-09-28 on branch `phase0/hard-split-registry-guards` of `a5c-ai/fabric`, as the follow-up to WP-RN-03 (`ar-provisioning.md`) and WP-RN-04 (`publish-guards.md`, `g4-npmjs-org-runbook.md`). This is the historical record of the re-lock and, together with the G4 runbook, the only phase-0 file allowed to spell the old scope with a slash; every other file in `docs/`, `scripts/`, `.github/`, `package.json` and `.npmrc` now carries `@fabricstack` and, where it is a historical record, a one-line pointer here.
The public repository `a5c-ai/babysitter` was never written to (`gh api repos/a5c-ai/babysitter --jq .pushed_at` → `2026-09-16T19:59:50Z` at start and end; only GET calls were issued; `git remote -v` → `upstream no_push (push)`), and nothing was published to `registry.npmjs.org`.
## Why
Spec 15 §2 proposed `@agentfabric` on the premise that the scope is "defensively registerable" on public npmjs (§4.3 G4). Preparing the G4 registration under WP-RN-04 found the scope third-party-owned: `@agentfabric/sdk` 1.0.1 (maintainer `defimessiah`, created 2026-03-18, "Agent Fabric SDK - Decentralized cloud for AI agents", MIT), the unscoped package `agentfabric` 0.0.2 (maintainer `mdirshadengineer`, created 2026-04-25), and `/-/org/agentfabric/user` → `200`. Consequences: the tombstone org could never be ours, and any consumer without the Artifact Registry routing line would resolve `@agentfabric/*` names against a stranger's packages (dependency confusion).
At breakpoint `phase0.npmjs-org` on 2026-09-28 the owner answered, verbatim: **"Re-lock to @fabricstack (Recommended)"** and **"NPM_TOKEN: Restrict now (Recommended)"**. The first is executed here. The second turned out to need the secret value through the API (`g3-npm-token-restriction.md`) and is **pending an owner UI action**; nothing was attempted against organization secrets in this work.
## Evidence that `@fabricstack` is free on public npmjs (read-only, 2026-09-28T16:44:59Z, re-checked after the smoke publish)
| Probe | Result |
|---|---|
| `curl -s -o /dev/null -w '%{http_code}' https://registry.npmjs.org/-/org/fabricstack/user` | `404` |
| `curl -s -o /dev/null -w '%{http_code}' https://registry.npmjs.org/fabricstack` | `404` |
| `curl -s "https://registry.npmjs.org/-/v1/search?text=%40fabricstack&size=20"` | `total: 0`, no package name starting with `@fabricstack/` |
| `curl -s -o /dev/null -w '%{http_code}' https://registry.npmjs.org/@fabricstack%2fsmoke` | `404` (before and after the AR publish) |
| `curl -s https://registry.npmjs.org/-/user/org.couchdb.user:fabricstack` | `401 {"ok":false}` — the endpoint answers `401` for every unauthenticated lookup (calibrated against the existing user `defimessiah`: also `401`), so it is not evidence either way |
| Calibration, same probes for `agentfabric` | org/user `200`, unscoped package `200`, search `total: 5` (`@agentfabric/sdk`, `agentfabric`, `@sf-agentscript/agentfabric-dialect`, two `agent-fabric` packages) |
| `curl -s -o /dev/null -w '%{http_code}' https://registry.npmjs.org/-/org/fabric-platform/user` | `200` — `@fabric-platform` is taken (added to spec 15 §2's rejected list) |
| `node scripts/ci/publish-isolation-guard.cjs --g4-status` (after the constant changed) | `publish-isolation-guard G4 status: unregistered — @fabricstack: not registered on registry.npmjs.org — G4 runbook can be executed` |
## What changed
Enumeration before: `git grep -In "@agentfabric" -- .` → **271** lines in **50** tracked files (a full-tree `grep -rIn --exclude-dir=node_modules --exclude-dir=.git` gave the identical 271/50, so no untracked or ignored file carried the string); `git ls-files | grep -i agentfabric` → none (no path embeds the scope). After: `git grep -c "@agentfabric/"` → only `phase0/g4-npmjs-org-runbook.md` (history) and this file; the unslashed form survives only in four clearly-labeled historical notes (spec 15 §2 rejected list + amendment, `ar-provisioning.md` header, `publish-guards.md` header + G4 row). `@fabricstack` → 264 lines after the mechanical pass, plus the hand-written sections.
- **Single constant**: root `package.json` `fabric.privateScope` = `@fabricstack` (`privateRegistry` and `legacyPublicScope` unchanged). `scripts/lib/registry-pin.cjs` doc comments follow.
- **Root `.npmrc`**: routing line is now `@fabricstack:registry=https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/`; the two workspace lines and the comment are unchanged; still zero credentials.
- **Spec 15 §2**: decision rewritten to `@fabricstack` with the rationale (neutral, fabric-derived, no `a5c` prefix, free on npmjs as of 2026-09-28 with the evidence above); `@agentfabric` (taken) and `@fabric-platform` (taken) added to the rejected alternatives; a dated amendment note explains the collision and the owner decision. §4.3 G4 and WP-RN-04's affected paths now name the `fabricstack` org. Every `@agentfabric/<name>` in §3 and elsewhere in the spec became `@fabricstack/<name>`.
- **Specs 10/20/30/40/50, `docs/UPSTREAM-INTAKE.md`, `docs/user-guide/private-install.md`**: scope mentions replaced (43, 6, 7, 19, 13, 1 and 9 lines respectively). `docs/DIVERGENCE-POLICY.md`, the PR template and `README.md` had no occurrence.
- **Phase-0 records** `ar-provisioning.md`, `publish-guards.md`: strings replaced mechanically and a header note added ("scope re-locked to `@fabricstack` on 2026-09-28, see `scope-relock.md`") stating that the quoted transcripts originally showed the old name. `publish-guards.md` G3 row links `g3-npm-token-restriction.md`; its G4 row and "Scope collision" section record the resolution.
- **G4 runbook** rewritten for the `fabricstack` org: status `PENDING OWNER ACTION — scope free as of 2026-09-28`, evidence table, a short "History" section for the collision, registration procedure and verification.
- **G3 record** `g3-npm-token-restriction.md` added (status `PENDING OWNER UI ACTION`, attempt, procedure, verification, rollback).
- **Workflows**: `.github/workflows/ar-smoke.yml` (`SMOKE_PACKAGE: '@fabricstack/smoke'`, job name, header comment), `ci.yml` and `release-artifact-verifier.yml` comments.
- **Guard fixtures and tests**: all 31 fixture manifests/workflows under `scripts/ci/fixtures/publish-guards/` and the ar-smoke fixture (`scripts/ci/fixtures/ar-smoke/package/package.json` → `@fabricstack/smoke`) renamed; no fixture directory embedded the scope. `scripts/ci/publish-guards.test.mjs` pins `config.scope === '@fabricstack'`; its malformed-scope case and the synthetic G4 probe use the new word. `packFixture` gained a 3× / 200 ms retry around the packed-tarball existence check and the `tar` extraction (a transient Windows antivirus lock had produced one ENOENT in test 15 earlier; the retry replaces silence, not the assertion).
## Artifact Registry rehearsal under the new scope
- Dispatch: `gh workflow run ar-smoke.yml -R a5c-ai/fabric --ref phase0/hard-split-registry-guards` → run **<https://github.com/a5c-ai/fabric/actions/runs/36454074285>** (run number 4, attempt 1, head `b4b3fa403`), conclusion **success**, every step green (`gh run watch --exit-status` → 0). The push of `b4b3fa403` also created run `36454063540` (number 3), conclusion `skipped`, as the workflow's gate intends.
- Log excerpts (job `109035832685`):
```text
Retrieving credentials from gcloud...
Success!
npm notice PING https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/
npm notice PONG 198ms
npm notice Publishing to https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/ with tag latest and default access (dry-run)
npm notice Publishing to https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/ with tag latest and default access
+ @fabricstack/smoke@0.0.0-smoke.4
name = '@fabricstack/smoke'
version = '0.0.0-smoke.4'
dist.tarball = 'https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/@fabricstack/smoke/-/@fabricstack/smoke-0.0.0-smoke.4.tgz'
```
- Registry state afterwards (`gcloud artifacts packages list --repository=fabric-npm --location=us-central1`): `@agentfabric/smoke` (created 2026-09-28T18:11:04, version `0.0.0-smoke.2` only) and `@fabricstack/smoke` (created 2026-09-28T19:52:14, version `0.0.0-smoke.4` only).
Local install (this machine, fresh directory outside the repository, following only `docs/user-guide/private-install.md`; `gcloud auth list` → `tal@a5c.ai *`):
```text
$ printf '@fabricstack:registry=https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/\n' > .npmrc
$ npx -y google-artifactregistry-auth --repo-config=.npmrc --credential-config="$HOME/.npmrc"
Retrieving application default credentials...
Retrieving credentials from gcloud...
Success!
$ npm init -y >/dev/null
$ npm view @fabricstack/smoke version --registry https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/
0.0.0-smoke.4
$ npm install @fabricstack/smoke@0.0.0-smoke.4
added 1 package, and audited 2 packages in 1s
found 0 vulnerabilities
$ node -e "console.log(require('@fabricstack/smoke'))"
{ ok: true }
$ node -e "const p=require('@fabricstack/smoke/package.json');console.log(p.name, p.version, p.publishConfig.registry)"
@fabricstack/smoke 0.0.0-smoke.4 https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/
$ grep resolved package-lock.json
"resolved": "https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/@fabricstack/smoke/-/@fabricstack/smoke-0.0.0-smoke.4.tgz"
$ grep -iE "_authToken|password|token=" .npmrc ; echo $?
1
```
Isolation after the publish: `curl -s -o /dev/null -w '%{http_code}' https://registry.npmjs.org/@fabricstack%2fsmoke` → `404`; `npm view @fabricstack/smoke --registry https://registry.npmjs.org/` from a directory without scope routing → `E404 Not Found - GET https://registry.npmjs.org/@fabricstack%2fsmoke`.
## Gates run (from `C:/work/fabric`, after the re-lock)
- `npm run test:publish-guards` → `# tests 17 / # pass 17 / # fail 0`.
- `npm run test:binary-renames` → `Binary rename guardrail passed for 6 renamed binaries and 8 emitted bin targets; single-bin policy (G5) holds over 32 workspace bin names.`
- `node scripts/ci/publish-isolation-guard.cjs --self-test` → `self-test passed; repository scan clean (101 files, 0 findings, 8 legacy-train notice(s))`.
- `node scripts/ci/public-push-guard.cjs --self-test` → `24/24 assertions passed`; plain scan → `179 files, 0 finding(s), 0 suppressed`.
- `node --test scripts/__tests__/publishable-packages.test.mjs` → 7/7; `npm run guard:packages` → `package-integrity guard passed` (also ran as the pre-commit hook).
- js-yaml loads every edited `.yml` (`ar-smoke.yml`, `ci.yml`, `release-artifact-verifier.yml`, the four fixture workflows); `node scripts/docs-style-check.cjs` → `issueCount 0` on all 13 edited docs; `npx markdownlint-cli2` → `Summary: 0 error(s)`.
- Orchestrator gate (verbatim; tail recorded in the WP output): `npm run test:publish-guards && npm run test:binary-renames && node scripts/ci/publish-isolation-guard.cjs --self-test && grep -q "@fabricstack:registry=" .npmrc && ! grep -rIl --exclude-dir=node_modules --exclude-dir=.git "@agentfabric/" docs scripts .github package.json .npmrc | grep -v "phase0/g4-npmjs-org-runbook.md\|phase0/scope-relock.md" && npx -y google-artifactregistry-auth --repo-config=.npmrc >/dev/null 2>&1; npm ping --registry https://us-central1-npm.pkg.dev/boot-464019/fabric-npm/ && ! grep -iE "_authToken|password|token=" .npmrc && echo RELOCK-PASS`.
## Cleanup candidates (nothing deleted; no AR change was made here)
- `@agentfabric/smoke@0.0.0-smoke.2` in `fabric-npm` (old-scope rehearsal package). Delete when convenient: `gcloud artifacts packages delete @agentfabric/smoke --repository=fabric-npm --location=us-central1 --project=boot-464019 --quiet`.
- The Artifact Registry repository description still reads "agentfabric private npm packages (fabric)" (set at creation, WP-RN-03). Cosmetic; `gcloud artifacts repositories update fabric-npm --location=us-central1 --project=boot-464019 --description="fabricstack private npm packages (fabric)"` when an owner wants it.
- The `push` trigger on `ar-smoke.yml` (registration aid for feature branches) can be dropped once the workflow reaches `main`.
- Developer machines: the helper's token line in `~/.npmrc` expires after about an hour; nothing to rotate.
## Pending owner actions (not done here, by design)
1. **G4**: register the `fabricstack` organization on npmjs per `g4-npmjs-org-runbook.md` (publish nothing; 2FA; sole owner). Until then the scope is merely free, not held.
2. **G3**: restrict the organization secret `NPM_TOKEN` to selected repositories excluding `a5c-ai/fabric` per `g3-npm-token-restriction.md` (GitHub UI; the API path needs the secret value).
## Commits (branch `phase0/hard-split-registry-guards`, pushed)
- `b4b3fa403` chore(scope): re-lock private npm scope @agentfabric → @fabricstack (owner decision, G4 collision)
- this record: see `git log -- docs/specs/platform-gaps/phase0/scope-relock.md`
## Rollback
Reverting `b4b3fa403` restores the old constant, routing line, fixtures and docs (the old smoke package is still in AR, so the old-scope rehearsal would install again). The new `@fabricstack/smoke@0.0.0-smoke.4` can be removed with `gcloud artifacts packages delete @fabricstack/smoke --repository=fabric-npm --location=us-central1 --project=boot-464019 --quiet`. Nothing on npmjs, GitHub settings or GCP IAM changed, so nothing there needs reverting.
documents
[]
Outgoing edges
None.
Incoming edges
contains_page1
- page:docs·PageBabysitter Docs