Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions docs/design/2026-09-22-managed-runtime-attestation-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[English](2026-09-22-managed-runtime-attestation-contract.md) | [简体中文](2026-09-22-managed-runtime-attestation-contract.zh-CN.md)

Status: contract foundation and attestation-only worker shell implemented; Java Broker wiring remains follow-up work. Updated: 2026-09-23.
Status: contract foundation and attestation-only worker shell implemented; Java Broker wiring remains follow-up work. Updated: 2026-09-24.

## Problem

Expand Down Expand Up @@ -32,7 +32,9 @@ This slice does not add the Hosted profile, Runtime provider, Java `RuntimeTrans

## Typed Route Manifest

`OWNED_MANAGED_RUNTIME_ROUTES` currently contains the one route implemented by this contract slice:
`OWNED_MANAGED_RUNTIME_ROUTES` declares the wire contracts owned by this
component. Its attestation entry is the only route currently implemented and
admitted:

```text
POST /internal/managed-runtime/v2/attest
Expand All @@ -42,9 +44,18 @@ responseBodyLimitBytes = 16384
cacheControl = no-store
```

The Express registrar reads its method, path, protocol version, and body limit from this entry. The raw HTTP gate compares the incoming method and unmodified request URL against the same entry. Query strings, trailing slashes, case variants, other methods, and unregistered paths therefore fail with 404 before Express.
The Express registrar reads its method, path, protocol version, and body limit
from this entry. The raw HTTP gate compares the incoming method and unmodified
request URL against this implemented route. Query strings, trailing slashes,
case variants, other methods, and non-admitted paths therefore fail with 404
before Express.

This manifest is intentionally not populated with preview-only health, v1 Tool, history, or v2 Tool routes. Each operation is added when its real handler is extracted, in the same change that registers it. This prevents a manifest entry from claiming that a route exists when `main` has no implementation.
The declaration manifest also contains the future v2 `execute`, `status`, and
`cancel` contracts so TypeScript and Java can share their wire definition.
Declaration does not imply admission: the raw gate rejects those routes until
their real handlers land. Each future handler and its gate admission must be
added in the same change. Preview-only health, v1 Tool, and history routes are
not declared.

## Attestation Request and Response

Expand All @@ -70,17 +81,17 @@ The language-neutral files live beside the TypeScript contract under `packages/c
- `managed-runtime-attestation-v2.schema.json` fixes the route metadata, closed request and response shapes, limits, and outcome classes.
- `managed-runtime-attestation-v2.fixtures.json` contains the canonical identity and cases for credential variants, every immutable identity mismatch, malformed and empty fields, exact error codes, unsupported media types, charsets and content encodings, oversized bodies, and exact-route rejection.

The TypeScript test materializes every case and sends it through `node:http` → the raw manifest gate → Express authentication and JSON parsing → the attestation handler. It checks status, classification, `no-store`, exact success body, and response size.
The TypeScript test materializes every case and sends it through `node:http` → the raw route gate → Express authentication and JSON parsing → the attestation handler. It checks status, classification, `no-store`, exact success body, and response size.

The Java attestation client reads these same files, sends the canonical request to a real HTTP endpoint, and classifies the response by status. It enforces the 16 KiB limit, the closed field set, and exact success-identity equality; 404 is not retryable. See the [Java client slice](2026-09-23-java-runtime-attestation-client.md). The client still does not implement acquire/execute, and it does not write the result into the Broker service.

## Attestation-only Worker Shell

The hidden `qwen managed-runtime-worker` command accepts exactly one JSON boot document on standard input. The closed document carries the v1 boot marker plus the immutable attestation identity, including the per-generation bearer token. Input is capped at 32 KiB, must close within 30 seconds, and fails startup on timeout or unknown fields. Keeping the token on standard input avoids exposing it in command arguments or a long-lived environment variable.

After validating the identity through the same attestation registrar, the process listens on an operating-system-assigned `127.0.0.1` port. The raw listener is wrapped by `ownedManagedRuntimeRouteGate`, so the only admitted operation is the manifest's exact attestation route. The process emits one closed v1 ready record containing its loopback URL and fencing identity, but never the token. `SIGINT` and `SIGTERM` close the listener before the process exits.
After validating the identity through the same attestation registrar, the process listens on an operating-system-assigned `127.0.0.1` port. The raw listener is wrapped by `ownedManagedRuntimeRouteGate`, so the only admitted operation is the exact attestation route. The process emits one closed v1 ready record containing its loopback URL and fencing identity, but never the token. `SIGINT` and `SIGTERM` close the listener before the process exits.

