Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,33 @@
|---|---|
| `managed-dependency-environment`、bundled npm、worker bridge | M1/M1.3 独立前置;不从旧 M2 分支重复携带 |
| Git candidate ref/commit、delta/path policy、orphan GC | M2.2 |
| T1 mutation profile/base freeze、owner-bound mutating admission | M2.3 |
| T1 mutation profile/base freeze、durable workspace reservation、accepted path truth | M2.3a |
| owner-bound mutating admission、reopen active-reservation gate | M2.3b |
| 真实 Write/Edit composition、Host crash/reopen | M2.4 |
| continuation boundary 绑定 workspace version | M3 |
| restore、rebaseline、publish、undo、replication | M4 |

## M2.3a 增量归属

| 文件 | 主要不变量 |
|---|---|
| `packages/core/src/runtime-event.ts` | T1-frozen managed mutation identity 与平台无关 path grammar |
| `packages/core/src/workspace-version-authority.ts` | successor exact changed paths 进入 immutable accepted truth |
| `packages/storage/src/sqlite-runtime-schema.ts` | schema 14 active reservation 与 changed-path projection |
| `packages/storage/src/sqlite-runtime-store.ts` | T1 reservation、generic T2 fence、successor consume、canonical rebuild |
| `packages/storage/src/workspace-version-authority-internal.ts` | 非 public active reservation reader capability |
| storage/core focused tests | schema、rollback、rebuild、真实 crash、双进程 exclusivity |
| `runtime-managed-workspace-mutation-reservation-v1.zh-CN.md` | owner、原子边界、失败状态与平台矩阵 |

M2.3a 不迁入 Runtime hook、ManagedWorkspaceOwner lease、candidate capture/discard 或真实 Write/Edit;前两项属于
M2.3b,后两项属于 M2.4。
## Commit 映射

| 当前重建内容 | 来源 | 说明 |
|---|---|---|
| core RED tests + causal successor facts | `14327f5f0` 的 core 最终状态 | 只保留 subpath contract |
| storage RED tests + atomic successor writer | `14327f5f0` 的 storage 最终状态 | 在 current-main schema 12 上新增 migration 13 |
| reservation RED tests + T1 owner projection | `36e1e3ec4` | 从 M2.2 stack 中只提取 M2.3a 自有差异,跳过旧 Git CLI candidate owner |
| 文档与 extraction ledger | 现行工程实践 | 记录最新 main、Gitoxide 换轨和 M2.2–M2.4 等待关系 |

## Diff 审核门槛
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

# Managed Workspace Mutation Reservation v1

- 阶段:M2.3a
- 状态:实现切片;保持 Draft,等待 M2.3b admission 与 M2.4 Write/Edit 生产消费者
- owner:SQLite workspace mutation authority

## 1. 主要不变量

同一个 `workspaceInstanceId` 从 managed mutation 的 T1 durable 起,到该 operation 被可信 successor
原子接受之前,只能存在一个 durable mutation owner。进程内 lease 只负责 capability 隔离,不再承担跨进程、
跨重启的排他真相。

T1 同时冻结 repository/workspace/epoch/instance identity、canonical base head、平台无关的 exact expected
paths、execution profile digest,以及 operation/dispatch identity。

任何 managed T1 都不得由通用 T2 writer 结算。成功只能通过 workspace successor authority 在同一个
SQLite transaction 中提交 `T2 + version_accepted + projection + head CAS`,并消费 reservation。

## 2. 权威与投影

唯一事实源仍是 immutable RuntimeEvents:

```text
function_call
+ toolDispatch.managedMutation
+ optional workspace version_accepted
```

`runtime_managed_mutation_reservations` 只是可重建投影。表以 `workspace_instance_id` 为主键,并对
`operation_id`、`dispatch_event_id` 建唯一约束。在线写入、canonical rebuild 和内部 reader 都先扫描
RuntimeEvents,再要求投影完全相等;删除或篡改投影不能改变事实。

## 3. 原子性边界

### 3.1 T1 reservation

一个 `BEGIN IMMEDIATE` transaction 内完成:

1. 重验 canonical workspace head;
2. 拒绝已有 active reservation;
3. 写 function call 与 dispatch RuntimeEvents;
4. 写 tool journal / operation projection;
5. 写 managed reservation projection;
6. COMMIT。

