machine-bridge-mcp 3.0.0-beta.29 → 3.0.0-beta.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +4 -2
  3. package/browser-extension/manifest.json +1 -1
  4. package/docs/ARCHITECTURE.md +8 -8
  5. package/docs/AUDIT.md +26 -0
  6. package/docs/CLIENTS.md +3 -1
  7. package/docs/LOGGING.md +2 -2
  8. package/docs/OPERATIONS.md +7 -7
  9. package/docs/RELEASING.md +1 -1
  10. package/docs/TESTING.md +4 -4
  11. package/docs/THREAT_MODEL.md +2 -2
  12. package/docs/TOOL_REFERENCE.md +36 -35
  13. package/docs/UPGRADING.md +15 -1
  14. package/package.json +1 -1
  15. package/scripts/install-published-prerelease.mjs +3 -3
  16. package/scripts/prerelease-activation.mjs +33 -10
  17. package/scripts/start-release-candidate.mjs +4 -4
  18. package/src/local/patch.mjs +20 -18
  19. package/src/local/process-execution.mjs +5 -10
  20. package/src/local/process-foreground-timeout.mjs +28 -0
  21. package/src/local/runtime-paths.mjs +2 -1
  22. package/src/local/runtime-tool-handlers.mjs +1 -1
  23. package/src/local/runtime.mjs +3 -3
  24. package/src/local/workspace-file-service.mjs +45 -44
  25. package/src/shared/foreground-timeout.d.mts +10 -0
  26. package/src/shared/foreground-timeout.mjs +42 -0
  27. package/src/shared/relay-contract.json +2 -2
  28. package/src/shared/server-metadata.json +2 -1
  29. package/src/shared/tool-catalog.json +36 -35
  30. package/src/worker/dpop.ts +73 -2
  31. package/src/worker/index.ts +84 -85
  32. package/src/worker/mcp-access.ts +5 -2
  33. package/src/worker/mcp-legacy-stream-prepare.ts +145 -0
  34. package/src/worker/mcp-pending-call-records.ts +17 -0
  35. package/src/worker/mcp-pending-call-store.ts +14 -3
  36. package/src/worker/mcp-request-fingerprint.ts +24 -0
  37. package/src/worker/mcp-resumption-config.ts +3 -1
  38. package/src/worker/mcp-resumption-records.ts +26 -2
  39. package/src/worker/mcp-resumption-request-index.ts +72 -0
  40. package/src/worker/mcp-resumption.ts +11 -20
  41. package/src/worker/mcp-stream-attempt.ts +27 -0
  42. package/src/worker/mcp-stream-channel.ts +54 -40
  43. package/src/worker/mcp-stream-dispatch.ts +12 -3
  44. package/src/worker/mcp-stream-prepare-retry.ts +47 -0
  45. package/src/worker/mcp-stream-proxy-contract.ts +13 -0
  46. package/src/worker/mcp-stream-proxy.ts +33 -4
  47. package/src/worker/mcp-stream-subscription.ts +49 -64
  48. package/src/worker/mcp-stream-terminal-socket.ts +72 -0
  49. package/src/worker/mcp-stream.ts +5 -3
  50. package/src/worker/nonce-store.ts +17 -0
  51. package/src/worker/observability.ts +64 -7
  52. package/src/worker/tool-timeout.ts +25 -25
  53. package/src/worker/worker-edge-guard.ts +10 -1
  54. package/src/worker/worker-entry.ts +4 -1
  55. package/src/worker/worker-rate-limit-key.ts +30 -0
  56. package/src/worker/worker-runtime-config.ts +1 -0
  57. package/wrangler.jsonc +5 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,59 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.0-beta.35 - 2026-08-03
4
+
5
+ ### Enforce the patch-helper call contract
6
+
7
+ - Remove the obsolete third argument from the workspace patch call after beta.32 intentionally removed path data from `applyUpdateHunks` errors. The extra argument had no runtime effect but violated the helper contract and was rejected by the zero-unaccepted-findings CodeQL gate.
8
+ - Add an architecture source-contract regression requiring the single workspace call to match the two-argument helper signature, so local verification catches the mismatch before remote CodeQL.
9
+
10
+ ## 3.0.0-beta.34 - 2026-08-03
11
+
12
+ ### Classify daemon terminal-result dispositions
13
+
14
+ - Replace the ambiguous Worker `unmatched_results` interpretation with an explicit `terminal_results` disposition matrix. Successful transient and durable settlements are counted separately from owner-missing results that are acknowledged to terminate normal at-least-once replay and stale-connection results that are rejected without acknowledgement.
15
+ - Retain `calls.unmatched_results` as a compatibility aggregate of `owner_missing_acknowledged` and `stale_connection_rejected`, and mark that scope machine-readably. Operators no longer need to treat a harmless duplicate after cancellation, timeout, reconnect, deployment, or lost acknowledgement as evidence of a connection-identity defect.
16
+ - Centralize the settlement-to-acknowledgement decision and test all four outcomes. A deployed Worker integration regression completes a real call, consumes its acknowledgement, resends the identical result, proves a second acknowledgement, and verifies that only `owner_missing_acknowledged` increases.
17
+ - Update architecture and operations contracts so stale ownership is diagnosed from `stale_connection_rejected`, while sustained owner-missing growth is investigated as acknowledgement loss or bounded lifecycle overlap rather than automatically classified as protocol corruption.
18
+
19
+ ## 3.0.0-beta.33 - 2026-08-03
20
+
21
+ ### Clarify prerelease rollback evidence
22
+
23
+ - Upgrade prerelease activation records to schema 2 and replace the ambiguous `previous` field with `global_package_rollback_baseline`. The field now states exactly what activation records retain: the globally installed npm package version and entrypoint available for operator-directed disaster recovery, not the service runtime active immediately before activation.
24
+ - Keep schema 1 activation records readable without rewriting historical evidence. Legacy `previous` values are normalized in memory to the schema 2 field, while mixed-version fields, duplicate baseline fields, relative entrypoints, and malformed baselines fail closed.
25
+ - Keep transaction-scoped service recovery separate. `runtime-activation` continues to capture and verify the actual pre-handoff service version and entrypoint during activation; the persistent activation record no longer invites those two recovery concepts to be conflated.
26
+ - Make both local-candidate and published-prerelease writers consume the shared activation schema constant, add disk-level migration and rejection regressions, and enforce the field distinction in architecture and release documentation gates.
27
+
28
+ ## 3.0.0-beta.32 - 2026-08-03
29
+
30
+ ### Typed file mutation failures
31
+
32
+ - Replace ordinary exceptions in workspace file, patch, and remote path-boundary operations with the existing stable `BridgeError` contract. `write_file`, `edit_file`, and `apply_patch` now preserve actionable error codes and bounded `details.reason` values through local execution, stdio MCP, daemon WebSocket transport, Worker adaptation, and public MCP tool results instead of collapsing expected state failures to `execution_failed`.
33
+ - Classify create-only collisions, optimistic SHA-256 mismatches, targets that appear during commit, unsupported target types, symbolic-link destinations, duplicate patch paths, and stale or ambiguous patch contexts as `conflict`. Missing edit text is `not_found`; malformed patch envelopes, invalid text/image inputs, and invalid line ranges are `invalid_request`; bounded read/write violations are `limit_exceeded`; hard-link read denial is `permission_denied`; workspace escape is `path_boundary`.
34
+ - Keep sensitive and irrecoverable failures fail-closed. Error details contain only bounded reason tokens, counts, limits, and hunk/line indexes, never paths, file contents, old/new text, or expected/actual hashes. Incomplete staged-write cleanup and incomplete patch rollback remain non-exposed `internal_error` results while retaining their causes locally.
35
+ - Add direct runtime, atomic fault-injection, Worker-adapter, and live stdio regressions proving stable code/reason propagation, no overwrite after create-only or stale-precondition failure, transactional rollback, and absence of absolute paths in public error objects. Update tool discovery descriptions, generated reference, architecture, testing, and client guidance.
36
+
37
+ ## 3.0.0-beta.31 - 2026-08-03
38
+
39
+ ### Preserve host delivery margin for synchronous tools
40
+
41
+ - Reduce the remote synchronous foreground ceiling from 85 to 60 seconds. The previous 85-second execution allowance plus five seconds of Worker settlement could consume roughly 90 seconds before terminal handling completed; live evidence showed a temporally aligned 83.5-second command complete locally after the ChatGPT task had already ended with a message-send timeout. Defaults remain 30 or 60 seconds, owner-local commands retain their local budget, and longer remote work continues through process sessions or managed jobs.
42
+ - Separate the daemon execution deadline from the Worker settlement deadline. A second review found that the first beta.31 candidate sent the 65-second settlement deadline to the daemon as its local execution deadline, so the claimed five-second margin was not real for tools governed only by the relay envelope. The daemon now receives at most 60 seconds, while the Worker records a settlement deadline five seconds later for result acceptance, persistence, acknowledgement, and terminal settlement. Admission and transport latency may consume part of that internal interval, so it is not an external host guarantee.
43
+ - Replace the ambiguous zero-recipient counter with explicit Worker-internal transport metrics for terminal publication, live internal-subscriber sends, storage responses, and the completion-between-lookup-and-subscription race. These metrics do not assert public SSE consumption or host receipt; `server_info.tool_delivery.host_terminal_receipt_observable=false` makes that boundary machine-readable without logging call IDs, arguments, or results.
44
+ - Reduce the unactivated legacy-stream retention ceiling from the obsolete 730-second local-envelope-derived value to 185 seconds: the 65-second maximum hosted settlement deadline plus the 120-second terminal replay window. Activated calls still extend their records across the actual operation/reconnect state machine; abandoned prepare records no longer occupy the bounded 64-stream capacity for more than the hosted contract requires.
45
+ - Update the executable tool catalog, client guidance, generated reference, timeout regressions, and upgrade documentation. Existing MCP hosts may retain an older cached tool schema until they rediscover or reconnect; Worker validation remains authoritative and rejects oversized requests before dispatch.
46
+
47
+ ## 3.0.0-beta.30 - 2026-08-02
48
+
49
+ ### Resumable MCP delivery under transient interruption
50
+
51
+ - Make the advertised and executed foreground timeout contract match the enforced Worker ceiling: configurable foreground tools now declare a maximum of 85 seconds and default to 30 or 60 seconds. Relay execution uses those same defaults when the argument is omitted, and a registered-command manifest cannot silently extend a relay call beyond 85 seconds; owner-local registered commands may retain their explicit local manifest budget. Longer remote work must use process sessions or managed jobs, eliminating host-generated or locally inherited 120–600 second work that outlived its Worker response.
52
+ - Stop legacy recovery subscribers from replacing one another. Up to four concurrent subscribers may observe the same persisted terminal result; excess subscribers receive a bounded retryable response, and terminal fan-out closes every subscriber cleanly.
53
+ - Extend internal terminal-subscription recovery from a sub-second retry burst to a bounded multi-second backoff. Cancelling a public SSE reader now releases only its internal delivery subscription while the durable legacy operation remains resumable through `Last-Event-ID`. DPoP-protected prepare retries use one outer-Worker-generated opaque retry ID: the first attempt atomically consumes the proof and binds it, and only the same internal request may reuse that proof for at most four authorization attempts; another request remains a replay failure.
54
+ - Make repeated signed-session legacy `tools/call` delivery idempotent throughout the bounded two-minute recovery window. OAuth token, signed MCP session, typed request ID, tool name, and a canonical SHA-256 argument fingerprint bind the stream before daemon dispatch; an identical retry reattaches to the active or terminal stream, while changed arguments are rejected instead of duplicating side effects. Sessionless legacy POSTs never retry an ambiguous prepare.
55
+ - Add regressions for concurrent subscriber fan-out and limits, delivery-subscription cleanup, canonical request fingerprints, persisted retry identity, the unified foreground timeout catalog, and effective relay timeout alignment for shell, direct-process, and registered-command execution. Clarify that a macOS sleep interval may legitimately surface as an event-loop-stall warning without implying daemon failure.
56
+
3
57
  ## 3.0.0-beta.29 - 2026-08-01
