Skip to content

feat(proxy): default-on TWZRD AutoGate pre-spend check before x402 sign - #218

Open
twzrd-sol wants to merge 4 commits into
BlockRunAI:mainfrom
twzrd-sol:twzrd/default-autogate-seat
Open

feat(proxy): default-on TWZRD AutoGate pre-spend check before x402 sign#218
twzrd-sol wants to merge 4 commits into
BlockRunAI:mainfrom
twzrd-sol:twzrd/default-autogate-seat

Conversation

@twzrd-sol

@twzrd-sol twzrd-sol commented Jul 25, 2026

Copy link
Copy Markdown

Why

ClawRouter is a high-traffic agent pay path (local proxy signs x402 for BlockRun models / Surf / etc.). Outer wrapFetch never sees the 402 — payment is internal. A third-party pre-spend check only works if it runs on the internal x402Client before sign.

TWZRD AutoGate (installTwzrdAutoGate) is that seat: free Solana wash/preflight, observe-mode on Base (no fake scores), kill switch env, measurable X-Twzrd-Caller identity.

What

After new x402Client() + scheme registration in proxy.ts:

await installTwzrdAutoGateOnClient(x402);
  • Default ON via dependency twzrd-x402-gate@^0.8.4
  • Kill: TWZRD_AUTO_GATE=0 or TWZRD_GATE_ENABLED=false
  • Base/EVM: unsupportedNetworkMode: \"observe\" — allow; Solana corpus does not invent Base reputation
  • Solana: full preflight; refuseWashFlagged: true; gateOnCanSpend: false (decision=block still aborts)
  • Soft-fail if package missing at runtime (proxy still boots)

Docs

README section Pre-spend trust (TWZRD AutoGate).

Tests

src/twzrd-autogate.test.ts — 3 passed (env kill + install surface).

Out of scope

  • Changing BlockRun facilitator or routing
  • Scoring Base merchants as Solana wallets
  • Facilitator volume / marketplace features

Fork-1 note (TWZRD)

This is a distribution pin: default check on a hot agent pay path, opt-out documented. Not a facilitator PR.

Summary by CodeRabbit

  • New Features

    • Added an optional TWZRD AutoGate pre-spend guard that runs before payment signing, with network-specific behavior (including observe mode on EVM and abort behavior on Solana when flagged).
    • Proxy startup now conditionally installs the guard when available and continues with the existing payment flow.
    • Added environment-variable kill switches to disable the gate.
  • Documentation

    • Updated the README with a new “Pre-spend trust (TWZRD AutoGate)” section describing behavior, activity indicators, and how it complements routing.
  • Tests

    • Added a Vitest suite covering disablement via environment variables and successful guard installation.

Install twzrd-x402-gate on the internal x402Client after scheme registration
and before payFetch. Pre-spend check runs on every payment creation:

- Solana: free TWZRD preflight (wash refuse); block aborts sign
- Base/EVM: observe mode (no fabricated Solana score; payment proceeds)
- Seat identity: X-Twzrd-Caller / X-TWZRD-Client stamped by the gate

Kill switch (default remains ON):
  TWZRD_AUTO_GATE=0
  TWZRD_GATE_ENABLED=false

Dependency: twzrd-x402-gate@^0.8.4 (optional peer for consumers who pin).
Soft-fails install if the package cannot load so proxy boot is never blocked.

Docs: README "Pre-spend trust (TWZRD AutoGate)" section.
Tests: src/twzrd-autogate.test.ts (env kill + install surface).
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a8f46fd5-cdcd-474e-befe-6c8465034906

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds optional twzrd-x402-gate integration to startProxy as a pre-spend trust check, with dynamic loading and targeted missing-module handling. It also adds environment and hook tests and documents network behavior, caller stamping, and kill switches.

Changes

TWZRD AutoGate

Layer / File(s) Summary
Optional package declaration
package.json
Adds twzrd-x402-gate version ^0.8.6 under optionalDependencies.
AutoGate installation and wiring
src/proxy.ts
Dynamically imports and installs the gate with configured behavior, soft-skipping only when twzrd-x402-gate itself is unavailable, then wires installation into startProxy before Solana registration and payment hooks.
AutoGate validation and documentation
src/twzrd-autogate.test.ts, README.md
Tests environment-variable behavior, hook registration, and missing-module matching, and documents network behavior, caller-header stamping, and kill switches.

Estimated code review effort: 2 (Simple) | ~15 minutes