因此不存在“有 managed T1、没有 durable reservation”的正常可见状态。

### 3.2 successor acceptance

一个 transaction 内完成:

1. 读取 T1 与 reservation;
2. 比较 base、profile、operation、dispatch 与 exact changed paths;
3. 写成功 T2;
4. 写 immutable `workspace.version_accepted`;
5. 写 version projection;
6. CAS 推进 canonical head;
7. CAS 删除 reservation;
8. COMMIT。

失败、进程退出或 SQLite 异常使整组写入回滚。COMMIT 后响应丢失时,exact retry 返回原来的 immutable
successor,不重复推进 head。

## 4. 失败状态

| 状态 | 行为 |
|---|---|
| base/head 已变化 | T1 前拒绝,不创建 operation |
| 同 workspace 已有 reservation | T1 前拒绝,报告占用 operation |
| managed T1 走 generic T2 | 拒绝,operation 保持 prepared |
| successor paths 与 T1 不同 | 整个 successor transaction 回滚 |
| reservation 投影缺失或被篡改 | authority read/retry fail closed;允许从 RuntimeEvents rebuild |
| T1 后进程崩溃 | reservation 跨进程保留;新的 mutation 不能取得所有权 |
| operation park | reservation 保留,禁止另一个 mutation 越过未知副作用 |

`safely_discarded` 的 canonical release fact 不属于本切片;M2.4 在拥有真实 candidate 与 Write/Edit 结果后
定义。M2.3a 不提供手工删除 reservation 的公共 API。

## 5. 路径合同

Durable fact 使用平台无关的 Git path 语法:`/` 分隔、非绝对、无空段、无 `.`/`..`、无 NUL、反斜杠
或冒号;首段 `.git` 和 `node_modules` 一律按 ASCII case-insensitive 拒绝。路径集合必须排序、去重,
数量为 1–32。

这只是 canonical syntax。symlink、reparse point、volume case sensitivity 与真实路径 containment 仍由
M2.3b/M2.4 的平台 owner 在副作用前验证。Core 不读取 `process.platform`。

## 6. 平台能力矩阵

| 能力 | Linux | macOS | Windows |
|---|---|---|---|
| SQLite T1/accept transaction | 承诺 | 承诺 | 承诺 |
| 多进程同 workspace 唯一 reservation | 承诺 | 承诺 | 承诺 |
| process-crash 后 reservation 重建 | 承诺 | 承诺 | 承诺 |
| path fact 跨平台同值同义 | 承诺 | 承诺 | 承诺 |
| filesystem mutation/candidate correctness | M2.4 | M2.4 | M2.4 |

本切片不承诺断电后的 Git/filesystem 收敛,也不接 Desktop/CLI。

## 7. 验证

- strict Core decode:未知字段、非 canonical path、未排序 path set 均拒绝;
- T1 + reservation 原子持久化与 exact retry;
- generic T2 抢占被拒绝;
- changed paths 同时绑定 T1、successor fact、online writer 和 rebuild;
- projection 删除后 read/retry fail closed,rebuild 恢复;
- 真实子进程在 T1 COMMIT 后被杀,reopen 仍保留唯一 owner;
- 真实双进程同时提交不同 operation,恰好一个获得 reservation;
- successor transaction kill/reopen 继续沿用 M2.1 crash matrix。

## 8. 后续切片

### M2.3b — Runtime admission composition

在 T1 前取得 owner-bound capability,重验平台路径、execution profile 和 canonical head;启动时读取 active
reservation,禁止新 admission 越过 prepared operation。它不得 capture/discard Git candidate,也不得自行写
successor。

### M2.4 — Write/Edit production settlement

真实 Write/Edit 执行、candidate capture/verification、owner-controlled settlement 与 reservation terminal
transition 在此闭环。Runtime 必须能区分:successor 已接受、candidate 可安全 discard、effect unknown/park;
不能在 managed callback 后自动写 generic T2。
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ M2.2 的 Git candidate owner;M2.1 只建立其唯一持久化出口。
| stale writer | base head 任一字段不一致即拒绝,且对应 tool operation 保持 `prepared` |
| corruption | malformed fact、断链、重复 version identity、tool evidence 不匹配全部 fail closed |
| 运行时回滚 | transaction 未提交时 T2/fact/projection/head 全部回滚 |
| 数据升级 | schema 12 baseline rows 原样升级到 schema 13;schema 13 不支持向旧 binary 降级 |
| 数据升级 | schema 12 baseline rows 原样升级;M2.1 使用 schema 13,M2.3a reservation/path projection 顺延为 schema 14;不支持向旧 binary 降级 |

