Everything cordn-side was verified against ts-mls, the MLS library their client happens to use. That covers the crypto layer and says nothing about the layer above it: the eleven coordinator tools, their argument names, which fields are optional, and the `cordn1…` group ref. That layer rested on our reading of the spec. `quartz/tools/cordn-vector-gen` closes it from their side. It generates `resources/cordn/coordinator-contracts.json` from `@cordn/core` (MIT) -- the package their reference coordinator and client both import -- by handing each payload we send to their zod schema, so a field we named wrong fails at generation time. Each method also carries a `rejects` set their schema must refuse, because a positive only means something if the schema is strict where we assume it is. Group refs round-trip through their bech32 codec. - CoordinatorContractVectorTest (15): drives CoordinatorClient through the real ContextVM transport, asserts the arguments the coordinator sees equal those vectors, then replays their result shapes back through our parser. - CordnGroupRefVectorTest (5): both directions, including the uppercase form (their `decodeGroupRef` accepts it though their `isGroupRef` screen does not) and a non-ASCII gid, which §4.1 requires to survive byte for byte. - CordnFixtureCoordinator now records each call's arguments and can serve a scripted result, which is what lets the same fixture do both directions. Mutation-checked, since 20 tests passing on the first run means nothing on its own: sending `after = 0` on a first-ever fetch instead of omitting it, and flipping the group-ref TLV emission to ascending order, each killed exactly one test. The TLV mutation was caught only by the encode-direction test -- decoders accept any order by spec, so a decode-only suite would have shipped that divergence. Also settles §4.1 (credential encoding) by implementing both rather than waiting on an agreement neither ecosystem has an incentive to reach. Marmot writes a pubkey as 32 raw bytes, cordn as 64 ASCII hex bytes; they are mutually exclusive by length, so no leaf can be misread as the other profile's. BothCredentialProfilesTest runs both groups on one engine and pins the `memberIdentityHex` hex-of-hex trap that would otherwise drop cordn members from a member list. Two findings recorded in the plan: - Tier B is blocked on licensing, not tooling. `packages/coordinator`, `packages/server` and `packages/test-utils` carry no LICENSE file and no `license` field, and neither does the repo root -- so the reference coordinator, and the ghcr image built from it, are unlicensed. Only `packages/core` and `packages/cli` are MIT. The plan's claim that "everything under Cordn-msg is MIT" was wrong and is corrected. - Their current `kp_publish` schema rejects the legacy `keyPackageBase64` field, so our fallback is for parsing old publication events only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012BfD4txdnsaPRXmNXbup9n
2.2 KiB
cordn-vector-gen
Emits quartz/src/commonTest/resources/cordn/coordinator-contracts.json from
@cordn/core — the package cordn's own reference coordinator and client
both import. Consumed by CoordinatorContractVectorTest and
CordnGroupRefVectorTest.
Why this exists
Our ts-mls fixtures (resources/tsmls/) cover the crypto layer: KeyPackages,
Welcomes, exporters, sealed payloads. They say nothing about the layer above —
the eleven coordinator tools, their argument names, which fields are optional,
and the cordn1… group ref. That layer had been verified only against our
reading of the spec, which is exactly the kind of agreement that holds right up
until someone runs a real coordinator.
So this generator goes the other way: it takes the payloads we put on the
wire and hands each one to their zod schema. A field we named wrong fails at
generation time. Each method also carries rejects — payloads their schema must
refuse — because a positive result only means something if the schema is strict
where we assume it is.
Group refs are round-tripped through their bech32 codec, and the vectors pin both directions: we must decode what they encode, and encode byte-identically. Only the second half catches TLV ordering, since the spec lets decoders accept any order.
Regenerating
cd quartz/tools/cordn-vector-gen
npm install
node generate.mjs > ../../src/commonTest/resources/cordn/coordinator-contracts.json
Output is deterministic — fixed actors, fixed timestamps, no randomness — so a regeneration that changes the file means cordn changed something. Commit the result with the reason.
Licensing
@cordn/core and @cordn/cli are MIT and each ship a LICENSE file; this
generator is a dev-only dependency on the first and ships in nothing.
The rest of the Cordn-msg/cordn repository — packages/coordinator,
packages/server, packages/test-utils, and the ghcr.io/cordn-msg/cordn
image built from them — carries no license file and no license field, so
default copyright applies. That is why Tier B (a live coordinator round-trip)
is not wired up here and why these vectors are generated from the two licensed
packages instead. See quartz/plans/2026-09-17-cordn-interop.md §7.