Suggested reviewers: 1bcmax

Sequence Diagram(s)

sequenceDiagram
  participant startProxy
  participant installTwzrdAutoGateOnClient
  participant twzrd_x402_gate
  participant x402

  startProxy->>installTwzrdAutoGateOnClient: install gate on x402 client
  installTwzrdAutoGateOnClient->>twzrd_x402_gate: dynamically import package
  twzrd_x402_gate-->>installTwzrdAutoGateOnClient: return gate module
  installTwzrdAutoGateOnClient->>x402: install configured pre-spend gate
  startProxy->>x402: register Solana scheme and payment hooks
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a default-on TWZRD AutoGate pre-spend check before x402 signing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
package.json (1)

97-109: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Move twzrd-x402-gate to optionalDependencies.

peerDependenciesMeta only applies to peerDependencies; it does not make the regular entry in dependencies optional. Keep the gate optional at install time so the runtime dynamic-import fallback can stay reachable. Update package-lock.json accordingly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 97 - 109, Move the twzrd-x402-gate entry from
dependencies to optionalDependencies in package.json, preserving its version
constraint and optional install behavior. Update package-lock.json to reflect
the dependency relocation and ensure the runtime dynamic-import fallback remains
reachable.
🧹 Nitpick comments (1)
src/twzrd-autogate.test.ts (1)

36-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert that a hook was actually registered.

typeof client.onBeforePaymentCreation is true before installation, so this test passes if installation is a no-op. Assert hooks.length > 0; ideally exercise the proxy installation seam so its invocation and options are covered too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/twzrd-autogate.test.ts` around lines 36 - 50, Update the installation
test around installTwzrdAutoGate to assert that the hooks array contains at
least one registered hook after installation, rather than only checking the
pre-existing registrar function type. Exercise the proxy installation seam with
the provided client and options so the registrar is invoked and the installation
options are covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/proxy.ts`:
- Around line 2014-2024: Update the catch handling in
installTwzrdAutoGateOnClient so only dynamic-import module-not-found errors are
treated as optional dependency warnings and return without blocking startup.
Ensure errors from installTwzrdAutoGate(client, ...) are rethrown, including
incompatible client-surface failures, so the proxy cannot continue with
unguarded payments.

In `@src/twzrd-autogate.test.ts`:
- Line 1: Remove the unused beforeEach symbol from the Vitest import in the test
file, while preserving the remaining describe, it, expect, vi, and afterEach
imports.

---

Outside diff comments:
In `@package.json`:
- Around line 97-109: Move the twzrd-x402-gate entry from dependencies to
optionalDependencies in package.json, preserving its version constraint and
optional install behavior. Update package-lock.json to reflect the dependency
relocation and ensure the runtime dynamic-import fallback remains reachable.

---

Nitpick comments:
In `@src/twzrd-autogate.test.ts`:
- Around line 36-50: Update the installation test around installTwzrdAutoGate to
assert that the hooks array contains at least one registered hook after
installation, rather than only checking the pre-existing registrar function
type. Exercise the proxy installation seam with the provided client and options
so the registrar is invoked and the installation options are covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f809e40b-12bc-495f-9269-b77085695a94

📥 Commits

Reviewing files that changed from the base of the PR and between 40c7a2a and 9f918a9.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • README.md
  • package.json
  • src/proxy.ts
  • src/twzrd-autogate.test.ts

Comment thread src/proxy.ts
Comment thread src/twzrd-autogate.test.ts Outdated
- installTwzrdAutoGateOnClient: only a genuinely missing twzrd-x402-gate
  module soft-skips (optional dep for forks); any hook-registration failure
  now rethrows so the proxy can never boot with unguarded payments
  (CodeRabbit Major)
- twzrd-autogate.test.ts: drop unused beforeEach import (CodeRabbit Minor)
  and a dead vi.unmock that vitest flags for hoisting
- package-lock.json: replace the previous 245-line churned delta with a
  purely additive +40 delta on upstream's lock; the branch failed npm ci
  (EUSAGE, @emnapi drift from a full re-resolve). Cold npm ci now passes
  (794 pkgs), tsc --noEmit clean, vitest 705 passed / 3 skipped

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/proxy.ts (1)

2010-2018: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Only soft-skip when twzrd-x402-gate itself is missing.

These generic checks also match a missing transitive dependency of an installed gate package. That incorrectly returns here and starts unguarded payments. Require the error message to identify twzrd-x402-gate; rethrow every other resolution failure.