“唯一 writer”不是注释:普通 RuntimeEvent writer 仍拒绝 workspace fact;successor writer 仅能通过
`workspace-version-authority-internal.ts` 中与具体 store 实例绑定的 capability 调用。
Expand Down Expand Up @@ -191,17 +191,29 @@ SQLite transaction 提供三平台一致的数据库原子性;本切片不声

该 PR 在 M2.4 消费者存在前保持 Draft。

### M2.3 — Mutation execution admission
### M2.3a — Durable mutation reservation

主要不变量:managed T1 与 workspace-instance-exclusive reservation 原子持久化;直到可信 successor 接受前,
另一个进程或重启后的 owner 都不能为同一 workspace 创建第二个 mutation T1。

- owner:SQLite workspace mutation authority;
- 原子边界:call + dispatch + operation projection + active reservation;
- accepted truth:successor fact 携带 exact changed paths,online/rebuild 均与 T1 比较;
- generic T2 被存储权威拒绝;
- 详细合同见
[Managed Workspace Mutation Reservation v1](./runtime-managed-workspace-mutation-reservation-v1.zh-CN.md)。

### M2.3b — Mutation execution admission

主要不变量:T1 前冻结 base workspace head、execution profile、operation identity 和 candidate lease;T1 后禁止切换
attached/managed mode 或退回旧直接写路径。

- owner:Runtime Host managed mutation admission;
- 原子边界:T1 durable dispatch 选择 `managed_mutation_v1`;
- 原子边界:消费 M2.3a,在 T1 durable dispatch 前签发 owner-bound capability;
- 失败状态:能力缺失、scope 失效、base/head/profile 不一致均在工具副作用前拒绝;
- 回滚:T1 前失败走标准 tool error;T1 后不确定状态保持 unsettled,交给 M2.4 收敛。

该 PR 不新增第二套 workspace writer,只能消费 M2.1/M2.2 的 opaque capabilities。
该 PR 不新增第二套 workspace writer,不 capture/discard candidate,只消费 M2.1/M2.3a 的 internal capability。

### M2.4 — Write/Edit production composition

Expand All @@ -223,7 +235,8 @@ M2.4 不接 workspace-bound continuation;那属于 M3。
- stale successor 不结算对应 prepared operation;
- 真实 child process 在 successor transaction 内被杀后,reopen 证明 T2/fact/projection/head 全回滚;
- 真实 child process 在 COMMIT 后被杀,reopen exact retry 收敛到同一 successor;
- populated schema 12 → 13 数据升级;
- populated schema 12 → 14 数据升级;
- managed T1 reservation 的真实 kill/reopen 与双进程唯一性;
- canonical origin 被篡改后 reader fail closed;
- schema、SQLite multi-process 与既有 recovery 定向 suites 保持通过。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,19 +611,21 @@ M1.1 合同见
这一步取代旧的“先做通用 checkpoint contract,再接 observe-only Git carrier”。不得同时维护两套
managed workspace version writer。

M2 按 owner 与原子边界拆成四个 stacked slices:
M2 按 owner 与原子边界拆成五个 stacked slices:

1. **M2.1 mutation version persistence authority(当前切片)**:定义 successor fact/scanner,并在一个
SQLite transaction 中原子提交 T2、`version_accepted`、version projection 和 head CAS;schema 13
从 populated schema 12 保留 baseline/head;不接真实 Write/Edit;
2. **M2.2 Git mutation candidate owner**:唯一拥有 operation-bound candidate ref/commit、delta/path
policy、artifact receipt 与 orphan GC;不写 T2;
3. **M2.3 mutation execution admission**:T1 前冻结 base head、execution profile、operation identity 与
candidate lease;T1 后禁止 silent fallback;
4. **M2.4 Write/Edit production composition**:把 owner-bound worker、candidate capture 与 M2.1 bundle
2. **M2.2 Gitoxide mutation candidate owner(等待 Gitoxide 数据面)**:唯一拥有 operation-bound
candidate commit/ref、exact-base CAS 与 artifact receipt;不写 T2,不恢复旧 Git CLI adapter;
3. **M2.3a durable mutation reservation(当前重建切片)**:schema 14 将 T1 与 workspace-instance-exclusive reservation
原子绑定,successor fact 固化 exact changed paths,generic T2 无权结算 managed mutation;
4. **M2.3b mutation execution admission**:T1 前冻结 base head、execution profile、operation identity,
消费 durable reservation gate;T1 后禁止 silent fallback;
5. **M2.4 Write/Edit production composition**:把 owner-bound worker、candidate capture 与 M2.1 bundle
串成唯一生产路径,并用真实 Host kill/reopen crash test 完成前三片的生产消费者。

