Sound compatibility rules. Type change / add-required / tighten-to-
required are breaking; add-optional / loosen are safe; remove / rename
are warnings. HasBreaking is the CI gate.
Idempotency that's actually safe. Run once per key; never cache
failures; expire keys past the client's retry horizon.
Tamper-evident opaque cursors. A mangled cursor errors; the client
cannot depend on the internal position scheme.
Tag-keyed diff. Fields are matched by tag number (protobuf
semantics), so rename/reorder are distinguishable from
add/remove/type-change. This is what makes the verdicts correct.
Severity, not boolean. Breaking / Warning / Safe lets CI block only
the truly dangerous changes while still surfacing "reserve the tag" and
rename hygiene.
Checksum, not crypto, on cursors. CRC catches accidental/garbled
cursors cheaply; for adversarial tampering you'd use an HMAC with a
server secret (noted as the production upgrade).
Don't cache idempotency failures. A cached failure would make a
transient error permanent for that key — the opposite of the goal.
Two-schema diff can't see history. Reusing a previously-removed tag
is the most dangerous change and needs a reserved-tag registry to
detect (exercise §6.2) — a schema registry does this.
Compat rules are policy. "Backward only" vs "full" compatibility is
an architecture decision with real cost (full compat constrains both
producers and consumers). The checker enforces whatever policy you set.
Idempotency storage is a real system. A production key store is a
TTL'd, replicated KV on the write path; its availability bounds the
API's. (db-20 / a Redis-class store.)
Opaque cursors trade debuggability for freedom. You can't eyeball a
cursor in a URL; that's the point, but add server-side decoding tools.