4
58
 
5
59
  ### Bounded security-audit throughput and retention
package/README.md CHANGED
@@ -31,6 +31,8 @@ Support boundaries are defined in [SUPPORT.md](SUPPORT.md). Repository participa
31
31
 
32
32
  The remote Worker authenticates and relays requests. It cannot directly read local files or start local processes. Local-user authority remains in the daemon process.
33
33
 
34
+ Expected file-state failures are machine-readable. File mutations return stable codes such as `conflict`, `not_found`, `invalid_request`, and `limit_exceeded`, with bounded `details.reason` tokens where useful. Conflict responses should trigger a fresh read and reconciliation rather than a blind retry; public errors do not include file contents, compared hashes, or hidden paths.
35
+
34
36
  ```text
35
37
  Hosted MCP client
36
38
  -> HTTPS + OAuth 2.1 / PKCE
@@ -169,7 +171,7 @@ The shared source of truth is `src/shared/policy-contract.json`. The generated m
169
171
 
170
172
  For remote calls, `server_info.authorization.effective_policy` and `effective_tools` are authoritative. Daemon policy and tools describe only the local capability ceiling before account-role and host-side filtering.
171
173
 
172
- `tools/list` is a stable discovery catalog for the authenticated account role. A brief relay interruption does not withdraw tool definitions or require a tools-list-changed notification. Discovery is not authority: every `tools/call` is still intersected with the current end-to-end-ready daemon policy and tool ceiling, and fails retryably with `unavailable` when no daemon is ready. `server_info.tool_delivery` distinguishes the stable advertised catalog from the currently effective daemon/account intersection. The remote catalog also narrows configurable foreground timeouts to 85 seconds while preserving each tool’s 30- or 60-second default; larger requests fail before daemon dispatch instead of being silently truncated after side effects may have begun.
174
+ `tools/list` is a stable discovery catalog for the authenticated account role. A brief relay interruption does not withdraw tool definitions or require a tools-list-changed notification. Discovery is not authority: every `tools/call` is still intersected with the current end-to-end-ready daemon policy and tool ceiling, and fails retryably with `unavailable` when no daemon is ready. `server_info.tool_delivery` distinguishes the stable advertised catalog from the currently effective daemon/account intersection. The remote catalog also narrows configurable foreground timeouts to 60 seconds while preserving each tool’s 30- or 60-second default; larger requests fail before daemon dispatch instead of being silently truncated after side effects may have begun.
173
175
 
174
176
  `full` is the daemon capability ceiling. An authenticated owner may exercise it without per-operation approval IDs. Delegated reviewer, editor, and operator accounts remain inside immutable role ceilings; out-of-role operations are denied rather than converted into a temporary elevation workflow. Process sessions, retained output, and managed jobs are additionally bound to account, client, and refresh-token family. See [local authorization](docs/LOCAL_AUTHORIZATION.md).
175
177
 
@@ -188,7 +190,7 @@ Machine Bridge does not launch or identify a separate browser profile. It contro
188
190
 
189
191
  ## Durable work and local resources
190
192
 
191
- Remote foreground process, shell, browser, and application calls are bounded to 85 seconds. Keep mutations and validation in independently terminal calls. A timeout is a protocol result, not proof that descendant cleanup has already completed; inspect `diagnose_runtime.runtime.processes` remotely (or `server_info.runtime.processes` over local stdio) when a heavy filesystem or process operation is still draining. Long, cleanup-sensitive, or remotely initiated workflows should use process sessions or managed jobs; managed jobs persist ordered argv steps and `finally_steps` under owner-only local state and continue across an MCP disconnect.
193
+ Remote foreground process, shell, browser, and application calls are bounded to 60 seconds of daemon execution. The Worker retains separate settlement ownership for five additional seconds, but neither that margin nor its internal stream metrics prove that an external MCP host consumed the terminal frame. Keep mutations and validation in independently terminal calls. A timeout is a protocol result, not proof that descendant cleanup has already completed; inspect `diagnose_runtime.runtime.processes` remotely (or `server_info.runtime.processes` over local stdio) when a heavy filesystem or process operation is still draining. Long, cleanup-sensitive, or remotely initiated workflows should use process sessions or managed jobs; managed jobs persist ordered argv steps and `finally_steps` under owner-only local state and continue across an MCP disconnect.
192
194
 
193
195
  Credentials and files can be registered by alias without returning their contents through MCP:
194
196
 
@@ -30,6 +30,6 @@
30
30
  "action": {
31
31
  "default_title": "Machine Bridge Browser"
32
32
  },
33
- "version_name": "3.0.0-beta.29",
33
+ "version_name": "3.0.0-beta.35",
34
34
  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxryYkpZhq8+VAQLHcGS9BAHQcyKX8RHGIpIwvtIVRU/rcOcE0bNdnM0aZJ/h6xWQsGDHlhvjT2+1aJaAn/9k8473BRWajzVXld961CdHYVFVHoce2hHiSJ0xydWrHMMZhAm0mN0UzjEpgZ0tMw209efcZHIvSwuxhteZMRy4kyiVjwFlOf5oXFCxRuCJnPj3AK9CmCf4XgEBuPIJ0TZmjGHOOdBvJmbCNnAWXYEo5/mf7MfCGhV4IJ1hNuhpoNQfOFKMUcw9/v/IpT62XpfXdGYTfGYCmCjC+gntK1spbkr2P4/2+sYMQtLpse71mpSNGXfcf3abU55Vpn+gncSxRQIDAQAB"
35
35
  }
@@ -29,7 +29,7 @@ A canonical workspace receives an independent profile, Worker name, secret set,
29
29
 
30
30
  `LocalRuntime` is the transport-independent local tool orchestrator. It owns the shared authorization/execution pipeline, manager construction, mutation serialization, cancellation, and the narrow delegation surface used by stdio and relay transports. Domain behavior remains in focused services:
31
31
 
32
- - `workspace-file-service.mjs` and `git-service.mjs` own canonical filesystem/Git operations;
32
+ - `workspace-file-service.mjs` and `git-service.mjs` own canonical filesystem/Git operations; file and patch state failures use stable `BridgeError` codes with privacy-bounded reason tokens, while incomplete rollback/cleanup remains a non-exposed internal failure;
33
33
  - `process-contract.mjs` owns argv shape/size validation; `process-tree-signal.mjs`, `process-tree-supervisor.mjs`, `process-tree-snapshot.mjs`, and `process-tree-ownership.mjs` separate cross-platform signaling, asynchronous escalation, bounded process-group observation, and PID/start-time ownership; `process-execution.mjs` and `process-sessions.mjs` own one-shot and interactive execution; and `process-tracker.mjs` retains active and draining process ownership until close;
34
34
  - `shared/tool-call-capacity.mjs` defines the control-tool set and generic admission algebra; local `call-capacity.mjs` and Worker `pending-call-capacity.ts` apply it independently, while `runtime-reporting.mjs` builds privacy-aware runtime and project snapshots;
35
35
  - `runtime-diagnostics.mjs` owns fixed local probes and their stable interpretation, while `runtime-diagnostic-state.mjs` projects privacy-safe control-plane state for remote diagnosis;
@@ -126,13 +126,13 @@ Public `/healthz`, `/`, discovery metadata, CORS preflight, and unknown-path 404
126
126
  - a bounded persistent index for legacy streamed daemon-call ownership, opaque connection generation, request correlation, result-transform metadata, and monotonic operation/reconnect deadlines;
127
127
  - bounded legacy resumable MCP delivery metadata and terminal responses for recently disconnected legacy SSE clients.
128
128
 
129
- `BridgeRoom` owns stateful routing, MCP authorization/dispatch, daemon WebSocket lifecycle, cancellation, and composition of the extracted state machines. `worker-entry.ts` owns outer-Worker static routing, stateful admission, protocol-era-aware SSE proxy selection, and privacy-safe gateway failures; `worker-static-routes.ts` and `worker-metadata.ts` own stateless public responses; `worker-edge-guard.ts` owns the burst guard and quota classification. Both outer and Durable Object `/mcp` boundaries validate the actual Origin. `mcp-http-contract.ts` owns modern per-request metadata, strict dual-media `Accept`, and mirrored-header validation, including `MCP-Protocol-Version`, `Mcp-Method`, `Mcp-Name`, and schema-declared `Mcp-Param-*`. `mcp-tool-call-input.ts` is the shared role-visible name/raw-argument/schema gate used by modern and legacy dispatch before side effects. `mcp-modern-controller.ts` owns modern request dispatch, while `mcp-modern-stream.ts` owns direct request/subscription SSE framing without event IDs or replay. `mcp-modern-proxy.ts` forwards exactly one modern Durable Object response, emits bounded keepalive comments, releases the internal reader on every terminal path, and maps public stream closure to a credential-free stream-scoped private cancel control; it has no prepare/subscribe phase or result registry. `mcp-stream-proxy.ts` routes modern direct streams and translates only legacy recovery descriptors. Every caller-supplied internal control header is stripped at the public boundary.
129
+ `BridgeRoom` owns stateful routing, MCP authorization/dispatch, daemon WebSocket lifecycle, cancellation, and composition of the extracted state machines. `worker-entry.ts` owns outer-Worker static routing, stateful admission, protocol-era-aware SSE proxy selection, and privacy-safe gateway failures; `worker-static-routes.ts` and `worker-metadata.ts` own stateless public responses; `worker-edge-guard.ts` owns the burst guard and quota classification. The outer Worker applies a two-level stateful burst guard before Durable Object routing: a high-capacity route/Worker bucket preserves aggregate abuse resistance, while a lower route/subject bucket isolates authenticated credentials or anonymous network identities through internal truncated SHA-256 keys. Raw credentials and addresses are never stored in application logs or returned by diagnostics; the hash is an opaque bucketing key, not a claim of cryptographic anonymity for low-entropy network addresses. Limiter failure is fail-open and never logs the key material. Both outer and Durable Object `/mcp` boundaries validate the actual Origin. `mcp-http-contract.ts` owns modern per-request metadata, strict dual-media `Accept`, and mirrored-header validation, including `MCP-Protocol-Version`, `Mcp-Method`, `Mcp-Name`, and schema-declared `Mcp-Param-*`. `mcp-tool-call-input.ts` is the shared role-visible name/raw-argument/schema gate used by modern and legacy dispatch before side effects. `mcp-modern-controller.ts` owns modern request dispatch, while `mcp-modern-stream.ts` owns direct request/subscription SSE framing without event IDs or replay. `mcp-modern-proxy.ts` forwards exactly one modern Durable Object response, emits bounded keepalive comments, releases the internal reader on every terminal path, and maps public stream closure to a credential-free stream-scoped private cancel control; it has no prepare/subscribe phase or result registry. `mcp-stream-proxy.ts` routes modern direct streams and translates only legacy recovery descriptors. Every caller-supplied internal control header is stripped at the public boundary.
130
130
 
131
- The legacy adapter remains isolated behind the same entrypoint. `mcp-stream-subscription.ts`, `mcp-stream-channel.ts`, `mcp-resumption-http.ts`, `mcp-resumption.ts`, `mcp-resumption-records.ts`, `mcp-resumption-index.ts`, `mcp-pending-call-store.ts`, `mcp-pending-call-records.ts`, and `durable-stream-calls.ts` own the MCP `2025-11-25` signed-session, persistent-call, recovery-GET, and `Last-Event-ID` contract. `runtime-alarm.ts` and `runtime-alarm-storage.ts` own earliest-deadline projection and coalesced alarm writes. `daemon-sockets.ts` owns socket role transitions, while `daemon-socket-attachment.ts` owns bounded attachment decoding. `mcp-jsonrpc.ts` owns JSON-RPC shape validation and result/error/tool-result projection. `mcp-session.ts` is legacy-only. `websocket-protocol.ts` owns record validation plus best-effort send/close/rejection helpers. `OAuthController` owns OAuth-store pruning, registration throttling, authorization submission, account-admin routing, token exchange, access-token verification, and the serialization queue for OAuth mutations. Worker-internal TypeScript imports use explicit `.ts` specifiers and JSON import attributes, so the same modules are directly executable under the pinned Node runtime and bundled by Wrangler.
131
+ The legacy adapter remains isolated behind the same entrypoint. `mcp-stream-subscription.ts`, `mcp-stream-channel.ts`, `mcp-resumption-http.ts`, `mcp-resumption.ts`, `mcp-resumption-records.ts`, `mcp-resumption-index.ts`, `mcp-pending-call-store.ts`, `mcp-pending-call-records.ts`, `mcp-request-fingerprint.ts`, and `durable-stream-calls.ts` own the MCP `2025-11-25` signed-session, persistent-call, recovery-GET, and `Last-Event-ID` contract. Active request identity includes a canonical argument fingerprint, so a lost prepare response can be retried and reattached without repeating side effects. Up to four internal delivery subscribers may coexist and receive the same terminal result; subscriber admission is serialized, excess receivers are retryable, and closing one public reader releases only that delivery socket. `runtime-alarm.ts` and `runtime-alarm-storage.ts` own earliest-deadline projection and coalesced alarm writes. `daemon-sockets.ts` owns socket role transitions, while `daemon-socket-attachment.ts` owns bounded attachment decoding. `mcp-jsonrpc.ts` owns JSON-RPC shape validation and result/error/tool-result projection. `mcp-session.ts` is legacy-only. `websocket-protocol.ts` owns record validation plus best-effort send/close/rejection helpers. `OAuthController` owns OAuth-store pruning, registration throttling, authorization submission, account-admin routing, token exchange, access-token verification, and the serialization queue for OAuth mutations. Worker-internal TypeScript imports use explicit `.ts` specifiers and JSON import attributes, so the same modules are directly executable under the pinned Node runtime and bundled by Wrangler.
132
132
 
133
133
  Modern MCP `2026-07-28` requests are independent. The Worker validates Origin, authenticates the direct request, checks body metadata and mirrored HTTP headers, intersects the tool with the account-visible catalog, and validates raw arguments before dispatch. OAuth token plus JSON-RPC request ID is deliberately not a global request key: two clients sharing one token may reuse the same ID concurrently. A modern streamed call remains owned by its initiating response stream and the ordinary bounded pending-call index. The outer response has no SSE event ID; public request abort, response-body cancellation, or failed keepalive delivery sends one random internal stream capability that removes the pending call and aborts the daemon operation. Public requests cannot supply that capability because internal headers are stripped, and the cancel control is processed before OAuth without forwarding Authorization or DPoP. There is no modern descriptor subscription, cross-event terminal Promise, or persisted replay result.
134
134
 
135
- Legacy MCP `2025-11-25` requests use the compatibility adapter. It issues a signed `Mcp-Session-Id`, scopes duplicate detection and explicit cancellation to token + session + typed JSON-RPC ID, and may persist bounded recovery state before dispatch. The outer Worker emits legacy sequence-zero/sequence-one event IDs; authenticated `GET /mcp` with the original session and `Last-Event-ID` may recover the terminal response. At most 64 legacy records and 1.5 MiB of terminal JSON per record are retained for two minutes. A Durable Object restart may rediscover a persisted legacy call; this recovery machinery is never consulted by the modern dispatcher.
135
+ Legacy MCP `2025-11-25` requests use the compatibility adapter. It issues a signed `Mcp-Session-Id` and treats token + signed session + typed JSON-RPC ID as a bounded idempotency and cancellation domain. Tool name plus a canonical argument fingerprint is persisted before daemon dispatch. During the two-minute recovery window, an identical signed-session POST reattaches to the active or terminal stream; the same ID with changed arguments is rejected because prior side effects may have started. The outer Worker emits legacy sequence-zero/sequence-one event IDs; authenticated `GET /mcp` with the original session and `Last-Event-ID` may recover the terminal response. At most 64 legacy records and 1.5 MiB of terminal JSON per record are retained for two minutes. A client that intentionally starts a new legacy operation must use a fresh typed request ID until the prior recovery record expires or sequence one is explicitly acknowledged, which atomically removes the replay record. Sessionless legacy requests intentionally remain independent because token-wide IDs are not a safe client identity; such clients have no POST idempotency guarantee, and the outer Worker does not automatically retry an ambiguous sessionless prepare. They should establish a signed session before side-effecting calls. A signed-session prepare protected by DPoP receives a fresh internal `retry_*` identifier generated after public headers are sanitized. Its proof JTI and retry identifier are atomically bound in Durable Object storage. At most four internal authorization attempts with the same binding are accepted, but a different outer request, a direct client replay, an invalid internal identifier, or inconsistent nonce/binding state is rejected. A Durable Object restart may rediscover a persisted legacy call; this recovery machinery is never consulted by the modern dispatcher.
136
136
 
137
137
  The shared tool catalog is executable protocol data rather than documentation only. `tool-argument-validation.mjs` compiles the supported JSON Schema 2020-12 subset at process/module initialization, rejects unsupported dialects or keywords instead of silently weakening them, refuses automatic network `$ref` dereference, and bounds schema depth, node count, pattern length, issue count, and total runtime validation steps. Array elements and each own object property consume work; object traversal does not allocate an unbounded key array before checking the budget. The open JSON portions of modern metadata, capabilities/extensions, and subscription filters use a separate 4,096-node/32-level/bounded-key structural walk, and resource subscription lists are count/length bounded. Worker validation prevents invalid remote calls from reaching the daemon or legacy durable state; local validation remains a second boundary for stdio, relay, and direct runtime entrypoints. Validation diagnostics contain only JSON Pointer instance path, keyword, and constraint text—never the rejected value or an unbounded caller-supplied identifier.
138
138
 
@@ -193,11 +193,11 @@ Remote OAuth binds each code, access token, and refresh token to a named Machine
193
193
  10. A modern `tools/call` receives a random relay call ID only after role-visible name and raw arguments pass the shared schema gate. A JSON response remains in the initiating Durable Object event. If the Worker selects SSE, the outer Worker assigns a random private stream capability, makes one authenticated direct Durable Object request, and forwards the non-resumable response stream. If the public stream closes, a second credential-free internal request presents only that capability; it is handled before OAuth/DPoP and can cancel only the matching active call. No modern descriptor, terminal-result registry, recovery GET, event ID, or `Last-Event-ID` state exists. A legacy streamed call validates first, then binds OAuth token + signed session + typed JSON-RPC ID, commits bounded durable call/recovery state before daemon dispatch, and returns a descriptor that the outer Worker turns into the sequence-zero/sequence-one resumable stream.
194
194
  11. The local runtime validates policy and arguments, executes the tool, and produces a bounded JSON-serializable result. It retains the daemon-to-Worker terminal envelope after WebSocket queueing and replays it until the Worker returns `tool_result_ack`; queue acceptance is not durable delivery. This relay acknowledgement contract is independent of the public MCP era. Closing a modern HTTP response cancels its pending call through the private stream control. Closing a legacy response leaves the bounded operation recoverable; only legacy `notifications/cancelled`, a deadline, or reconnect-grace expiry cancels it.
195
195
  12. The Durable Object accepts a result only from the registered WebSocket generation. A transient modern call settles its in-memory pending record and current HTTP response; a legacy streamed call settles the generation-checked durable terminal store. If the daemon socket drops, both call classes may detach below the MCP transport for the bounded same-daemon reconnect interval. The same daemon-process identifier may reclaim them only after a fresh readiness probe; a new daemon process cannot. A stale socket result or close event cannot settle or detach a rebound call. Modern public HTTP recovery is still impossible: if that response stream is gone, its call is cancelled rather than exposed through replay.
196
- 13. Daemon delivery is at-least-once until `tool_result_ack`. The generation guard, idempotent already-terminal handling, and authoritative `resume_calls` set make duplicate delivery converge without reviving removed calls. Modern response closure and legacy explicit cancellation remove their respective pending ownership before a late result can be delivered. On readiness handover, the runtime cancels active calls and queued results absent from `resume_calls` before accepting `ready_ack`.
196
+ 13. Daemon delivery is at-least-once until `tool_result_ack`. The generation guard, idempotent already-terminal handling, and authoritative `resume_calls` set make duplicate delivery converge without reviving removed calls. Result handling records the disposition rather than collapsing every missing owner into one anomaly: committed transient and durable results are distinct from safely acknowledged owner-missing replays, while results from a stale connection are rejected without acknowledgement. The legacy `unmatched_results` metric is only the aggregate of owner-missing and stale-connection dispositions. Modern response closure and legacy explicit cancellation remove their respective pending ownership before a late result can be delivered. On readiness handover, the runtime cancels active calls and queued results absent from `resume_calls` before accepting `ready_ack`.
197
197
  14. A tool deadline cancels only that operation and never infers daemon death from tool duration. The independent daemon-liveness alarm owns socket invalidation. If same-instance readiness does not return before the grace deadline, the Worker rejects the detached request and the local runtime cancels ordinary calls, terminates their process trees, and discards queued results. A newly started daemon has a different instance identifier and cannot inherit prior calls.
198
198
  15. `start_job` is different: after durable acceptance, the detached runner is no longer bound to an MCP response stream or daemon socket. Later cancellation uses `cancel_job` or the local CLI.
199
199
 
200
- Modern HTTP JSON-RPC IDs are scoped to each request or response stream and are not used as a token-wide duplicate key, so independent clients may reuse the same typed ID. Legacy HTTP duplicate detection and cancellation are scoped to OAuth token + signed MCP session + typed JSON-RPC ID. Stdio has one process-local in-flight ID index because all requests share one explicit transport channel.
200
+ Modern HTTP JSON-RPC IDs are scoped to each request or response stream and are not used as a token-wide duplicate key, so independent clients may reuse the same typed ID. Legacy HTTP idempotency, replay, and cancellation are scoped to OAuth token + signed MCP session + typed JSON-RPC ID for the bounded recovery lifetime; intentional new work uses a fresh ID during that interval. Stdio has one process-local in-flight ID index because all requests share one explicit transport channel.
201
201
 
202
202
  ## Stdio request lifecycle
203
203
 
@@ -293,7 +293,7 @@ Browser-origin handling separates CORS response sharing from protocol authentica
293
293
 
294
294
  ## Observability
295
295
 
296
- Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, managed-job counts, resource alias names without paths or values, relay route state without endpoint details, authenticated/probing/ready socket counts, end-to-end readiness evidence, local execution guardrails, explicit OS-enforcement gaps, and privacy-preserving capability-routing evidence. It separates the daemon capability ceiling from the authenticated account authority: `daemon.policy`/`daemon.tools` retain the pre-role ceiling, while `authorization.effective_policy`/`authorization.effective_tools` and the top-level `tools` report the role-intersected authority before any host-side filtering. It explicitly reports that the host-exposed subset is unknown to the server. The Worker projects a remote-only foreground timeout schema of 1–85 seconds from the broader local catalog and rejects larger values before any daemon message is sent. `diagnose_runtime` runs fixed local probes, explicitly reports that its own request reached the daemon, and on macOS projects the default route into a coarse VPN/TUN interception class without returning interface or endpoint data.
296
+ Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, managed-job counts, resource alias names without paths or values, relay route state without endpoint details, authenticated/probing/ready socket counts, end-to-end readiness evidence, local execution guardrails, explicit OS-enforcement gaps, and privacy-preserving capability-routing evidence. It separates the daemon capability ceiling from the authenticated account authority: `daemon.policy`/`daemon.tools` retain the pre-role ceiling, while `authorization.effective_policy`/`authorization.effective_tools` and the top-level `tools` report the role-intersected authority before any host-side filtering. It explicitly reports that the host-exposed subset is unknown to the server. The canonical MCP catalog advertises one foreground timeout contract of 1–60 seconds with tool-specific 30- or 60-second defaults, and the Worker rejects larger values before any daemon message is sent. `tool-timeout.ts` derives distinct daemon-execution and Worker-settlement deadlines, so the five-second settlement-deadline offset is not passed back to the daemon as additional execution time. `foreground-timeout.mjs` is the shared source for execution defaults and limits; `process-foreground-timeout.mjs` applies them again at the local relay execution boundary so omitted values and registered-command manifests cannot outlive the Worker response. Owner-local registered commands may still use their explicit local manifest timeout. Longer remote work uses process sessions or managed jobs rather than a synchronous foreground response. `diagnose_runtime` runs fixed local probes, explicitly reports that its own request reached the daemon, and on macOS projects the default route into a coarse VPN/TUN interception class without returning interface or endpoint data.
297
297
 
298
298
  Foreground logging defaults to `info`; autostart uses `warn`. Authenticated readiness, persistent degradation, and recovery are user-visible state transitions. Brief relay interruptions, raw transport close details, retry timing, and all per-tool starts/successes/failures/cancellations/durations are debug-only. Unexpected local and Worker infrastructure errors are reduced to classes. Messages, strings, arrays, object depth/key counts, and serialized fields are bounded.
299
299
 
@@ -301,7 +301,7 @@ Cloudflare sampling is size control rather than an audit log. The project intent
301
301
 
302
302
  ## Release integrity
303
303
 
304
- Repository-local checks cannot prove the ordinary deployed path. `local-release-acceptance.mjs` builds the exact tarball and promotion-content digest. The owner executes `release:candidate:activate`, which installs the tarball under the private state root and invokes the extracted `runtime-activation` state machine. The transaction acquires the machine-service lock before the workspace startup lock, rejects foreground or unverifiable ownership before provider mutation, authenticates the candidate daemon through the real Worker, and proves relay readiness before writing the service definition. Installation commits a machine-global owner record for the exact workspace, state root, entrypoint, and version. The login-service handoff succeeds only when that owner's daemon lock publishes the post-`ready_ack` readiness checkpoint; provider-active state alone cannot satisfy acceptance. A first explicit device-authentication rejection triggers one same-name, same-identity repair deployment and bounded candidate retry. If remote preparation has already advanced the deployment and activation still fails, cleanup installs and starts the compatible candidate service rather than restoring an incompatible previous runtime. Before remote transition, an older service is considered restored only when the same version and entrypoint reappear as a verified service daemon. The activation wrapper has no outer transaction-wide `SIGKILL`; each deployment, network, relay, service-manager, and convergence stage owns its bounded deadline so cleanup cannot be bypassed. Fault-injection tests cover lock ordering/release, pre-mutation foreground refusal, owner transaction failure, missing/corrupt/pending owner state, readiness failure, authentication repair and exhaustion, compatible-service recovery, legacy identity restoration, cleanup aggregation, failed service start, and convergence timeout.
304
+ Repository-local checks cannot prove the ordinary deployed path. `local-release-acceptance.mjs` builds the exact tarball and promotion-content digest. The owner executes `release:candidate:activate`, which installs the tarball under the private state root and invokes the extracted `runtime-activation` state machine. The transaction acquires the machine-service lock before the workspace startup lock, rejects foreground or unverifiable ownership before provider mutation, authenticates the candidate daemon through the real Worker, and proves relay readiness before writing the service definition. Installation commits a machine-global owner record for the exact workspace, state root, entrypoint, and version. The login-service handoff succeeds only when that owner's daemon lock publishes the post-`ready_ack` readiness checkpoint; provider-active state alone cannot satisfy acceptance. A first explicit device-authentication rejection triggers one same-name, same-identity repair deployment and bounded candidate retry. If remote preparation has already advanced the deployment and activation still fails, cleanup installs and starts the compatible candidate service rather than restoring an incompatible previous runtime. Before remote transition, an older service is considered restored only when the same version and entrypoint reappear as a verified service daemon. That transaction-scoped service identity is distinct from the activation record's optional `global_package_rollback_baseline`, which names only the globally installed npm package available for later operator-directed disaster recovery. Activation schema 2 makes the distinction explicit; schema 1 `previous` records are accepted only as legacy input and normalized to the new field. The activation wrapper has no outer transaction-wide `SIGKILL`; each deployment, network, relay, service-manager, and convergence stage owns its bounded deadline so cleanup cannot be bypassed. Fault-injection tests cover lock ordering/release, pre-mutation foreground refusal, owner transaction failure, missing/corrupt/pending owner state, readiness failure, authentication repair and exhaustion, compatible-service recovery, legacy identity restoration, cleanup aggregation, failed service start, and convergence timeout.
305
305
 
306
306
  Accepted prereleases use explicit npm/GitHub channels and a registry-verified activation record. `release-soak.mjs` enforces elapsed major/minor/patch observation windows. `promotion-digest.mjs` hashes the npm package inventory, file modes, and bytes while normalizing only synchronized version metadata; stable release is blocked if any functional packaged content differs. Guarded push, portable CI acceptance, GitHub source release, npm publication, and stable publication all validate the relevant acceptance/soak evidence. GitHub tag/Release mutation additionally requires an explicit confirmation flag and real owner TTYs before any fetch or verification, then holds a process-identity publication lock at the common Git state path so linked worktrees share the same owner. Release commands require `HEAD === origin/main` and never push `main` implicitly.
307
307
 
package/docs/AUDIT.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Security and privacy audit notes
2
2
 
3
+ ## 2026-08-03 version 3.0.0-beta.31 host-delivery margin review
4
+
5
+ The reported “message send timed out” interruption did not coincide with a daemon crash or a current relay outage. Launchd still owned one verified beta.30 daemon process with `runs=1`; Worker and daemon versions matched; and the local security-audit chain recorded a temporally aligned `exec_command` as successfully completed after 83,514 milliseconds. During the incident the Worker showed two durable `exec_command` calls still active, the oldest at roughly 81 seconds. Both later reached terminal state, while the host ended the task. The privacy-preserving audit deliberately omits raw command text, so an exact one-to-one mapping to the UI task cannot be proven; the timestamps and active-call counts nevertheless align. This separates execution completion from message delivery: persistence can preserve a legacy result, but it cannot force a host that has abandoned the response to resume it.
6
+
7
+ The beta.30 claim that 85 seconds was host-safe was therefore too strong. Its maximum execution budget plus the five-second Worker overhead allowed a terminal deadline of 90 seconds, leaving no credible allowance for request admission, Durable Object work, public SSE forwarding, host processing, or final assistant-message submission. The exact host deadline is external and not a Machine Bridge contract, so beta.31 does not claim a mathematically guaranteed bound. It conservatively caps remote synchronous execution at 60 seconds, records the Worker settlement deadline five seconds later, and directs longer work to durable process sessions or managed jobs. Admission and transport latency can consume part of that interval.
8
+
9
+ A second source review found that the first beta.31 candidate did not actually preserve that split. `daemonToolTimeoutMs` returned the execution budget plus overhead, and the Worker reused the same value both for its pending-call deadline and for the daemon `tool_call.timeout_ms`. Tools whose handler had no narrower inner timeout could therefore execute for the entire 65 seconds and consume the intended settlement margin. Beta.31 now computes an explicit `{executionTimeoutMs, settlementTimeoutMs}` budget: the daemon receives 60 seconds at most, while the Worker deadline is recorded at 65 seconds from Worker registration. Tests assert the two values independently for transient and durable stream paths, including the one-second integration timeout case.
10
+
11
+ The same review found a discovery-cache mismatch outside the current repository source: the live beta.30 Worker and canonical catalog enforced an 85-second maximum, while the tool schema supplied to the active ChatGPT conversation still advertised 600 seconds. A 120-second request was consequently generated by the host and rejected before dispatch. Beta.31 publishes a 60-second canonical schema and documents that an already-open host may need rediscovery or reconnection; the Worker remains the authoritative validation boundary. Because Machine Bridge cannot invalidate a host-owned schema cache, it must continue failing oversized requests with `side_effects_started=false`.
12
+
13
+ The same second review rejected the first observability fix as semantically ambiguous. A terminal publication with zero live internal subscribers can be normal: completion may precede subscription, after which the outer Worker obtains the persisted result through a storage-backed HTTP response. Conversely, a successful internal WebSocket send proves only Durable Object-to-outer-Worker queueing, not public SSE consumption or host receipt. Beta.31 therefore exposes separate aggregate counters for terminal publications, live internal-subscriber sends, storage responses, and storage-race sends/failures. `server_info.tool_delivery` explicitly states that host terminal receipt is not observable and that these counters cover legacy resumable Worker-internal storage and subscription transport only. Request identity, tool arguments, command text, and result content remain absent.
14
+
15
+ The resumption configuration retained another stale dependency on the former local 610-second relay envelope. A stream created during legacy prepare but never activated could remain for 730 seconds, consuming one of 64 bounded stream slots, even though hosted settlement now ends by 65 seconds. New unactivated records are capped at 185 seconds: maximum hosted settlement plus the 120-second replay window. Once activated, the existing operation/reconnect expiry algebra remains authoritative and extends the record as required.
16
+
17
+ ## 2026-08-02 version 3.0.0-beta.30 interruption and recovery review
18
+
19
+ A repeated-call incident was reproduced while the local launchd daemon remained the same healthy beta.29 process. Recent security-audit records showed that many 20–78 second local calls reached terminal state even when the MCP host reported interruption, and the public MCP endpoint was briefly unreachable while the daemon connection identity remained unchanged. Live Cloudflare sampling after recovery showed no Worker exceptions; internal legacy subscription WebSockets closed frequently as part of their ordinary terminal lifecycle. The evidence therefore separates three cases: local execution failure, Worker/DO delivery interruption after admission, and a connection failure before Worker code runs. Only the first two are observable or repairable inside this repository; a pre-Worker edge/TCP/TLS failure still requires host retry or an independently operated alternate endpoint.
20
+
21
+ The review found five concrete amplification defects. The shared tool catalog advertised 120-second defaults and a 600-second maximum while the Worker rejected values above 85 seconds, allowing the host to generate requests that could never pass remote validation. After the catalog was corrected, the full gate exposed the inverse execution mismatch: `exec_command` and `run_process` still defaulted to 120 seconds locally when relay arguments omitted the field, and `run_local_command` could inherit a 600-second owner manifest even though the Worker waited only 60 or 85 seconds. Legacy internal subscription recovery retried only over roughly 400 milliseconds and every new resume forcibly closed the previous subscriber, allowing concurrent original/resume paths to replace each other. A lost prepare response caused the outer Worker to repeat no request, while a client retry had no explicit argument fingerprint for safe in-flight reattachment. Finally, the stateful burst limiter keyed only by Worker hostname, so every account and client shared one 120-request/minute bucket.
22
+
23
+ Beta.30 makes the foreground catalog truthful at its source: every configurable synchronous tool advertises a maximum of 85 seconds and a 30- or 60-second default on every MCP surface. A shared timeout module now drives both Worker admission and local relay execution; omitted relay values use the advertised default, and registered-command manifests are capped at the remote ceiling before process spawn. Owner-local registered-command invocation remains allowed to use its explicit local manifest budget. Longer remote work uses process sessions or managed jobs. Signed-session legacy preparation now retries a small bounded set of transient DO failures with an exact cloned request; token, signed session, typed JSON-RPC ID, tool name, and a canonical SHA-256 argument fingerprint bind the stream before daemon dispatch and remain through its bounded terminal-retention window, so an identical retry reattaches and changed arguments fail rather than duplicating side effects. Terminal subscriptions retry over a bounded multi-second window, permit four simultaneous receivers, multicast one persisted terminal result, and release only the delivery socket when a public reader disappears. A serialized subscriber-admission gate prevents concurrent limit bypass. Sessionless legacy requests remain independent by design because a shared bearer token and typed ID cannot safely identify one client; the exact-POST reattachment guarantee therefore requires the signed session issued by legacy initialization. Sessionless POST preparation is attempted once so an ambiguous response cannot cause an automatic duplicate side effect. For DPoP-bound access tokens, the outer Worker replaces any public internal header with a fresh random retry ID. The Durable Object transaction atomically consumes the proof and stores `proof replay key -> retry ID`; only that same opaque internal request may reuse the proof for at most four authorization attempts, and the binding is accepted only while the primary nonce record remains present. Different retry IDs, malformed IDs, missing nonce state, and ordinary client replay fail closed.
24
+
25
+ The burst guard is now layered: a 1,200-request/minute route/Worker bucket limits aggregate abuse, while a 120-request/minute route/subject bucket isolates authenticated credentials or an anonymous network identity through a truncated SHA-256 digest. Raw credentials, addresses, request keys, arguments, and results are never used as log fields. Limiter failure remains fail-open so the optional guard cannot become a control-plane outage.
26
+
27
+ A separate 100-second `runtime.event_loop.stall` warning was correlated exactly with macOS sleep from 07:15:31 to the 07:17:40 wake. The unchanged daemon PID and power-management log prove that warning was correct sleep/wake accounting rather than JavaScript blockage. Sleep can still interrupt network transport; same-daemon relay recovery remains bounded by the existing reconnect contract.
28
+
3
29
  ## 2026-08-01 version 3.0.0-beta.29 security-audit storage review
4
30
 
5
31
  Review of the live 4,096-event audit chain found that moving persistence to a worker thread removed daemon event-loop blocking but did not remove storage amplification. Each sparse batch still read roughly 3 MiB, parsed the complete document, recalculated every SHA-256 link, serialized the complete state, atomically replaced it, and called `fsync`. On the inspected machine, a cold full-chain verification took approximately 1.3 seconds. The previous implementation therefore could accumulate audit work at ordinary interactive call rates even though tool-result delivery itself remained asynchronous.
package/docs/CLIENTS.md CHANGED
@@ -163,7 +163,9 @@ The local `full` profile controls Machine Bridge's own tool catalog, path resolv
163
163
 
164
164
  Machine Bridge itself does not block files because their names look sensitive. In remote mode, first inspect `server_info.authorization.effective_policy` and `effective_tools`; `daemon.policy` is only the local ceiling. If the effective profile is `full` and the effective tool is present but a direct call is still rejected before a structured result, the host/connector may have blocked delivery. If `diagnose_runtime` responds but its fixed process or shell probe fails, the likely source is local OS policy, endpoint-security software, permissions, or shell configuration. Changing `--profile`, `--unrestricted-paths`, or `--absolute-paths` cannot override either layer.
165
165
 
166
- Remote configurable foreground tools advertise an 85-second maximum while preserving each tool’s 30- or 60-second default. Missing or role-hidden tools, non-object arguments, and requests above that limit fail at the shared Worker schema boundary before daemon dispatch; schema failures include `side_effects_started=false`. A legacy client asking for SSE receives the same pre-persistence rejection as a JSON client rather than an allocated recovery stream. Do not treat this as a retry invitation for the same oversized mutation, and do not attempt to evade a host refusal by renaming, encoding, or switching to another arbitrary execution tool. Instead:
166
+ Expected file-operation failures arrive as ordinary MCP tool-error results, not JSON-RPC transport failures. Clients should branch first on `structuredContent.error.code`, then optionally on the bounded `details.reason`. For example, `conflict/already_exists`, `conflict/hash_mismatch`, `conflict/text_ambiguous`, and `conflict/context_not_found` require a fresh read and reconciliation; `not_found/text_not_found` means the requested edit fragment is absent; `invalid_request` means the request or patch syntax must change. Do not log or display tool arguments to reconstruct diagnostics: public error details intentionally omit paths, file content, edit fragments, and compared hashes.
167
+
168
+ Remote configurable foreground tools advertise a 60-second maximum while preserving each tool’s 30- or 60-second default. That value bounds daemon execution; the Worker records its settlement deadline five seconds later. Admission and transport latency may consume part of that interval, and it is not a guarantee of host receipt. Missing or role-hidden tools, non-object arguments, and requests above that limit fail at the shared Worker schema boundary before daemon dispatch; schema failures include `side_effects_started=false`. A legacy client asking for SSE receives the same pre-persistence rejection as a JSON client rather than an allocated recovery stream. Do not treat this as a retry invitation for the same oversized mutation, and do not attempt to evade a host refusal by renaming, encoding, or switching to another arbitrary execution tool. Instead:
167
169
 
168
170
  1. register credentials locally as resource aliases so their values never enter MCP arguments;
169
171
  2. submit a complete owner-authorized `start_job` plan before the workflow depends on later cleanup calls; `stage_job` is only a non-running draft, while an explicit local operator may use `machine-mcp job submit PLAN.json`;
package/docs/LOGGING.md CHANGED
@@ -63,11 +63,11 @@ Brief network interruptions are expected on laptop network changes, Worker deplo
63
63
  - a verified replacement is a distinct warning and permanently stops the older daemon;
64
64
  - failure to receive `hello_ack` within the handshake deadline, or `ready_ack` within the independent end-to-end readiness deadline, terminates the candidate socket and retries;
65
65
  - lack of inbound heartbeat activity terminates a half-open socket and reconnects;
66
- - a late local heartbeat tick is classified as `runtime.event_loop.stall`, sends a fresh probe, and defers disconnect for a bounded recovery interval instead of being mislabeled as immediate remote failure.
66
+ - a late local heartbeat tick is classified as `runtime.event_loop.stall`, sends a fresh probe, and defers disconnect for a bounded recovery interval instead of being mislabeled as immediate remote failure; a macOS sleep/wake interval may legitimately produce this warning without a daemon fault.
67
67
 
68
68
  A WebSocket close code such as `1006` means the transport ended without a normal close handshake. It is useful for debug diagnosis but not useful as the default user message. It is not evidence that the daemon process restarted. Worker `daemon_transport_error` / `daemon_liveness_timeout` messages and their 1012 close frames are likewise retryable connection conditions, not upgrade instructions. Only an unknown/incompatible Worker error, authentication failure, or identity/version mismatch may produce the fatal protocol/configuration log and daemon exit. Default logs therefore describe the affected layer, duration, classification, and recovery behavior rather than printing raw close envelopes.
69
69
 
70
- Streamed-call diagnostics are deliberately coarse. Modern request-scoped stream ownership is memory-only; legacy MCP `2025-11-25` may additionally report aggregate persistent active/detached counts, oldest age, tool-name counts, alarm mutations, unmatched-result counts, and whether a legacy call is transient or durable. Worker event counters are scoped to the current isolate and say so in `metric_scope`; persisted durable calls can begin in one isolate and complete in another, so `started`, `completed`, and `failed` are not algebraically closed process-lifetime totals. The persistent pending-call snapshot is authoritative for current ownership. Logs and `server_info` must not include tool arguments, terminal results, command text, request keys, account identifiers, raw call IDs, raw connection generations, mirrored parameter values, private paths, or subscriber payloads. A stale-generation result is counted as unmatched rather than logged with its envelope.
70
+ Streamed-call diagnostics are deliberately coarse. Modern request-scoped stream ownership is memory-only; legacy MCP `2025-11-25` may additionally report aggregate persistent active/detached counts, oldest age, tool-name counts, alarm mutations, unmatched-result counts, opened/coexisting/limited delivery-subscriber counts, terminal publications, live internal-subscriber sends, storage responses, and storage-race sends/failures. These counters describe legacy resumable Worker-internal storage and subscription transport; they do not prove public SSE consumption or MCP-host receipt. Worker event counters are scoped to the current isolate and say so in `metric_scope`; persisted durable calls can begin in one isolate and complete in another, so `started`, `completed`, and `failed` are not algebraically closed process-lifetime totals. The persistent pending-call snapshot is authoritative for current ownership. Logs and `server_info` must not include tool arguments, terminal results, command text, request keys, account identifiers, raw call IDs, raw connection generations, mirrored parameter values, private paths, or subscriber payloads. A stale-generation result is counted as unmatched rather than logged with its envelope.
71
71
 
72
72
  Examples:
73
73
 
@@ -59,19 +59,19 @@ A successful diagnostic result applies only to that probe. An MCP host can still
59
59
 
60
60
  ### Concurrent chat windows and pending calls
61
61
 
62
- Machine Bridge supports concurrent calls: the Worker admits 32 pending daemon calls (30 ordinary plus two reserved control calls), and the local runtime admits 16 active tool calls (14 ordinary plus two reserved control calls). The same `diagnose_runtime`/`list_roots` control set is enforced at both layers. These are capacity limits, not a single global execution queue. Modern MCP `2026-07-28` HTTP requests are independent: JSON-RPC IDs are scoped to each request/response stream, so separate clients may reuse the same numeric ID even when they share one OAuth account and token. Legacy MCP `2025-11-25` initialization still receives a signed `Mcp-Session-Id`; duplicate detection, explicit cancellation, and replay for that compatibility path remain session-scoped.
62
+ Machine Bridge supports concurrent calls: the Worker admits 32 pending daemon calls (30 ordinary plus two reserved control calls), and the local runtime admits 16 active tool calls (14 ordinary plus two reserved control calls). The same `diagnose_runtime`/`list_roots` control set is enforced at both layers. These are capacity limits, not a single global execution queue. Modern MCP `2026-07-28` HTTP requests are independent: JSON-RPC IDs are scoped to each request/response stream, so separate clients may reuse the same numeric ID even when they share one OAuth account and token. Legacy MCP `2025-11-25` initialization still receives a signed `Mcp-Session-Id`; idempotency, explicit cancellation, and replay for that compatibility path remain session-scoped. Within the bounded two-minute recovery window, a typed request ID denotes one operation and must not be intentionally reused for new work.
63
63
 
64
64
  `server_info.worker.pending_calls` reports `active`, `detached`, `request_keys`, `maximum`, `oldest_ms`, `by_tool`, `transient`, and `durable_streams`. `worker.sockets_live` separately reports `authenticated`, `probing`, `ready`, and `candidates`; only `ready` sockets contribute to `daemon.connected` and `authorization.effective_tools`. A nonzero `active` count means work is in flight, not that the bridge is globally locked. `detached > 0` means the daemon WebSocket was lost and calls are inside the bounded same-daemon reconnect interval. This relay-layer state exists below both MCP eras.
65
65
 
66
- For modern MCP `2026-07-28`, the public response stream is the request owner: closing it cancels the transient pending call, and no request-key or replay record should remain. For legacy MCP `2025-11-25`, the signed session and typed JSON-RPC ID own duplicate detection and explicit `notifications/cancelled`; closing a resumable public stream alone does not cancel the operation. Legacy terminal completion, explicit cancellation, timeout, or reconnect-grace expiry must eventually return active/detached/request-key counts to zero. A verified same-daemon replacement may reclaim detached relay calls after readiness, while a new daemon process cannot. Delayed results from the old socket are rejected. `detached > 0` materially beyond the two-minute grace, a modern transient call surviving response closure, or a legacy request-key count remaining after active calls reach zero is a lifecycle defect.
66
+ For modern MCP `2026-07-28`, the public response stream is the request owner: closing it cancels the transient pending call, and no request-key or replay record should remain. For legacy MCP `2025-11-25`, the signed session and typed JSON-RPC ID own bounded idempotency and explicit `notifications/cancelled`; closing a resumable public stream alone does not cancel the operation. Legacy terminal completion, explicit cancellation, timeout, or reconnect-grace expiry must eventually return active/detached/pending-call request-key counts to zero, while the separate stream-level replay identity may remain until the two-minute recovery record expires. A verified same-daemon replacement may reclaim detached relay calls after readiness, while a new daemon process cannot. Delayed results from the old socket are rejected. `detached > 0` materially beyond the two-minute grace, a modern transient call surviving response closure, or a legacy request-key count remaining after active calls reach zero is a lifecycle defect.
67
67
 
68
68
  A Worker-requested `daemon_transport_error` or `daemon_liveness_timeout` is a retryable connection invalidation. The local daemon must close only the affected socket, preserve pending-call detach semantics, and reconnect; it must not enter the fatal `relay_protocol_error` path or exit for launchd to restart. The Worker uses close code 1012 for these transient cases. The daemon also recognizes the bounded close reasons `daemon pong failed`, `daemon send failed`, and `daemon liveness timeout` if the preceding error frame is not delivered. Unknown error codes, authentication rejection, and server identity/version mismatch remain permanent failures and require operator action.
69
69
 
70
70
  For modern MCP `2026-07-28`, every POST advertises both `application/json` and `text/event-stream` with valid positive HTTP quality values, carries protocol version and capabilities in request `_meta`, and mirrors the version/method/applicable name into validated HTTP headers. The actual `/mcp` Origin must be absent, same-origin, built-in, or explicitly allowlisted; CORS preflight accepts only fixed protocol headers plus exact catalog-declared `Mcp-Param-*` names. A JSON response completes immediately; a streamed `tools/call` receives a request-scoped SSE stream without event IDs. Closing that response stream is cancellation: the outer Worker observes request abort, response-body cancellation, or failed bounded keepalive delivery and sends one random internal capability without Authorization or DPoP headers. The Durable Object consumes it before OAuth only to remove the already-active matching pending call and send `cancel_call` when work has been dispatched; caller-supplied internal headers are stripped. Modern streams are never resumed through GET or `Last-Event-ID`. Local Wrangler does not propagate a raw TCP close into the Worker cancellation callbacks reliably, so deterministic proxy tests enforce this control path and live candidate verification must exercise it on the deployed edge.
71
71
 
72
- Legacy MCP `2025-11-25` retains the older delivery contract for existing hosts. Name, account-visible tool membership, and raw arguments are validated before any resumable record is allocated; malformed or role-hidden calls return `-32602` with no daemon dispatch. For a valid call, the outer Worker emits sequence-zero and sequence-one event IDs while `BridgeRoom` persists bounded session-bound stream/call ownership before daemon dispatch. A compatible legacy host may recover with authenticated `GET /mcp`, its original `Mcp-Session-Id`, and `Last-Event-ID`; it must not repeat the POST. Legacy records are token/session-bound, retained for at most two minutes, limited to 64 streams, and persist at most 1.5 MiB of terminal JSON. Errors `-32002`, `-32003`, and `-32005` in this area are legacy recovery diagnostics, not modern protocol errors. Caller-supplied internal stream headers are removed at the public boundary in both eras.
72
+ Legacy MCP `2025-11-25` retains the older delivery contract for existing hosts. Name, account-visible tool membership, and raw arguments are validated before any resumable record is allocated; malformed or role-hidden calls return `-32602` with no daemon dispatch. For a valid call, the outer Worker emits sequence-zero and sequence-one event IDs while `BridgeRoom` persists bounded session-bound stream/call ownership before daemon dispatch. A compatible legacy host should recover with authenticated `GET /mcp`, its original `Mcp-Session-Id`, and `Last-Event-ID`. If transport loss makes the original POST preparation or terminal response uncertain, an exact signed-session retry is safe throughout the stream's bounded recovery lifetime: the request identity and canonical argument fingerprint reattach it to the active or terminal stream, while changed arguments are rejected. Intentional new work must use a fresh typed request ID until that record expires or the client explicitly acknowledges sequence one, which deletes the replay record. Sessionless legacy POSTs remain independent for compatibility with clients that share one bearer token; without a signed session they do not receive POST idempotency, the outer Worker does not retry an ambiguous prepare, and the client must not blindly repeat an ambiguous side-effecting request. Legacy records are token/session-bound, retained for at most two minutes, limited to 64 streams, and persist at most 1.5 MiB of terminal JSON. Errors `-32002`, `-32003`, and `-32005` in this area are legacy recovery diagnostics, not modern protocol errors. Caller-supplied internal stream headers are removed at the public boundary in both eras.
73
73
 
74
- The daemon-to-Worker terminal protocol is at-least-once until `tool_result_ack`. Queueing a WebSocket frame is not durable delivery: the runtime retains a bounded terminal envelope, replays it after same-daemon reconnect or heartbeat, and removes it only after acknowledgement or the authoritative `resume_calls` reconciliation excludes it. The modern public stream has no replay surface; the legacy terminal store is generation-checked and exactly-once from the client's recovery perspective. `server_info.worker.observability.calls.unmatched_results` counts late results whose pending owner was already removed. A small increase may accompany cancellation or timeout races; sustained growth together with old pending calls indicates mixed versions or a lifecycle defect. The counter contains no arguments or result data.
74
+ The daemon-to-Worker terminal protocol is at-least-once until `tool_result_ack`. Queueing a WebSocket frame is not durable delivery: the runtime retains a bounded terminal envelope, replays it after same-daemon reconnect or heartbeat, and removes it only after acknowledgement or the authoritative `resume_calls` reconciliation excludes it. The modern public stream has no replay surface; the legacy terminal store is generation-checked and exactly-once from the client's recovery perspective. `server_info.worker.observability.terminal_results` separates the actual disposition of daemon result envelopes: `transient_committed` and `durable_committed` reached their owners; `owner_missing_acknowledged` arrived after the owner had already settled or been removed and was safely acknowledged to stop at-least-once replay; `stale_connection_rejected` came from a connection that no longer owned the durable call and was not acknowledged. The older `calls.unmatched_results` field remains a compatibility aggregate of the last two counters and must not be interpreted alone. Growth only in `owner_missing_acknowledged` usually indicates acknowledgement loss, cancellation, timeout, or deployment/reconnect overlap; growth in `stale_connection_rejected`, especially with old pending calls or protocol errors, indicates a connection-identity or lifecycle defect. These counters contain no arguments or result data.
75
75
 
76
76
  ### MCP host or connector internal-storage errors
77
77
 
@@ -85,7 +85,7 @@ A reconnect warning proves a transport interruption, not a daemon crash. Compare
85
85
 
86
86
  Brief retryable outages reconnect automatically. A persistent outage emits bounded summaries; identity/version mismatch, authentication rejection, and unexpected protocol messages remain permanent failures requiring version convergence or credential repair. Compare outage intervals with sleep/wake records and `diagnose_runtime.runtime.relay.heartbeat` before classifying them as active network faults; local stdio `server_info.runtime.relay.heartbeat` exposes the same state. A nonzero `event_loop_stall_count` with a large `max_event_loop_lag_ms` means the local daemon was not scheduled promptly; during recovery grace it sends a new heartbeat and deliberately postpones disconnect. That is distinct from a relay that remains silent after local scheduling has recovered. Use `--verbose` only when close codes, heartbeat deadlines, and retry delays are required.
87
87
 
88
- A foreground MCP tool is not a durable job. Hosted clients can impose a request ceiling below the local/stdio schema, so the remote catalog accepts at most 85 seconds and reserves terminal-delivery margin. Longer work belongs in `start_process` plus bounded `read_process`, or in a managed job. Keep mutation and verification in independently terminal calls when a host exposes only a foreground shell tool.
88
+ A foreground MCP tool is not a durable job. Every advertised MCP surface accepts at most 60 seconds of daemon execution. The Worker records a settlement deadline five seconds later than the daemon execution duration for result acceptance, persistence, acknowledgement, and terminal settlement. Admission and transport latency may consume part of that interval, and it is not a guarantee that an external host will consume the final frame. Relay execution applies the same 30- or 60-second default when the field is omitted, and a registered-command manifest cannot extend a relay call past 60 seconds. An owner-local registered command may retain a longer explicit manifest timeout because it does not depend on a hosted response stream. Longer remote work belongs in `start_process` plus bounded `read_process`, or in a managed job. Keep mutation and verification in independently terminal calls when a host exposes only a foreground shell tool.
89
89
 
90
90
  The daemon honors `HTTPS_PROXY`/`HTTP_PROXY` and `NO_PROXY` through standard environment-proxy resolution for remote Worker health and relay traffic. `wss:` targets use HTTPS proxy selection and `ws:` targets use HTTP proxy selection. Only HTTP and HTTPS proxy URLs are accepted. Invalid URLs or unsupported protocols fail startup with corrective guidance instead of entering the reconnect loop. `diagnose_runtime.runtime.relay.network_route` reports remotely, while local stdio `server_info.runtime.relay.network_route` reports `system-network-stack`, `application-http-proxy`, or `invalid-application-proxy-configuration`. This field describes only Machine Bridge application-level proxy selection: an operating-system VPN/TUN may still intercept `system-network-stack` traffic. `network_route_scope`, outage timestamps/durations, close category/code, transport error class, and next retry timing make that distinction explicit; proxy endpoints and credentials are never returned or logged. The browser-broker CLI health probe is a separate loopback-only path: it accepts only canonical `127.0.0.1`, uses direct Node HTTP with no proxy agent, and does not depend on `NO_PROXY`.
91
91
 
@@ -199,7 +199,7 @@ Uninstall acquires a state-root `maintenance.lock` that blocks new profile/state
199
199
 
200
200
  ### Lifecycle and pending-call diagnosis
201
201
 
202
- Remote `diagnose_runtime.runtime.lifecycle` reports `ready`, `starting`, `running`, `failed`, `stopping`, or `stopped`; `diagnose_runtime.observability.in_flight_calls` reports ordinary versus reserved local capacity; and `diagnose_runtime.runtime.processes` distinguishes active calls, draining calls whose protocol result already settled, currently terminating processes, and pending escalation checks. It also returns `runtime.execution_guardrails` and `runtime.security_audit`. Local stdio `server_info` exposes the equivalent fields under `server_info.runtime`, `server_info.observability`, and `server_info.security_audit`. A returned timeout therefore does not claim that all kernel or descendant work has already stopped. Worker `server_info.worker.pending_calls` reports the internal-call index, legacy request-key index, detached-call count, ordinary/control capacity, and current ordinary/control occupancy across transient and durable calls. Modern HTTP stream closure should remove its transient stream owner and pending daemon call; there is no modern replay record or request-key entry. Legacy terminal result, explicit cancellation, timeout, or reconnect-grace expiry must return active/detached/request-key counts to zero. During a brief daemon interruption, legacy `active` and `request_keys` may remain nonzero while `detached` identifies the recoverable subset; after same-instance readiness, `detached` returns to zero without losing those requests. Nonzero legacy request-key counts after active calls reach zero indicate a lifecycle defect rather than normal load. `worker.observability.calls.unmatched_results` is the bounded counter for late results that no longer have a receiver.
202
+ Remote `diagnose_runtime.runtime.lifecycle` reports `ready`, `starting`, `running`, `failed`, `stopping`, or `stopped`; `diagnose_runtime.observability.in_flight_calls` reports ordinary versus reserved local capacity; and `diagnose_runtime.runtime.processes` distinguishes active calls, draining calls whose protocol result already settled, currently terminating processes, and pending escalation checks. It also returns `runtime.execution_guardrails` and `runtime.security_audit`. Local stdio `server_info` exposes the equivalent fields under `server_info.runtime`, `server_info.observability`, and `server_info.security_audit`. A returned timeout therefore does not claim that all kernel or descendant work has already stopped. Worker `server_info.worker.pending_calls` reports the internal-call index, legacy request-key index, detached-call count, ordinary/control capacity, and current ordinary/control occupancy across transient and durable calls. Modern HTTP stream closure should remove its transient stream owner and pending daemon call; there is no modern replay record or request-key entry. Legacy terminal result, explicit cancellation, timeout, or reconnect-grace expiry must return active/detached/pending-call request-key counts to zero; the stream-level idempotency identity remains only for bounded replay retention. During a brief daemon interruption, legacy `active` and `request_keys` may remain nonzero while `detached` identifies the recoverable subset; after same-instance readiness, `detached` returns to zero without losing those requests. Nonzero legacy request-key counts after active calls reach zero indicate a lifecycle defect rather than normal load. Diagnose late results through `worker.observability.terminal_results`: `owner_missing_acknowledged` is a safely terminated replay or race, while `stale_connection_rejected` is an ownership mismatch. `worker.observability.calls.unmatched_results` is retained only as their compatibility aggregate.
203
203
 
204
204
  Stable errors include `policy_denied`, `invalid_request`, `timeout`, `cancelled`, `network_error`, `unavailable`, `limit_exceeded`, and `integrity_error`, with retryability metadata. Diagnose by code first; free-form messages are guidance, not an API contract.
205
205
 
@@ -306,7 +306,7 @@ Defense-in-depth limits include:
306
306
  - process stdin write: 64 KiB per call;
307
307
  - local simultaneous tool calls: 16 total, with 14 ordinary slots and two reserved for bounded control-plane diagnosis/recovery;
308
308
  - Worker pending daemon calls: 32 total, with 30 ordinary slots and two reserved for bounded control-plane diagnosis/recovery;
309
- - local/stdio command timeout schema: 1–600 seconds; the remote Worker schema is 1–85 seconds with tool-specific 30- or 60-second defaults, reserves five seconds for terminal delivery, and rejects larger values before dispatch;
309
+ - synchronous foreground timeout schema on every MCP surface: 1–60 seconds with tool-specific 30- or 60-second defaults; the daemon execution deadline is capped at that value, while the Worker uses a separate deadline five seconds later for terminal settlement; the relay execution boundary reapplies the execution default/ceiling before process spawn, including registered commands whose local manifest is longer; use process sessions or managed jobs for longer remote work;
310
310
  - process-session read wait: at most 30 seconds, measured with monotonic elapsed time;
311
311
  - direct directory result: 10,000 entries and 4 MiB of path metadata;
312
312
  - recursive walk: 200,000 visited entries;
package/docs/RELEASING.md CHANGED
@@ -165,7 +165,7 @@ From the exact accepted source checkout, the owner runs:
165
165
  npm run prerelease:install -- --allow-worker-deploy
166
166
  ```
