Skip to content

feat(eqc): BRC-178 economic query client and overlay-express registerRouter hook - #549

Draft
sirdeggen wants to merge 48 commits into
mainfrom
claude/eqc-economic-query-client-9f9bde
Draft

sirdeggen wants to merge 48 commits into
mainfrom
claude/eqc-economic-query-client-9f9bde

Conversation

@sirdeggen

Copy link
Copy Markdown
Contributor

Draft. Stacked on #525 (codex/overlay-admission-s03): this branch starts at 1a1b15693, which is in that branch, so the diff here shows only this work. When #525 merges, retarget to main. A trial merge of this head into the current #525 tip (7392dbe01) has no conflicts, and docs:packages:check plus the governance count tests pass on the merged tree.

Program and scope

  • Tracker or issue: none. Requested directly by a maintainer; the approved design is in this PR at docs/superpowers/specs/2026-09-18-eqc-brc178-design.md, the plan at docs/superpowers/plans/2026-09-18-eqc-economic-query-client.md.
  • Program gate(s) advanced: not applicable.
  • Why this change is needed: implements BRC-178 (race-settled collection markets) so independent overlay nodes and message box servers can compete to answer one query and be paid by client-measured arrival order, with BRC-136 topic anchors reported as a consistency signal for overlay lookups.
    • New package @bsv/eqc: protocol core (canonical JSON query IDs, canonical payload hashing, wallet-only BRC-77 attestations, Fibonacci payouts, BRC-29 derivation bound to query and rank), the EQC client (new EQC(wallet); SLAP-bootstrapped discovery like LookupResolver, race, one payout transaction, collect, hash verification, local reputation), and framework-agnostic host handlers at @bsv/eqc/host for GET /economic/params, POST /economic/query, POST /economic/collect.
    • @bsv/overlay-express: additive registerRouter(path, factory) that mounts application routers after the BRC-103 middleware and before the admin routes and 404 handler.
  • Explicitly out of scope (design phases 2 and 3): wiring infra/message-box-server and infra/overlay-server (both consume published packages, so they need @bsv/eqc on npm first), collectionGrant storage, multi-host message box anointing and send fan-out, collection grants end to end, host gossip, query deposits.
  • Exact head SHA reviewed: 5bb4950775e9ffcb0a4f46b7235e5e5e1ede248d

Impact

  • No public package source or manifest changed
  • Public package source or manifest changed; affected packages are listed below
  • Infrastructure source, dependency, image, or deployment configuration changed
  • Public API, exports, types, runtime targets, or browser/mobile behavior changed
  • Security-sensitive boundary changed
  • Documentation or examples changed

Affected packages/services and intended patch versions (publication occurs only
through the release workflow after approval):

  • @bsv/eqc — new, 0.1.0 (release notes 0.0.0 -> 0.1.0, minor). Peer dependency: @bsv/sdk only. No express or @bsv/overlay import; host handlers are typed structurally.
  • @bsv/overlay-express — 2.7.1 -> 2.8.0 (additive method and two exported types; no existing behaviour changed).

Security-sensitive surface, for the reviewer:

  • The client spends only through one createAction per query, capped by maxFeeSats (default 2000), and makes no wallet call when fewer than threshold hosts attest one hash.
  • AuthFetch pays any well-formed HTTP 402 with no cap. The transport therefore gives it a wallet allowlist (getPublicKey, createSignature, verifySignature, createHmac, verifyHmac); an end-to-end test has a host demand 1,000,000 satoshis and asserts the wallet is asked for exactly one action.
  • Hosts locate their own payout by deriving the script they expect, never by a client-supplied index; message-list is served only to the authenticated recipient; the free attestation path is bounded (entries, estimated heap bytes including query params, per-client cap, TTL).
  • Known and documented, not fixed here: the threshold counts identity keys, not operators, so hostOverrides pinning is the defence for value-bearing reads; AuthFetch buffers authenticated responses before any byte cap can apply (an @bsv/sdk limitation); the wallet registerRouter hands out has no storage provider and cannot internalize payments, so operators must pass a storage-backed wallet built from the same root key.

