David dispatched the mainnet cutover this morning: deploy-mainnet.yml ran successfully at
2026-07-31T11:00:06Z-11:01:20Z, deploying commit 04e410b (the PR #11 merge, itself the tip of
main after PRs #9/#10/#11 all merged 10:39:29Z-10:39:59Z the same morning). Testnet had already
auto-deployed the identical commit at 10:40:01Z-10:41:50Z. The non-custodial migration is now
complete on both hosted instances, not just in the code - the exact moment the prior docs pass's
deliberately-hedged notice was written for.
Verified directly before writing anything, not taken on faith from the dispatch: git/gh confirm
the merge timestamps and that both deploy workflow runs targeted 04e410b exactly; the custody
grep and safety.ts's absence were reconfirmed on this exact commit; both hosted endpoints
(https://mcp.vector.mainnet.apexfusion.org/sse and the testnet equivalent) were probed directly
with a bare curl request and both returned HTTP 401 right now - meaningful evidence on its own,
since the pre-PR#8 image had no auth at all, so a 401 today proves post-migration code is what's
actually running, not just what the deploy logs claim.
- README.md: the deployment-status callout rewritten with the dated, both-networks-current
facts, replacing the custody caveat with an access caveat - both instances require a bearer
token from the operators now (an access control, not a custody signal; neither instance would
accept a mnemonic from an authenticated caller either, since the tool schemas that would carry
one no longer exist). The connect command now shows the bearer-token header syntax, verified
against Claude Code's own current `claude mcp add` documentation before writing it (`--transport
sse` accepts `--header "Authorization: Bearer <token>"`, same as `--transport http`). The
security notice rescoped from "this codebase, not every deployment" to a dated claim: complete
in this codebase and on both hosted instances as of the 2026-07-31 cutover deploy specifically,
explicitly not a "forever" claim - a future deploy is a separate operational action.
- packages/signer/README.md: the two passages scoped to "this codebase" in the prior docs pass
now scoped to "any instance running the 2026-07-31 deploy or later," mainnet included, with the
same access-control caveat about the bearer token.
- docs/architecture/non-custodial-split.md: PR-sequence row 9 (mainnet cutover) gets the same
landed-marker style as rows 6-8, dated; section 11's rollout paragraph gets its one now-historical
clause corrected to past tense with a dated annotation appended, following the established
forward-only annotation convention rather than rewriting the paragraph.
Open public access (no token, per-IP rate limiting) remains a planned follow-up, not yet an open
PR or branch - checked directly (gh pr list, git branch -a) rather than assumed, and stated in
the docs as planned, not implied as already in progress.
Critical truthfulness defect found by review: README.md's security notice claimed, in
unconditional present tense, that "the non-custodial migration is complete... No tool on this
hosted server accepts a mnemonic... this server never holds one" - sitting directly below the
README's own mainnet hosted-URL connect example. Per docs/architecture/non-custodial-split.md's
own rollout section, mainnet stays on its last custodial image until a separate, deliberate
cutover deploy ships - and nothing on this branch (or the two PRs it stacks on) has even merged
yet. A reader who followed the mainnet connect line and trusted the notice as written would be
told something the repo's own architecture doc directly contradicts. The rewrite had also
dropped the prior notice's hedge ("prefer self-hosting until the migration completes") and
replaced it with a strictly stronger, zero-caveat claim - the exact failure mode this migration
exists to prevent, reproduced at the documentation layer.
Fixed by rescoping every claim to the codebase and adding an explicit deployment-status caveat:
- README.md: added a deployment-status note directly beneath the hosted-servers URL table
(before the connect command), stating plainly that testnet auto-deploys from main but mainnet
stays on its last custodial image until a separate cutover deploy, and to treat the mainnet
instance's signing tools as custodial until then. The security notice itself now says "as of
this release, the non-custodial migration is complete in this codebase" and "no server running
this release ever holds one," with an explicit closing line that this is a claim about the
code, not about every deployment of it. The "Local signer" section got the same rescoping
(it made the identical unscoped claim). The Self-Improvement Module features bullet was also
adjusted: it had "all keyless" sitting directly next to a pre-existing "(live on Vector
mainnet)" parenthetical, risking the same conflation between the on-chain module's blockchain
deployment and this codebase's MCP-server code state - now stated as two separate facts.
- packages/signer/README.md: the "keyless across the board" pairing-status bullet and the
"keeps your mnemonic off the hosted server" closing line both rescoped to "in this codebase" /
"off any server running this release," each with an explicit note that the mainnet hosted
instance is not yet running this release.
- .superpowers/sdd/pr9-body.md (gitignored, not part of this commit): opening paragraph and the
stacked-PR timing note both updated with the same scoping - merging this PR does not deploy
it anywhere, and the mainnet cutover is a separate future step.
Grepped the tree afterward for other unscoped "hosted server ... keyless"-class claims: found
none beyond what's fixed above. Pre-existing, unrelated mentions of "hosted server" in
docs/architecture/non-custodial-split.md (the historical problem statement) and README.md (a
self-hosting logistics note) were checked and left alone - correctly scoped by their own
surrounding context already.
README, packages/signer/README.md, docs/VECTOR.md, and docs/architecture/non-custodial-split.md
updated for the family-3 (self-improvement) keyless migration - the last of the three families
this migration ever touched:
- README: security notice rewritten as the migration-complete statement (zero tools accept key
material, every signing operation happens on the local signer, enforced by the now-empty,
size-zero-pinned custody boundary allowlist); tool count 23 to 24; Self-Improvement Module
table replaced with browse/analyze plus the four build_* rows, the two-step proposal pair
marked as two transactions, agent-orchestrated; features and safety copy updated to
signer-owned spend limits everywhere; Configuration table's three dead spend-limit/audit-log
rows removed (nothing reads those env vars any more); Safety Layer box removed from the
architecture diagram entirely (box-drawing alignment verified programmatically, not by eye);
Testing section names tier-1 vs gated E2E vs LEGACY_FULL for all three keyless families
including their stake costs.
- packages/signer/README.md: pairing-status bullet and closing line rewritten - all four
families are keyless now, this signer is the single signing point, nothing is left open.
- docs/VECTOR.md: four new tool sections for the self-improvement build_* family (this doc never
documented self-improvement under any name before, so these are additions, not renames - same
situation as the registry family in the prior PR's docs task); Safety Controls section's
custodial-family list corrected to reflect that none remain.
- docs/architecture/non-custodial-split.md: family-3 landed marker on the PR-sequence table,
plus the four content-alignment fixes pre-assigned to this PR by
rehaul-handoff-2026-07-30-content-alignment.md (the "governance" to "self-improvement" renames
in the two-step-flow heading, the "last family" sentence, the family table label, and the
rollout row), plus the "Float -> bigint amount math" wording fix.
- .env.example: verified Task 5's edit already states the migration-complete scope correctly
with a pointer to packages/signer/README.md; no further change needed.
Content rules followed for all new copy in this commit: no "governance" (GOV_* env-var names
exempted, pre-existing deployed config keys), no em dashes, no "funds", research-themed
examples where new examples were needed. Caught and fixed one self-introduced violation before
committing: docs/VECTOR.md's four new tool sections initially copied the file's own pre-existing
em-dash-based parameter-bullet convention; replaced with colons in exactly those new lines,
verified zero em dashes remain in the added range.
README, .env.example, packages/signer/README.md, and docs/architecture/non-custodial-split.md
updated for the family-2 keyless migration (agent-registry build_* tools, no mnemonic
parameters): security notice narrowed to name the Self-Improvement Module as the only
remaining custodial family; agent-registry tool table renamed to the five build_* rows;
features bullets, self-hosting copy, Configuration/spend-limit scope notes, and the
architecture diagram's Safety Layer footnote all updated to "self-improvement only"; signer
README's pairing-status bullet and closing line extended to cover wallet/tx/contract AND
agent-registry; architecture doc's PR-sequence table marks family 2 as landed.
docs/VECTOR.md gains five new tool sections (register/update/transfer/deregister/message) -
this doc never documented the registry family under any name before, so these are additions
rather than renames; keyless framing (changeAddress, no mnemonic, unsigned CBOR + 4-call flow)
matches the style of the existing wallet/tx/contract sections. Safety Controls section's
custodial-family list also corrected to self-improvement only.
#7 (signer) and #8 (builder hardening) merged into main this morning; this
branch is rebased onto the result and packages/signer is now in-tree. Three
sites still said pairing the signer with the hosted builder "does not yet
remove the custody exposure" (true when #7 was written, before this PR's
keyless build_* tools existed - now false for the wallet/tx/contract family):
- README.md's "Local signer" section: now states the 4-call non-custodial
flow (signer_get_address -> build_* -> signer_sign -> submit -> await) is
live today for that family, names the signer's four tools, and keeps the
agent-registry/self-improvement families explicitly scoped out.
- packages/signer/README.md's "Known limitations" bullet and "Running it"
closing line: same correction, with the specific now-keyless build_* tool
names and an accurate (not overclaiming) description of what the E2E test
exercises - it signs with the same CML primitives sign.ts uses, as a
stand-in for calling vector_signer_sign directly, not a call into the
signer package's own code.
Grepped case-insensitively across the repo for "does not yet remove" /
"custody exposure" / "signer half is ready" / "builder half is not yet"
before and after: exactly these 3 sites found, all corrected, zero stale
instances remain.
The review verified six obfuscations that bypass boundary.test.ts's ambient-
global and forbidden-import checks: globalThis['fetch'](...), an alias
(const f = fetch; f(...)), an aliased bracket reference, the comma-operator
trick ((0, globalThis.fetch)(...)), and two dynamic import()s with a
concatenated specifier (import('node:' + 'dns'), import('child_' +
'process')). README.md called the check "the package's central security
guarantee" and boundary.test.ts's header claimed the signer "CANNOT reach
the network -- not that it chooses not to." Neither line was true of what a
text scan can actually promise.
Hardened cheaply, within reach of a text scan:
- FORBIDDEN_IMPORTS gains node:dns, node:dns/promises, node:http2,
node:worker_threads, node:vm, each with a one-line rationale.
- AMBIENT_NETWORK_GLOBALS gains globalThisQualifiedAccess(name), matching a
global reached via globalThis in either dot or bracket ("computed member
access") notation, plus navigator['sendBeacon'] bracket notation.
Verified empirically against the real hardened check (temporary probe
files under src/, one per evasion, deleted immediately after -- see the
task report for the full per-file breakdown): globalThis['fetch'](...),
the aliased-bracket-reference variant, and the comma-operator
globalThis.fetch trick are now all caught. The plain-identifier alias and
both concatenated dynamic imports still pass -- those need real data-flow
tracking or evaluating an arbitrary runtime expression, neither of which a
text scan can do, and no attempt was made to chase them.
Reworded both the README section and boundary.test.ts's header comment to
say what the check actually verifies: today's shipped src/ has no
accidental or careless network capability. Deliberate obfuscation is named
as a code-review responsibility, not something this file promises to catch.
Final whole-branch review, Fix 4 of 4.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
vector-signer-audit-log.json resolves inside the repo checkout by default,
and the README self-disclosed that it was NOT in .gitignore (unlike the
builder's vector-audit-log.json). A documented footgun is worse than no
footgun when the fix is one line. Adds the entry and updates the README
paragraph that described the gap to describe the fix instead.
Final whole-branch review, Fix 1 of 4.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Includes an opt-in testnet round-trip test (keyless build -> decode -> policy
-> sign, never submits), excluded from CI because it needs a funded wallet.
Run against the real funded testnet wallet: pass 3, fail 0, nothing submitted.
Verified every README claim against the code as implemented, not just the
brief text, and corrected several:
- VECTOR_SIGNER_AUDIT_LOG_PATH's default resolves against the package's own
install location (repo root), not the process's cwd as originally stated --
and that default filename is not yet covered by .gitignore.
- An audit-log write failure blocks ALL signing, not just accounting:
audit.append() throws by design and vector_signer_sign withholds an
already-produced signature rather than release one with no durable record.
- Documented the #private-field defense against accidental key leakage via
JSON.stringify/console.log, and the read-only/sign tool split that keeps
the signing key out of scope for get_address/decode/get_spend_limits.
- Documented that pairing this signer with the CURRENT hosted builder does
not yet remove the custody exposure it's designed to fix: no builder tool
is keyless yet, and there is no submit_transaction tool to hand a produced
signature to. That's the next stage of the migration, not shipped here.
Env-var cross-check (brief's Step 6, both directions) passes clean.