167
167
 
168
- This command verifies that the npm registry tarball SHA-1/SHA-512 and dist-tag match the locally accepted candidate, installs that exact published version globally, updates the Worker and login daemon, verifies both versions, and writes an owner-only `npm-prerelease` activation record. The formal soak clock starts from this activation record, not from a local unpublished candidate.
168
+ This command verifies that the npm registry tarball SHA-1/SHA-512 and dist-tag match the locally accepted candidate, installs that exact published version globally, updates the Worker and login daemon, verifies both versions, and writes an owner-only `npm-prerelease` activation record. Schema 2 names any retained fallback explicitly as `global_package_rollback_baseline`: it identifies the globally installed npm package and entrypoint available for operator-directed disaster recovery, not the service runtime that was active immediately before activation. The activation transaction captures and verifies that previous service identity separately while the handoff is in progress. Schema 1 records using the legacy `previous` field remain readable and are normalized in memory without rewriting historical evidence. The formal soak clock starts from this activation record, not from a local unpublished candidate.
169
169
 
170
170
  Use the prerelease normally. Exercise the changed areas under real workloads. A crash, authorization anomaly, data-loss risk, repeated relay failure, incorrect service lifecycle, significant compatibility regression, or security/privacy defect is blocking.
171
171
 
package/docs/TESTING.md CHANGED
@@ -79,10 +79,10 @@ The suite includes:
79
79
  - no filename-based sensitive-file denial under unrestricted policy;