Verification

  • Local commands and results (all run by the author at 5bb495077, all exit 0):
    • pnpm --filter @bsv/eqc test — 21 files, 280 tests passed, 0 skipped; test:property 6 passed; end-to-end suite (real HTTP, real createAuthMiddleware, real AuthFetch) run three more times, 6/6 each
    • pnpm --filter @bsv/eqc typecheck, lint, format:check, build
    • pnpm --filter @bsv/eqc pack:check — packed payload, all conditional exports, source maps, publint, strict type resolution, esm/cjs clean consumers
    • pnpm --filter @bsv/eqc test:browser — exact-tarball browser contract verified
    • pnpm --filter @bsv/overlay-express test — 13 suites, 344 tests passed
    • pnpm health:check — 43 projects, 35 public packages, 0 contract findings, 0 control errors
    • pnpm typecheck, pnpm lint, pnpm format:check (repo-wide)
    • pnpm docs:facts:check — 0 findings; pnpm --filter docs-site validate — 125 files, frontmatter and links OK
    • node scripts/check-sdk-peer.mjs — 38 manifests, no violations
    • pnpm install --frozen-lockfile --ignore-scripts — tree stays clean
    • Reported by the implementing agent at an earlier head and not re-run at this head: repo-wide pnpm build, pnpm audit:security, and pnpm test:mutation --target eqc-protocol (89.47%, floor 85).
  • Hosted CI run: pending on this draft.
  • Conformance evidence: none added. BRC-178 has no shared vectors yet; the design's "Protocol decisions" table records 16 encoding choices that should be fed back into the BRC before vectors are written.
  • Coverage delta: new package; test:coverage reported statements 95.34%, branches 90.54%, functions 100%, lines 97.45% before the final fix wave added 76 tests.
  • Lint/typecheck delta: clean, no suppressions.
  • Browser/mobile/packed-consumer evidence: pack:check and test:browser above; the client bundle contains only @bsv/eqc and @bsv/sdk.
  • Performance or bundle-size delta: new browser-budget.json for @bsv/eqc entry . — measured vite raw 508859 / gzip 131707 / brotli 110327, esbuild raw 393706 / gzip 120831 / brotli 103337, budget set at 1.1x of the first measurement.
  • I self-reviewed the complete diff for correctness, security,
    compatibility, public API, artifacts, dependencies, docs, and operations
    (every task passed a task-scoped review; a whole-branch review with seven review seats and three adversarial verifiers per finding confirmed 18 findings, all fixed and re-reviewed 18/18 addressed; 44 Minor findings deferred, see below)
  • All applicable checks are terminal and successful on the exact head; any
    scope-based skip is expected and validated by the merge gate

Security and dependencies

  • No dependency or lockfile change
  • Changelog, runtime relevance, peer compatibility, transitive graph, and
    audit results were reviewed
  • CodeQL/negative tests cover any changed trust boundary
  • The exact-head CodeQL analysis has no new alert
  • The exact-head repository quality gate reports zero new Sonar findings
    (including accepted or false-positive issue states) and zero unreviewed hotspots;
    Sonar's aggregate Quality Gate passed verdict alone is not merge evidence
  • No new override, advisory dismissal, quality suppression, or skipped test
  • Any temporary exception is registered with owner, evidence, review date,
    and removal condition (not applicable: none added)
  • Workflow permissions and lifecycle-script behavior remain least privilege

Dependency evidence

  • Release notes and necessity: @bsv/eqc adds no runtime dependency. Its dev dependencies (vitest, @vitest/coverage-v8, tsdown, fast-check, oxlint, express, @types/express, @bsv/auth-express-middleware workspace link) are versions already used elsewhere in the workspace.
  • Runtime, build, and peer compatibility: @bsv/sdk is a peer (^2.4.1) and a dev dependency (workspace:^), never a dependency; check-sdk-peer.mjs passes.
  • Deduplicated lockfile: NOT minimal, please look. Adding the importer made pnpm re-key the shared vitest@4.1.11 instance and move its transitive tinyexec 1.2.4 -> 1.3.1 and picomatch 4.0.5 -> 4.0.7. --frozen-lockfile passes. Regenerating from the base lockfile with pnpm install --lockfile-only --ignore-scripts may give a smaller diff.
  • Audit and CodeQL: pnpm audit:security reported clean at an earlier head; CodeQL pending.
  • Package and consumer tests: see Verification.
  • Bundle and performance impact: see Verification.
  • Affected public package versions: @bsv/eqc 0.1.0 (new), @bsv/overlay-express 2.8.0.

