Files
zeekayandHanzo Dev 52d568067a cert: weigh a gossiped certificate against the set, and derive its quorum
Two gaps, one rule.

The portable certificate had only Cert::verify — structure, ordering and every
signature — and that is not an accept rule: its last clause counts distinct valid
accepts against the certificate's OWN threshold, so one declaring 1 clears it on
a single signature. Nothing on this side could weigh a GOSSIPED certificate
against a validator set at all, while Go's gossip path could, and a certificate
two implementations admit and one cannot weigh is not one rule. Cert now carries
verify_weighted(const Keys&, const Stake&), clause for clause with Go's
VerifyWeighted and Rust's verify_weighted, over a new node-keyed Stake seam —
separate from Keys because membership and weight are separate facts read from
separate places.

And the quorum a certificate declares is now the set's number in both objects.
QuorumCertEngine::verify_cert has always demanded the derived floor exactly; the
portable one demands it too, and the free function signer_floor(Tier, n) is the
one definition both read, which is Go's chain.SignerFloor and Rust's
finality::signer_floor. Equality and not a lower bound, in both directions.

decision.json carries the declaration beside the derived floor so a runner checks
one against the other, and three of its eighteen rows declare something else on
purpose. The LOCAL gate is handed no certificate and therefore no declaration, so
it accepts those three and the harness says so outright: two objects, two
questions. The rest of the corpus is byte-identical — cert_verify and cert_wire
included, because the structural predicate did not move.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-02 00:11:53 -07:00
..