80
80
  - shared local/Worker free-form log redaction, sensitive content under non-sensitive Worker keys, immutable local/Worker structured metadata, control-character handling, message/field bounds, suppression of both successful and failed per-tool events outside debug, service warning-level configuration, JSON-mode parity across event and direct logger methods with timestamp/stream/redaction assertions, current-schema reset, and bounded tail trimming;
81
81
  - deterministic relay connection lifecycle coverage for transport construction/error/deadline, failed `hello` delivery, pre-handshake `welcome` validation, separate `hello_ack` authentication and `ready_ack` end-to-end readiness, session-bound probe return and probe-delivery races, pre-ready tool rejection, premature-ready rejection, identity/version mismatch, retryable Worker hello/readiness/transport/liveness errors, retryable close-only transport/liveness delivery, fatal unknown protocol errors, autonomous outage-reminder backoff, handshake/readiness/heartbeat timeout, brief-outage suppression, sustained-outage escalation, recovery summaries, and supersession;
82
- - shared no-follow bounded-file reads for normal files, over-limit data, directories, and symbolic links;
82
+ - shared no-follow bounded-file reads for normal files, over-limit data, directories, symbolic links, and multiple-hard-link denial; typed file-mutation regressions cover create-only collisions, stale SHA-256 preconditions, missing/ambiguous edit text, malformed/stale patches, transactional rollback, Worker preservation, stdio projection, and path/content/hash non-disclosure;
83
83
  - owner-only directory enforcement rejecting final symlinks, failing closed on POSIX chmod errors, verifying `0700`, and retaining Windows portability; Worker temporary-secret lifecycle coverage for process-start-bound names, valid stale-owner reclamation, ambiguous-owner retention, `0600` mode, deletion failures, and simultaneous deployment/cleanup failures;
