page:docs-specs-platform-gaps-phase0-scope-relock
Scope re-lock record: `@agentfabric` → `@fabricstack` (spec 15 §2, owner decision) reference
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.
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.jsonfabric.privateScope=@fabricstack(privateRegistryandlegacyPublicScopeunchanged).scripts/lib/registry-pin.cjsdoc 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
@fabricstackwith the rationale (neutral, fabric-derived, noa5cprefix, 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 thefabricstackorg. 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 andREADME.mdhad no occurrence. - **Phase-0 records**
ar-provisioning.md,publish-guards.md: strings replaced mechanically and a header note added ("scope re-locked to@fabricstackon 2026-09-28, seescope-relock.md") stating that the quoted transcripts originally showed the old name.publish-guards.mdG3 row linksg3-npm-token-restriction.md; its G4 row and "Scope collision" section record the resolution. - **G4 runbook** rewritten for the
fabricstackorg: statusPENDING 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.mdadded (statusPENDING OWNER UI ACTION, attempt, procedure, verification, rollback). - **Workflows**:
.github/workflows/ar-smoke.yml(SMOKE_PACKAGE: '@fabricstack/smoke', job name, header comment),ci.ymlandrelease-artifact-verifier.ymlcomments. - **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.mjspinsconfig.scope === '@fabricstack'; its malformed-scope case and the synthetic G4 probe use the new word.packFixturegained a 3× / 200 ms retry around the packed-tarball existence check and thetarextraction (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, headb4b3fa403), conclusion **success**, every step green (gh run watch --exit-status→ 0). The push ofb4b3fa403also created run36454063540(number 3), conclusionskipped, as the workflow's gate intends. - Log excerpts (job
109035832685):
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, version0.0.0-smoke.2only) and@fabricstack/smoke(created 2026-09-28T19:52:14, version0.0.0-smoke.4only).
Local install (this machine, fresh directory outside the repository, following only docs/user-guide/private-install.md; gcloud auth list → tal@a5c.ai *):
$ 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 $?
1Isolation 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 0on 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.2infabric-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
pushtrigger onar-smoke.yml(registration aid for feature branches) can be dropped once the workflow reachesmain. - Developer machines: the helper's token line in
~/.npmrcexpires 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)
b4b3fa403chore(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.