This shell is an executable ownership boundary for the next Java client and process provisioner. It does not load a model, Harness, tool manifest, Session, or workspace execution engine. Adding any Tool operation requires its real handler and route manifest entry in the same later change.
This shell is an executable ownership boundary for the next Java client and process provisioner. It does not load a model, Harness, tool manifest, Session, or workspace execution engine. Adding any Tool operation requires its real handler and raw-gate admission in the same later change.

## Security and Failure Semantics

Expand All @@ -98,7 +109,7 @@ The Hosted Runtime integration proceeds in this order:
1. this change starts the attestation-only process, wraps its listener with `ownedManagedRuntimeRouteGate`, and registers `registerManagedRuntimeAttestationRoute`;
2. make the Java attestation client emit and parse the shared fixture shape with a 16 KiB response cap;
3. reconcile physical identity before sending credentials, then commit the attestation result with the original database operation generation before opening the local ready gate;
4. extract each real owned Tool handler and add its route to the manifest in the same commit; and
4. extract each real owned Tool handler and admit its declared route through the raw gate in the same commit; and
5. add the Java Broker plus TypeScript worker process E2E and make the cross-language gate required in CI.

## Validation
Expand All @@ -113,7 +124,7 @@ The focused TypeScript suite must pass all fixture cases through a real TCP list
- Bodies over 16 KiB receive 413, compressed bodies and unsupported JSON charsets or content encodings fail as JSON protocol errors, and every response has `Cache-Control: no-store`.
- Unknown fields, wrong protocol version, and malformed digests fail as protocol errors; lease and immutable identity differences fail as conflicts.
- TypeScript and Java consume the same fixture file and agree on all five classifications.
- The worker rejects malformed, oversized, or non-closed boot input; binds a loopback ephemeral port; emits a token-free ready record; exposes only the manifest route; and terminates cleanly.
- The worker rejects malformed, oversized, or non-closed boot input; binds a loopback ephemeral port; emits a token-free ready record; admits only the attestation route; and terminates cleanly.
- No Hosted profile, Runtime provider, Broker transport, public API, or ordinary daemon behavior is introduced.

## Follow-Up Boundary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[English](2026-09-22-managed-runtime-attestation-contract.md) | [简体中文](2026-09-22-managed-runtime-attestation-contract.zh-CN.md)

状态:契约基础和仅提供身份证明的 worker 外壳已实现;Java Broker 接线仍是后续工作。更新日期:2026-09-23。
状态:契约基础和仅提供身份证明的 worker 外壳已实现;Java Broker 接线仍是后续工作。更新日期:2026-09-24。

## 问题

Expand Down Expand Up @@ -32,7 +32,7 @@ TypeScript worker 和未来 Java transport 还需要一份可共同评审的线

## Typed Route Manifest

`OWNED_MANAGED_RUNTIME_ROUTES` 当前只包含本契约切片实际实现的一条路由:
`OWNED_MANAGED_RUNTIME_ROUTES` 声明该组件持有的线路契约。其中 attestation 条目是当前唯一已经实现并被放行的路由:

```text
POST /internal/managed-runtime/v2/attest
Expand All @@ -42,9 +42,9 @@ responseBodyLimitBytes = 16384
cacheControl = no-store
```

Express registrar 从该条目读取 method、path、协议版本和 body 限制。raw HTTP gate 使用同一条目对传入 method 与未经修改的 request URL 进行比较。因此,query string、尾随斜杠、大小写变体、其他 method 和未登记 path 都会在进入 Express 前以 404 失败。
Express registrar 从该条目读取 method、path、协议版本和 body 限制。raw HTTP gate 使用这条已实现路由对传入 method 与未经修改的 request URL 进行比较。因此,query string、尾随斜杠、大小写变体、其他 method 和未放行 path 都会在进入 Express 前以 404 失败。

manifest 刻意不预先加入仅存在于预览分支的 health、v1 Tool、history 或 v2 Tool routes。每个操作都在提取真实 handler 的同一变更中加入。这样可以避免 manifest 声称某条路由存在,而 `main` 实际没有实现。
声明 manifest 还包含未来 v2 `execute`、`status`、`cancel` 的契约,使 TypeScript 与 Java 能共享线路定义。声明不代表放行:在真实 handler 落地之前,raw gate 会拒绝这些路由。未来每个 handler 与对应的 gate admission 必须在同一变更中加入。仅存在于预览分支的 health、v1 Tool 与 history routes 不会被声明。

## Attestation 请求与响应

Expand All @@ -70,17 +70,17 @@ handler 永不返回 bearer token。token 通过等长 `timingSafeEqual` 比较
- `managed-runtime-attestation-v2.schema.json` 固定 route metadata、闭合请求与响应形状、大小限制和结果分类。
- `managed-runtime-attestation-v2.fixtures.json` 包含规范 identity,以及凭据变体、每个不可变身份不一致、非法或空字段、精确错误码、不支持的媒体类型、charset/content encoding、超大 body 与精确路由拒绝等用例。