84
84
  - SARIF security-gate behavior for unknown findings, exact accepted rule/path matches, path mismatch rejection, rationale quality, and exception expiry;
85
- - deterministic property tests over hostile browser-protocol byte strings, canonical/custom policy combinations, argv bounds/NULs, and a real direct process proving shell metacharacters remain literal argv; process-tree tests also assert Darwin uses a target-PGID `ps` query, preserve the global inspection budget, and repeatedly prove anti-`SIGTERM` descendants exit after foreground timeout;
85
+ - deterministic property tests over hostile browser-protocol byte strings, canonical/custom policy combinations, argv bounds/NULs, and a real direct process proving shell metacharacters remain literal argv; direct timeout-alignment tests prove relay shell/direct-process defaults are 60 seconds, relay registered commands are capped at 60 seconds even when their owner manifest is longer, daemon execution and Worker settlement deadlines remain distinct, and owner-local registered commands retain the manifest budget; process-tree tests also assert Darwin uses a target-PGID `ps` query, preserve the global inspection budget, and repeatedly prove anti-`SIGTERM` descendants exit after foreground timeout;
86
86
  - prototype-shaped command, action, role, profile, form-field, keyboard, and resource names proving that inherited object properties are never interpreted as dispatch or authority; current-schema malformed OAuth roles are repaired to disabled reviewer accounts with credential revocation;
