fix: repair the 35 defects of the 2026-09-16 read-only audit and connect the missing service paths - #126
Merged
Conversation
…nd abort (BE-DEF-015) Replace the unconditional throws behind the five private submission routes with a real path: owned relay endpoints from UNIVERSE_PRIVATE_RELAY_ENDPOINTS (SOCKS proxy plus onion/i2p submit URL, network-checked), bounded transaction validation, a MySQL submission table (schema 110), a leased bounded-retry worker that relays through socks-proxy-agent and tracks confirmation on the owned node, owner-token authenticated readback and an atomic pre-relay abort that reports abort-too-late once relay has started. Without a database the feature reports durable-store-unavailable; no in-memory mode, no signing, no third-party broadcaster. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… adapter (BE-DEF-001, BE-DEF-002) Query Studio parses a bounded SELECT grammar, renders parameterised statements against an allowlist of explorer tables and runs them on a dedicated read-only pool named by UNIVERSE_QUERY_ENGINE_DSN with a deadline, row and byte limits and cursor pagination; schema discovery reads information_schema; history is appended per API-key owner; usage reads the in-process owner usage ledger and reports no-observations honestly. Restart and rollback discover the owned deployment adapter through EXPLORER_DEPLOYMENT_CONTROL_ENDPOINT and _KEY, preview from its capability document, drive its jobs to completion with a bounded wait, and derive the rollback target from the adapter journal. The adapter itself (scripts/universe/deployment-control-adapter.mjs) wraps release.sh cutover and rollback behind HMAC-verified loopback requests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… the protocol pages FE-D01 protocol directory: every registry attempt is its own inner stream with loading, result mapping and catchError inside the switchMap, so a failed read no longer completes the retry subscription and Retry cancels the attempt in flight. The 20 s budget is kept. FE-D02 protocol directory: the view model carries the network the registry request was addressed to, and the intro and empty-state copy name it (Signet, Testnet, Testnet4, Regtest, mainnet) instead of "Bitcoin mainnet". FE-D03 pulse service and strip: explicit observation state (unknown, observed, unavailable, stale with the last sample time). The initial state is unknown, a batch whose every item the authority refused never marks it answering, only resolved items are counted, a generation token drops work from a previous network or a stopped sample, and the strip shows "no sample" instead of unmeasured zeros. FE-D04 universe-api: getPropagationObservation$ uses backendBase like the nodes and templates reads, keeping the encoded txid path and SSR base. FE-D05 protocol detail: route resolution is typed (loading, registry-error, missing, found), the registry failure is caught inside the attempt, the error panel has a Retry control, and activity/object reads are cancelled on every new resolution so a late answer cannot paint a previous protocol. FE-D06 protocol detail: availability comes from the shared protocol-availability helper (current authority state plus declared capability), the release status is a separate qualifier, and limitation() explains every non-available state including a stale or unreachable authority behind a verified reader. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ract The broadcast page keeps the owner token returned once at creation in memory, sends it on readback and abort, understands the durable relay states (relaying, submitted, confirmed, rejected, cancelled, abort-too-late) and reports an abort that came too late as exactly that. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eplay fence, real tx status, sigop accounting, fiat provenance BE-DEF-007/008/009: scheduleSingleTask releases its slot (identity-compared) before running so a task can reschedule itself; runSingleTask resets the running flag in finally and returns a typed SingleTaskOutcome. The admin task handler verifies only a completed outcome whose persisted checkpoint reads back complete; reindex reports scheduled only when the indexer accepted. BE-DEF-010: track-txs never defaults to confirmed; each id is resolved as mempool, replaced, confirmed (real block height/hash from the node), unknown or unavailable, deduplicated and bounded. BE-DEF-011: the JavaScript block template accumulates sigops per placed transaction and resets per bounded block. BE-DEF-003/004/006/013: cancellable is persisted in the run document; runs get an initial lease and an owner token; lock conflicts leave a FAILED record; executors heartbeat with compare-and-set while work runs; reconciliation is batched, revalidates the lease, and returns a structured result that surfaces storage failures. Schema 110 adds admin_adapter_runs.owner_token. BE-DEF-005: admin nonces are claimed atomically in a shared store (MySQL admin_nonces table, or Redis SET NX PX); no shared store fails closed; the in-memory store is only used on the explicit EXPLORER_ADMIN_REPLAY_STORE=memory opt-in and never evicts a live nonce. BE-DEF-012: stored fiat rates are retained but not advertised as current when the feed is disabled, the network is unpriced, or the observation is stale; the prices route and websocket conversions carry the observation state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…telemetry (BE-DEF-014) Nodes, propagation and templates come from the relay collector's mempool poll lifecycles, the template collector's candidate templates and the local mempool. One observer is labelled as one observer; regions, clock offsets and inter-node latency are unknown; unobserved transactions and empty collectors answer with explicit states. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts: # backend/src/api/database-migration.ts
…faults, align container pins RC-ORIGIN-001: scripts/universe/check-origins.mjs now parses hostnames with the WHATWG URL class, normalises case and trailing dots, rejects forbidden providers by host equality and dot-suffix, flags infix lookalikes, and applies an explicit runtime-origin policy: call sites and runtime configuration may only name relative paths, loopback, container names, bitcoinuniverse.io hosts, or the documented Liquid asset catalogue metadata exception. Build inputs are allowed in build context only, citations in documentation and comments, and credentials in a URL are reported without ever being printed. Source and bundle scans are separate; the blanket production/, docker/, rust/ and workflow exemptions are gone. scripts/universe/check-origins.test.mjs pins the six audit fixtures, lookalikes, credentials, ports, redirects and the metadata and citation contexts. RC-ORIGIN-002: docker/backend/start.sh, docker/frontend/entrypoint.sh and the production templates no longer default any endpoint to mempool.space or its onion; the start scripts refuse a disallowed, malformed or credential-bearing endpoint with exit 78 and name only the field and host. Fiat prices and the mining pool refresh are off unless configured. The frontend's onion switch is now the explicit ONION_SERVICES_API field instead of a hostname-based provider change. scripts/universe/docker-runtime-defaults.test.mjs renders both start scripts and proves the minimal, owned and rejected cases. Docs list the owned endpoint prerequisites and the exact scope of the metadata exception. RC-PACKAGE-001: the container images pin Node 24.19.0 / npm 11.17.0 and Rust 1.89.0 (verified at build time), install from the lock file, and use the fork's production frontend build. .github/workflows/docker.yml is a build-only gate for develop/main pull requests touching the templates, with publication only from an explicit dispatch; workflow-safety.test.mjs pins that shape. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The origin gate now refuses the inherited mempool.space onion as a backend default; the field starts empty and the deny fixture in the relay test is marked as such. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sured plans and authorized operator jobs BE-DEF-018: a signed catalogue (UNIVERSE_BOOTSTRAP_SNAPSHOT_CATALOGUE) with ed25519 producer keys and operator-pinned Bitcoin Core commitments backs listSnapshots/getSnapshot; verifySnapshot streams the actual bytes from an allowlisted source under a size and deadline bound, checks sha256, manifest signature, network magic, base block and height against the owned node, and reproduces Core's hash_serialized_3 while streaming (proved against a real Core 28.0 regtest dumptxoutset fixture). Runs persist in universe_bootstrap_verifications; a missing run is 404, a missing store 503. BE-DEF-019: createBootstrapPlan uses the measured node capabilities and chainstate, a statfs or operator-measured capacity, and a verified pinned snapshot compatible with the node's exact release; it rejects unsupported network/version, missing capability, unmeasured or stale capacity, insufficient space, unverified snapshots and ineligible chainstates. BE-DEF-020: operator POST routes sit behind the admin adapter guard (private origin plus signed request) and loads need signed elevation and a typed confirmation; jobs are durable (universe_bootstrap_jobs) with idempotency keys and leases, executed by a bounded worker that issues dumptxoutset or loadtxoutset with a configured path only and records Core's own result and the observed chainstate; a timeout or a crash after the RPC ends in needs-review, never a re-issued RPC. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…6-go # Conflicts: # backend/src/api/database-migration.ts
…ipt trust (BE-DEF-016, BE-DEF-017) diagnoseTransaction reads the requested transaction's own mempool entry and the owned policy floor; unknown transactions are a typed 404. The ordering methods compare each mined block's order with the templates recorded for its height and the relay first-seen observations, with no-template-observed as an explicit coverage state. Accelerator providers come from the owned directory named by UNIVERSE_ACCELERATOR_PROVIDER_DIRECTORY and receipts verify against its keys (ed25519 or BIP-340 Schnorr) over a documented deterministic payload, with replay detection. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ure the raw body The operator prefix mounts the raw-body parser before the general JSON parser so the signed request can be verified, the guard is given the same shared replay store as the admin adapter, and the public job readback no longer carries the operator key id or the host path of the written snapshot. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts: # backend/src/api/intelligence/private-submission/private-submission.service.ts # backend/src/api/intelligence/private-submission/private-submission.test.ts # backend/src/api/intelligence/private-submission/submission-input.test.ts
…reads Pinned from the regenerated backend-apis manifest: tap_doge gains chain-list, chain-detail, holders and events descriptors, collection rows carry their pagination style and detail routes use the controllers' real parameter names. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…io and submission contracts truthfully Bootstrap: the planner renders the backend's measured feasibility plan (node facts, capacity, required bytes and headroom, selected verified snapshot, assumptions, download estimates labelled as assumptions, expected transitions, actions not executed, rollback) and its typed rejection stages, instead of gating on sync hours the backend never measures. The verifier starts a run, polls the 202 record until a final state with a bounded readback that is cancelled on edit, network switch and destroy, renders every independent check with expected/observed and reason, shows caller inputs as inputs, and keeps 404 apart from 503. The overview renders the four subfeature statuses with reasons; snapshot list and detail render the catalogue fields, verification state and the signed manifest link. Network observatory: models follow the single-observer contract; the page labels the one observer as such, unknown regions and unmeasured latency as unmeasured, renders propagation and template states (observed, not-observed, no-observations, no-templates-observed) without a fabricated timeline, and shows a 503 owned-node-unavailable as an unavailable state with a retry that cancels the in-flight attempt. Query Studio: typed models for schema discovery (tables, missing tables, grammar, source) and execution (exact big-number strings, truncated, opaque cursor); rejected-by-grammar with position, unavailable engine with reason, and deadline are rendered as distinct failures; a next page is fetched through the cursor. Developer usage renders observed counts, quota, latency and coverage or the no-observations state, and a failed read as unavailable rather than zero. Private submission: providers from the owned directory (identity, keys and validity windows, terms, unmeasured health, null expiry) validate and render; receipt verification renders each stage distinctly from its 200/409/503/400 answer; diagnosis renders the transaction's own mempool facts or transaction-not-in-mempool; ordering renders the typed states, the findings envelope with no-blocks-observed, and 404s as not observed rather than empty success; the overview renders relay, queue and worker facts. Docs: track-txs documents the per-transaction status field and that confirmed is only true alongside blockHeight and blockHash. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ed network
Audit WP-PO-01 step 4 / frontend targeted task 4. The frontend hard-coded
network=mainnet on every Dogecoin and Zcash read, so the overlay's new
per-chain network scopes could not be reached and the Bitcoin selector was
the only network context on the page.
- UNIVERSE_CHAIN_NETWORKS, a new optional frontend env key: a JSON object
(or JSON string, the Docker form) naming the network each non-Bitcoin
chain is read from, e.g. {"dogecoin":"testnet"}. Default {} keeps every
chain on mainnet. Values other than mainnet|testnet|regtest, a bitcoin
entry, or unparseable input are ignored with one console warning and
that chain reads mainnet. Read in chain-network.ts from
StateService.env, memoized on the raw value.
- UniverseApiService.chainNetwork(chain) / chainNetwork$(chain): Bitcoin
follows the selector, every other chain its configured network. Used by
every getChain* route, protocol list/detail/section, search, sources,
status, the scoped universe routes, the live websocket subscription and
envelope check, bookmarks, the picker labels and the chain docs page.
- getChains$ reads /api/v1/chains/<chain>?network=<resolved> per chain,
since the overlay lists /api/v1/chains by one network and a Signet
reader with Dogecoin on testnet has no single list. A record answering
another network is rejected; a typed unavailable record for the
configured scope passes through under its own network.
- A 503 <chain>-network-unavailable body renders a message naming the
configured network; nothing falls back to mainnet.
- generate-config.js emits object settings as JSON and quotes them in the
Docker template; the frontend entrypoint defaults the variable to {}.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… was born from A restart or rollback replaces the backend that drives it, so the original executor never sees the adapter job finish. On mount the new process reads every RUNNING deployment run that recorded its job id, reads the job back from the adapter and closes the run with the same evidence, instead of leaving it for the reconciler to mark abandoned. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…fore closing Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The backend reconnects to its database, runs migrations and reloads the mempool before it listens again, which took 8 to 10 s on the validation stack; the 5 s window answered 502 twice per restart. Eleven seconds stays inside the 12 s bound the gateway tests hold a dead upstream to. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ndbox Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BACKEND=none is refused by this fork because every address lookup would fail while the site still offers them; the compose template now names an owned Esplora on the container loopback (socket or published port) and documents the topology. The non-publishing container gate exercises exactly this file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Response to
audits/chatgpt-readonly-20260916-1919/mempool_HANDOFF_2026-09-16.zip. Every mempool-side defect (BE-DEF-001 to 020, FE-D01 to D06, RC-ORIGIN-001/002, RC-PACKAGE-001) is repaired here; the overlay defects PO-D01 to D05 are in bitcoinuniverseio/backend-apis#197 and the DRC-20 decision authority in bitcoinuniverseio/ord-dogecoin#55.Backend
track-txslooks the transaction up on the owned node and never reports an unknown id confirmed (BE-DEF-010); JS template selection accumulates block sigops (BE-DEF-011).scripts/universe/deployment-control-adapter.mjs(BE-DEF-002).Frontend
Repository and controls
Verification: backend unit suite 2025 passed (the 13 failing tests are the native-engine suites that CI builds), frontend 2241 vitest passed, lint 0 errors, all text/origin/branding gates green; the isolated Signet app on this branch passes 22 real API journeys (evidence in the handoff package).
🤖 Generated with Claude Code