feat(conformance): a kit that answers "does MY deployment conform?" (Track 7) #51
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "track7/conformance-kit"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Track 7 of the OSS-usability plan.
tests/answers "does this repo's code work". Nothing answered "does your deployment satisfy the contract" — a different question, for a different person, and the one that matters now that this project is meant to work for people with none of the triform infrastructure.Zero dependencies (node builtins only), no reliance on this repo's fixtures, a Chromium build, or triform.
Decisions worth reviewing
specfield.verification/can assume the reader has the tree open; this can't, so "FAIL" without a citation is useless to the audience.NOTHING_RAN, not PASS. A run where nothing applied proved nothing.offer. The load-bearing half ofcb_wire_envelope.his what a conforming peer must refuse:sdp_offer(the historic v0 tag),byecarryingdata, a missingfrom./json/protocolis asserted NOT probed. EnumeratingCb.*that way is what a naive kit would do — and on this worker it CHECK-FATALs the browser. The check that looks most natural is the one that kills the thing under test, so the hazard is encoded as a SKIP carrying the reason, putting CLAUDE.md's trap where someone debugging a SIGABRT will find it.Wire rules were read off
cb_wire_envelope.cc'sDecode/DecodeData, and the registration handshake offsignaling/server.go:505-560— the code is what a real peer does.Verified, not assumed
node --test conformance/__tests__/*.test.mjs)cr7727-f9e46a1434b5) on a runner's dind, inside the container's network namespace:…and the worker was still healthy afterwards (4/4 supervisord programs), since the hazard endpoint was never touched.
0help,2usage error,2bad role,1required-check failure.CI wiring
Two places, for two reasons:
Not included
The
signaling-wiresuite ships but is unexercised against a live broker — I had no two-peer session to drive in this environment. Its rules are read from the C++ decoder rather than guessed, but I'd rather say that plainly than imply a verification I didn't do. Themedia-sanitysuite named in the README is not implemented yet.Track 7. tests/ answers "does this repo's code work". Nothing answered "does YOUR deployment satisfy the contract" — a different question, for a different person, and the one that matters as soon as this project is usable by people with none of the triform infrastructure. A third party running their own broker, their own build of the worker, or a reimplementation of either had no way to check short of reading C++. node conformance/run.mjs --target=ws://localhost:8080 --role=signaling node conformance/run.mjs --target=http://localhost:9222 --role=cdp --json Zero dependencies (node builtins only) and no reliance on this repo's fixtures, a Chromium build, or triform. `npm install` before you can ask "am I conforming?" is a barrier this kit should not have. Design decisions worth stating: * EVERY check names the spec clause it enforces. verification/ can assume the reader has the tree in front of them; this cannot. "FAIL" without a citation is unusable by the audience, so the registry REFUSES to register a check with no `spec` field. * required vs advisory, enforced in the verdict algebra rather than by convention. Advisory failures are reported loudly and do NOT set the exit code — otherwise "recommended" silently means "mandatory" and the distinction the README advertises is a lie. * a required ERROR counts as FAIL. A check that could not run has not demonstrated conformance, and treating "couldn't tell" as "fine" is how a green result stops meaning anything. * an all-SKIP run reports NOTHING_RAN, not PASS. A run where nothing was applicable proved nothing; a caller seeing PASS would reasonably believe otherwise. * the negative checks are the point. Anyone can relay a well-formed `offer`. The load-bearing half of cb_wire_envelope.h is what a conforming peer must REFUSE — `sdp_offer` (the historic v0 tag), `bye` carrying `data`, a missing `from`. A deployment that accepts them works right up until it meets a peer that assumes the documented behaviour. * the /json/protocol check asserts the endpoint is NOT probed. Enumerating Cb.* that way is what a naive kit would do, and on this worker it CHECK-FATALs the browser — the check that looks most natural is the one that kills the thing under test. Encoding the hazard as a SKIP with the reason attached puts CLAUDE.md's trap where someone debugging a SIGABRT will actually find it. The wire rules were read off cb_wire_envelope.cc's Decode/DecodeData, and the registration handshake off signaling/server.go:505-560, rather than paraphrased from prose — the code is what a real peer does. VERIFIED, not assumed: * 23/23 self-tests pass (node --test conformance/__tests__/*.test.mjs). * Run against a REAL worker (cr7727-f9e46a1434b5) on a runner's dind, inside the container's network namespace — verdict=PASS, both required CDP checks green, and the worker still healthy afterwards (4/4 supervisord programs) since the hazard endpoint was never touched. * Exit codes checked directly rather than through a pipe: 0 help, 2 usage error, 2 bad role, 1 required-check failure. CI wiring, in two places for two reasons: * Lint runs the kit's own tests — no network, no image, always gating. * smoke runs the kit AGAINST the image it just proved boots. If the reference implementation cannot pass its own conformance suite, the suite is wrong and CI should say so before a third party does. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Update: the
signaling-wiresuite is no longer unexercised. I ran the real Go broker (signaling/, auth disabled) on :18080 and drove the suite against it.Two things worth noting.
The kit found a real divergence on its first live run.
cb_wire_envelope.h:27saysbyeomitsdataentirely — "not present, not null, not{}" — andcb_wire_envelope.cc'sDecodeDataenforces it (if (data) return nullopt, rejecting the whole envelope). The Go broker relaysbyeverbatim,dataincluded. So a peer that sentbye {data:{}}through this broker would have it silently dropped by the far side, which then waits out its own timeout instead of seeing the disconnect.It is correctly advisory, not a bug to fix. I checked both real emitters before deciding:
client/src/session.ts:63typesbyeasdata?: undefined, andcb_offerer_driver.cc:1186explicitly leaves the field unset. Neither in-repo peer can trip this, and a relay-only broker that never parsesdatais a legitimate design — failing a deployment for it would make "required" mean "matches our broker's implementation choices" rather than "satisfies the contract". The advisory classification did exactly its job: reported loudly,verdict=PASS, exit 0.This is the case the kit exists for — a contract clause that no in-repo test covers, because no in-repo peer violates it. A third party writing a broker from the spec would learn this from one command instead of from a stalled session.
CI on this PR is green across Lint (23/23 conformance self-tests confirmed executed in the log), Docs, both CodeQL, E2E, and both native-peer gates.
The step I added in the previous commit failed on its first CI run: Error: Cannot find module '/conf/run.mjs' `-v "${PWD}/conformance:/conf:ro"` resolves the bind SOURCE on the DAEMON, which on this host is a sibling dind with its own filesystem. It cannot see the job's checkout, so docker silently created an empty directory at that path and node found nothing to run. This is the identical trap e2e.yml's "Probe daemon filesystem sharing" step exists for -- documented in this same file two commits ago, and then walked into anyway. The e2e job needs compose bind-mounts and so must SKIP when the filesystem is not shared; this step only needs to get ~15 KiB of JS into a container, which `docker cp` does through the daemon's own API regardless of whether any filesystem is shared. So: create -> cp -> start, and the step works on a shared-fs runner and a sibling-dind runner alike. The smoke test itself passed in that run (PASS, 17121-byte PNG); only the new step failed. Verified before pushing this time -- the exact create/cp/start sequence, run on the same runner dind against cr7727-f9e46a1434b5: devtools up after 4s ✓ PASS devtools-reachable ✓ PASS page-target-exists · SKIP protocol-endpoint-hazard (advisory) verdict=PASS EXIT=0 Also adds the runner container to the cleanup trap; the previous version leaked it when the kit exited non-zero. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>