87
87
  - canonical Worker deployment URL extraction proving unrelated `/mcp`, `/healthz`, path-bearing, and wrong-name URLs cannot be persisted as upload evidence;
88
88
  - byte-exact UTF-8 DOM-source truncation across emoji and Chinese partial-code-point boundaries, including equality between the reported byte count and the encoded returned source;
@@ -93,7 +93,7 @@ The suite includes:
93
93
  - P-256 root generation, root-certified ephemeral session issuance, macOS trust-broker build/signature checks, signed WebSocket preflight, one-time transactional nonce consumption, challenge transcript binding, wrong-root/session/tamper/expiry/replay rejection, and prevention of unauthenticated candidate churn;
94
94
  - request-scoped effective authority and catalog-wide risk review; non-escalatable reviewer/editor/operator ceilings; authenticated-owner direct execution; control-plane root denial; external and sensitive path composition; persistence-target rejection; symbolic-link ancestor and patch-move canonicalization; owner-only browser/application/data-export and persistent-plan effects; account/client/refresh-family ownership of processes, output sessions, and jobs; delegated sandbox fail-closed behavior; legacy-lease non-consumption; and malformed-record rejection;
95
95
  - root-certified ephemeral P-256 account-administration requests with origin/method/path/body/key/time/nonce binding, transactional one-time nonce consumption, removal of the long-lived administration secret, certificate/signature/body tamper rejection, nonce replay rejection, malformed nonce-state fail-closed behavior, one-megabyte response bounds, immediate oversized-response cancellation, and strict successful JSON-object validation;
