fix(builder): close boundary-test gaps, drop dangling spend-limits copy, guard tool descriptions end-to-end
Addresses opus reviewer findings on the Task 5 commit (33c4b52). Important: - agent-network.ts (3 sites) and self-improvement.ts (2 sites): response copy no longer tells a caller to run vector_get_spend_limits (deleted in Task 5) after a safety-limit error. Replaced with "Server spend limits for this tool are set via VECTOR_SPEND_LIMIT_PER_TX / VECTOR_SPEND_LIMIT_DAILY" (matching each site's existing phrasing). Nothing else in either file touched - both stay custodial until PRs 7/8. Also reworded the two comments (of my own, from Task 5) that named the deleted tool - tool-inventory.test.ts's header docblock and rate-limit-gating.test.ts's probe-choice comment - so a final `grep -rn vector_get_spend_limits packages/` is clean except run.test.ts (Task 6's, left untouched as instructed). - boundary.test.ts: added a third test pinning CUSTODIAL_UNTIL_LATER_PR.size === 2, so PR 7/8 shrinking it is a visible, reviewable number change rather than a silent list edit. - boundary.test.ts: FORBIDDEN is no longer word-bounded (`/(mnemonic|seed|bip39|fromSeed|walletFromSeed|selectWallet\.fromSeed)/i`, \b dropped) so it catches `seedPhrase`, `WALLET_SEED`, `bip39x`-shaped vocabulary, not just whole-word matches. Verified empirically (not just by inspection) that this introduces zero new hits outside the two allowlisted files - grepped `seed`/`bip39`/`mnemonic` case-insensitively across all of packages/builder/src first, confirmed every hit was already confined to agent-network.ts/self-improvement.ts, then reran the full boundary suite to prove it: no benign collisions, nothing to report back before committing. Added a fourth test pinning every FORBIDDEN alternative against a fixture corpus (mnemonic/MNEMONIC/seedPhrase/WALLET_SEED/bip39/ fromSeed/walletFromSeed/selectWallet.fromSeed/seed all match; "address-only wallet"/"unsigned transaction"/"changeAddress" don't) so deleting an alternative from the regex fails a named test instead of silently narrowing the guard. Cheap folds: - vector.ts: the five build_* tool DESCRIPTIONS (not response copy - that already taught the confirm step as of Task 5) now end with "...then broadcast with vector_submit_transaction and confirm with vector_await_transaction." Regenerated the snapshot; verified structurally that the delta is description-field-only on exactly those five entries (inputSchema untouched, all 23 keys unchanged) - this is also what makes the Task 5 addition-A docblock's "descriptions teach the full flow" claim actually true end-to-end. - tool-inventory.test.ts: each per-tool test now also asserts 'description' in schemaSnapshot[toolName] before the deepStrictEqual, so a regen that silently drops a description (e.g. JSON.stringify eating an undefined value) fails by naming the tool, not as an opaque diff. - regen-tool-schemas.mjs: server entry point and snapshot output path are now resolved from import.meta.dirname instead of hardcoded repo-root-relative strings, so the script runs from any cwd. Verified by actually invoking it from packages/builder (not the repo root) and confirming it wrote to the one correct packages/builder/test/smoke/tool-schemas.snapshot.json. Full gate re-run after all of the above: typecheck 0 errors, test:unit 144/144 (140 baseline + 4 boundary tests, up from 2), test:smoke 26/26, test:integration:auth 12/12. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,9 +7,10 @@ import { startServer, stopServer, ServerContext } from '../setup.ts';
|
||||
/**
|
||||
* Snapshot of the current tool surface (23 tools) for the non-custodial split
|
||||
* series (see docs/architecture/non-custodial-split.md). PR 6 (Task 5) is the
|
||||
* PR that took this list from 25 to 23: it deleted `vector_get_address` and
|
||||
* `vector_get_spend_limits` outright (the safety-layer/wallet-info tools have
|
||||
* no keyless equivalent — spend limits are gone because the builder no longer
|
||||
* PR that took this list from 25 to 23: it deleted `vector_get_address`
|
||||
* outright, along with the tool that reported per-transaction/daily
|
||||
* SafetyLayer spend status (the safety-layer/wallet-info tools have no
|
||||
* keyless equivalent — spend status is gone because the builder no longer
|
||||
* holds keys to limit) as part of making the remaining query tools
|
||||
* (`vector_get_utxos`, `vector_get_transaction_history`, `vector_dry_run`)
|
||||
* keyless. PRs 2, 6, 7 and 8 each deliberately restructure and rename tool
|
||||
@@ -141,6 +142,14 @@ describe('tool schema snapshot', () => {
|
||||
live,
|
||||
`Tool "${toolName}" is in the snapshot but was not returned by the live server's listTools().`
|
||||
);
|
||||
// Named separately from the deepStrictEqual below: a regen that
|
||||
// silently drops descriptions (e.g. JSON.stringify dropping an
|
||||
// `undefined` description key) should fail by naming exactly that,
|
||||
// not just show up as an opaque diff.
|
||||
assert.ok(
|
||||
'description' in (schemaSnapshot[toolName] as any),
|
||||
`Snapshot entry for "${toolName}" has no "description" key in test/smoke/tool-schemas.snapshot.json.`
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
{ description: live.description, inputSchema: live.inputSchema },
|
||||
schemaSnapshot[toolName],
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
}
|
||||
},
|
||||
"vector_build_deploy_contract": {
|
||||
"description": "Build an UNSIGNED transaction deploying a Plutus/Aiken smart contract (locks funds at its script address). Takes no key material - sign with your local signer, then broadcast with vector_submit_transaction.",
|
||||
"description": "Build an UNSIGNED transaction deploying a Plutus/Aiken smart contract (locks funds at its script address). Takes no key material - sign with your local signer, then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
},
|
||||
"vector_build_interact_contract": {
|
||||
"description": "Build an UNSIGNED transaction interacting with a deployed Plutus/Aiken contract - lock AP3X at it or spend from it. Takes no key material - sign with your local signer, then broadcast with vector_submit_transaction.",
|
||||
"description": "Build an UNSIGNED transaction interacting with a deployed Plutus/Aiken contract - lock AP3X at it or spend from it. Takes no key material - sign with your local signer, then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -139,7 +139,7 @@
|
||||
}
|
||||
},
|
||||
"vector_build_send_apex": {
|
||||
"description": "Build an UNSIGNED transaction sending AP3X to a recipient. Takes no key material - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction.",
|
||||
"description": "Build an UNSIGNED transaction sending AP3X to a recipient. Takes no key material - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -170,7 +170,7 @@
|
||||
}
|
||||
},
|
||||
"vector_build_send_tokens": {
|
||||
"description": "Build an UNSIGNED transaction sending Vector native tokens. Takes no key material - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction.",
|
||||
"description": "Build an UNSIGNED transaction sending Vector native tokens. Takes no key material - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -210,7 +210,7 @@
|
||||
}
|
||||
},
|
||||
"vector_build_transaction": {
|
||||
"description": "Build an UNSIGNED multi-output transaction with optional metadata. Takes no key material and never submits - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction.",
|
||||
"description": "Build an UNSIGNED multi-output transaction with optional metadata. Takes no key material and never submits - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Reference in New Issue
Block a user