Skip to content

refactor(protocol): generate TypeScript contracts and enforce complete tool policies - #389

Draft
NianJiuZst wants to merge 6 commits into
Tencent:mainfrom
NianJiuZst:codex/protocol-contract-check
Draft

NianJiuZst wants to merge 6 commits into
Tencent:mainfrom
NianJiuZst:codex/protocol-contract-check

Conversation

@NianJiuZst

@NianJiuZst NianJiuZst commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Closes #388 when the agreed implementation is merged.

Draft for design discussion. The architecture, compatibility policy, and rollout still need maintainer agreement.

Problem and resulting behavior

Protocol changes currently require updating Rust payloads, handwritten TypeScript mirrors, JSON Schema files, dispatcher registrations, and method classifications separately. These copies can drift: the old TypeScript error union omitted Rust's user_aborted, and the checked-in handshake/session-stop schemas omitted fields already sent on the wire.

This PR uses the Rust method catalog and payload types as the shared source, generates extension contracts, validates the transport boundary, and requires complete handler and local-policy coverage. Evaluation retains the existing bounded timeout/cancellation behavior; an unresolved evaluation does not retain the session queue indefinitely.

Implementation

  • The Rust catalog ties each method to its wire name, owner, browser effect, and parameter/result types. Extension handlers and policies must cover every extension method; daemon policy exhaustively matches Method using named fields. Effect-classification rationale remains next to effect().
  • scripts/protocol.mjs generates 44 extension methods, 220 contract definitions, and 114 standalone JSON Schemas. Schemars 1.2.2 exports receiving and sending contracts separately. protocol:generate updates both generated directories; protocol:check detects missing, changed, or unexpected files in either directory without modifying source files.
  • dump-schema derives method roots from the catalog, skips unconstrained daemon-private payloads by schema/ownership rather than a hardcoded Schemars type name, and supports boolean schema roots. Checked-in schemas include audit_enabled, handshake audit responses, and window_released.
  • Generated TypeScript, immutable normalizers, and Ajv standalone validators replace handwritten DTO mirrors. Optional typed nulls normalize to omission; arbitrary JSON and dictionary nulls remain intact. The extension ships generated validation functions without a runtime schema compiler.
  • Envelope and parameter checks run before typed dispatch. Result checks run after the handler and report protocol_error with effect_state: "unknown" on mismatch; a malformed result does not prove that the action had no effect. Failed session-start result validation cleans up the allocated session.
  • Evaluation keeps the base branch's timeout/cancellation lifecycle. Neither a deadline nor a cancel acknowledgement proves that page JavaScript stopped. Execution settlement and recovery require a separate design with an explicit teardown path; this refactor makes no new execution-safety guarantee after timeout.
  • Main integration includes extraction, element waits, video action/result contracts, and protocol 1.4 incognito fields. Preserve extraction-handle targeting, wait response grace, video finalization, and the same-task video/action-recording reservation.
  • The existing browser archive regression bundles its dependencies before serving them to Chrome, so generated protocol imports resolve in that harness. Its test cases and assertions are unchanged.

Generate and check

pnpm protocol:generate
pnpm protocol:check
cargo run -p bsk-protocol --bin dump-schema --locked -- --out-dir /tmp/bsk-schema

Standalone schemas are compared from a temporary export. The substantial JSON diff includes regeneration under Schemars 1.x, including ordering and description formatting changes.

Validation — 2026-10-20

Merged upstream main e8777ab71bb851196895515b53eea2481462dd57 into the original branch. Environment: macOS ARM64, Rust 1.94.1, Node 26.10.0, pnpm 10.17.0, Chrome for Testing 153.0.8010.12.

Check Result
protocol:check 44 methods, 220 definitions, 114 standalone schemas; no stale artifacts
Rust workspace tests, serial 864 passed, 1 ignored
Rust formatting and production-target Clippy Passed
Extension suite 2,675 passed, 244 skipped
DSH plugin 538 passed
TypeScript, Biome, Stylelint, production build Passed
Node script tests 13 passed
Dispatcher/video tests after reservation repair 73 passed
Out-of-tree reservation regression Failed before repair; both active-video rejection and startup-failure release now pass
Independent P0–P2 review Complete; the merge's missing recording reservation was repaired and the follow-up review passed

A fresh private daemon, installed production extension and isolated Chrome exercised snapshot, element wait, extraction via a discovered target handle, and video list/start/stop/discard through the real CLI. During active video, a same-task tool.record_start sent through daemon IPC was rejected; the resulting video remained ready with nonzero bytes. These calls passed the generated request/result boundary. No new probes, fixtures, screenshots or logs are committed; existing tests only received interface adaptations.

Check boundary: all-target local Clippy hits redundant_iter_cloned in the unchanged updater test at crates/bsk-cli/src/cli/update.rs:1428. The same failure was reproduced on untouched main e8777ab; production-target Clippy and the full Rust tests pass. Browser-gated skips and untested released-peer combinations are not counted as passes. Hosted CI is tracked separately on the current PR head.

Compatibility and remaining design decisions

  • Protocol 1.4 and minimum compatible protocol 1.0 match current main. Strict validation is a behavior change; these checks do not establish compatibility with every released peer or all real-browser result shapes.
  • Empty console/network results emit entries: []; Serde readers still accept omission. More precise debug enums and result structures constrain previously permissive shapes.
  • Browser permissions, ownership, readiness, URL/regex semantics, and actual side effects remain handler responsibilities.
  • Generated validators remain committed and minified. Generator choice, generated-code review conventions, compatibility rollout, and whether runtime enforcement should land separately remain maintainer decisions.

…licies

Refs Tencent#388. Derive extension contracts and validators from the Rust catalog, enforce exhaustive handler and execution policies, and preserve evaluation settlement across caller deadlines.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: unify the Rust-TypeScript protocol contract and require complete tool policies

1 participant