96
- - live local Worker OAuth registration and authorization metadata; PKCE, DCR, refresh rotation/replay, account/client/family revocation, DPoP, actual `/mcp` Origin checks, bounded CORS/CSP, exact callback handling, and bounded OAuth persistence; modern MCP `2026-07-28` per-request `_meta`, open-JSON structural budgets, bounded resource subscriptions, strict dual-media `Accept` quality values, mirrored header/body validation, `server/discover`, result identity, cache hints, same-token/same-request-ID concurrency, role-hidden/unknown/schema `-32602` non-dispatch, credential-free private cancellation (including public-header forgery and DPoP replay controls), request-scoped streaming, filtered `subscriptions/listen`, removed-method 404 behavior, and no session/replay leakage; plus the complete legacy MCP `2025-11-25` initialize, pre-persistence raw-argument validation, signed-session cancellation, sequence event, recovery GET, `Last-Event-ID`, duplicate-domain, and replay-isolation suite. The same integration covers shared Worker/local timeout ceilings, daemon candidate/probing/ready replacement, malformed daemon messages, rich content, account-role projection, and stable catalog behavior before/during/after daemon availability.
96
+ - live local Worker OAuth registration and authorization metadata; PKCE, DCR, refresh rotation/replay, account/client/family revocation, DPoP, actual `/mcp` Origin checks, bounded CORS/CSP, exact callback handling, and bounded OAuth persistence; modern MCP `2026-07-28` per-request `_meta`, open-JSON structural budgets, bounded resource subscriptions, strict dual-media `Accept` quality values, mirrored header/body validation, `server/discover`, result identity, cache hints, same-token/same-request-ID concurrency, role-hidden/unknown/schema `-32602` non-dispatch, credential-free private cancellation (including public-header forgery and DPoP replay controls), request-scoped streaming, filtered `subscriptions/listen`, removed-method 404 behavior, and no session/replay leakage; plus the complete legacy MCP `2025-11-25` initialize, pre-persistence raw-argument validation, signed-session cancellation, sequence event, recovery GET, `Last-Event-ID`, bounded idempotent-retry/conflict domain, and replay-isolation suite. The same integration covers the shared 60-second foreground timeout ceiling and matching local relay execution defaults, signed-session cloned prepare retry, DPoP proof/retry-ID atomic binding and replay isolation, sessionless no-retry safety, and active-or-terminal stream reattachment, canonical argument fingerprints, concurrent legacy subscriber multicast/limits/cancellation cleanup, layered global/subject rate-limit identity, daemon candidate/probing/ready replacement, malformed daemon messages, rich content, account-role projection, and stable catalog behavior before/during/after daemon availability.
97
97
  - local runtime proof that one blocked tool handler does not serialize an independent handler, plus relay fault injection proving an undeliverable terminal result interrupts the ambiguous socket and enters reconnect backoff.
