error contract: freeze the closed set; extension conditions get a gated registry - #381
Merged
Conversation
…ed registry Adopt the ruling #193 proposed: the error variant's closed set is frozen — a historical artifact of what the contracts named when the variant was designed, not a tier of generality — and every named condition since, kind-level and algorithm-level alike, is an extension pair under "polymorph:webcrypto". The package already practices this (message-too-long is kind-level and shipped as a pair); the contract prose now says so, and restates the absolute boundary: no extension condition may carry a verification verdict. With two conditions, the pair spellings graduate from prose to a machine-readable registry (#194's trigger): wit/extension-conditions.json records (origin, name) -> defining interface -> DOMException name -> summary, and the static spelling sites are gated against it: - rust/core: the constants (and so the Error constructors) must match the registry exactly, both directions; - rust/guest: the extension constants module likewise — and the gate's first catch is real: the SDK had no MESSAGE_TOO_LONG constant at all (consumers could not match the second condition without spelling the pair themselves), and its origin constant still carried the pre-rename LANN_WEBCRYPTO name (now extension::ORIGIN); - js/componentize: the DOMException table moves to extension-errors.js, and check-extension-conditions.mjs (run by componentize::typecheck) requires it to mirror the registry exactly — previously a typo'd or missing entry was unobservable even in principle, because both known pairs' mappings coincide with the unknown-pair fallback. The hosts' construction sites (rust/core transport, js/jco, js/deltic) and the conformance literals stay ungated by design: the conformance suites pin those exact pairs behaviorally on every target.
…reads the source componentize-js resolves only the WIT specifiers — a nested relative import panics its module linking (resolve_import), which the shim's header documents as the single-module constraint and the first CI run demonstrated. EXTENSION_ERRORS moves back into webcrypto.js (with both pairs), and check-extension-conditions.mjs brace-matches the literal out of the source instead of importing it; extraction failures and all three drift directions fail loudly. Composed demo and WPT census gates re-verified against the pinned toolchain.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #193, Fixes #194 — one decision plus its enforcement artifact: the freeze ruling defines what the registry registers, and the registry's gates are what make the ruling more than prose, so they land together.
The ruling (#193)
wit/README.md's error contract drew the closed/extension boundary by level ("the generic kinds' universal conditions" vs "algorithm- and feature-specific conditions"). The package's second named condition falsified that language:message-too-longis kind-level (public-encryption) and shipped as an extension pair. The contract now says what the package practices:"polymorph:webcrypto", defined by the interface whose contract says when it occurs.authentication-failedand nothing else; no extension condition may ever carry a verification verdict.AGENTS.md's summary of the contract is updated to match.
The registry (#194)
#194 deferred the machine-readable registry until the second condition made spelling drift a real bug class; that trigger fired.
wit/extension-conditions.jsonnow records each pair → defining interface →DOMExceptionname → summary, and the static spelling sites are gated against it:rust/coreconstants +Errorconstructorsjust test/just check)rust/guestextensionconstants moduleEXTENSION_ERRORStablecheck-extension-conditions.mjsbrace-matches the literal out ofwebcrypto.js(componentize-js resolves only WIT specifiers, so the shim stays a single module — the first CI run'sresolve_importpanic proved the constraint) and requires an exact mirror; wired intojust componentize::typecheckThe gates found real drift immediately, which is the issue's thesis demonstrated:
MESSAGE_TOO_LONGconstant at all — a consumer wanting to branch on the package's second condition (the fall-back-to-hybrid-wrapping signal) had to spell the pair itself;LANN_WEBCRYPTOname (no in-repo consumers; renamed toextension::ORIGINunder the fix-in-place regime);message-too-long— behaviorally invisible, because both known pairs'DOMExceptionmappings coincide with the unknown-pair fallback (OperationError), which is exactly why extension-condition registry: one machine-readable source for known (origin, name) pairs, gated — deferred until the second condition #194 called the table unobservable-in-principle and why the gate is static rather than behavioral.Deliberately not gated
The construction sites in the hosts (
rust/coretransport,js/jco,js/deltic) and the conformance/demo literals stay as they are: those spellings are pinned behaviorally by the conformance suites on every target (sha1_checked_postures, thersa_oaepmessage-too-long probes) and by the componentize-demo transport check. The registry gates cover exactly the surfaces the suites cannot see.Verification
just check(fmt, clippy, validate-wit — a.jsoninwit/is inert to WIT resolution — and the Rust tests, including both new gates)just componentize::typecheck(tsc + the new registry check)just componentize::test(composed demo, 19 checks including the extension-error transport pin) andjust wpt::test(census green) pass locally against the pinned toolchain