/** * Point the user's OWN app at a twin, then read what it did. * * WHY THIS TOOL EXISTS, in the words of an agent that hit the gap: * * "The catch — this didn't touch your actual app. Your real checkout * endpoint, your real /api/webhooks/stripe handler, and your real email * send were never called. That's still a mock, just a fancier one — it * proves Stripe's API behaves like Stripe says it does, not that your * integration wired to it correctly." * * Measured 2026-09-24. The agent then asked for exactly this capability — * "you point your app's Stripe base URL at the sandbox and give FetchSandbox a * reachable URL for your webhook endpoint" — and could not reach it, because * the endpoint shipped to prod without a tool in front of it. * * That also explains a number we had been reading as agent behaviour: across * 57,275 twin requests since 2026-05-09, 1.72% ran under a non-default * scenario. An agent declining to arm a failure on OUR canned workflow is not * being lazy — arming one there proves nothing about the caller's code, and it * was right about that. */ export interface ValidateIntegrationInput { /** Where THEIR app is reachable. The one fact we cannot derive. */ app_base_url?: string; /** Providers the app integrates — ["paddle", "resend"] for a relay. */ providers?: string[]; /** Carry this back to continue; it makes re-validation a diff, not a restart. */ session_id?: string; /** Probe ID returned by the session matrix; activate its failure scenario. */ arm?: string; /** Probe ID to evaluate after exercising the app under that scenario. */ probe?: string; /** Attempt ID returned by arm, required for evaluation or cancellation. */ run_id?: string; /** Abort an interrupted attempt or retry failed scenario cleanup. */ cancel?: boolean; suite?: "receipt_delivery_v1" | "receipt_recovery_v1" | "application_workflow_v1"; receipt_config?: { webhook_url: string; recipient_a: string; recipient_b: string; purchase_marker: { field: "html" | "text" | "subject" | "tags"; tag_name?: string; }; observation_seconds?: number; app_version: string; source_lookup_required: boolean; purchase_context?: Record; }; execute?: boolean; preflight?: boolean; fixtures?: { id: string; steps: Record[]; }; application_context?: Record; application_config?: Record; } export declare const validateIntegrationTool: { readonly name: "validate_integration"; readonly description: string; readonly inputSchema: { readonly type: "object"; readonly properties: { readonly providers: { readonly type: "array"; readonly items: { readonly type: "string"; }; readonly description: string; }; readonly app_base_url: { readonly type: "string"; readonly description: string; }; readonly session_id: { readonly type: "string"; readonly description: string; }; readonly arm: { readonly type: "string"; readonly description: "Probe ID from the matrix to arm before running the app. Requires session_id."; }; readonly probe: { readonly type: "string"; readonly description: "Probe ID from the matrix to evaluate after running the app. Requires session_id and run_id."; }; readonly run_id: { readonly type: "string"; readonly description: "Attempt ID returned by arm. Required with probe or cancel; prevents stale calls from consuming a newer attempt."; }; readonly cancel: { readonly type: "boolean"; readonly description: "Abort the attempt or retry failed cleanup. Requires session_id and run_id; cannot combine with arm or probe."; }; readonly suite: { readonly type: "string"; readonly enum: readonly ["receipt_delivery_v1", "receipt_recovery_v1", "application_workflow_v1"]; readonly description: "Configure the declared application receipt suite on this session."; }; readonly receipt_config: { readonly type: "object"; readonly properties: { readonly webhook_url: { readonly type: "string"; readonly description: "Exact normal application webhook URL, including path."; }; readonly recipient_a: { readonly type: "string"; readonly description: "Expected test recipient for purchase A, fixed before execution."; }; readonly recipient_b: { readonly type: "string"; readonly description: "Different test recipient for the different-customer case."; }; readonly purchase_marker: { readonly type: "object"; readonly properties: { readonly field: { readonly type: "string"; readonly enum: readonly ["html", "text", "subject", "tags"]; }; readonly tag_name: { readonly type: "string"; }; }; readonly required: readonly ["field"]; readonly additionalProperties: false; readonly description: "Where the normal receipt includes its Paddle transaction ID; same-record recipient/marker matching is required."; }; readonly observation_seconds: { readonly type: "number"; readonly minimum: 0.1; readonly maximum: 5; readonly description: "Observation window after each checkpoint; default 2 seconds. Verdict covers only measured windows."; }; readonly app_version: { readonly type: "string"; readonly description: "Declared application build identifier; not code attestation."; }; readonly source_lookup_required: { readonly type: "boolean"; readonly description: "Whether the app reads the source provider during its normal webhook handler."; }; readonly purchase_context: { readonly type: "object"; readonly description: "Application routing custom_data, e.g. test workspace ID. Never credentials."; }; }; readonly required: readonly ["webhook_url", "recipient_a", "recipient_b", "purchase_marker", "app_version", "source_lookup_required"]; readonly additionalProperties: false; }; readonly preflight: { readonly type: "boolean"; readonly description: "Read-only public readiness check for a configured application_workflow_v1. Requires session_id/run_id. Checks frozen empty baseline and token enforcement without creating orders, injecting faults or rotating secrets. Retry same run after its exact setup blocker is repaired."; }; readonly execute: { readonly type: "boolean"; readonly description: "Drive the configured app and evaluate the frozen receipt suite. Requires session_id/run_id; configuration acknowledgment alone is not proof. Starts the existing backend job asynchronously and returns promptly; follow status in this agent without allocating a background helper."; }; readonly fixtures: { readonly type: "object"; readonly required: readonly ["id", "steps"]; readonly additionalProperties: false; readonly description: "Prepare session-owned twin data before app tests. Requires session_id. Stable id makes repeated calls replay-safe. Every step names spec, method and relative path. Use {{step1.id}} for dependencies. End with GET and an exact identity assertion. No live provider calls."; readonly properties: { readonly id: { readonly type: "string"; readonly minLength: 1; readonly maxLength: 100; }; readonly steps: { readonly type: "array"; readonly minItems: 1; readonly maxItems: 40; readonly items: { readonly type: "object"; readonly required: readonly ["spec", "method", "path"]; readonly additionalProperties: false; readonly properties: { readonly name: { readonly type: "string"; }; readonly spec: { readonly type: "string"; }; readonly method: { readonly type: "string"; readonly enum: readonly ["GET", "POST", "PUT", "PATCH", "DELETE"]; }; readonly path: { readonly type: "string"; }; readonly body: { readonly type: "object"; }; readonly query_params: { readonly type: "object"; }; readonly expect_status: { readonly type: "integer"; readonly minimum: 200; readonly maximum: 299; }; readonly assertion: { readonly type: "object"; readonly required: readonly ["select", "equals", "required", "count"]; readonly additionalProperties: false; readonly description: "GET read-back only. Exactly four fields, e.g. {select: data.id, equals: '{{step2.id}}', required: true, count: 1} for Paddle. Use separate GET assertions for amount and currency; application all_of/where and JSON scalar predicates are not supported here."; readonly properties: { readonly select: { readonly type: "string"; }; readonly equals: { readonly type: "string"; }; readonly required: { readonly type: "boolean"; readonly enum: readonly [true]; }; readonly count: { readonly type: "integer"; readonly enum: readonly [1]; }; }; }; }; }; }; }; }; readonly application_context: { readonly type: "object"; readonly required: readonly ["goal"]; readonly additionalProperties: false; readonly description: "Bounded inspected app summary, not credentials or raw code. The existing requirements model proposes rules; it cannot issue a verdict. Requires session_id; separate from fixtures/execution."; readonly properties: { readonly goal: { readonly type: "string"; }; readonly app_version: { readonly type: "string"; }; readonly workflow: { readonly type: "string"; }; readonly entry_points: { readonly type: "array"; readonly items: { readonly type: "string"; }; }; readonly state_store: { readonly type: "string"; }; readonly fixture_requirements: { readonly type: "array"; readonly items: { readonly type: "string"; }; }; }; }; readonly application_config: { readonly type: "object"; readonly required: readonly ["app_version", "disposable_test_app", "checks"]; readonly additionalProperties: false; readonly description: "Frozen HTTP app drive/read-back contract: 1-30 checks, 1-20 actions per executable check, at most 300 declared actions in total, below 64 KiB. Preserve intermediate reads within these bounds; do not silently remove them. First check id=baseline must establish success. Checks require id, name, before {path,assertion}, ordinary HTTP actions [{method,path,body?,expect_status?}] or signed-event actions [{event:{provider,type,payload},expect_status?}], observe {path}, and assertion using select/equals/count/required or all_of. where and all_of must be lists of assertion objects, not field maps. equals accepts JSON strings, numbers, booleans and null; numeric/boolean literals preserve type, and null must be a present null field. Stripe event.payload is only the resource inside data.object, never a full event or a data.object wrapper: the server constructs and signs the envelope. Optional per-check observation_deadline_seconds (0-180, repeat=1 only) records bounded polling for eventual saved state; it does not drive a browser or turn a timeout into a pass. Every check first reads its declared starting-state precondition. Baseline requires count=0 on the same observed collection, with no where filter. Use {{run_id}} to scope fresh synthetic records. All paths are app-relative without query strings or fragments, including non-secret run_id queries; preserve run scoping through an inspected protected path-segment observer. Baseline permits only ordinary HTTP actions without signed events; prove signed purchase/access in later checks. Do not combine event actions with method/path/body/headers. {{step1.id}} binds a real action response to read-back. assertion.repeat (1-5) and stable_under_repeat support replay. Optional fault {provider,scenario} requires independently recorded provider refusal. Unsupported checks contain id,name,unsupported_reason only. No user-supplied credentials, auth headers or live data. require_verifier_token=true generates an owner-only temporary Bearer token through secure handoff for protected test endpoints."; readonly properties: { readonly app_version: { readonly type: "string"; }; readonly disposable_test_app: { readonly type: "boolean"; readonly enum: readonly [true]; }; readonly require_verifier_token: { readonly type: "boolean"; }; readonly coverage_review: { readonly type: "array"; readonly maxItems: 17; readonly description: "Applicability review against the returned coverage_policy. Missing dimensions remain unreviewed. Link relevant dimensions to declared checks, including explicitly unsupported checks. This is a proposed review, not execution proof."; readonly items: { readonly type: "object"; readonly required: readonly ["dimension", "relevance", "reason", "rule_ids"]; readonly additionalProperties: false; readonly properties: { readonly dimension: { readonly type: "string"; }; readonly relevance: { readonly type: "string"; readonly enum: readonly ["relevant", "not_applicable", "unresolved"]; }; readonly reason: { readonly type: "string"; }; readonly rule_ids: { readonly type: "array"; readonly items: { readonly type: "string"; }; }; }; }; }; readonly event_destinations: { readonly type: "object"; readonly additionalProperties: { readonly type: "string"; }; readonly description: "Session-provider to same-origin webhook path without query/fragment. Requires require_verifier_token=true and the isolated FETCHSANDBOX__WEBHOOK_SECRET from secure handoff. Complete signed action shape: {event:{provider,type,payload},expect_status:200}; exact replay: {event:{provider,replay_of:'{{step2.event_id}}'},expect_status:200}. No method/path/body/headers on signed actions. Baseline uses ordinary HTTP actions; signed events belong in later checks. Existing signature checks must remain enabled."; }; readonly observation_seconds: { readonly type: "number"; readonly minimum: 0.1; readonly maximum: 5; }; readonly checks: { readonly type: "array"; readonly minItems: 1; readonly maxItems: 30; readonly items: { readonly type: "object"; }; }; }; }; }; readonly additionalProperties: false; }; }; export declare function runValidateIntegration(input: ValidateIntegrationInput): Promise;