Test Evidence — PayAna Market Sentinel 1.2.0 RC1

Release-audit checkpoint: 2026-09-07T22:31:20Z

Aggregate result

PASS releaseCandidate: payana-market-sentinel-1.2.0-rc1 assertions: 189 mutation steps: 35 total checks: 224

The release audit runs the mutation suites sequentially. This became a required control after a deliberately reproduced test-harness race showed that statically imported suites which temporarily replace globalThis.fetch can interfere with each other even when each suite passes independently.

The aggregate audit is executable at tests/release_audit.ts.

Suite 1 — live/core behavior

tests/selftest.ts

101 / 101 PASS

The suite exercises live Binance public market evidence for all five allowlisted symbols:

  • BTCUSDT
  • ETHUSDT
  • BNBUSDT
  • SOLUSDT
  • XRPUSDT

Per-symbol controls include:

  • valid evidence state;
  • read-only boundary;
  • positive price;
  • non-negative spread;
  • order-book imbalance bounded to [-1, 1];
  • stability score bounded to [0, 1];
  • explicit non-probability wording;
  • winning hypothesis present;
  • opposite hypothesis present;
  • alternative hypothesis present;
  • supporting evidence present;
  • opposing evidence present;
  • multiple alternative explanations;
  • observable falsifiers;
  • explicit next discriminating test;
  • NO_TRADE_DECISION invariant;
  • exactly three source receipts on the full-data path;
  • short-horizon series present;
  • current ticker timestamp (<5 minutes at execution).

Global negative controls include invalid symbol formats, non-allowlisted/injection-like strings, an unsupported POST analysis request and unknown route behavior.

Suite 2 — source-failure and malformed-response mutation

tests/failure_modes_selftest.ts

23 / 23 PASS

This suite replaces the network fetch function with controlled synthetic responses and verifies failure behavior rather than the happy path.

Validated mutations:

  1. ticker source returns HTTP 503 while order book and candles remain valid;
  2. ticker returns HTTP 200 with malformed/invalid shape;
  3. ticker is the only surviving source;
  4. order book returns HTTP 200 with malformed/empty shape;
  5. all three market sources fail.

Important proven controls:

  • HTTP_200 != VALID_SOURCE_SHAPE;
  • malformed ticker receives INVALID_TICKER_SHAPE;
  • malformed order book receives INVALID_DEPTH_SHAPE;
  • failed/malformed sources do not become numeric zero;
  • unavailable derived metrics are returned as null;
  • surviving directional sources remain usable in PARTIAL state;
  • ticker-only evidence yields INSUFFICIENT_EVIDENCE, not a fabricated neutral/directional score;
  • all-source failure yields FAIL + INSUFFICIENT_EVIDENCE + NO_TRADE_DECISION;
  • source-missing risk flags are explicit;
  • recovery/next-test instructions are generated.

This suite directly tests the invariant:

MISSING_EVIDENCE != ZERO

Suite 3 — OAuth/CIMD/PKCE flow

tests/oauth_flow_selftest.ts

34 / 34 PASS

This suite verifies the local authorization contract without using a real Binance account. Controls include:

  • stable HTTPS non-root CIMD client_id;
  • exact callback URI;
  • Authorization Code only;
  • PKCE S256 challenge shape;
  • exact Agent OS resource parameter;
  • random state generation;
  • server-side temporary state/verifier storage;
  • state one-time consumption;
  • state replay rejection;
  • invalid callback rejection before token exchange;
  • RFC 9207 issuer-mismatch rejection before token exchange;
  • provider error values are not reflected into the callback page;
  • /oauth/status explicitly reports no token persistence and no automatic tool call.

Suite 4 — OAuth token/MCP catalog mutation

tests/oauth_mcp_probe_selftest.ts

25 / 25 PASS

The network layer is replaced with synthetic token and MCP responses. This proves the callback integration logic without touching an account:

  • token exchange is form-encoded POST;
  • no Authorization header or client_secret is sent to the public-client token endpoint;
  • client_id, redirect URI, resource and PKCE verifier are exact;
  • a returned refresh token is reduced to a boolean receipt and not exposed as a retained token value;
  • MCP 2026-07-28 protocol/method headers are present;
  • modern requests carry protocol version, client capabilities and current PayAna client identity in _meta;
  • only server/discover and tools/list are issued;
  • tools/call is never issued;
  • market-data tools are identified from a mixed catalog;
  • place_order, account-related and transfer/wallet tools are excluded from the safe-market set;
  • the access token is absent from the probe result.

