Repository navigation
services: Arcade the default broadcaster through the typed config; main into beta (#300, beta's half) - #312
Conversation
Fix round (the cold review's findings 1 to 4)Commits (on 8075398; nothing rewritten, a plain push):
Proof (foreground, The ratchet, last, after Not this round's: the 🤖 Generated with Claude Code |
…default, the Nightly on dispatch, the HANDOFFs (beta requires linear history) This is the content of the merge commit 98d2972 (origin/main e7844c4 into beta 687f0b6, PR 312's first commit) applied onto beta as one linear commit, because beta's protection requires a linear history and a merge-shaped branch cannot land (the rebase-merge replays main's 32 commits and conflicts where the merge had resolved them). The resolution is the merge's: beta's content where the two lines differ, nightly.yml main's (no schedule, plus PR 308's floors), ci.yml beta's plus main's one comment line. main keeps its own commits; this commit carries their content. The typed broadcaster mode, the harness's explicit classic and the docs follow as PR 312's own commits. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… GorillaPool's ARC never a rung; no classic ARC config in Arcade mode (#300, beta's half) The owner's word of 2026-10-27 ("arc is old af... we use arcade now for everyting") and the keeper's reading on #300, landed on main in PR 302 through an env read in services_env.rs. Beta reads the environment only in src/config.rs (A7), so the same behaviour is expressed through the typed configuration here; the effect is main's, rule for rule. - config.rs: ServicesSettings carries one `arc_mode: ArcMode` in place of the two booleans (`arc_mode_arcade`, `arcade_flag`). ARC_MODE wins when set (blank is unset): `arcade` or `classic`, any case; any other value is a ConfigError naming ARC_MODE (refused at start for every command but `config`, which prints the table with the row marked, and `init`, #172). Unset, ARCADE decides: 1/true/yes Arcade, 0/false/no classic, anything else refused by name. Both unset is Arcade. `fn arcade()` reads the mode. - knobs: the ARC_MODE row is the mode in effect, `arcade (default)` or `classic`, its source env when ARC_MODE or ARCADE is set, else default; ARCADE's row is its value as set; ARC_URL's row is the broadcaster the mode reaches (`unset` for a testnet wallet in Arcade mode, which has no default). The log line quotes a value with a space, so each setting stays one word. - services_env.rs: `arc_gorillapool_url = None` in both modes (the knob stays the broadcast verifier's third-party store); Arcade mode passes no arc_config and logs a set TAAL_API_KEY / MAIN_TAAL_API_KEY once at warn as unused (TAAL_KEY_UNUSED_WARNING, the toolbox's TAAL provider posts unauthenticated until toolbox #317); classic applies them as before; `arcade_url_for` refuses a testnet wallet in Arcade mode without ARC_URL by name (NO_TESTNET_ARCADE_DEFAULT); `arcade_runtime` takes the chain; the first services build logs `post_beef_ladder` at info. - broadcast_verify.rs: the configuration's plane resolves through `arcade_url_for`; a refused plane turns the verifier off (no source, every verdict Inconclusive). `post_beef_ladder` lives here, beside the plane, since it names the explorers that are also broadcasters (A3's allowlist only shrinks). - The ratchet holds: `ArcMode` in src/config/arc_mode.rs, its tests in src/config/arc_mode/tests.rs and src/services_env/arc_mode_tests.rs, the knob rows' broadcaster part and the classic ARC config in their own functions, so no file passes 800 lines and no function 60. - The call sites (serve, serve_fleet, daemon_tenant, reconcile-broadcasts, the served reconcile loop) pass the chain. - Tests: main's ported to the typed form (unset is Arcade, classic the one opt-out, any case, an unknown mode refused by name, GorillaPool never a rung, no classic config in Arcade mode, ARC_URL in either mode, blank ARC_URL, testnet refused, the TAAL warning, the ladder against the toolbox's own count), the knob rows and sources, the refused row, the redacted TAAL key in either mode, the testnet verifier off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit d87713f)
…oadcaster's knobs in README, CLAUDE.md and the changelog fragment (#300, beta's half) Arcade is now the wallet's default broadcaster (the previous commit), and the hermetic stub plays classic ARC only until #299 gives it an Arcade face. Dropping ARC_MODE would now run Arcade against the stub, so the harness names the deprecated classic mode explicitly: - tests/e2e/lib/hermetic.js: `ARC_MODE: 'classic'` in the forced env, with the reason and #299 beside it; ARCADE stays dropped; ARC_MODE leaves the dropped list. - docs/E2E-HERMETIC.md: the /arc row, the /arc routes, the Arcade V2 limit and the forced environment say the harness sets classic explicitly until #299; ARC_GORILLAPOOL_URL= leaves GorillaPool out of the verifier's stores (never a broadcaster); postBeef's explorers sit behind one ARC. - README.md: the broadcaster's table (ARC_MODE, ARCADE, ARC_URL, the deprecated TAAL knobs) and the providers in each mode, PromiseAll on toolbox 0.14.0-beta.1; ARC_GORILLAPOOL_URL's row is the verifier's store. - CLAUDE.md and src/CLAUDE.md: the env lines. - changelog.d/300.md (rule 12). tools/differential runs the hermetic suite through the same applyEnv on both sides, so it needs no change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit df9677c)
… the cold review's finding 1) The three blocks still described the old default: classic ARC unless ARC_MODE=arcade or ARCADE=1 enabled Arcade, and the TAAL keys as Arcade mode's TAAL failover. Under #300 all three are false. They now match README's broadcaster section: ARC_MODE unset is Arcade, the default; classic is deprecated and the hermetic stub's until #299; ARCADE is the older switch, read only when ARC_MODE is unset; ARC_URL has no testnet Arcade default (a testnet wallet in Arcade mode without it is refused by name); the TAAL keys are classic only, deprecated, and logged once as unused in Arcade mode (toolbox #317). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 0e339dd)
…view's finding 2) The merge of main brought main's nightly.yml, which has no schedule, so the page's 03:00Z cron and "the cron becomes live when beta merges into main" (line 3) and "the schedule runs from main" (the concurrency paragraph) were false on beta. Line 3 now says dispatch only, in the owner's words as nightly.yml's head comment carries them (one dispatched measurement before each minor tag, none for a prerelease, and on demand), and the concurrency paragraph gives its reason without the schedule. Nothing else on the page moves (PR 308's table stays). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 15893e9)
…ot 0 (the cold review's finding 4) The page said the run under serve makes no walled attempt. This lane's run (E2E_HERMETIC=1 node tests/e2e/run.js --hermetic, 24/24 at 15893e9) walled 168, every one known and none served: CONNECT api.whatsonchain.com:443 x84 and CONNECT api.bitails.io:443 x84, one of each beside each of the stub ARC's 84 POST /v1/tx (the toolbox's postBeef posts to every provider in parallel). The review's run and the PR body counted the same. The page now says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit a95f83d)
…re-check, ruling (b)) The re-check's one finding: line 9 said "Unset, blank or `arcade` (any case) is Arcade", but the code reads a blank ARC_MODE as unset and ARCADE then decides (ARC_MODE= with ARCADE=0 runs classic, on main too); README's broadcaster section has it right. The line now says so. A docs-only fold on the MERGE verdict, under the 2026-10-26 ruling (b). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Landing shape (the captain). beta's protection requires a linear history, so the merge-shaped branch (main merged into beta) could not land: the rebase-merge replays main's 32 commits and conflicts where the merge had resolved them. The branch is now a linear series on beta 9daefc6 with the same content: one port commit carrying the merge commit 98d2972's content ( |
a95f83d to
bef225c
Compare
Bsv-rs #268/#105 carries type, flat list entries, hex signatures and base64 keyrings. Migrate the six certificate test doors and the MCP parameters; expose the direct keyring and proof verifier fields. Add the explicit, idempotent certificates --reverify command for toolbox #188: counts only, no certificate changed. Its test keeps a valid and an invalid signature. The hermetic certificate scenario signs the BRC-52 bytes, checks the new field-key scheme (#203), decrypts the selective proof, and executes both discovery calls. The local certifier sends x-bsv-auth-identity-key (#269). Public-HTTPS issuance URL validation precludes a loopback issuance endpoint, so this local lifecycle imports the certifier's answer through direct acquire. The exact beta.1 missing-field refusal selects its older scheme only for the differential's base run. Both discover tools pin empty results under CLI #331 (toolbox #388); the known overlay requests stay behind the wall. Add the #216 overlong-spend case, #245/#264 deterministic review race, #312/#357/#359 expiry and #337/#371 remittance witnesses for the final recording. The wire fixture's classic mode is explicit (#317) and its incomplete-ancestry coin meets #295's metadata predicate. No fixture bytes are recorded in this commit. Certificate's 1 MiB, 16 MiB and 72-byte bounds and verify-false are tested; direct acquisition still owes #374's checks. Proof: certificate integration 4 passed; certificate bounds/reverify 2 passed; MCP certificate tools 1 passed; hermetic scenario 6 passed with both discovery calls and no new walled target. Full wire replay follows recording. Co-Authored-By: GPT-6.1 Sol (gpt-6.1-sol) <noreply@openai.com>
WIRE_RECORD=1 records 157 fixtures after the code. Moved or new rows: - 025-revealCounterpartyKeyLinkage.ok.json: bsv-rs #105: flat key linkage, byte fields and protocolID/keyID. - 027-revealSpecificKeyLinkage.ok.json: bsv-rs #105: flat key linkage, byte fields and protocolID/keyID. - 044-acquireCertificate.brc100Type.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 045-relinquishCertificate.brc100Type.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 046-proveCertificate.brc100Type.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 047-acquireCertificate.direct.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 048-listCertificates.one.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 049-proveCertificate.held.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 050-relinquishCertificate.held.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 051-relinquishCertificate.unknown.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 052-proveCertificate.unknown.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 120-createAction.namedChange.json: toolbox #241: named-change words. - 143-createAction.tenByteDeclaration.json: toolbox #216: overlong spend refused, stored unsigned action retained, shorter spend succeeds. - 144-signAction.spendLongerThanDeclared.json: toolbox #216: overlong spend refused, stored unsigned action retained, shorter spend succeeds. - 145-listActions.afterOverlongSpend.json: toolbox #216: overlong spend refused, stored unsigned action retained, shorter spend succeeds. - 146-signAction.shorterThanDeclared.json: toolbox #216: overlong spend refused, stored unsigned action retained, shorter spend succeeds. - 147-createAction.doubleSpendReview.json: toolbox #245/#264, bsv-rs #339: typed double-spend review and stored-state witness. - 148-listActions.afterDoubleSpendReview.json: toolbox #245/#264, bsv-rs #339: typed double-spend review and stored-state witness. - 149-createAction.expiryUnsupported.json: toolbox #312/#359: BRC-177 capability and grammar refusals. - 150-createAction.expiryBatch.json: toolbox #312/#359: BRC-177 capability and grammar refusals. - 151-createAction.expiryNever.json: toolbox #312/#359: BRC-177 capability and grammar refusals. - 152-createAction.expiryDuplicate.json: toolbox #312/#359: BRC-177 capability and grammar refusals. - 153-internalizeAction.missingRemittance.json: toolbox #337/#371: remittance exclusivity before BEEF. - 154-internalizeAction.exclusiveRemittance.json: toolbox #337/#371: remittance exclusivity before BEEF. - 155-acquireCertificate.fieldAtBound.json: bsv-rs #275/#301 and toolbox #374: direct-acquire bound boundary as published. - 156-acquireCertificate.fieldAboveBound.json: bsv-rs #275/#301 and toolbox #374: direct-acquire bound boundary as published. - 157-acquireCertificate.signatureAboveBound.json: bsv-rs #275/#301 and toolbox #374: direct-acquire bound boundary as published. MANIFEST.json records empty discovery with the exact reason "toolbox #388 (CLI #331)" for 053-discoverByIdentityKey.ok.json, 054-discoverByAttributes.ok.json, 137-discoverByIdentityKey.limitAtBound.json, 138-discoverByIdentityKey.limitAboveBound.json, 139-discoverByAttributes.limitAtBound.json and 140-discoverByAttributes.limitAboveBound.json. Those six fixture bodies remain byte-identical: the host bound still refuses above 10000. 086, 094-098, 100, 101 and 106 are byte-identical after the correct base64 translation; 103 retains INVALID_BEEF, offset 176 and the script reason, with no stored invalid action, under CLI #330. The WIRE defect row is now closed at beta.1 rather than claiming the invalid spend was accepted. All other old wire files, the consumers and gate-vector bytes are unchanged. Co-Authored-By: GPT-6.1 Sol (gpt-6.1-sol) <noreply@openai.com>
Bsv-rs #268/#105 carries type, flat list entries, hex signatures and base64 keyrings. Migrate the six certificate test doors and the MCP parameters; expose the direct keyring and proof verifier fields. Add the explicit, idempotent certificates --reverify command for toolbox #188: counts only, no certificate changed. Its test keeps a valid and an invalid signature. The hermetic certificate scenario signs the BRC-52 bytes, checks the new field-key scheme (#203), decrypts the selective proof, and executes both discovery calls. The local certifier sends x-bsv-auth-identity-key (#269). Public-HTTPS issuance URL validation precludes a loopback issuance endpoint, so this local lifecycle imports the certifier's answer through direct acquire. The exact beta.1 missing-field refusal selects its older scheme only for the differential's base run. Both discover tools pin empty results under CLI #331 (toolbox #388); the known overlay requests stay behind the wall. Add the #216 overlong-spend case, #245/#264 deterministic review race, #312/#357/#359 expiry and #337/#371 remittance witnesses for the final recording. The wire fixture's classic mode is explicit (#317) and its incomplete-ancestry coin meets #295's metadata predicate. No fixture bytes are recorded in this commit. Certificate's 1 MiB, 16 MiB and 72-byte bounds and verify-false are tested; direct acquisition still owes #374's checks. Proof: certificate integration 4 passed; certificate bounds/reverify 2 passed; MCP certificate tools 1 passed; hermetic scenario 6 passed with both discovery calls and no new walled target. Full wire replay follows recording. Co-Authored-By: GPT-6.1 Sol (gpt-6.1-sol) <noreply@openai.com>
WIRE_RECORD=1 records 157 fixtures after the code. Moved or new rows: - 025-revealCounterpartyKeyLinkage.ok.json: bsv-rs #105: flat key linkage, byte fields and protocolID/keyID. - 027-revealSpecificKeyLinkage.ok.json: bsv-rs #105: flat key linkage, byte fields and protocolID/keyID. - 044-acquireCertificate.brc100Type.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 045-relinquishCertificate.brc100Type.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 046-proveCertificate.brc100Type.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 047-acquireCertificate.direct.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 048-listCertificates.one.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 049-proveCertificate.held.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 050-relinquishCertificate.held.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 051-relinquishCertificate.unknown.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 052-proveCertificate.unknown.json: bsv-rs #268/#105 and toolbox #311/#249/#260/#270: certificate JSON and validated metadata. - 120-createAction.namedChange.json: toolbox #241: named-change words. - 143-createAction.tenByteDeclaration.json: toolbox #216: overlong spend refused, stored unsigned action retained, shorter spend succeeds. - 144-signAction.spendLongerThanDeclared.json: toolbox #216: overlong spend refused, stored unsigned action retained, shorter spend succeeds. - 145-listActions.afterOverlongSpend.json: toolbox #216: overlong spend refused, stored unsigned action retained, shorter spend succeeds. - 146-signAction.shorterThanDeclared.json: toolbox #216: overlong spend refused, stored unsigned action retained, shorter spend succeeds. - 147-createAction.doubleSpendReview.json: toolbox #245/#264, bsv-rs #339: typed double-spend review and stored-state witness. - 148-listActions.afterDoubleSpendReview.json: toolbox #245/#264, bsv-rs #339: typed double-spend review and stored-state witness. - 149-createAction.expiryUnsupported.json: toolbox #312/#359: BRC-177 capability and grammar refusals. - 150-createAction.expiryBatch.json: toolbox #312/#359: BRC-177 capability and grammar refusals. - 151-createAction.expiryNever.json: toolbox #312/#359: BRC-177 capability and grammar refusals. - 152-createAction.expiryDuplicate.json: toolbox #312/#359: BRC-177 capability and grammar refusals. - 153-internalizeAction.missingRemittance.json: toolbox #337/#371: remittance exclusivity before BEEF. - 154-internalizeAction.exclusiveRemittance.json: toolbox #337/#371: remittance exclusivity before BEEF. - 155-acquireCertificate.fieldAtBound.json: bsv-rs #275/#301 and toolbox #374: direct-acquire bound boundary as published. - 156-acquireCertificate.fieldAboveBound.json: bsv-rs #275/#301 and toolbox #374: direct-acquire bound boundary as published. - 157-acquireCertificate.signatureAboveBound.json: bsv-rs #275/#301 and toolbox #374: direct-acquire bound boundary as published. MANIFEST.json records empty discovery with the exact reason "toolbox #388 (CLI #331)" for 053-discoverByIdentityKey.ok.json, 054-discoverByAttributes.ok.json, 137-discoverByIdentityKey.limitAtBound.json, 138-discoverByIdentityKey.limitAboveBound.json, 139-discoverByAttributes.limitAtBound.json and 140-discoverByAttributes.limitAboveBound.json. Those six fixture bodies remain byte-identical: the host bound still refuses above 10000. 086, 094-098, 100, 101 and 106 are byte-identical after the correct base64 translation; 103 retains INVALID_BEEF, offset 176 and the script reason, with no stored invalid action, under CLI #330. The WIRE defect row is now closed at beta.1 rather than claiming the invalid spend was accepted. All other old wire files, the consumers and gate-vector bytes are unchanged. Co-Authored-By: GPT-6.1 Sol (gpt-6.1-sol) <noreply@openai.com>
The word. The owner, 2026-10-27: "arc is old af... we use arcade now for everyting". The keeper's reading (#300): GorillaPool's ARC is a rung of no gate and no courier. Arcade is the default mode. Classic ARC stays only as the hermetic stub's explicit mode until #299. Main's half landed in #302 and closed #300; this PR is beta's half.
Main into beta (98d2972). This is the first true merge of main into beta (merge base 3d195c2). Main's 0.18.x patch commits were already carried on beta, so every conflict keeps beta's side except where main brings content beta lacks:
nightly.yml, main's);ci.ymlcomment line on the macOS build leaving the required set;Conflicted and kept on beta's side: Cargo.toml and Cargo.lock (the beta.1 pins), CHANGELOG, README, RELEASING, CLAUDE.md,
explorers.rs,test_support.rs,cleanup_abandoned.rs,receive.rs,handlers.rsand its tests (#157's bound is beta'svalidate_internalize_instructions), andrespend_witness/main.rs.#300's files kept beta's structure in the merge. Main's behaviour follows in d87713f through the typed config (A7: no env read outside
src/config.rs). Beta then moved (#138); it merged clean in 8075398.The change.
ServicesSettings: onearc_mode: ArcMode(src/config/arc_mode.rs) replacesarc_mode_arcadeandarcade_flag.ARC_MODEwins when set (blank is unset) and takesarcadeorclassicin any case; any other value is aConfigErrornamingARC_MODE. Under Config follow-ups from PR 169's review: --json nulls and booleans, services_env's remaining parsers, the untested groups #172's rule,configprints the table with the row marked and exits 1,initruns, and every other command refuses at start. WhenARC_MODEis unset,ARCADEdecides:1/true/yesis Arcade,0/false/nois classic, anything else is refused by name. With both unset the mode is Arcade.bsv-wallet config: printsARC_MODEasarcade (default)orclassic, with its source (env whenARC_MODEorARCADEis set, else default). The log line quotes a value that contains a space.services_env, the same effect as main's env read:arc_gorillapool_url = Nonein both modes;ARC_GORILLAPOOL_URLstays the verifier's third-party store.arc_config, and a set TAAL key is warned once as unused (toolbox docs: NORTH-STAR points at the release milestones, not the Phase ones (the hygiene pass, #316) #317).arcade_url_forrefuses a testnet wallet in Arcade mode withoutARC_URLby name; the verifier is then off.post_beef_ladderis logged once at the first services build. It lives inbroadcast_verify.rsbecause A3's allowlist only shrinks.hermetic.jsforcesARC_MODE: 'classic', with the reason and Hermetic e2e: the stub plays Arcade V2 (the EF submit, GET /tx/{txid}, the SSE stream and the callback), so the suite runs in the default Arcade mode and classic ARC mode leaves the CLI #299 named;ARCADEstays dropped.changelog.d/300.md.tools/differentialruns the suite through the sameapplyEnvon both sides, so it needs no change.Proof (foreground, private target dir, toolchain 1.98.1 for the ratchet and the differential):
The wire worlds build their own mock services and read only
quiet_config(), whose mode is now Arcade by default. No fixture reads the broadcaster config, and the corpus replays byte for byte../target/release/bsv-wallet config, scratch wallet,CHAINTRACKS_URL=off:Hermetic,
E2E_HERMETIC=1 node tests/e2e/run.js(Node 24, binaries from the lane's target dir):The base beta binary under the differential walls the same 168 with the same 84 classic posts. The walls come from the toolbox's PromiseAll Bitails and WhatsOnChain post rungs, so they predate this PR. E2E-HERMETIC's "walled 0" sentence (line 193) is stale on beta.
Differential (
tools/differential --base origin/beta, and the floor):Python tools and checks:
The ratchet, last, after
git fetchand the #138 merge (RUSTUP_TOOLCHAIN=1.98.1 python3 tools/ratchet --check --base <(git show origin/beta:docs/ratchets.json)):Not this PR's: the stub's Arcade face (#299), the toolbox's TAAL provider behind Arcade (toolbox #317), and the mainnet gate.
docs/NIGHTLY.md:3still describes the 03:00Z schedule that main's merged dispatch-only word removed.Refs #300
🤖 Generated with Claude Code