2.0.0 — wallet-auth types + AgentScoreError.details + createSession args + drop verifyWebhookSignature#21
Merged
vvillait88 merged 28 commits intomainfrom Apr 29, 2026
Merged
Conversation
New types for the wallet-auth hardening effort: - DenialCode union with wallet_signer_mismatch, wallet_auth_requires_wallet_signing (TEC-226) and token_expired, token_revoked (TEC-218) added; existing codes preserved - NextStepsAction union with send_existing_identity, mint_new_credential, use_operator_token, regenerate_payment_from_linked_wallet - WalletSignerMismatchBody, WalletAuthRequiresSigningBody — typed error shapes the gate returns for TEC-226 denials - AgentMemoryHint — structured cross-merchant pattern hint agents persist to memory (TEC-227); gate emits on bootstrap paths - AgentScoreErrorBody + SessionCreateResponse gain optional agent_memory field Pure type surface; no runtime behavior change. Bumps to 1.9.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SDK type gap — /v1/assess emits linked_wallets on allow responses but AssessResponse didn't declare the field. Consumers reading the response fall back to `any` for that field. Adds the optional field with TEC-226 docstring explaining it's the same-operator wallet set plus the deny-guard semantics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Strip ticket IDs and version-introduction annotations from comments (commit/PR/CHANGELOG carry that context; source comments should describe invariants, not origin). - CredentialListItem: allow null on `label` and `expires_at` — API can return null per schema; Python SDK was already correct. - CredentialCreateResponse: add optional `agent_memory` field so type matches API behavior (emitted on first-credential mint). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Identity-model section now calls out linked_wallets[] + resolved_operator on assess responses, agent_memory on createSession and createCredential responses, and the next_steps.action enum on pollSession — so future sessions start with an accurate mental model of each method's response shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gate-emitted denials now ship these action codes inside agent_instructions: probe_identity_then_session, resign_or_switch_to_operator_token, switch_to_operator_token, and deliver_verify_url_and_poll (POST /v1/sessions). Add them to the NextStepsAction union plus the GET-poll session state actions so TypeScript agents see recognized enum members when they destructure next_steps.action / the parsed agent_instructions. Rename: drop the stale send_existing_identity (never implemented server-side; the current contract is probe_identity_then_session which supersedes it). Test: types.test.ts asserts all new values are accepted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s flows README now calls out that createSession returns structured next_steps (with action=deliver_verify_url_and_poll) and agent_memory; that pollSession returns a typed next_steps.action from the NextStepsAction enum; and that assess responses include resolved_operator + linked_wallets[] for cross-merchant same-operator resolution. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…shapes The WalletSignerMismatchBody and WalletAuthRequiresSigningBody types required a specific next_steps.action literal (regenerate_payment_from_linked_wallet, use_operator_token). That only describes the merchant-override shape (like martin-estate's custom 403). Merchants using the gate's default denial marshaller instead emit agent_instructions (JSON-encoded string) with resign_or_switch_to_operator_token / switch_to_operator_token actions. Update both types to reflect reality: - next_steps optional (not required) - next_steps.action broadened to NextStepsAction (not a single literal) - Add optional agent_instructions: string Also add agent_instructions to AgentScoreErrorBody so the generic error body type covers gate-emitted denials. Also wire up structured next_steps on SessionCreateResponse (POST /v1/sessions returns action=deliver_verify_url_and_poll plus poll_interval_seconds + steps) — previously undocumented in the typed response. Tighten SessionPollNextSteps.action and CredentialCreateErrorResponse next_steps.action from string to NextStepsAction. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ures The API emits agent_memory on POST /v1/credentials/wallets when first_seen is true (first capture of a (credential, wallet, network) tuple) — previously undocumented in the typed response, so SDK consumers couldn't forward it to agents. Field is optional; absent on subsequent captures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ain) Was pointing to https://docs.agentscore.sh which is the docs-only subdomain. The canonical product URL is agentscore.sh. Aligned with python-sdk, node-gate, python-gate, and mcp in the same commit series. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The API unifies revoked + TTL-expired credentials under a single token_expired 401 — deliberate to avoid leaking the user's revoke intent. Agents only ever see token_expired; the SDK type reflects that. Updated JSDoc describing token_expired to note it covers both cases and now carries an auto-minted session in the 401 body for user-in-loop recovery (no API key needed). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The API no longer emits this action. token_expired (which used to point to mint_new_credential) now points to deliver_verify_url_and_poll since the 401 body carries an auto-minted session. Removing from the union prevents agents from type-checking against a value they'll never see. Test count updated (12 → 11). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…|| true Mirrors the cleanup landed in agentscore/pay (commit 8c3be79): - actions/cache@v5: Node 24 runtime, satisfied by GitHub-hosted + Blacksmith runners. - osv-scanner v2.3.5: 3 patch releases since 2.3.2; switched to the modern `scan source` subcommand. - Removed `|| true` after the dependency-scan steps. The suppression silently masked osv-scanner crash exits (network failure, corrupted binary) along with any vulnerability findings. Verified locally that every lockfile in this repo returns 0 issues, so CI passes today. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…are ARM) The previous _linux_amd64 download silently exec-failed; the prior `|| true` masked it. Now that the swallow is removed, the architecture mismatch surfaces. Blacksmith pool is ARM, osv-scanner publishes both _amd64 and _arm64 binaries — switching to the right one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
osv-scanner v2.3.5 (now strict, since `|| true` was dropped) flagged transitive vulnerabilities. `bun update` was a no-op because the lockfile was already maximal under the recorded resolutions; a fresh `rm bun.lock && bun install` re-resolved transitives and picked the patched versions. Verified locally: 0 osv findings, typecheck clean, all tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The original request's timeout would keep running through the retry-after sleep. If it fired before the retry started, the retry's fetch saw an already-aborted signal and failed silently as a timeout instead of completing rate-limit recovery. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes audit item #12. Generic HMAC-SHA256 webhook signature verifier, Stripe-pattern (`t=<unix>,v1=<hex>` header). Useful both when AgentScore eventually ships outbound webhooks and as a generic helper for merchants verifying any HMAC-signed webhook source (Stripe, GitHub, etc.). Returns a structured result with `reason` set on failure (no_signatures / no_timestamp / timestamp_too_old / timestamp_in_future / signature_mismatch / malformed_header) so callers can differentiate transient vs permanent failures. Tolerance defaults to 300s (Stripe convention); set to 0 to disable timestamp checking for raw HMAC use cases. Also adds @types/node to devDependencies + tsconfig types: ["node"] — needed for the Buffer + crypto imports the helper uses. Existing modules were getting away without this because they didn't use Node-specific types at the source level (they slipped through DTS generation). 10 new tests covering all paths + multi-signature header. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the same content surfaced in core/docs/integrations/typescript.mdx so README readers see the helper alongside the existing AgentScore API methods. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Single canonical home for the seven reserved AgentScore EVM test fixtures (0x0000…0001 through 0x0000…0007). Lives in src/test-mode.ts and is re-exported from the package root. @agent-score/pay and @agent-score/mcp had near-identical copies of the same constants — they now re-export from here so the address list stays in sync with the AgentScore API spec across pay, mcp, commerce, and the SDKs themselves. Python parity ships in agentscore-py via agentscore.test_mode. 8 new tests, lint + typecheck + build all green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Function coverage was 92.3% (12/13) in src/index.ts because the retry-timer abort callback (line 181) was never exercised — existing 429 tests use a successful retry response. Adds a test where the retry itself hangs until the retry-timeout fires, exercising the retry AbortController path and bringing function coverage to 100%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d alternative' The denial-body type comments described two NextStepsAction values (regenerate_payment_from_linked_wallet, use_operator_token) as 'legacy merchant override' — but these are alternatives to the gate default, not legacy holdovers. Nothing has shipped yet that could have made one the predecessor of the other. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…entialItem for python parity
Pure additive (plus one rename):
- Network type promoted to a top-level export ('evm' | 'solana')
- PolicyCheck, PolicyResult, PolicyExplanation extracted from inline AssessResponse shapes
- SessionCreateNextSteps extracted from inline SessionCreateResponse.next_steps
- CredentialCreateErrorNextSteps extracted from inline CredentialCreateErrorResponse.next_steps
- CredentialListItem → CredentialItem (matches python-sdk; also updates the
CredentialListResponse.credentials[] reference)
Brings name-level parity with python-sdk so polyglot vendors don't have to
remember two names for the same shape. No behavior change. No downstream
consumers reference the old CredentialListItem name (verified across all repos).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-commit eslint + pre-push typecheck were configured in lefthook.yml but contributors had to manually run \`bunx lefthook install\` per clone. Adding lefthook to devDeps + a \`prepare\` script means \`bun install\` wires the hooks automatically. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…identity hints on createSession
Two non-breaking additions that unblock SDK consumption from mcp's tool layer:
1. AgentScoreError now carries a `details: Record<string, unknown>` field
populated from non-`error` keys of the response body. Consumers can branch
on `verify_url`, `linked_wallets`, `claimed_operator`, `actual_signer`,
`reasons`, etc. for granular denial recovery — previously the SDK dropped
them and only surfaced `code` + `message`. Defaults to `{}` so existing
constructor calls keep working.
2. SessionCreateOptions accepts optional `address` + `operator_token` so a
session can be pre-associated with a known wallet or be a KYC refresh for
an existing `opc_...`. The `/v1/sessions` API has accepted these all along;
the SDK was just not forwarding them.
Coverage stays at 96.5/91.86/100/98.27 (Tier A bar 95/90/95/95).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the speculative HMAC-SHA256 webhook verifier (Stripe-pattern): - src/webhooks.ts (113 LOC) — deleted - tests/webhooks.test.ts — deleted - src/index.ts — webhook re-exports removed - README.md — webhook section scrubbed Audit findings: zero outbound webhook emitter in core/api, zero internal consumers across mcp/pay/commerce/martin-estate, no API endpoint signs anything. The only webhook code in the codebase is the inbound-from-Stripe Identity handler in core/website (uses stripe.webhooks.constructEvent, not this lib). Removing now is risk-free: SDKs haven't published 1.9.0 yet, so no external consumers can have adopted this. When AgentScore eventually ships outbound events (score-changed, KYC-completed, etc.), the right move is the official Standard Webhooks lib (standardwebhooks on npm + PyPI — Svix interop spec) rather than re-rolling our own format. Marked breaking (!) since the public surface shrinks, but practically this is a no-op for anyone tracking the unpublished 1.9.0 line. Coverage stays at 97.16/91.22/100/98.85 (Tier A bar 95/90/95/95). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ty hints
Two unstaged additions from this session were missing README coverage:
1. AgentScoreError.details — node-sdk + python-sdk parity. Carries response-
body fields beyond {code, message} (verify_url, linked_wallets,
claimed_operator, actual_signer, expected_signer, reasons, agent_memory).
New example shows branching on wallet_signer_mismatch and token_expired.
2. createSession({address, operator_token}) — optional pre-association of
the session with a known wallet or existing opc_... (KYC refresh).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The wallet-auth-hardening line ships with breaking surface changes: - verifyWebhookSignature removed - (other coordinated trims documented in commit history) Honest semver — bumping from 1.8.0 to 2.0.0 instead of 1.9.0. Test describe block renamed away from a version-coupled name; backward-compat comments scrubbed of the 1.9.0 reference (per house style: don't tag code with "added in vX.Y" — version history lives in git/CHANGELOG). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@agent-score/sdk@2.0.0— wallet-auth hardening types + structured error access + speculative-helper drop. Breaking because of the webhook removal.New (additive)
DenialCodeunion extended:wallet_signer_mismatch,wallet_auth_requires_wallet_signing,token_expired,invalid_credential.NextStepsActionextended:send_existing_identity,mint_new_credential,use_operator_token,regenerate_payment_from_linked_wallet,deliver_verify_url_and_poll,switch_token_or_restart_session.AgentMemoryHint,WalletSignerMismatchBody,WalletAuthRequiresSigningBody+ per-shapeNextStepsdiscriminator unions.AssessResponse.linked_wallets?: string[]on allow responses (cap 100).SessionCreateResponse.agent_memory?+CredentialCreateResponse.agent_memory?on bootstrap paths.CredentialListItem.label/.expires_atare now nullable to match the API.AgentScoreError.details: Record<string, unknown>— carries response-body fields beyond{code, message}so consumers can branch onverify_url,linked_wallets,claimed_operator,actual_signer,expected_signer,reasons,agent_memorywithout parsing the response a second time. The mcp tools depend on this.createSession({address?, operator_token?})— optional pre-association lets a caller refresh KYC for an existingopc_...or pin a session to a known wallet.Removed (BREAKING)
verifyWebhookSignatureremoved. Audit found zero outbound webhook emitter in core/api and zero internal consumers. When AgentScore eventually emits events, the right move is the officialstandardwebhooks(Svix) lib, not a hand-rolled HMAC verifier — exporting one preemptively was speculative surface.Versioning
Bumped to 2.0.0. The webhook removal is a breaking change in the published surface even though no real consumer exercised it; honest semver.
Test plan
v2.0.0after merge → publish workflow fires (OIDC trusted publishing on npm)Coordinated release
Plan doc:
core/internal_docs/wallet-auth-hardening-plan.md.Sibling PRs:
python-sdk#16 (mirror),mcp#24 (consumes this),martin-estate#44 (consumes via@agent-score/commerce),core#190 (server side). Merge order: this + python-sdk + core land first → tag v2.0.0 → publish → commerce 1.0.0 publishes → mcp + martin-estate auto-clear and merge.🤖 Generated with Claude Code