98
98
  - a real headless-Chrome OAuth navigation regression with bounded browser startup, DevTools discovery, WebSocket connection, and per-command deadlines, covering four cases: `form-action 'self'` blocks the first cross-origin callback, allowing only the registered callback blocks the regional redirect, allowing the registered and regional callbacks blocks the final Copilot Studio redirect, and the complete policy preserves `code` and `state` through all three cross-origin hops. Linux CI fails if Chrome is unavailable; other environments skip only this browser executable check while retaining the Worker CSP assertions.
99
99
 
@@ -180,7 +180,7 @@ The stdio integration test also sends an oversized line, verifies bounded reject
180
180
 
181
181
  `npm run mcp-resumption:test` directly exercises stream cursor parsing, OAuth-token/MCP-session isolation, immediate pending/terminal polls, active and completed replay, orphaned-stream restart ambiguity, persisted-call restart recovery, strict call-record validation, request-key uniqueness, operation/reconnect deadlines, repeated detach/rebind retention extension, stale-generation rejection, prototype-safe aggregation, exactly-once completion, result-size fallback, SHA-256 tamper detection, transient persistence failure, expiry, capacity, completed-record eviction, the four-row plain-stream budget, and the fixed six-row durable-call lifecycle budget.
182
182
 
183
- `npm run worker-runtime-infrastructure:test` verifies both delivery eras. Modern coverage proves private prepare/subscribe/cancel control headers are stripped at the public edge, transient ownership is memory-only, cancellation releases it exactly once, no event ID or replay record is created, and already-attached internal settlement cannot make a cancelled stream reusable. Legacy coverage retains descriptor/subscriber adaptation, sequence-zero/sequence-one framing, hibernatable subscription replacement, durable ownership/settlement, timeout/reconnect alarms, two-minute/64-stream/1.5-MiB bounds, stale-generation rejection, result acknowledgement/replay, and same-instance handover. Shared checks cover stateful burst limiting, gateway failures, daemon call deadlines, socket isolation, output/log maintenance, and no request-key leaks.
183
+ `npm run worker-runtime-infrastructure:test` verifies both delivery eras. Modern coverage proves private prepare/subscribe/cancel control headers are stripped at the public edge, transient ownership is memory-only, cancellation releases it exactly once, no event ID or replay record is created, and already-attached internal settlement cannot make a cancelled stream reusable. Legacy coverage retains descriptor/subscriber adaptation, sequence-zero/sequence-one framing, hibernatable subscription replacement, durable ownership/settlement, timeout/reconnect alarms, two-minute/64-stream/1.5-MiB bounds, stale-generation rejection, result acknowledgement/replay, and same-instance handover. Shared checks cover stateful burst limiting, gateway failures, separate daemon-execution/Worker-settlement deadlines, storage-backed versus live-subscriber terminal paths, socket isolation, output/log maintenance, and no request-key leaks.
184
184
 
185
185
  `npm run worker:integration-test` exercises the real Wrangler/OAuth/daemon path. It runs ordinary modern and legacy regression cases by default. When `MBM_OFFICIAL_CONFORMANCE_CHECKOUT` and `MBM_OFFICIAL_CONFORMANCE_SCENARIOS` are set, it also drives the pinned official MCP conformance checkout through a test-only loopback proxy that injects the already-created short-lived test bearer token. The production OAuth endpoint is unchanged, the alpha conformance package is not added to the dependency graph, and `tests/mcp-conformance-baseline.yml` contains only check-scoped exclusions for capabilities the production server intentionally does not advertise. A new unrelated failure or a stale expected-failure entry fails the run. The checkout must be a real directory with a committed lockfile and installed dependencies; missing or cleaned checkouts fail before Worker startup rather than surfacing as an ambiguous spawn error. Treat the alpha runner as an external audit tool: record its exact commit, inspect its own `npm audit` result, run it only against the loopback proxy, and remove the checkout afterward.
186
186
 
@@ -171,7 +171,7 @@ Use a narrower profile, separate OS account, container, or VM when prompts, repo
171
171
 
172
172
  ### Public Worker endpoint and quota guards
173
173
 
174
- The default public endpoint remains the automatically provisioned `workers.dev` origin so ordinary users need no DNS zone or custom domain. The in-Worker Rate Limiting binding is deliberately a Durable Object burst guard, not an authentication boundary or an exact global quota accountant. It runs after a Worker invocation begins, is scoped by Cloudflare location, and currently uses one deployment-wide stateful bucket per location. A concentrated source can therefore cause a temporary localized denial for other clients sharing that location, while distributed traffic can still consume the account-wide Workers request allowance. Binding failure is fail-open to avoid turning a quota helper into an account outage. Operators who already control an external edge may add pre-Worker filtering independently, but the public package does not require or assume a private domain.
174
+ The default public endpoint remains the automatically provisioned `workers.dev` origin so ordinary users need no DNS zone or custom domain. The in-Worker Rate Limiting bindings are deliberately Durable Object burst guards, not authentication boundaries or exact global quota accountants. They run after a Worker invocation begins and are scoped by Cloudflare location. A high-capacity route/Worker bucket bounds aggregate stateful pressure, while a lower route/subject bucket isolates a presented credential or an anonymous network identity through an internal truncated SHA-256 key. Raw credentials and addresses are not logged or returned by diagnostics; the network-address hash is a bucketing mechanism, not cryptographic anonymization of low-entropy IP space. Random invalid credentials cannot bypass the aggregate bucket. Distributed traffic can still consume the account-wide Workers request allowance, and a sufficiently concentrated source can exhaust its own local subject bucket. Binding failure is fail-open to avoid turning a quota helper into an account outage. Operators who already control an external edge may add pre-Worker filtering independently, but the public package does not require or assume a private domain.
175
175
 
176
176
  ### Bearer clients
177
177
 
@@ -217,7 +217,7 @@ Code cannot create a second independent reviewer, npm OIDC trust relationship, p
217
217
 
218
218
  Regression suites cover:
219
219
 
220
- - account roles, trusted clients, account-version revocation, refresh-family rotation/replay, DPoP proofs, and non-escalatable effective authority;
220
+ - account roles, trusted clients, account-version revocation, refresh-family rotation/replay, DPoP proofs, and non-escalatable effective authority; Transparent legacy prepare retry does not weaken that replay boundary: a trusted outer Worker creates an unguessable internal retry ID, public copies of the internal header are stripped, and the Durable Object accepts the consumed proof again only for the same atomically stored ID, a live primary nonce, and a maximum of four uses. The identifier is scoped to one public request and is not returned to the client.
221
221
  - root-certified ephemeral sessions, preflight nonce replay, daemon challenge binding, readiness, reconnect, and candidate replacement;
222
222
  - signed account administration, client revocation, bounded strict-JSON administration responses, and removal of the long-lived administration secret;
223
223
  - control-plane path denial, path canonicalization, symlink handling, sensitive/persistence targets, and object ownership;