M2.2/M2.3 在 M2.4 消费者存在前保持 Draft。M2.4 不绑定 continuation boundary;该能力仍属于 M3。
M2.2/M2.3a/M2.3b 在 M2.4 消费者存在前保持 Draft。M2.4 不绑定 continuation boundary;该能力仍属于 M3。

### M3 — Workspace-bound continuation / resume

Expand Down Expand Up @@ -662,8 +664,9 @@ M0.1 Git artifact owner (merged)
└─> M1.3 explicit environment provisioning
└─> M2.1 mutation version persistence authority
└─> M2.2 Git mutation candidate owner
└─> M2.3 mutation execution admission
└─> M2.4 Write/Edit production composition
└─> M2.3a durable mutation reservation
└─> M2.3b mutation execution admission
└─> M2.4 Write/Edit production composition
└─> M3 workspace-bound continuation
└─> M4 restore / rebaseline / publish / replication

Expand Down
54 changes: 54 additions & 0 deletions packages/core/src/__tests__/runtime-event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,60 @@ describe('RuntimeEvent content variants', () => {
});

describe('RuntimeEvent actions', () => {
test('decodes only a platform-independent T1-frozen managed mutation identity', () => {
const managedMutation = {
protocol: 'managed_mutation_v1',
repositoryId: 'repository_11111111111111111111111111111111',
workspaceId: 'workspace_22222222222222222222222222222222',
workspaceEpochId: 'epoch_33333333333333333333333333333333',
workspaceInstanceId: 'instance_44444444444444444444444444444444',
objectFormat: 'sha1',
baseWorkspaceVersionId: 'version_55555555555555555555555555555555',
baseAcceptedEventId: 'baseline-event-1',
baseHeadRevision: 1,
baseCommitOid: '1'.repeat(40),
baseTreeOid: '2'.repeat(40),
expectedPaths: ['src/a.ts'],
executionProfileDigest: `sha256:${'a'.repeat(64)}`,
} as const;
const toolDispatch = {
protocol: 't1_after_preflight_v1',
operationId: 'operation-1',
providerToolCallId: 'call-1',
toolName: 'Write',
canonicalArgsHash: `sha256:${'b'.repeat(64)}`,
recoveryMode: 'reconcile',
managedMutation,
} as const;

assert.deepEqual(
decodeRuntimeEvent(baseEvent({ role: 'system', author: 'system', actions: { toolDispatch } }))
.actions?.toolDispatch?.managedMutation,
managedMutation,
);
for (const invalid of [
{ ...managedMutation, expectedPaths: ['src/../secrets.txt'] },
{ ...managedMutation, expectedPaths: ['NoDe_MoDuLeS/pkg/index.js'] },
{ ...managedMutation, expectedPaths: ['.GiT/config'] },
{ ...managedMutation, expectedPaths: ['z.txt', 'a.txt'] },
{ ...managedMutation, expectedPaths: ['x'.repeat(4097)] },
{ ...managedMutation, baseAcceptedEventId: 'event id with spaces' },
{ ...managedMutation, baseHeadRevision: 0 },
{ ...managedMutation, baseTreeOid: 'not-an-oid' },
{ ...managedMutation, extra: true },
]) {
assert.throws(() =>
decodeRuntimeEvent(
baseEvent({
role: 'system',
author: 'system',
actions: { toolDispatch: { ...toolDispatch, managedMutation: invalid } as never },
}),
),
);
}
});

test('permission and user-question interactions are first-class actions', () => {
const actions: RuntimeEventActions = {
permissionRequest: {
Expand Down
Loading