This suite directly tests:

ACCESS_TOKEN_EPHEMERAL != TOKEN_PERSISTED AUTHORIZED_TOOL_CATALOG != TOOL_CALL

Suite 5 — OAuth state storage, expiry and replay

tests/oauth_state_storage_selftest.ts

6 / 6 PASS

This suite exercises the real val-scoped SQLite state store with synthetic OAuth states and cleans up after itself. It proves:

  • states older than the ten-minute TTL are pruned when a new authorization starts;
  • a fresh verifier can be consumed once;
  • sequential replay is rejected;
  • two concurrent consumers of the same state produce exactly one winner;
  • self-test states are not left pending;
  • the durable pending-state population remains within the hard 500-row cap.

The implementation also prunes the table to the newest 500 rows on every authorization-start transaction, bounding storage even if many abandoned flows are created. The first aggregate rerun exposed a real LibSQL concurrency defect: two simultaneous state consumers could produce SQLITE_BUSY: database is locked. The consumer was changed from a multi-statement SELECT+DELETE transaction to an atomic conditional DELETE ... RETURNING, with bounded retry only for SQLITE_BUSY and best-effort expired-state pruning. The storage suite then passed 5 consecutive executions including concurrent double-consumption, and the full release audit passed again. This is classified as a fixed failure class rather than a flaky test suppression.

Suite 6 — rate-limit mutation

tests/rate_limit_selftest.ts

requests 01–30 -> HTTP 200 requests 31–35 -> HTTP 429 PASS

This proves the current per-runtime limiter logic. It does not prove a globally distributed rate limiter; the architecture documentation explicitly records that limitation.

Browser/render validation

Independent JavaScript-rendering extraction was used after CSP hardening. React-only DOM selectors were requested, including:

  • .app-shell
  • .source-item
  • .hypothesis-card
  • .next-test

The render fetches completed without selector-not-matched failure. This is evidence that the JavaScript application rendered under the final strict CSP and that dynamic evidence/hypothesis elements existed in the DOM.

What remains intentionally unclaimed:

  • screenshot-based visual QA;
  • click-through browser automation of symbol switching and Refresh;
  • screen recording.

Those interactive witness paths were attempted through TinyFish and Firecrawl, but both external providers reported insufficient account credit at the checkpoint. This is classified as an external validation blocker, not as an application PASS or FAIL.

MCP boundary validation

The official Binance Agent OS MCP endpoint was probed without credentials. It returned an OAuth authorization challenge rather than an authenticated MCP session. Authorization-server metadata was read successfully and showed Authorization Code + PKCE S256, public-client token authentication and CIMD support.

After the CIMD document was live on the canonical production domain, audits/oauth_authorization_acceptance_probe.ts performed a credential-free authorization-surface probe. Binance returned HTTP 202 with a JavaScript/anti-robot interstitial ("JavaScript is disabled ... verify that you're not a robot") and no obvious invalid-client, client-metadata or redirect-URI error. This is classified PARTIAL, not PASS: transport reached the Binance authorization surface, but automated execution cannot prove that Binance fetched/accepted the CIMD because the anti-bot gate stops the flow before an authorization page is observable.

The application now has a tested user-initiated CIMD/PKCE callback path, but no real Binance account authorization has been executed or claimed. The current durable database contains only the temporary OAuth-state schema; after the release audit there were zero pending state rows, and the val has zero user-configured environment variables. No Binance access token, refresh token, API key or account identifier is durably stored.

Therefore:

MCP_ENDPOINT_KNOWN != MCP_SESSION_AUTHORIZED OAUTH_FLOW_READY != USER_AUTHORIZED_SESSION AUTHORIZED_TOOL_CATALOG != TOOL_CALL

A real MCP authorization receipt remains an external human/account gate. When that gate is completed, PayAna is designed to use the callback token ephemerally to read the tool catalog, generate a sanitized receipt, and discard the token.