TypeScript 测试物化每个用例,并通过 `node:http` → raw manifest gate → Express 鉴权与 JSON 解析 → attestation handler 的完整路径发送请求。测试校验 status、分类、`no-store`、精确成功 body 和响应大小。
TypeScript 测试物化每个用例,并通过 `node:http` → raw route gate → Express 鉴权与 JSON 解析 → attestation handler 的完整路径发送请求。测试校验 status、分类、`no-store`、精确成功 body 和响应大小。

Java attestation client 读取同一批文件,向真实 HTTP endpoint 发送规范请求,并按 status 解析响应。它执行 16 KiB 上限、闭合字段和成功身份全等;404 不可重试。详见[Java client 切片](2026-09-23-java-runtime-attestation-client.zh-CN.md)。该客户端仍不实现 acquire/execute,也不把结果写入 Broker service。

## 仅提供身份证明的 Worker 外壳

隐藏命令 `qwen managed-runtime-worker` 从标准输入接收且只接收一份 JSON boot 文档。这个闭合文档包含 v1 boot 标记和不可变 attestation identity,其中包括每个 generation 独立的 bearer token。输入上限为 32 KiB,且必须在 30 秒内关闭;超时或出现未知字段都会让启动失败。通过标准输入传入 token,可避免它出现在命令参数或长期环境变量中。

进程使用同一个 attestation registrar 校验 identity 后,在操作系统分配的 `127.0.0.1` 端口监听。raw listener 由 `ownedManagedRuntimeRouteGate` 包装,因此唯一放行的操作是 manifest 中精确的 attestation route。进程输出一份闭合的 v1 ready record,其中包含 loopback URL 和 fencing identity,但永不包含 token。收到 `SIGINT` 或 `SIGTERM` 时,进程先关闭 listener 再退出。
进程使用同一个 attestation registrar 校验 identity 后,在操作系统分配的 `127.0.0.1` 端口监听。raw listener 由 `ownedManagedRuntimeRouteGate` 包装,因此唯一放行的操作是精确的 attestation route。进程输出一份闭合的 v1 ready record,其中包含 loopback URL 和 fencing identity,但永不包含 token。收到 `SIGINT` 或 `SIGTERM` 时,进程先关闭 listener 再退出。

这个外壳为下一步 Java client 和 process provisioner 提供可执行的 ownership boundary。它不加载 model、Harness、tool manifest、Session 或 workspace execution engine。后续增加任何 Tool 操作时,必须在同一个变更中加入真实 handler 和 route manifest 条目。
这个外壳为下一步 Java client 和 process provisioner 提供可执行的 ownership boundary。它不加载 model、Harness、tool manifest、Session 或 workspace execution engine。后续增加任何 Tool 操作时,必须在同一个变更中加入真实 handler 和 raw gate admission。

## 安全与失败语义

Expand All @@ -98,7 +98,7 @@ Hosted Runtime 按以下顺序集成:
1. 本变更启动仅提供身份证明的进程,使用 `ownedManagedRuntimeRouteGate` 包装 listener,并注册 `registerManagedRuntimeAttestationRoute`;
2. 让 Java attestation client 按共享 fixture 发送和解析数据,并施加 16 KiB 响应上限;
3. 发送凭据前先 reconcile 物理身份,然后使用原数据库 operation generation 提交 attestation 结果,最后才能打开本地 ready gate;
4. 提取每个真实 owned Tool handler,并在同一提交中把它的 route 加入 manifest;
4. 提取每个真实 owned Tool handler,并在同一提交中让其已声明 route 通过 raw gate;
5. 增加 Java Broker + TypeScript worker 进程 E2E,并把跨语言 gate 设为 required CI。

## 验证
Expand All @@ -113,7 +113,7 @@ Hosted Runtime 按以下顺序集成:
- 超过 16 KiB 的 body 返回 413;压缩 body 以及不支持的 JSON charset 或 content encoding 按 JSON 协议错误失败;所有响应都带 `Cache-Control: no-store`。
- 未知字段、错误协议版本和非法 digest 按协议错误失败;lease 和不可变 identity 差异按冲突失败。
- TypeScript 与 Java 消费同一个 fixture 文件,并对五种分类达成一致。
- worker 拒绝非法、超大或非闭合 boot input;绑定 loopback 随机端口;输出不含 token 的 ready record;只暴露 manifest route;并能干净终止。
- worker 拒绝非法、超大或非闭合 boot input;绑定 loopback 随机端口;输出不含 token 的 ready record;只放行 attestation route;并能干净终止。
- 不引入 Hosted profile、Runtime provider、Broker transport、公共 API 或普通 daemon 行为变化。

## 后续边界
Expand Down
Loading
Loading