Skip to content

revert: restore the settlement-version quote gate (re-apply #23) - #25

Merged
jacderida merged 2 commits into
WithAutonomi:mainfrom
grumbach:reapply/pr-23-settlement-version
Sep 7, 2026
Merged

jacderida merged 2 commits into
WithAutonomi:mainfrom
grumbach:reapply/pr-23-settlement-version

Conversation

@grumbach

@grumbach grumbach commented Aug 21, 2026

Copy link
Copy Markdown
Member

Linear issue

Closes V2-975 — https://linear.app/autonominetwork/issue/V2-975/refuse-to-quote-clients-that-cannot-settle-correctly-instead-of

What this is

Re-applies #23 by reverting d56ef1b. #23 was pulled from the 2026-08-18 train
in #24 so the settlement-version set could land whole, rather than shipping the
wire vocabulary ahead of the node and client code that uses it. That was the
right call for that train. This puts it back for the next one.

Nothing landed between the #23 merge (af6a435) and the revert (d56ef1b), so
this is a clean re-application with no rebase: the resulting tree is
byte-identical to af6a435.

Why now

ant-node#204 and ant-client#171 both carry the same single remaining merge
blocker: they pin ant-protocol through a personal fork branch and need to
repin to a published registry release. That release cannot exist while the
protocol change is off main, and the two PRs cannot merge without it, so the
set is deadlocked until this lands.

Opened to unblock the release manager: this side is ready whenever the train is.

Risk tier

  • T0 — docs / tooling / CI / pure UX-output. Repo CI only.
  • T1 — client-only, no network-facing behavior change. CI + prod compat smoke.
  • T2 — node/client logic with behavioral surface, no protocol/format/economics change. Dev testnet + ADR.
  • T3 — protocol / storage format / payments / routing. T2 evidence + adversarial testing.

Same tier and same content as #23. This crate supplies the vocabulary and
enforces nothing, but the vocabulary is the wire contract.

Compatibility

  • Wire: additive, no cutover. Two ChunkMessageBody variants and one ProtocolError variant are appended; every existing discriminant keeps its value and CHUNK_PROTOCOL_ID stays autonomi.ant.chunk.v1. A peer built against 2.3.x decodes current traffic unchanged and rejects the new variants as an unknown discriminant rather than misreading a variant it knows. Consequence to plan for: a client sending V2 gets no answer from a node on 2.3.x, so nodes must be upgraded before clients start sending V2. ant-client#171 handles the mixed fleet with a per-peer fallback.
  • Storage: none. No stored-data format is touched.
  • API: additive only. New public items are CURRENT_SETTLEMENT_VERSION, MIN_SUPPORTED_SETTLEMENT_VERSION, settlement_version_is_supported, client_update_required_message, ChunkQuoteRequestV2, MerkleCandidateQuoteRequestV2 and the two enum variants. Nothing is renamed, removed or retyped, and both enums were already #[non_exhaustive].

Semver impact

  • breaking
  • feature
  • fix

No version bump is taken here; the release train owns that.

Test evidence

Run on this branch:

  • cargo test --lib — 87 passed, 0 failed
  • cargo test --lib chunk — 25 passed, 0 failed
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo fmt --all — clean
  • cargo doc --no-deps with RUSTDOCFLAGS="--deny=warnings" — clean
  • Tree verified byte-identical to af6a435, the reviewed and approved feat(chunk): declare a settlement version on quote requests #23 merge

The discriminant regression test from #23 comes back with it:
appending_v2_variants_leaves_existing_discriminants_untouched pins the wire
byte for every existing variant (PutRequest 0, GetRequest 2, QuoteRequest
4, MerkleCandidateQuoteRequest 6, new variants 8 and 9), which is what the
incremental-rollout design rests on: postcard assigns discriminants by
declaration order, so inserting a variant anywhere but the end would make every
older peer silently misread every message from a newer one.

New dependency

none

ADR

ADR-0010: Settlement version and pre-payment compatibility (Proposed), carried on the ant-node branch:

https://github.com/grumbach/ant-node/blob/settlement-version-quote-gate/docs/adr/ADR-0010-settlement-version-and-pre-payment-compatibility.md

Note: ant-node#204 and ant-client#171 both cite this ADR at a
WithAutonomi/ant-node URL, which 404s — the branch only exists on the fork.
Worth correcting on those two PRs.

Mitigation / rollback

Revert this PR. It is a pure re-application of a known-good tree, and #24 already
demonstrated that dropping it returns main to the exact v2.3.2 tree with no
downstream fallout, because nothing on main consumes the new variants yet.
Until a node build ships that answers V2, the added vocabulary is inert.

Note for the reviewer

#23 was approved by @dirvine at head e979016 before it was merged. This branch
restores exactly that tree, so the prior review still applies to the content.

@grumbach

Copy link
Copy Markdown
Member Author

CI note: Security Audit is red, but it is inherited from main, not introduced here.

The advisory is RUSTSEC-2026-0258 (h2 unbounded empty DATA frames, published 2026-08-17). main and this branch both resolve h2 0.4.15, and the h2 entry in Cargo.lock is untouched by this PR:

main   : h2 0.4.15
this PR: h2 0.4.15

Every other check is green: Clippy, Format, Documentation, Publish dry-run, Tests on ubuntu/macOS/no-default-features, plus linear-link and pr-template.

ant-node cleared the same advisory in WithAutonomi/ant-node#209 with a two-line Cargo.lock bump to h2 0.4.16. ant-protocol has not had that bump yet, so it will stay red here until it does. Happy to open the equivalent one-line PR for this repo if that is useful — I have deliberately kept it out of this one so the diff stays a pure re-application of #23 and the tree stays byte-identical to af6a435.

@dirvine dirvine left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

APPROVE — reviewed exact head f2bf6e42547ef06bf6ab46acbc4941a5d3a1014d.

No material blockers found. The V2 request/refusal vocabulary is additive, existing postcard discriminants are pinned by regression tests, and the compatibility directions remain distinct. Local verification: formatting and all 87 library tests passed.

The Security Audit failure is inherited from main (h2, RUSTSEC-2026-0258), not introduced here. Release version bumps are intentionally left to the release owner.

Reverts d56ef1b, which dropped WithAutonomi#23 from the 2026-08-18 train so the
settlement-version set could land whole rather than shipping the wire
vocabulary ahead of the code that uses it.

Nothing landed between the WithAutonomi#23 merge and the revert, so this is a clean
re-application: the tree is byte-identical to af6a435.

ant-node #204 and ant-client #171 are both still blocked on repinning to
a published ant-protocol release, so the protocol side has to be back on
main before either can clear its last merge blocker.
@jacderida
jacderida force-pushed the reapply/pr-23-settlement-version branch from f2bf6e4 to a22897d Compare August 30, 2026 22:12
jacderida added a commit to grumbach/ant-node that referenced this pull request Aug 30, 2026
The protocol PR (WithAutonomi/ant-protocol#25) was rebased onto its main
(now v2.3.3) ahead of the settlement-gate testnet run, which moved the
head of the pinned branch. A plain `cargo update -p ant-protocol` kept
the stale pre-rebase rev, so the lock is bumped with `--precise` to the
rebased head (a22897d).

Verified: 964 unit tests pass against the new rev.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAwPdhJzE1S63ghxuJhg3G
jacderida added a commit to grumbach/ant-client that referenced this pull request Aug 30, 2026
The protocol change now lives on WithAutonomi/ant-protocol#25 (the
reapply of the reverted WithAutonomi#23), and that branch was just rebased onto its
main (v2.3.3) ahead of the settlement-gate testnet run. Point the git
pin at the PR's actual head branch instead of the retired WithAutonomi#23 branch,
and lock its rebased head with `--precise` (a plain `cargo update`
keeps the stale pre-rebase rev for git branch pins).

Verified after the rebase onto main and this bump: 614 lib tests plus
the merkle/self-encryption unit suites pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAwPdhJzE1S63ghxuJhg3G
@jacderida

Copy link
Copy Markdown
Member

Testnet evidence — ADR-0013 mixed-fleet + refusal-flip run (V2-1151, 2026-09-04)

Validated at a22897d (current HEAD of this PR), alongside WithAutonomi/ant-node#204 @ e6222d2 and WithAutonomi/ant-client#171 @ 69e8c93.

This PR carries the appended V2 wire variants, so what a deployment can test is whether the new wire shape survives a genuinely mixed fleet in both directions — and whether the legacy fallback is actually exercised rather than merely present.

5.5h run, 337 nodes at T0 rising to 458, deliberately mixed: 225 nodes and 3 uploaders/2 downloaders on the new code, 105 nodes and a matching client set on released 0.17.2 / 0.3.4, ~30% of node VMs behind simulated NAT on both sides, across two providers and eight regions. Then a third cohort built against this PR's fork with MIN = CURRENT = 2 was joined in three stages to force the refusal path.

Old nodes cannot decode the versioned request, and nothing breaks

Released 0.17.2 nodes have no knowledge of the V2 variants. Branch clients probed them, fell back to the legacy shape, and completed:

  • Phase 1 upload success: branch 198/198 = 100%, released 227/227 = 100% — the new-wire cohort is not below the old-wire control
  • cost of the fallback probe, per uploader, against the released cohort as control: +21.7s (300 MB), +9.8s (500 MB), +15.0s (1200 MB)
  • those offsets are flat across the 3h window (trends −2.4% / −3.7% / +11.9%) — a bounded per-upload probe cost, not a compounding one, and no timeout spiral against relayed/NAT'd old peers

New nodes serve old clients unchanged

The reverse direction matters as much: released clients send unversioned requests and must keep being served by nodes that speak V2. They were, in every phase —

227/227, 33/33, 51/51, 44/44 uploads = 100%, with refusal_seen=0 on every single attempt, right through all three refusal flips. Branch nodes logged the unversioned-adoption counter 279 times, confirming those requests were arriving and being recognised as unversioned rather than silently mishandled.

Downloads — the untouched path — were the invariant

100% success in all four windows on both cohorts (Phase 1 and all three flip stages), across node joins of 1, 30 and 90. No PUT-time payment-verification failures attributable to quoting.

Version negotiation refuses only where it should

Refusal lines appeared only on the MIN = 2 cohort (310 / 1260 / 1140 across its three stages) and zero on either the branch or released node fleets. When refusal did fire, the client's abort named ≥2 distinct corroborating peers on every one of 725 occurrences and 569 aborted uploads spent nothing — verified per-attempt, by exact-integer wallet reconciliation (residual 0), and on-chain to the atto.

Full criteria table and method: V2-1151. 11 of 12 acceptance criteria passed; the twelfth (paid-then-refused) had an empty population, explained on WithAutonomi/ant-client#171.

@jacderida

Copy link
Copy Markdown
Member

Recommendation: merge. Scheduled for Monday 2026-09-07; full decision record on Linear V2-975.

The testnet evidence (comments above; runs V2-1109 and V2-1151) closes every ADR-0013 release gate a deployment can close: mixed-fleet compatibility, NAT/relay probe cost, and the corroboration quorum verified decisively (zero aborts against a solo refuser; all 725 aborts corroborated by exactly 2 distinct peers). 1,032 refused uploads across the two measured runs spent zero atto, confirmed on-chain. The change ships inert (MIN = CURRENT = 1), the wire change is append-only with every pre-existing discriminant pinned by test, and revert is free.

Mechanics for this repo: this PR merges first of the three (the downstream PRs repoint their git pins to the merged commit before they merge). One more merge-up onto main is needed (9 commits behind after rc-2026.8.4/9.1). The failing Security Audit check is RUSTSEC-2026-0258 in transitive h2 — it has failed every merge to this repo since 2026-08-12 and is not this PR's; it gets its own ticket.

Deferred to the author's return, on V2-975: ADR denial-resistance wording (run 4 shows N is always exactly 2 with process-wide accumulation), the optional paid-then-refused demonstration, and ADR-0013 Proposed → Accepted.

Brings the branch level with main ahead of merging, per the decision
recorded on V2-975.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDQxmDv2kaB8s3hauY2DM1
@jacderida
jacderida merged commit 88ad3f1 into WithAutonomi:main Sep 7, 2026
11 of 14 checks passed
jacderida added a commit to grumbach/ant-node that referenced this pull request Sep 7, 2026
Merges main into the settlement branch ahead of merging the PR, per the
decision recorded on V2-975, and moves the ant-protocol pin off the
personal-fork branch onto the WithAutonomi main commit that merged
WithAutonomi/ant-protocol#25 (88ad3f1).

That protocol source now carries main's temporary stacked saorsa-core
dependency (the v2-903 route-diagnostics branch, pending
WithAutonomi/saorsa-core#162), so a matching [patch.crates-io] override
redirects this crate's registry saorsa-core to the same source —
mirroring ant-client main — or the graph holds two copies of MultiAddr
and ant-devnet fails to compile. The patch comes out together with the
git ant-protocol pin when the release train publishes both.

Verified: 967 lib tests pass against the merged graph.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDQxmDv2kaB8s3hauY2DM1
jacderida added a commit to grumbach/ant-client that referenced this pull request Sep 7, 2026
Merges main into the settlement branch ahead of merging the PR, per the
decision recorded on V2-975. The Cargo.toml conflict — main's published
`ant-protocol = "2.3.5"` against this branch's fork-branch git pin — is
resolved by unifying the whole graph on one source: ant-core goes back
to the registry form main uses, and the workspace [patch.crates-io]
override (which main introduced for the stacked v2-903 protocol branch,
now merged into protocol main) is repointed at the WithAutonomi main
commit that merged WithAutonomi/ant-protocol#25 (88ad3f1). That commit
contains both the settlement wire types and the v2-903 changes, so the
previous state of two ant-protocol copies in the lock collapses to one.
The saorsa-core patch stays exactly as main has it.

The patch override comes out when the release train publishes
ant-protocol with these types.

Verified: workspace check clean; 640 ant-core lib tests pass; the lock
holds a single ant-protocol sourced at 88ad3f1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDQxmDv2kaB8s3hauY2DM1
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