Proposed fix
-    if (
+    const missingGatePackage =
       code === "ERR_MODULE_NOT_FOUND" ||
       code === "MODULE_NOT_FOUND" ||
-      /Cannot find module/i.test(msg)
-    ) {
+      /Cannot find module/i.test(msg);
+    if (missingGatePackage && /['"]twzrd-x402-gate['"]/i.test(msg)) {
#!/bin/bash
set -euo pipefail

ast-grep outline src/proxy.ts --type function --match installTwzrdAutoGateOnClient
rg -n -C2 'ERR_MODULE_NOT_FOUND|MODULE_NOT_FOUND|Cannot find module|twzrd-x402-gate' \
  src/proxy.ts src/twzrd-autogate.test.ts package.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/proxy.ts` around lines 2010 - 2018, Update the error handling in
installTwzrdAutoGateOnClient so the soft-skip only occurs when the resolution
error message identifies twzrd-x402-gate itself. Keep the existing error-code
and “Cannot find module” checks as supporting conditions, but rethrow resolution
failures for missing transitive dependencies or any message that does not
reference twzrd-x402-gate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/proxy.ts`:
- Around line 2010-2018: Update the error handling in
installTwzrdAutoGateOnClient so the soft-skip only occurs when the resolution
error message identifies twzrd-x402-gate itself. Keep the existing error-code
and “Cannot find module” checks as supporting conditions, but rethrow resolution
failures for missing transitive dependencies or any message that does not
reference twzrd-x402-gate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 88cf4d1b-97a7-4743-bf52-b8ef1ed23c8d

📥 Commits

Reviewing files that changed from the base of the PR and between 9f918a9 and af324cb.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • src/proxy.ts
  • src/twzrd-autogate.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/twzrd-autogate.test.ts

CodeRabbit residual majors on BlockRunAI#218 tip (af324cb):

- Soft-skip MODULE_NOT_FOUND only when the missing package is
  twzrd-x402-gate itself; transitive / unrelated resolution failures
  rethrow so the proxy cannot boot unguarded.
- Move twzrd-x402-gate from dependencies → optionalDependencies (^0.8.6)
  and drop the dead peerDependenciesMeta entry (meta only applies to peers).
- Tests: assert hooks.length > 0 after install; unit the soft-skip matcher.

vitest src/twzrd-autogate.test.ts: 4 passed. tsc --noEmit clean.
The previous tip had an incomplete lockfile that failed npm ci on Node 22.22.2 / npm 10.9.4. Regenerate it with npm install --package-lock-only under the target toolchain.

No source or test changes. Gate logic, the optionalDependencies ^0.8.6 pin, and the soft-skip matcher remain unchanged.

Verified: npm ci; focused AutoGate tests (4/4); npm run typecheck; git diff --check.
@twzrd-sol

Copy link
Copy Markdown
Author

Following up with validation on the current head (c0852f07) and a concrete ask, since this has been open a few days.

The CodeRabbit Major is fixed. The original installTwzrdAutoGateOnClient caught everything, so a hook-registration failure would have let the proxy boot with payments unguarded — the opposite of the PR's purpose. Now only a genuinely missing module soft-skips (ERR_MODULE_NOT_FOUND / MODULE_NOT_FOUND / "Cannot find module"); every other failure rethrows, so it fails closed. CodeRabbit's review on the current head is passing.

Cold-clone validation, run from scratch:

  • npm ci clean on Node 22.22.2 (matching engines: >=22) and also on Node 20 — 720 packages, no EUSAGE, no @emnapi resolution churn.
  • npx tsc --noEmit clean.
  • npx vitest run706 passed / 3 skipped, 61 files.
  • The gate is an optionalDependency pinned in the lockfile, so forks that omit twzrd-x402-gate are unaffected and still install cleanly.

The ask — any of these three is a good outcome, and I'd rather have a no than silence:

  1. Merge it as-is (default-on with TWZRD_AUTO_GATE=0 as the kill switch), or
  2. Tell me default-on is the blocker and I'll flip it to opt-in (off unless explicitly enabled) — that's a small change and I'm happy to make it, or
  3. Tell me this isn't a direction you want in ClawRouter and I'll close it myself, no hard feelings.

If it helps the decision: the change is dependency-optional, fails closed on real errors, fails open only when the package is absent, and adds nothing to the request path when disabled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant