Receiver policy: version pin + per-op callback replaces per-field declaration; asset handles - #15
Merged
Merged
Conversation
…laration; asset handles Replaces #13's declaration model (accept/events/queries name lists, SURFACE_V1, compilePolicy, bitmask strict decoding, event-field filter) with a smaller mechanism of the same fail-safe property; keeps #14's hardening and driver split. - Policy { version, check(op), query?(name) }. `version` pins the `PROTOCOL VERSION` from the proto header; createDriver refuses any other, so a receiver upgrade cannot silently widen what a policy reviewed. `check` sees createElement/setAttribute/setProperty/ addListener/bindMarker with interned strings resolved and the element's tag (tracked through clone-template/bind-path); templates are checked once at register-template, flattened into the same shapes. A rejection aborts the stream with a PolicyError. `query` gates the WIT queries; refusal answers none/false. - Strict decoding whenever a policy is present: one boolean per skip branch; unknown ops, fields and enum values reject. - `PROTOCOL VERSION: 1` in the proto header, mirrored as stream_dom_proto::PROTOCOL_VERSION (build.rs) and the receiver's PROTOCOL_VERSION (test re-reads the .proto). - SetAttribute.value / TemplateAttr.value gain an `asset` arm resolved by `resolveAsset`; wire-compatible, bench baseline unchanged. Batch::set_attribute_asset on the Rust side. - Backends and PolicySink pin template tags, attribute names and values at registration, so a later re-intern cannot make the applied DOM diverge from what the policy approved. remote.ts now rejects an un-interned template ref at registration, as native always has. - events.ts restored byte-for-byte to its pre-#13 form. - docs/design.md: Policy section rewritten for this model (records the declaration alternative and why it was removed); new "Assets are handles" decision; open question 10 updated.
lannbot
force-pushed
the
receiver-policy
branch
from
September 6, 2026 20:25
aedc2aa to
0df6457
Compare
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.
Replaces #13's per-field declaration model with a smaller mechanism carrying the same fail-safe property, and adds asset handles. #14's hardening and driver split are kept and wired into.
Policy model
Policy { version, check(op), query?(name) }onMountOptions/DriverOptions.versionpins thePROTOCOL VERSIONfrom the proto header;createDriverrefuses any other. Upgrading the receiver library cannot silently widen what a policy reviewed — bumping the pin is the embedder saying "I have read what changed".check(op)seescreateElement/setAttribute/setProperty/addListener/bindMarkerwith interned strings resolved and the element's tag (tracked throughclone-template/bind-path). Templates are checked once atregister-template, flattened into the same shapes. A returned reason aborts the stream with aPolicyError { opIndex, op, reason }. No drop-and-continue.query?(name)gates the WITqueriesimports; a refusal answersnone/false, never throws.Removed:
accept/events/queriesname lists,ALL_*_FIELDS,SURFACE_V1,compilePolicy, the bitmask decoder path, the event-payload field filter (events.tsis byte-identical to pre-#13). The design record keeps the declaration alternative as a considered-and-removed option: same guarantee for one integer instead of a hundred-name list in two languages.Assets
SetAttribute.value/TemplateAttr.valuebecomeoneof { text; asset }.assetis an opaque handle resolved byresolveAsset; absent hook + asset value is an error. Wire-compatible (textkeeps its field number and type);bench/wire-baseline.jsonunchanged. Rust:Batch::set_attribute_asset.Registration-time pinning
Backends and
PolicySinkresolve template tags, attribute names and values atregister-template, so a laterInternoverwrite cannot make the applied DOM diverge from what the policy approved.remote.tsnow rejects an un-interned template ref at registration, asnative.tsalways has.Also
PROTOCOL VERSION: 1in the proto header →stream_dom_proto::PROTOCOL_VERSION(build.rs) and the receiver'sPROTOCOL_VERSION(a test re-reads the .proto).deno lintfailures in Receiver: fail closed on hostile streams; split the DOM driver out of mount #14's test shims fixed (no-this-alias).Gates
just check,just test(95 deno tests, all cargo suites in both workspaces),deno fmt --check,deno lint receiver— all pass locally.