Skip to content

Ordex mainnet implementation: protocol, verifiers, SDK and documentation product - #58

Open
bitcoinuniverseadmin wants to merge 57 commits into
developfrom
impl/ordex-mainnet-20260929
Open

bitcoinuniverseadmin wants to merge 57 commits into
developfrom
impl/ordex-mainnet-20260929

Conversation

@bitcoinuniverseadmin

Copy link
Copy Markdown
Collaborator

Implements the Ordex handoff packages in this repository (handoff: ordex_HANDOFF_2026-09-29):

  • Protocol, verifiers and SDK: OX-P01 SafeOps v2, OX-P02 swap acceptance v2, OX-P03 cold signing v2, OX-P04 Runes parity with ord 0.29.0, OX-P05 funded offers (no buyer padding; two independent policy signer hashes), OX-P06 SDK/API integration, OX-P09 revocation context, OX-P10 Counterparty move semantics (v11.4.0), OX-P11 recoverable webhook delivery keys.
  • Documentation product: OX-S01 to OX-S12, OX-P07/P08 (MCP 2026-07-28 stateless engine; self-hosted Node docs service replacing the unconfigured Worker target).
  • Contract list shapes aligned with Core's served routes.

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

bitcoinuniverseadmin and others added 30 commits September 29, 2026 01:22
…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>
bitcoinuniverseadmin and others added 27 commits September 29, 2026 10:32
…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

No deployments
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