Repository navigation
Ordex mainnet implementation: protocol, verifiers, SDK and documentation product - #58
Open
bitcoinuniverseadmin wants to merge 57 commits into
Open
bitcoinuniverseadmin wants to merge 57 commits into
bitcoinuniverseadmin wants to merge 57 commits into
Conversation
…mance data Split the shared conformance executor from Node file loading (scripts/docs/vector-loader.mjs) and give it one family registry used by the generator, CLI, Lab and Studio. Client and Worker bundles resolve the verifiers' node:crypto import to a pinned SHA-256/HMAC implementation tested byte for byte against Node; verifier/events.js now encodes with TextEncoder instead of Buffer. Verification runs in a dedicated Worker with timeout and cancel. Generated vector data keeps every source case whole under stable family IDs, is pinned to vector/spec/verifier digests, and every expected field (rune safe, runestone, flaw, offer hash, carried index) is compared. Empty suites never report success. API examples are built from and validated against the referenced OpenAPI 3.1 schema, and missing ones say why. Protocol Lab edits each family variant's real argument shape, runs candidates without a manufactured expectation, blocks secrets with the shared sanitizer, clears stale results, compares pinned runs and exports a digest-only report. Conformance Studio runs the full generated suite in the Worker with exact counts. Browser gates for /lab and /verify run in CI on the self-hosted runner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cation burn checks decipherRunestone now consumes fields the way ord 0.29.0 Runestone::decipher does (Tag::take arity and range, conditional Etching/Terms/Turbo flags, leftover even fields and flag bits, u128 supply overflow), so a duplicate pointer, a premine without etching and a one-value mint are cenotaphs. New allocateRunes and verifyRuneAllocation apply the ord rune_updater allocation (edicts, output-count split, pointer or first spendable default, OP_RETURN and no-destination burns) to exact indexed balances. verifyRuneBurnSafety refuses any burn path that can reach a balance, including a readable runestone whose pointer is its own OP_RETURN. conformance/ord-differential runs the pinned ordinals crate on all 88 rune vectors and 1500 seeded random transactions; the verifier and SDK must match its recorded answers field by field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every Sandbox verification step now runs a reference verifier on explicit arguments taken from the checked-in conformance vectors through the OX-S07 registry, dispatched to the verifier Worker. The registry no longer imports nonexistent verifier exports or returns hardcoded verdicts, and scenario refusal codes are the ones the verifiers actually return. Failure injections are bounded mutations of a clone of the step input (hand written or the exact field changes of a refusal vector); the reducer marks the step pending and the verifier decides. Replay is idempotent from stored results keyed by step and injection, history is bounded, refused steps block later steps and produce no artifacts, injections can be removed, and versioned checkpoints reject a different build, scenario or injection. State the sandbox cannot observe (a confirmed competing spend) is a labelled fixture using the contract's Validation.nodeStatus value, and no step claims chain proof. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
verifyAttachmentFollows no longer traces a sat range. It applies the Counterparty Core v11.4.0 rule: every attached input moves to the first output select_utxo_destination does not pass over, decoded from raw script bytes (malformed OP_RETURN, empty and CHECKMULTISIG-ending scripts are destinations; a one-byte 0x6a push is passed over). New counterpartyMoveDestination, counterpartyUtxoGates and counterpartyMoveOutcome model MOVE, DETACH_BY_SPEND, STRANDED and DETACH_MESSAGE with the utxo_support and spend_utxo_to_detach activation heights per network. Every input must carry its ledger attachment list, so undeclared co-traveling assets and co-moving foreign attachments refuse. verifyCounterpartyLedgerEvents reconciles UTXO_MOVE, ATTACH_TO_UTXO and DETACH_FROM_UTXO events after confirmation. testnet4 is an accepted network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tection The Artifact Lens parser now implements BIP174 v1.4.4 and BIP370 as pinned (blobs ecaa5d12 and 93b56e88): PSBT_GLOBAL_VERSION 0xfb, v2 transaction version 0x02, fallback locktime 0x03, input count 0x04, output count 0x05; the v0 unsigned transaction is decoded for the exact map counts; separators and end of data are required; keys are unique, CompactSize key types and lengths must be minimal; per-type key data and value rules (public keys on the curve, UTXO txid binding, locktime ranges) are enforced; unknown keys are kept as raw bytes; BIP370 locktime determination is implemented. A new parseRawTransaction decodes legacy and SegWit transactions with txid and wtxid and round trips. Every pinned valid and invalid BIP vector passes. Comparison uses real SHA-256 digests, claims identity only for identical bytes, compares version, locktime, outpoints, order, sequence, sighash, amounts and scripts field by field plus every map key, separates signer and finalizer additions, reports dropped fields per map, derives fees only from carried prevouts and keeps missing context inconclusive. Mutation fixtures are real BIP174 vectors with the exact equal-size change each title names. Artifact Lens routes all input through the strict parser and never calls a changed artifact safe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le persistence Adds a versioned journey schema: a context (network, gateway origin, protocol version, source build), evidence records from real tool runs, sessions that cite evidence for each completed stage, and settings. Imports and stored data are validated field by field; unknown schemas are refused and version 1 sessions migrate with their click-based progress kept for review only. Settings migrate keeping the mainnet default. The IndexedDB store now acknowledges a write only after its transaction commits, rejects aborts with typed errors (quota, revision conflict, unavailable), uses compare-and-update revisions, shares one open, closes on version change, reports blocked/quota/ephemeral state, prunes evidence and runs, keeps transferred artifacts by opaque id with digest checks, and notifies other tabs by id only through BroadcastChannel or a storage event. Missions complete stages only from matching evidence in the current context and build; tool links carry the session and stage as opaque ids; Lab, Conformance Studio, Sandbox and Artifact Lens record their runs. The settings menu shows and edits the real network, gateway origin, mode, protocol and build. Release history no longer carries invented contract digests and places SafeOps and swaps at protocol 1.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…proved signatures Adds a dependency-free transaction foundation shared by the verifiers: verifier/secp256k1.js (ECDSA with strict DER and low S, BIP340 Schnorr, BIP341 tweak) and verifier/bitcoin-tx.js (raw transactions, PSBT v0/v2 with BIP371 fields, legacy/BIP143/BIP341 sighashes, per-input signature checks, Bitcoin Core v29 dust threshold). They pass the BIP340, BIP341, BIP143, BIP174, BIP370 and BIP371 test vectors, agree with OpenSSL ECDSA, and match rust-bitcoin 0.32.5 sighashes over a seeded corpus except SINGLE|ANYONECANPAY without a matching output, where Bitcoin Core consensus is followed. SafeOps moves to ordex.safeops-plan/v2: inscriptions and rare sats follow their absolute sat position, runes the ord 0.29.0 allocation, Counterparty attachments the v11.4.0 move rule, and transitions must equal the derived multiset. Duplicate inputs, null signing and unexamined inventories refuse; one zero-value runestone is a data output; dust is per script and postage is a separate product floor. Signed results carry the raw transaction and every input signature is verified cryptographically. SDK and OpenAPI mirror it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The API Playground builds every request from the OpenAPI 3.1 contract: editable path, query and header parameters and a JSON body are validated against their schemas before sending, path values are encoded, unresolved templates and unsafe integers are refused, and ?operation= deep links work. Effects are enforced in the dispatch path: read-only mode never sends a write, writes and broadcasts go only to Signet, Testnet4 or Regtest after confirming the exact request (any change clears the approval), and operator routes are refused. Responses are checked against the schema documented for their status separately from HTTP success; requests time out, cancel, and suppress stale results; cURL is byte exact. Contract examples are shown as examples, never as gateway results. The Event Playground has a deterministic example replay that survives pause, and connected SSE (Last-Event-ID resumption) and WebSocket (subscribe with cursor) transports on the configured gateway that validate ordex-event/v1 envelopes, deduplicate, bound the buffer, advance the cursor only after processing, back off on reconnect and stop for resync on an expired cursor. Webhook checks pass nowSeconds and the exact body to the events verifier and never store the secret. Every documentation page now carries the shared settings menu, and both playgrounds record mission evidence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Gateway Doctor now runs eleven bounded read-only requests with exact assertions from spec/openapi.json and spec/api.md: the health endpoint answers, the health report matches its schema, listings are verifiable now (storage, configuration, readiness, ord lag and observation age), the protocol contract matches its schema and the selected version, health and protocol report the selected network, the catalog and an orderbook page match their schemas with every amount a decimal string, keyset paging is consistent, a malformed cursor is a 400 error envelope and a missing order a 404 error envelope, and the page can read responses (CORS, browser only). An unreachable gateway (the http://127.0.0.1:1 repro) now fails and every dependent check is blocked; cancelled checks stay cancelled. Each check keeps its request and a masked response excerpt with the body SHA-256, and the report digest is a real SHA-256 over the report. The run snapshots origin, network and protocol from the shared settings and records mission evidence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…signed policy The expected transaction manifest moves to v2. Its digest commits to the exact unsigned transaction bytes (version, locktime, every sequence, input and output order), every prevout, and the protection policy: who signs which input with which sighash, preserved foreign signatures, expected assets with quantities and outputs, fee and bound. Display text stays outside it. compareSignedResultToManifest parses the signed PSBT (v0 or v2) or raw transaction from bytes, checks the presented identity and prevouts, verifies every user signature under BIP143 or BIP341, requires a seller signature to be preserved byte for byte, and demands an independent, exactly equal observation of every protected asset. P-R11, P-R12 and P-R13 refuse. PSBT partial signatures now only count for the key the script commits to. OpenAPI drops the unreferenced signaturePresent transaction description. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nership Swap acceptance moves to ordex.swap-acceptance-plan/v2. Every asset movement is derived from the inputs' authority inventories by the owning protocol (new verifier/asset-flow.js, now shared with SafeOps): inscriptions and rare sats by absolute sat position, runes by the ord 0.29.0 allocation, Counterparty by the v11.4.0 move rule. Stated transitions must equal them. Outputs belong to the maker receive script or the taker scripts, never both. Given assets must reach the taker receive script with their exact quantity, required assets the maker in at least their quantity, everything else its owner. Fee shares come from each party's value flow with postage kept with the asset; the declared split must match and stay inside the maker budget. Adapters the intent relies on must be ones the verifier runs. verifySwapSignedTransaction proves the settlement from signed bytes: the planned transaction, both parties' signatures valid and closing with ALL. P-R09 (missing required Rune) and P-R10 (give paid back to maker) refuse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ransports, self-hosted docs service OX-S04: one typed MCP 2026-07-28 engine (site/src/lib/mcp/server.ts) with ten read-only tools, resources and prompts, server/discover and per-request _meta, used by the Agent Bridge, a bounded stdio transport and the HTTP service. dist/mcp/ordex-mcp-stdio.mjs is a self-contained build. Agent Bridge: per-client setup at the exact build revision with a setup check, local runs labeled local, a real remote check and send, HTTP and curl examples from the shared builder, awaited clipboard with an announcement. OX-P07: Streamable HTTP transport (worker/mcp-http.js): POST only, Origin allowlist, required and matching MCP-Protocol-Version, Mcp-Method and Mcp-Name headers (-32020), -32022 with the supported list, 404/202/405/413/415 codes, preflight for MCP headers, real tool results. OX-P08: typed docs endpoints (worker/docs-api.js, site/src/lib/docs/docs-contract.mjs): bounded enumerated fields, redaction, consent, 503 when storage is missing or failing, idempotent feedback receipts read back, atomic raw plus hourly event writes, retention, extractive Ask with real citations and version refusal. Hosting (integration owner decision): worker/node-host.mjs serves the fetch handler over node:http with a D1-compatible node:sqlite binding, a migration ledger that refuses changed files, /health with the build revision, loopback default, graceful shutdown. PUBLIC_ORDEX_DOCS_API_BASE build setting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…two keyed policy signers The funded output is now fixed exactly: internal key BIP341 H, an acceptance leaf <termsHash> DROP <A> CHECKSIG <B> CHECKSIGADD 2 EQUAL and a recovery leaf <minimal expiry> CLTV DROP <recoveryKey> CHECKSIG. offerOutputTree rebuilds every byte; leaves and control blocks are compared exactly, never by substring. Acceptance (ordex.offer-acceptance/v2) is verified from the signed transaction: seller inputs first, the funded output last, asset outputs that absorb exactly the seller sats, then the exact price, then buyer change. The Feline's derived satpoint must reach the buyer output and every other asset stays with its owner. Both policy signatures and every seller signature are verified; offerPolicySighash is the one hash each policy signer signs. The buyer padding gap is closed by removing buyer padding: the buyer signs nothing at acceptance, a buyer input is refused, and no signature is assumed. ITEM, COLLECTION and TRAIT eligibility is proved against the collection root, and TRAIT offers commit their eligible member set in criteriaHash. Recovery (ordex.offer-recovery/v2) reads locktime, domain and sequence from the bytes. Expiry is limited to heights below 500000000. P-R14, P-R15 and P-R16 refuse. Bitcoin Core 26.0 libbitcoinconsensus verdicts for every vector transaction are recorded by conformance/script-differential and replayed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kits A pure deterministic generator (site/src/lib/kits/generator.ts) replaces the fixed Node template. Node, browser and fetch-handler worker kits each get their own entry, build-before-start scripts, tests and start command. Selected capabilities wire real SDK verifier calls and ship the checked-in conformance vectors as the kit's own tests; gateway mode adds typed read-only SDK reads and refuses a gateway on another network. The SDK (not on any registry) is vendored as built from sdk/src; tools are pinned in a lockfile taken from this repository's; browser and worker bundles use the site's node:crypto implementation and no Node built-ins. CI in the kit uses self-hosted runners and SHA-pinned actions. The page reads the ZIP back before download and reports its file count, size and SHA-256, and records kit evidence. scripts/docs/verify-kits.mjs builds, tests and starts every runtime and mode; CI runs it with a real npm ci from each kit's lockfile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ort-safe bounded reads The v1.2 contract gains the request bodies, query and header parameters and the developer bearer scheme the gateway already accepts, attached to the request schemas it already declared (plus seven small request schemas), and schema.ts is regenerated from it. OrdexClient now wraps 70 of the 79 operations with exact generated types, including PATCH and DELETE, capability and idempotency headers, and the server sent event stream. SDK_EXCLUDED_OPERATIONS names the other nine with reasons: the two relay routes (the client broadcasts nothing) and the seven funded offer routes the gateway does not serve yet (Core OX-B01). An aborted signal sends nothing; an abort during a request or a retry wait rejects at once with the caller's own reason and is never retried. Reads retry only transient failures inside one deadline with capped cancellable backoff; writes are sent once. Settings are range checked, iterators refuse a repeated cursor or a non-page answer, and Basic credentials are UTF-8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n and signer verifyManifestRevocation now compares the revocation network and collection id with the target manifest before the digest and signer are considered (REVOCATION_CONTEXT_MISMATCH, the code the Core registry already emits), requires bip322 signature material (address and base64 signature), and labels every pass with its scope: TARGET_BOUND with the manifest, STRUCTURE_ONLY without it, which proves no target and authorizes no registry state. The spec states that registry changes need a TARGET_BOUND verdict plus the gateway's own BIP-322 check over the revocation digest. Five new vectors cover cross-network and cross-collection replay, the structure-only scope and malformed signature material; P-R17 refuses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…osis Diagnostic rules are now generated from the verifier sources: every code a verifier can return (174, including the template-built MAKER_ASSET_UNASSIGNED and TAKER_ASSET_UNASSIGNED) is bound to each source line and function that returns it, the spec statement naming it, its lifecycle, inputs and recovery per verifier variant, protocol versions from the family introduction (checked against spec status lines), and one reproducer per family: a checked-in conformance case plus a JSON Patch, found by deterministic single-mutation search or written by hand, and executed during generation. One branch (FEE_CHANGED in SafeOps signed results) is recorded as unreachable with the reason. The detector is conclusive only for a registered code in a structured position and classifies Doctor reports, Artifact Lens comparisons, gateway errors and events. The Failure Navigator runs reproducers in the verifier Worker with expected beside actual, exports a runnable script pinned to the build, keeps code deep links, links the Lab (?reproduce=) and matching Sandbox scenarios, and records reproduce evidence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…otation overlap spec/events.md kept only a hash of the signing secret while requiring every delivery to be signed with the secret itself. The contract now generates a whsec_ key returned once, stores it only as AEAD ciphertext bound to its subscription and version under a key encryption key the delivery worker alone may use, shows reads only a version and hint, keeps authentication hashes separate, and never treats a hash as a signing key. Rotation keeps a bounded verification overlap: signWebhookDelivery takes the current and unexpired secrets and emits one v1 per secret, and verifyWebhookSignature accepts a secret or a list and any matching v1, with one t and one d required. Retries and replays re-sign the same id and bytes. tests/integration/webhook-key-lifecycle.test.js runs the lifecycle end to end (restart, hint-only reads, wrong key encryption key, moved ciphertext, hash as key, overlap, retries) and now runs in npm test. Seven new event vectors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ources npm run build output after OX-P04, P10, P01, P03, P02, P05, P06, P09 and P11: the vector, refusal, diagnostic, operation and specification data in site/src/data, the API reference, llms-full.txt and the pages and hashed bundles that embed them. Built once from a clean docs/ so no orphaned bundles from intermediate builds are added; the build is deterministic. Integration with the docs stream must rebuild after merging. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ase gates Tours come from one manifest (site/src/lib/experience/tours.json): each step names its page and a data-tour target, and TourOverlay (mounted in the experience shell) outlines the real element, follows scroll and resize, waits for late targets, reports missing ones, and supports Next, Back, Pause (kept in journey settings), Resume, End and Escape with focus restored and reduced motion. The illustrated fake screenshots are removed; capture-walkthroughs.mjs now drives the built site in Chromium through the live overlay and records revision, route, viewport, theme, digest and hotspot, and no longer runs in the build. Action and accent tokens meet WCAG AA (dark ink on Bitcoin orange, darker orange for text, muted, warning and success text), fixed two-column grids are responsive, the Command Center follows the combobox/listbox pattern with a Tab trap, focus restore, empty state and the OX-S05 playground deep link, and the experience shell gains the theme toggle. The build clears stale docs assets and runs scripts/docs/coverage-check.mjs; CI adds axe on every route in both themes, overflow checks from 320 to 1440 px, tour gates and a capture run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d Core v12 shapes
Integration owner decision: the served paginated shapes win. The contract now
answers listWebhookSubscriptions with {items}, listSigningSessions with
{rows, nextCursor} of session summaries (nextCursor empty on the last page),
and listPrivateSwaps with {privateSwaps}, documenting that the gateway
currently refuses enumeration with 404 PRIVATE_SWAP_LIST_UNAVAILABLE.
WebhookSubscription is the record Core serves (id, accountId, updatedAt,
verification, secretVersion). A V12Network enum with testnet covers the
webhook and signing session schemas, whose routes accept testnet; the shared
Network schema is unchanged. schema.ts, generated docs and site data rebuilt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dance Ask, Feedback and Insights call the self-hosted docs service through docs-client.mjs (PUBLIC_ORDEX_DOCS_API_BASE, bounded, cancellable, typed outcomes). Ask validates the answer envelope, shares extractive retrieval with the service (rankCorpus), falls back to the bundled documentation with that said, offers only indexed versions and refuses key material before sending. Feedback succeeds only on a stored receipt, retries with the same submission id and keeps the draft. Insights shows the service aggregates or says they are unavailable; the fabricated numbers are gone. Recipes are generated from one step definition into SDK, fetch and cURL/jq views with carried values; wizards require answers, keep progress, record wizard evidence, and lead to real routes including a starter kit with the chosen runtime and capabilities. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The service worker is generated per build (scripts/docs/build-service-worker.mjs from scripts/docs/sw-template.js) with exactly the built files, relative to the registration scope, and a version from their contents. Install precaches into an Ordex cache for this scope and version and fails whole on any missing file; activation deletes only older Ordex caches of the same scope. Only listed GET files are served from the cache; API, MCP, gateway, credentialed and unlisted requests are never handled or stored. Offline navigation serves the saved page for that route or an honest 503. OfflineStatus registers at BASE_URL, asks the worker what is saved, offers an update instead of forcing it, and no longer claims offline features that are not installed. The coverage check verifies the precache list against the build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Atlas records a reading run (read:<diagram>) when a diagram is walked to its last step, the one stage that had no emitter; the diagnose mission's integrate stage no longer asks for a nonexistent kit:diagnostics and accepts a verified starter kit. A new test checks the exact operation template each tool records and that all nine missions' evidence stages are satisfiable only by matching runs in the current context; the browser gate adds Failure Navigator and Atlas stage completion on real IndexedDB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolved package.json, parity and detector counts; generated site data is regenerated by the follow-up reconciliation commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…otocol refusal code Integration of impl/ordex-docs-20260929 into impl/ordex-mainnet-20260929 (7f90b02). - Reproducers: the refusal scanner reads ternary refusals and passed-on parser reasons, and names helper-module sites (asset-flow, bitcoin-tx) with the families that reach them. 333 reproducers for 250 codes, 0 unavailable; 37 authored with the verifiers' helpers and test keys (scripts/docs/author-reproducers.mjs). TX_MALFORMED and PSBT_MALFORMED are never returned (every caller wraps them). - Registry: runes allocation, swaps signed and counterparty-asset ledger variants with their own verdict field; revocation manifest is optional (P09 vector); offers and collection-manifest expected fields. One new vector per new entry point via scripts/make-vectors.mjs (353 vectors); protocol and SDK vector tests dispatch per entry point, and the ord parity check compares an allocation vector with the recorded answer for the identical transaction. - Browser/Worker/kit bundles: RIPEMD-160 in the node:crypto shim (checked against Node), and no Buffer in verifier/bitcoin-tx.js, verifier/secp256k1.js or sdk/src/bitcoin-tx.ts (atob, TextEncoder, a byte compare). - OrderSummary.verification references VerificationView, the shape Core serves. - S08 consolidation scenario rebuilt as a SafeOps v2 plan; stale vector ids remapped. - Counts updated to the merged vector sets; docs/ rebuilt from clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lockfile only; astro's unifont dependency resolves the patched release. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…line status, mission evidence - Settings dialog is named "Connection settings", so the Network select is the only control labelled Network. The Failure Navigator live region announces a summary instead of repeating the visible evidence sentence. - Contrast: light-theme link/focus, evidence and status colors darkened to at least 4.5:1; inline tour links underlined. Scrollable tables and the Atlas diagram are focusable regions; the version selects have labels; alert lists keep list semantics; the recipes tablist holds only tabs. - Reflow: both headers wrap on narrow screens, grids use minmax(min(Npx, 100%), 1fr), panel headers, Lab tabs, Atlas controls, API reference rows and matrix controls wrap. - Offline: once saved, the status region says so to screen readers. - Mission workspace counts runs made outside any mission, as evaluateStage already allows, so a Failure Navigator or Atlas run opened directly completes its stage. - Tests: the Lab reproducer gate uses TRACKED_ASSET_UNASSIGNED (MAKER_ASSET_UNASSIGNED is no longer returned since OX-P02); the kit gate matches the MISMATCH cell exactly (refusal codes such as SELLER_VALUE_MISMATCH contain the word). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…et, swap capability, offers, reviewed quotes Contract (spec/openapi.json) now declares what the Core gateway and v1.2 controllers serve: - heritage operations and market (OX-X19): relayHeritageOperation (200, x-ordex-success-status), getHeritageOperation, draftHeritageAsk, draftHeritageSwap, publishHeritageIntent, acceptHeritageIntent, with HeritageOperation, HeritageExpectedLedgerEvent and draft schemas; - X-Ordex-Swap-Capability on the swap session routes, and the private acceptance body (intent, takerChangeScriptHex, takerIdentityProof) with the once-only sessionCapability; - funded offers as served over OX-P05: traitMembers on publish, the revalidate body, a BIP-340 withdrawal proof over the tagged withdrawal message, and the acceptance plan Core answers (inputs by party, psbt, acceptance document, checkpoint); - reviewed quotes (OX-B12): Quote.quoteId, PreflightRequest requires quoteId. The SDK wraps the new heritage routes and the funded offer routes Core now serves, takes sessionCapability on swap sessions, and excludes the heritage relay because it broadcasts. Rune vectors carry the count beside exact balances, and allocation verdicts report their burn safety, so a count-only consumer reaches the same safety verdict. The docs recipe quotes before it preflights. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hown for incomplete forms - journeyStore.saveSettings runs saves one after another, so choosing a network and then saving a gateway origin can no longer write the origin back to empty. - authorizePlan decides the route and the mode before form completeness: read-only mode states that it never sends an effect even while the body is still empty. - Gateway Doctor's own field is labelled "Gateway to check", distinct from the shared settings' Gateway origin. - Tests: the Event Playground Connect button is matched exactly (Disconnect contains it); the offline gate excludes the docs service API (/ordex/api/) rather than every path containing /api/, which wrongly included the /reference/api/ page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e cursor back The Event Playground told the transport an event was processed for duplicates too, so the SSE and WebSocket clients took the duplicate's older id as the resume cursor and a reconnect replayed from there. Only a newly accepted event moves the cursor now. The offline browser gate reports navigator.onLine, service worker control, the status region and unhydrated islands when the offline banner does not appear. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t is offline navigator.onLine can stay true while the network fails (captive or failing networks, and emulated offline), so the offline banner never appeared. The service worker now records the pages it answered from the cache after a failed network fetch and reports that in its status reply; the page shows the offline banner for them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cg3-v3hh Lockfile only (npm audit fix --package-lock-only in a copy): js-yaml 4.3.1 -> 4.3.2 and @redocly/openapi-core 1.34.19 -> 1.34.20; the lock's own version now matches package.json (1.0.0). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A rune on a 330 or 546 sat output could never move: RUNE_BATCH_TRANSFER refused every input without a rune allocation, so nothing could fund the postage, change and fee. An input without a rune allocation is now allowed when it carries no tracked asset at all; an input carrying any other asset without a rune allocation is still refused, and at least one input must carry a rune allocation (both RUNE_INPUT_MISSING_ALLOCATION). Asset movement is still derived by asset-flow, so a funding input only ever moves sats. Three vectors (accepted dust rune with a funding input, a funding input with an inscription refused, all-asset-free refused); every existing SafeOps vector keeps its verdict. SDK mirror, spec rule 5, reproducer index, counts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rker tests pin The three D7 SafeOps vectors bring the suite to 356 cases and the Node kit subset to 204. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erage rows tests/acceptance runs every Documentation coverage row a browser can prove against the built site and prints one ORDEX-ROW line per row with the run and commit; a new CI job runs it on the self-hosted runners. Rows that need a deployed gateway, docs service or an installed third-party MCP client are recorded as blocked with the reason. Product repairs the gates found: - Failure Navigator: "What the specification requires" is the whole spec sentence (or the table row) naming the code, never a wrapped fragment or a bare list of codes. - API Playground: every operation shows a contract example; the example builder samples the remaining id patterns and oneOf alternatives that only name required fields. - Sandbox: "Open this input in Protocol Lab" hands the step's exact verifier input over as a stored artifact (the URL carries only its id); the Lab loads it with its digest. The old link to /inspect/ opened the Lens sample, not the scenario artifact. - Artifact Lens: a transaction version change example joins the mutation examples. - Missions: stages open the tool their evidence needs (operate: Playground for prepare, simulate and inspect; diagnose: Playground for validate); Start Mission links are named per mission. - Insights: a 24 hour window (service and page). - Atlas: the exported SVG is standalone (resolved colors, size, background, title). - verify-kits: verifyKitDir builds, tests and starts a kit already on disk (a download). - Counts follow the three SafeOps vectors of aac5d6c (356 vectors, 204 kit cases). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… are told apart - Visual Protocol Atlas: the 16 diagrams move to scripts/docs/atlas-diagrams.json, each step audited against spec/*.md, the OpenAPI and AsyncAPI contracts and the verifiers, and each names its source (a spec heading, an operation or a channel) and, where one runs, the verifier. generate-all-data refuses an unknown heading, operation, channel, actor or verifier. Corrections include the Nostr kind (802, signed by the seller), SSE resume by Last-Event-ID, the real order states, and removing invented counts. The step panels show that source and verifier instead of a made-up wire payload and a blanket Worker claim. - Failure Navigator: a family with two reproducers for one code (its own branch and a shared helper it reaches) now has separate run state and file names; Lab links carry covers= so the Lab opens the same one. - Mission criteria wording follows spec/purchase.md. - Acceptance: per-check time limit with start markers, per-file CI steps with limits, --test-force-exit, and fixes for the checks the first run reported (Lens tiles, session wait, insights window, download button names). New atlas acceptance file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…run their helpers asynchronously The Atlas Source panel's specification link sat in running text with color only (link-in-text-block in both themes); it is underlined now. The recipe gate ran the page's SDK, fetch and cURL programs with a synchronous exec while the contract gateway they call runs in the same process, so every call waited forever; they run asynchronously now. The event stream gate destroys its WebSocket connections on close, tour steps are found inside their card, and the navigation gate counts failed responses except the docs service this static build does not include. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…orter wizard
Opening a wizard by ?wizard= rendered once with the step saved for the previous wizard
before the new wizard's progress loaded, so a one-step wizard read steps[2] and threw
("Cannot read properties of undefined (reading 'isMulti')"). The wizard now starts from the
URL and the step is clamped to the wizard's own steps on every render.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s and samples event streams The webhook routes document a developer API key (developerBearer), but the playground had no way to send one, so every webhook operation could only ever answer 401. A key field now appears for those routes; the key stays in the page, joins the request only when it is sent and never enters the plan, its approval fingerprint, cURL or saved evidence. streamOrdexEvents never ends, so the request waited for its 15 s timeout. An event stream is now sampled for 3 s (16 KiB at most), closed, and shown as received without a contract verdict or mission evidence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The orderbook check flagged OrderSummary.inspection.outputValuesSats, a list of decimal strings, as "not sent as decimal strings" because the list itself is not a string. Run against the Signet gateway this failed a compliant orderbook. A list under a key ending in Sats is now checked item by item and a bad item is named by its index. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… labels name "Read the catalog or an order" and "Request a quote or preflight" accepted any playground request, so a health read completed a purchase mission's prepare stage. They now count getCatalog, listOrders or getOrder, and quoteOrder, preflightOrder, composeBatchPurchase or preflightBatchPurchase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lifetime and scope Claude Code 2.1.281 (the installed client, over HTTP at revision 2026-07-28) connected and listed the tools, then refused resources/list and prompts/list as invalid results: both lacked ttlMs and cacheScope, which tools/list already had. Every list result now carries them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…age hydrates The Kits page is server rendered with the default runtime and applies ?runtime= when its island hydrates. The gate read the radio as soon as the label existed, so on a slower runner it saw the server-rendered default. It now waits for hydration first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ere Core needs it The published contract stays the public protocol; it moves only where it was internally inconsistent or would lose information a client needs for safety or resume: - SafeOps plan answers name planId, state, psbt and timestamps (every later plan route takes the id); a refused RBF or CPFP bump carries a null plan; CPFP names the changeOutpoint and the child destination; shield carries outcome and retryable. - Swap intent views carry their id; swap preflight answers allowed with a SwapPreflightResult instead of a bare verification view. - The private swap store returns its deleteCapability once; a destroyed envelope has a null ciphertext. Signing session rows use sessionId like the session, and the open answer returns its capabilities once. - Heritage asset, utxo and address reads carry readiness, completeness and the page cursor as objects. - The batch purchase 409 carries the shared error envelope; every by-id route documents 404. - AsyncAPI: the SSE id is <sequence>:<eventId>, the exact resume position with no lookup; the WebSocket frames name each subscription and wrap each event with its own cursor. The event playground follows both. - api.md states the 404 rule and the stateless MCP 2026-07-28 transport. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inality information Core could not serve these without losing information, so the contract moves: - PARTIALLY_SIGNED is a signing session state (multi-party sessions sit there between signatures). - A SUPERSEDE revision answers without a revocation; revocation is REVOKE only. - Plan and CPFP package fee rates are exact decimal rates, not atomic amounts, so the rate a plan was built at is never rounded. - A settled offer carries settlementFinal, the reorg-depth finality signal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The SDK dependency audit started failing on three new brace-expansion advisories (GHSA-q2hr-2g5m-vwhr, GHSA-qhr7-859c-m2p7, GHSA-6j4f-fj2g-mc7p); npm audit fix moves the dev-only transitive to the patched release. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reconciled contract - A partition lists SafeOpsPartitionPlan entries (a plan result without its own partition), so the schema has no cycle and the playground builds its createSafeOpsPlan and getSafeOpsPlan examples (OX-S-C828, OX-S-C829). - The playground example builder has a sample for the decimal fee rate. - The Event Playground stores the transport position as its resume cursor: the SSE id <sequence>:<eventId>, or the WebSocket frame cursor. The acceptance stream serves those ids and op-framed WebSocket events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e:test after The resume-position helper was named after, which collided with the imported after hook and stopped the playground acceptance file from loading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s stored Pausing wrote the step to the journey store without waiting, so a page opened right after (the /tour/ Resume link) could read the store before the write landed; the tours browser gate failed on that race. The URL now changes once the write resolves, and the gates wait for that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eflight limits in the contract text - ProtocolContract.protocolVersion and api.md: the gateway advertises one version everywhere, the contract info.version, including the MCP serverInfo version. - SwapSession.preflight and swaps.md: served only by a gateway that can state the maximum age of a session preflight; Core does not, so the preflight route's SwapPreflightResult is the verdict. - AsyncAPI eventsStream and events.md: sequences are per network; a stream with no network filter resumes exactly for the event's network and restarts the others from their oldest retained event (duplicates dropped by event id, never a gap); one stream per network gives an exact resume. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…outes answer 503 ORDER_CHECKING Core (impl/ordex-live-stability-20260930, cbcacba52) keeps an order LIVE on its last complete evidence while the inventory catches up to a new block, only while its inputs are unspent at the node, the new round found only missing evidence, no reorg was seen, and the evidence is at most 300 s old. A spend, withdrawal, contamination or reorg ends LIVE immediately. - spec/lifecycle.md documents the hold, its bounds and what ends it; spec/batch-purchase.md says a checking batch is retried, not refused. - quoteOrder, preflightOrder and preflightBatchPurchase document a retryable 503 (OrderChecking: the error envelope with code ORDER_CHECKING). composeBatchPurchase documents a 503 BatchPurchaseChecking whose refusals reuse BatchRefusal; the 409 refusals come first. - spec/openapi.test.js pins the four 503s and the shared refusal shape. No version change: request and success shapes are unchanged, and the new answer is a documented error status under the existing envelope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Against the Signet gateway a purchase quote checks the complete output inventory and answers in about 21 s, so the playground's 15 s bound cut every quote off with TIMEOUT and the operation could never be exercised. Requests now wait up to 60 s; Cancel stays available. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… batch preflight codes, heritage assetId Documentation rerun on Core 82bfc237c (C716, C717, C719, C720, C771): - Quote, preflight, batch purchase and batch preflight answer every 503 with a code from PurchaseUnavailableCode. ORDER_CHECKING stays the catch-up hold of the listing; a buyer output Ordex could not check for assets is the distinct INPUT_INVENTORY_UNAVAILABLE. The batch purchase 503 keeps its ORDER_CHECKING refusals (BatchPurchaseUnavailable). This replaces the ORDER_CHECKING-only 503 schemas added in a68d1fe. - AssetView: every protocol view of the sold inscription (ruling 2026-09-30). Required on Quote and on each batch placement, carried by PreflightResult. - BatchPreflightResult carries rejectCode (PLACEMENT_REFUSED, NODE_REJECTED) and rejectReason when allowed is false; each refused placement carries a BatchPreflightPlacementCode. - The heritage attach request names the asset by assetId, the numeric Counterparty id as a decimal string (required); assetName is an optional hint that must match the ledger record. - api.md and counterparty-utxo-asset.md say the same; spec/openapi.test.js pins the 503 codes and the view disclosure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Implements the Ordex handoff packages in this repository (handoff: ordex_HANDOFF_2026-09-29):
Local results at the head: build pass, npm test 737 pass, conformance 353/353, SDK tsc clean, SDK tests 566/566, every refusal code has an executable reproducer (2 documented unreachable parse codes). Browser gates (tests/e2e) run only in this CI on self-hosted runners.
Not a release: main publishes GitHub Pages; this goes to develop. Functional Signet acceptance is tracked separately in the handoff.
🤖 Generated with Claude Code