Release and operations

  • No npm publication was performed from a workstation or from this PR
  • Required npm patch bumps are included or intentionally deferred by the
    controlling program
  • Image/SBOM/provenance/deployment/rollback impact is documented (not applicable: no infrastructure or image change)
  • Documentation, changelog, migration, and operational guidance are current

Completion evidence

  • The linked tracker is updated only for work fully proved by merged code,
    passing checks, resolved alerts, measurements, or an approved exception
  • Review conversations are resolved
  • Documentation, changelog, migration notes, release notes, and operator
    guidance are current or concretely not applicable
  • No pending, failed, stale, cancelled, or unexpectedly skipped check is
    being handed to another contributor as “complete”
  • One qualified maintainer approval is sufficient; no last-pusher
    restriction is assumed

Notes for the reviewer

  • Departures from BRC-178 as published, each argued in the design document: HTTP paths are /economic/* rather than /brc178/*; the default floor is 1000 satoshis rather than 2; the overlay-lookup content hash covers the sorted outpoint section only, with BEEF delivered beside it (honest hosts hold different proof state, so hashing BEEF would never reach a threshold); the client broadcasts with a normal createAction rather than after delivery (a host's internalizeAction broadcasts on receipt anyway); a host's required share is the remainder-free Fibonacci share of the fee it quoted (the share "at its own floor" including the rounding remainder is not monotone, so an honest rank-1 host could refuse a larger payment).
  • Commit trailers are mixed. Commits were written by agents on different models and each used the Co-Authored-By line its own session named (Claude Fable 5.1, Claude Sonnet 5, Claude Opus 5 (1M context)). Say if you want them rewritten to one form before merge.
  • Deferred: 44 Minor review findings and four Minor residuals from the fix wave (a same-millisecond 409-instead-of-410 window; ERR_EQC_PAYMENT with a misleading message when every ranked host is below its advertised minPayoutSats; hostSetHint crowding; the test-quality policy's invariants list not naming the new requiredShare property). packages/overlays/overlay-express/API.md (ts2md-generated) does not yet list the two new exported types.

🤖 Generated with Claude Code

Base automatically changed from codex/overlay-admission-s03 to main September 19, 2026 14:29

@ty-everett ty-everett left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainer review: keep this draft and rebuild a focused diff on current main, preserving the already-merged overlay/security work. Resolve paid-result recovery before release. The documented BRC-178 differences in paths, fee defaults, content hashing and payment timing also need an explicit interoperability decision and shared vectors. Recheck the AuthFetch buffer assumption and peer floor against the current SDK, finish generated API documentation, and obtain complete exact-head CI and zero-new-finding analysis. Distinct public keys alone should not be described as independent operators.

{ queryId: request.queryId, host, payload, supplement },
originator
)
await store.completeSettle(request.queryId)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve an idempotent recovery path for paid delivery. completeSettle releases payload/supplement and marks the query settled before this HTTP response is delivered. If the response is lost, a retry returns ERR_QUERY_SETTLED/409, while the client has already broadcast payment. Persist the paid outcome and retrievable signed delivery, bound retention explicitly, and test lost responses, duplicate collection and process restart without charging twice or losing the answer.

sirdeggen and others added 27 commits October 2, 2026 15:55
Design for a new @bsv/eqc package (EQC client, protocol core, host
handlers) and an additive registerRouter hook in @bsv/overlay-express.
Records the BRC-178 ambiguities resolved during design and how BRC-136
topic anchors serve as a consistency signal for raced overlay lookups.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Replace the static host list with LookupResolver-style discovery from
DEFAULT_SLAP_TRACKERS, with the ls_slap step answered free and covered by
the target query's fee. Default floorFeeSats to 1000 and maxFeeSats to
2000. Rename the HTTP binding from /brc178/* to /economic/*.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Eighteen test-first tasks covering the protocol core, host handlers, the
EQC client, end-to-end tests, the overlay-express registerRouter hook,
and governance registration.

Planning surfaced that AuthFetch pays any well-formed HTTP 402 with no
cap, so the design now requires a transport whose wallet facade cannot
create actions. The design also gains the maxHosts and now options and a
source layout and test split that match the plan.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
decodeOutpointList's three unguarded varint reads let Utils.Reader
propagate a plain Error (not TypeError) for a 0xff-prefixed 64-bit
varint above 2^53, breaking the module's malformed-input contract.
Add one guarded read helper used at all three call sites (count,
outputIndex, contextLength) and cover each position with a test.

Also add a test proving a rebuilt LookupAnswer (Atomic BEEF per
output) canonicalizes back to the identical payload and content
hash; canonicalizeLookupAnswer already handles Atomic BEEF correctly
via Transaction.fromBEEF/Beef.mergeBeef, so no implementation change
was needed there.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
InMemoryPendingStore.put replaced a record that was already stored under
the same queryId. The old record's bytes were never released, so repeating
one queryId drove the counter past maxBytes and made every later put fail
with too-many-pending; worse, an overwrite reset a settling record to
pending, letting beginSettle succeed twice and breaking the atomic claim
two concurrent identical queries rely on.

put now answers 'duplicate' for a queryId it already holds that is not
purge-eligible, leaving the record and the byte counter untouched. The
query handler re-reads the record and shares the existing-record branch,
so both racers get the one stored attestation.

The byte budget also counted number[] elements while maxBytes was
documented as 256 MiB. A V8 number[] element costs about 8 bytes, so the
store under-estimated its own footprint roughly 8x on a free route.
sizeOf now multiplies by that constant; the option name and default are
unchanged and now mean estimated heap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Utils.toArray(envelope.transaction, 'base64') ran before the try that
guards Transaction.fromAtomicBEEF, so a non-base64 transaction field
threw a raw Error instead of returning { ok: false, reason: 'malformed' }
as the PaymentVerification union promises. Move the decode inside the
try block and add a test asserting a non-base64 transaction is rejected
as malformed without touching the wallet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…enges

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
referenceFor took Math.max over every winner's claimed blockHeight with
no corroboration, so a single dishonest winner could set the topic's
reference tip and TAC, marking honest hosts lagging and excusing a
genuinely diverged minority host in classifyMinority.

Per controller ruling R11: the reference height for a topic is now the
highest blockHeight reported by at least two distinct winners. With no
such corroborated height there is no reference, every winner that
reported the topic is unknown, and blockHeight/tac are omitted. A
winner above the reference is unknown, below it is lagging, at it is
agreed only when every winner at that height shares one TAC (otherwise
diverged). classifyMinority uses the same corroborated reference and
no longer treats an uncorroborated or TAC-less reference as an excuse.

Rewrote the one consistency.test.ts case that encoded the old
uncorroborated semantics, and added tests for the A/B/C poisoning
scenario, a single reporting winner, and classifyMinority not excusing
a diverged host behind a fabricated height.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Controller ruling R12: a resolver failure must not be cached. discover()
now signals a resolver rejection as undefined, distinct from a successful
but empty answer, and hostsFor skips the cache write on failure while
still returning that call's additionalHosts.

Controller ruling R13: message-list targets now cache per recipient
(message-list:<recipient>) so resolving message boxes for two identities
never mixes their hosts, while hostOverrides/additionalHosts stay keyed
under the shared 'message-list' market key as the design document states.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
getParams and post compared decoded text.length against the byte caps
after the whole response had already been buffered, so an untrusted
host could force an unbounded allocation before the cap ever fired,
and a multi-byte UTF-8 body could exceed the byte cap while passing
the character-count check.

getParams now rejects immediately on an oversized content-length
header, and otherwise streams response.body through a reader,
counting bytes and cancelling the reader plus aborting the request as
soon as MAX_PARAMS_BYTES is crossed (falling back to arrayBuffer()
only when no body stream is available). post measures
arrayBuffer().byteLength against maxResponseBytes before decoding,
with a comment noting that AuthFetch itself buffers the whole
response with no AbortSignal, so this check cannot bound or cancel
allocation below the SDK boundary.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`EQC.params()` negative-cached every failure for the full `paramsTtlMs` and
re-threw a fabricated error, so a two-second connectivity drop while candidates
probed its hosts left `ERR_EQC_NO_HOSTS` standing for five minutes. Add
`TransportStatusError`, carrying the HTTP status, and cache a refusal only for a
4xx answer, which is the host stating it runs no market. Timeouts, network
errors, parse errors, and 5xx answers are re-thrown unchanged and uncached, and
a cache hit re-throws the very error the transport raised.

The ranking tests asserted exact arrival order across 8 ms gaps on real timers,
which a loaded runner can reorder. Every gap an assertion depends on is now at
least 25 ms, with the race windows and host timeouts scaled to match, and every
assertion kept as strong as it was.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sirdeggen and others added 12 commits October 2, 2026 15:55
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Host half of the final review fix wave (rulings R17, R18, R20-R23).

- requiredShare: the remainder-free Fibonacci share. Collect requires it at the
  quotedFeeSats the host signed and no longer re-evaluates floorFeeSats, so a
  fee above the floor can never be refused at rank 1.
- A wallet that throws during internalizeAction is a 'wallet-error': logged
  with queryId, rank, client and txid, answered 500, settle claim released.
  Only accepted !== true is still a 402.
- The advertised topK is enforced on the query route.
- maxPayloadBytes defaults to 2 MiB and bounds the estimated encoded delivery.
- The pending store budgets the stored query, and an expired unsettled record
  releases its bytes and its per-client slot at once. Collect holds the payload
  before settling so a mid-settle release cannot empty a paid delivery.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Client half of the final review fix wave (rulings R19, R20, R24-R27, R31).

- nonPayingWallet is an allowlist: only the five calls BRC-103 authentication
  makes reach the wallet, listCertificates answers an empty list, and every
  other method rejects by name, so a host cannot harvest certificates.
- DiscoveredHost carries identityKeys, every key advertised for a URL. A
  session key outside the list rejects the host for the query as a soft
  event; a signer that differs from the session key stays hard.
- collect-failed is a hard reputation event; diverged-answer is soft.
- Hosts of equal reputation are shuffled before the maxHosts cut.
- paramsTimeoutMs (2000 ms) bounds each params probe, and a passing failure
  is negative-cached for min(paramsTtlMs, 15 s) and recorded as a soft event.
- Hosts advertising a smaller topK are skipped, and a ranked host whose share
  is below its advertised minPayoutSats gets no output and no collect.
- Tests pin the client-side supplement check and the per-host deadline on
  authenticated calls, in the loopback network and over real HTTP.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… code

Documentation half of the final review fix wave (rulings R17, R20, R21,
R27-R30).

- The wallet a registerRouter factory receives is the BRC-103 authentication
  wallet: no storage provider, cannot create or internalize actions. The eqc
  examples build a storage-backed wallet from the same root key instead, and
  the overlay-express README, docs page, and JSDoc say so.
- The threshold counts identity keys, not operators; hostOverrides pinning is
  the defence for value-bearing reads.
- Authenticated responses are buffered by AuthFetch before the byte cap can
  apply; maxHosts and hostTimeoutMs bound the exposure.
- The enforceable per-delivery minimum is max(minPayoutSats, share at rank K
  of K), and maxPayloadBytes relates to the server response limit.
- The design document matches the code: corroborated consistency reference,
  transport caps, params caching, reputation events, decision 6, host options,
  pending store accounting, wallet facade, discovery identity keys.
- The implementation plan gains frontmatter and its two quoted links no longer
  trip the docs link checker, so docs-site validate passes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Kills the two string mutants the eqc-protocol mutation target left alive in
requiredShare.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Moves the development toolchain to the versions main now uses (Vitest 5,
V8 coverage 5.0.1, tsdown 0.23.0, oxlint 1.83, @types/node 26.6.1) and
widens the @bsv/sdk peer to ^2.8.0 || ^3.0.0. SDK 2.8.0 is the first
release whose AuthFetch accepts bounded transport options and whose SLAP
advertisement template enforces canonical names and https/wss/js8 URIs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sements

@bsv/sdk 2.8.0 lets AuthFetch take a response byte cap and a fetch client,
so the transport now passes maxResponseBytes and its fetch through instead
of rechecking a fully buffered body. The same release only builds and
decodes SLAP advertisements with canonical ls_ names and https, wss or js8
URIs, so plain http hosts under the local preset can only come from
configuration. Tests build malformed advertisements without the template,
move the http case to hostOverrides, advertise e2e hosts over https with a
loopback fetch, and pin the SDK-level byte cap. Docs drop the stale
buffering limitation and state that distinct keys are not evidence of
independent operators.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The root entry grew from the SDK 3.0.0 trust-boundary graph it pulls in
(AuthFetch, LookupResolver, SLAP template, wallet-result validation);
@bsv/eqc itself is about 32 KB. Records the measured sizes in the browser
artifact disposition and sets limits with roughly 15% headroom, matching
the convention used for other SDK 3 consumers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sorts with one explicit UTF-16 code-unit comparator (never localeCompare,
which would make canonical bytes depend on the runtime locale) instead of
nested ternaries and a bare sort, splits the discovery, consistency, and
query-validation functions below the complexity limit, writes the random
range constants as powers of two, uses optional chains and a length
matcher, and names the JSON round trip the test loopback performs. Output
and wire encodings are unchanged; the property suite still pins them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the ts2md doc script used across the stack and the generated
references for the @bsv/eqc and @bsv/eqc/host entries, linked from the
README and the package page. The e2e loopback fetch now refuses Request
inputs instead of silently dropping their method and body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sirdeggen
sirdeggen force-pushed the claude/eqc-economic-query-client-9f9bde branch from 5bb4950 to 50fa5b8 Compare October 2, 2026 21:29
collect,
mount(router) {
router.get(ECONOMIC_PATHS.params, params)
router.post(ECONOMIC_PATHS.query, query)
mount(router) {
router.get(ECONOMIC_PATHS.params, params)
router.post(ECONOMIC_PATHS.query, query)
router.post(ECONOMIC_PATHS.collect, collect)
const wallet = new HostWallet()
const app = express()
app.use(express.json({ limit: '1mb' }))
app.use(createAuthMiddleware({ wallet, allowUnauthenticated: true, logLevel: 'error' }))
sirdeggen and others added 9 commits October 3, 2026 00:08
Follows main's conventions for the newly reported rules: in-memory store
methods and the non-paying wallet facade return settled promises instead
of async functions without an await, sequential work is expressed as a
pump or an ordered reduce chain, and independent work (topic anchors,
test-wallet output checks) runs concurrently. Splits the consistency
reference computation below the complexity limit. Refreshes the measured
browser sizes. Behavior is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o claude/eqc-economic-query-client-9f9bde

# Conflicts:
#	governance/test-quality/policy.json
…o claude/eqc-economic-query-client-9f9bde

# Conflicts:
#	docs/reference/package-api-migrations.md
#	docs/reference/stack-facts.md
#	governance/repository-health/baselines.json
…o claude/eqc-economic-query-client-9f9bde
…o claude/eqc-economic-query-client-9f9bde
…o claude/eqc-economic-query-client-9f9bde
Main's @bsv/sdk 4.0 (#1243) and @bsv/color-permission-module raised the
same package counts this branch raises; the auto-merge kept one
increment, so the supply-chain count, package ledger and test-governance
totals now include both. EQC's @bsv/sdk peer adds ^4.0.0 alongside its
SDK2 and SDK3 ranges, as main does for every first-party package; its
tests, typecheck and browser contract pass on the SDK 4 candidate, and
the recorded browser sizes are re-measured against it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

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.

3 participants