Repository navigation
feat: collapsed verifyWalletSignerMatch + per-adapter quota/fail-open helpers - #4
Merged
Merged
Conversation
Per `core/internal_docs/branding.md` — first-mention bare "commerce SDK" / "Commerce" replaced with "AgentScore Commerce" in the examples README intro. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…en paths
Closes TEC-265 (Node side). Opt-in (failOpen=false default) is preserved.
When failOpen=true and AgentScore-side infra fails (429/5xx/network timeout):
- Gate result carries `degraded: true` + `infraReason: 'quota_exceeded' |
'api_error' | 'network_timeout'` so merchants can log/alert without parsing
console output. Compliance denials (sanctions, age, jurisdiction, etc.) are
unaffected — those still deny regardless of failOpen.
### Core (`src/core.ts`)
- `EvaluateOutcome.allow` extended with optional `degraded` + `infraReason`
- New 429 branch on `/v1/assess` response (was collapsed into generic api_error)
- Catch path distinguishes `TimeoutError` / `AbortError` (`network_timeout`) from
generic `Error` (`api_error`)
- All 3 short-circuit sites updated; non-infra short-circuits (empty identity,
402) keep the existing plain-allow shape — degraded only marks real infra
failures
### Adapters (5)
- hono.ts, express.ts, fastify.ts: extend GateState with degraded + infraReason;
new `getGateDegradedState()` helper for merchants to read the flag
- web.ts: degraded + infraReason added to `GuardResult.allowed=true` variant
- nextjs.ts: passes degraded + infraReason through to handler's gate object
### Agent-facing copy (`_response.ts`)
- New `API_ERROR_INSTRUCTIONS` block with `action: 'retry_with_backoff'` + steps
+ user_message so agents distinguish transient AgentScore-side issues from
compliance denials. Also added to `DEFAULT_AGENT_INSTRUCTIONS` map. Existing
`next_steps: { action: 'retry', retry_after_seconds: 5 }` shape preserved for
back-compat.
All 540 existing tests pass; typecheck + lint clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nfraReason
End-to-end audit found that `withAgentScoreGate` (in web.ts, used by Cloudflare
Workers / Bun / Deno consumers) destructured the GuardResult into
`{data, captureWallet, verifyWalletSignerMatch}` and dropped `degraded` /
`infraReason` — vendors using `withAgentScoreGate` could not read the degraded
flag from the handler. The Next.js-flavored variant (`nextjs.ts`) was correct.
Fix: spread `degraded` + `infraReason` into the gate object passed to the
handler when present. Type updated to declare the optional fields on the
handler's gate parameter.
Pairs with the Python audit-follow-up (TEC-265 closeout commit in
python-commerce: get_gate_degraded_state helper added to all 6 Python
adapters, dead AssessResult fields dropped, QuotaExceededError subclasses
RuntimeError for back-compat).
540 tests pass; typecheck + lint clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…losure cleanup - 429 fail-closed denials now carry contact_merchant agent_instructions (do-not-retry guidance) instead of generic retry_with_backoff that would loop forever - 429 fail-open path returns degraded=true + infraReason='quota_exceeded' on EvaluateOutcome.allow - Per-adapter regression tests for degraded propagation across hono/express/fastify/nextjs/web (+8 tests) - README adds Fail-open behavior section with the get/with helpers - Strip metering/pricing language from agent_instructions, source comments, and HTTP response bodies (public-package strict surface) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e description Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
verifyWalletSignerMatch now makes a single sdk.assess call with resolveSigner set; the API's signer_match block is projected onto the gate's VerifyWalletSignerResult. Repeat (claimed, signer) lookups read a per-cache-entry signerMatchBySigner sub-map and skip both the round trip and SDK-side telemetry post (the API records the verdict server-side). Falls back to the legacy 2-resolve path when the response has no signer_match. Bumps sdk peer dep to ^2.2.0. getGateQuotaInfo(c) per-adapter helper exposes the SDK's quota field (captured from X-Quota-* response headers on the success path) on every framework adapter — express, hono, fastify, nextjs, web. EvaluateOutcome gains an optional quota field; gate state stashes it during the allow path. Mirrors the existing getGateDegradedState pattern. Bumps to 1.1.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pulls in just-published @agent-score/sdk@2.2.0 (typed assess errors + X-Quota header capture + ResolveSigner/SignerMatch types) so commerce gates can consume the new typed error surface and signer_match response field. Picks up 5 mppx security patches (Stripe proxy header strip, SSE multiline forge prevention, Tempo escrow override hardening, challenge-bound memo validation, post-force-close charge blocking).
Coverage delta vs main: - Statements: 95.07% → 96.54% (above 95% threshold) - Functions: 94.73% → 98.02% (above 95% threshold) - Lines: 95.82% → 97.52% (above 95% threshold) - Branches: 88.72% → 89.36% (still 0.64% short of 90%) Added focused tests for read helpers (getAgentScoreData, getGateQuotaInfo) across express + fastify + hono. Mirror the test_gate_quota_info.py pattern from python-commerce: prime the framework state container directly, verify the helper returns it. Also added passthrough-import tests for src/payment/signer.ts and src/api/index.ts re-export shims (previously 0% coverage because nothing imported through them). v8 ignore'd peer-dep absence guards in: - src/stripe-multichain/mppx_stripe.ts - src/payment/mppx_server.ts (mppx + tempo.charge + tempo.session guards) - src/payment/x402_server.ts (@x402/core + @coinbase/x402 + @x402/evm exact + @x402/evm upto + @x402/svm + @x402/extensions guards) Per the coverage-standards rule, peer-dep factory bodies that can't run without a peer dep the test env doesn't bundle are excluded with focused inline comments + a reason.
… ignore Adds the missing branch-coverage path on buildWellKnownMpp by exercising every optional field at once (description, openapi, catalog, required_fields, optional_fields, purchase.extra, purchase.identity, shipping). Pushes branch coverage from 89.36% → 90.01% — barely above the tier-A 90% threshold but enough to clear CI. Also v8-ignore'd the @x402/extensions/bazaar peer-dep-absence guards in src/discovery/bazaar.ts (mirrors the same treatment applied to mppx_server / mppx_stripe / x402_server in the prior commit).
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
Identity / signer matching:
verifyWalletSignerMatchcollapses the prior 3-call gate fan-out into a single/v1/assesscall carryingresolve_signer; API emits asigner_matchverdict in the same response(claimed, signer)cache so repeat lookups skip the APIsigner_match(canary rollout safety)Fail-open + quota helpers across the 5 framework adapters (hono, express, fastify, nextjs, web):
failOpen: trueflag onagentscoreGate(...); 429 / 5xx / network-timeout pass through to the handler withdegraded=true+infraReasonon gate state. Compliance denials still deny.getGateDegradedState(request)reads{degraded, infraReason?}from framework stategetGateQuotaInfo(request)returns the assess quota envelope captured during evaluateBrand + disclosure scrubs:
Deps:
@agent-score/sdk2.1.1 → 2.2.0 (typed assess errors + X-Quota capture + ResolveSigner/SignerMatch types just published)mppx0.6.8 → 0.6.13 (5 wevm security patches: Stripe proxy header strip, SSE multiline forge prevention, Tempo escrow override hardening, challenge-bound memo validation, post-force-close charge blocking)Version: 1.0.3 → 1.1.0 (additive minor).
,.
Test plan
bun run test— 562 passing, 4 skipped, 47 files)🤖 Generated with Claude Code