machine-bridge-mcp 3.0.0-beta.30 → 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.
- package/CHANGELOG.md +44 -0
- package/README.md +4 -2
- package/browser-extension/manifest.json +1 -1
- package/docs/ARCHITECTURE.md +4 -4
- package/docs/AUDIT.md +14 -0
- package/docs/CLIENTS.md +3 -1
- package/docs/LOGGING.md +1 -1
- package/docs/OPERATIONS.md +4 -4
- package/docs/RELEASING.md +1 -1
- package/docs/TESTING.md +4 -4
- package/docs/TOOL_REFERENCE.md +33 -33
- package/docs/UPGRADING.md +8 -0
- package/package.json +1 -1
- package/scripts/install-published-prerelease.mjs +3 -3
- package/scripts/prerelease-activation.mjs +33 -10
- package/scripts/start-release-candidate.mjs +4 -4
- package/src/local/patch.mjs +20 -18
- package/src/local/runtime-paths.mjs +2 -1
- package/src/local/runtime.mjs +3 -3
- package/src/local/workspace-file-service.mjs +45 -44
- package/src/shared/relay-contract.json +2 -2
- package/src/shared/server-metadata.json +2 -1
- package/src/shared/tool-catalog.json +33 -33
- package/src/worker/index.ts +18 -19
- package/src/worker/mcp-resumption-config.ts +3 -1
- package/src/worker/mcp-stream-channel.ts +15 -15
- package/src/worker/mcp-stream-dispatch.ts +10 -3
- package/src/worker/observability.ts +57 -5
- package/src/worker/tool-timeout.ts +16 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
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
|
+
|
|
3
47
|
## 3.0.0-beta.30 - 2026-08-02
|
|
4
48
|
|
|
5
49
|
### Resumable MCP delivery under transient interruption
|
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
|
|
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
|
|
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.
|
|
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
|
}
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -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;
|
|
@@ -193,7 +193,7 @@ 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
|
|
|
@@ -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 canonical MCP catalog advertises one foreground timeout contract of 1–
|
|
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,19 @@
|
|
|
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
|
+
|
|
3
17
|
## 2026-08-02 version 3.0.0-beta.30 interruption and recovery review
|
|
4
18
|
|
|
5
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.
|
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
|
-
|
|
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
|
@@ -67,7 +67,7 @@ Brief network interruptions are expected on laptop network changes, Worker deplo
|
|
|
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, opened/coexisting/limited delivery-subscriber counts, and
|
|
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
|
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -71,7 +71,7 @@ For modern MCP `2026-07-28`, every POST advertises both `application/json` and `
|
|
|
71
71
|
|
|
72
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.
|
|
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. Every advertised MCP surface accepts at most
|
|
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/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. `worker.observability.
|
|
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
|
-
- synchronous foreground timeout schema on every MCP surface: 1–
|
|
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
|
|
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; direct timeout-alignment tests prove relay shell/direct-process defaults are 60 seconds, relay registered commands are capped at
|
|
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`, bounded idempotent-retry/conflict domain, and replay-isolation suite. The same integration covers the shared
|
|
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
|
|
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
|
|