Expand description
v0.177 (#643): the canonical normal form of a cross-context contract, and its hash.
A workers build compiles context A against context B’s contract, and
nothing at runtime checks that the deployed B still matches what A was
compiled against — deploy --context NAME institutionalises the skew. The
fix is to stamp a hash of the compiled contract beside X-Bynk-Caller and
fail closed on mismatch (ADR 0092’s pattern: a compile-time constant in a
reserved header, metadata beside the payload, no crypto).
The hash is only as good as the form it hashes. Two rules make it usable:
- Semantically-equal contracts must hash equal, or a working deployment 409s spuriously — which is worse than no check at all, because it breaks what worked and destroys trust in the mechanism. This is why the form is canonical (predicates as a sorted set, record fields sorted by name) rather than a rendering of source order.
- Both sides must canonicalise the same thing. The callee’s contract
is canonicalised in the callee’s own namespace, from the callee’s own
type table, on both sides — never in the caller’s. The caller reaches
that table through
consumed_types[callee]and the callee through its own combined table; both are produced by the samecombined_types_for, so the two views cannot diverge by construction. A caller never canonicalises a consumed type in its own namespace, where its rebranding would make the same type render differently.
Functions§
- canon_
capability_ op_ signature - P8.1 (#1512, [DECISION C]): the canonical form of a
CapabilityOpSignature— added by PR #1517’s own bot review (finding #3): acapabilitydeclaration’s own ops are the abstract signature a consumer’sCap.op(...)call site compiles against. - canon_
fn_ signature - P8.1 (#1512, [DECISION C]): the canonical form of a
FnSignature— extends this module’s owncanon_type(ADR 0200) to a shape it doesn’t reach today. Body-free by construction ([DECISION B]): there is nobody/requires/ensuresfield onFnSignatureto accidentally include here. - canon_
handler_ signature - P8.1 (#1512, [DECISION C]): the canonical form of a
HandlerSignature.givenrenders sorted — its renderedCapRefnames have no meaningful order to preserve (it’s a set, not a sequence).kindis rendered first (PR #1517’s own bot review, finding #1) — two handlers that differ only in HTTP method or route, or inon callvs.on message, must not canonicalise identically. - canon_
predicate - canon_
refinement - Predicates canonicalise as a sorted set.
- canon_
store_ field_ signature - P8.1 (#1512, [DECISION C]): the canonical form of a
StoreFieldSignature. - canon_
unit_ signature - P8.1 (#1512, [DECISION C]):
UnitSignature::canonical’s own implementation — the single rendering R3.14’s own stability proof compares. Every category is rendered sorted (by the caller’s ownBTreeMap/BTreeSetkeys, or an explicit sort forVec-shaped fields like a handler’s owngiven), so construction order never perturbs the form — the same “compare the canonical string, not map/vec iteration order” disciplineservice_normal_form’s record-field sort already established for ADR 0200. - contract_
hash - FNV-1a (64-bit) over the canonical form, rendered as 16 lowercase hex chars.
- own_
contract_ hashes - v0.177 (#643): a context’s own
on callcontract hashes, keyed by service name — the constants its Worker entry compares an incomingX-Bynk-Contractagainst. - service_
contract_ hash - The stamped contract hash for one consumed service.
- service_
normal_ form - The canonical normal form of one
on callservice contract.