Skip to content
Draft
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
@@ -0,0 +1,58 @@
<!--
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.
-->

# Runtime managed mutation pure transform v1

## 1. 不变量

managed Write/Edit 不读写 live checkout。Runtime 使用自己的原始工具参数和 Host 提供的 immutable accepted-tree base content,计算唯一 result content 与 provider result。

该转换允许 recovery 在 T2 前根据完全相同的 durable input 重新计算;它不拥有 filesystem、network 或 process 副作用。跨进程安全性来自 deterministic input/output 与后续 at-most-one acceptance,而不是 invocation count。

```text
Runtime-owned args + T1 expectedPath + accepted base content
-> pure Write/Edit transform
-> immutable mutation result proof
```

Host 不能返回完整 `executionArgs`,也不能替换 `content`、`old_string` 或 `new_string`。它只能提供 accepted-tree base content;路径来自已经与 durable function call 严格匹配的 T1 `expectedPath`。

## 2. Owner

- Runtime:参数、transform、provider result、strict JSON snapshot;
- Host admission:accepted-tree base content 与 terminal proof;
- Gitoxide candidate owner:后续消费 mutation result proof;
- SQLite:后续决定 terminal/accepted truth。

## 3. 失败状态

- Write 参数无效;
- Edit 目标缺失;
- Edit 匹配缺失或不唯一;
- immutable base envelope 畸形。

前三类是“operation completed with no workspace effect”,由 Runtime 转成 error proof,后续 owner 在确认没有 candidate 后提交 `operation_failed_no_effect`。Host envelope 畸形在 T1 前拒绝。

## 4. 非目标

- 不发布 candidate receipt;
- 不推进 accepted head;
- 不物化 projection;
- 不接 Desktop/CLI;
- 不允许 filesystem worker 获得 managed worktree 写权限。
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!--
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.
-->

# Runtime managed mutation settlement proof v1

## 1. 主要不变量

在一次存活的 Runtime execution 内,managed Write/Edit 的 provider result 与 durable response 由 Runtime 从同一个 strict-JSON snapshot 构造,并且只构造一个 response event。Host 可以选择并提交 workspace terminal,但不能替换或重新解释 provider 结果。

本切片不承诺跨进程的 transform invocation exactly-once。T2 前进程退出后,后续 recovery owner 可以基于同一个 durable operation、accepted base 与冻结参数重新计算无外部副作用的 deterministic transform;安全属性是“最多接受一个精确 successor”,不是“纯函数只调用一次”。

```text
Runtime-owned strict JSON result
-> immutable RuntimeEvent outcome proof
-> Host-owned Git/SQLite terminal commit
-> Runtime exact adoption
```

## 2. Owner 与权限

- Runtime 拥有原始 tool args、pure transform、provider result 和 response envelope。
- Runtime 向 settlement owner 暴露只读 `RuntimeManagedMutationOperationProof`;其中的 `durableOutcome` 是冻结的精确事件。
- no-change 或明确业务失败时,Runtime 额外签发与 T1 identity 绑定的 `terminalOutcome`。
- Host 不能返回 execution args,也不能要求 Runtime 采用另一个 success result。
- Storage 只通过 owner-bound execution-stores capability 暴露 head/version/reservation 读取和 successor/terminal 原子写入;裸 SQLite writer 不进入 Host API。

## 3. 原子性边界

- T1:function call、dispatch 和 durable reservation 在一个 SQLite transaction 中提交。
- T2:tool response 与 successor/head,或 tool response 与 no-effect terminal/reservation release,在一个 SQLite transaction 中提交。
- Git candidate receipt 与 SQLite 不是一个事务;候选 ref/receipt 只能作为派生证明,不能自行推进 accepted head。

## 4. 失败状态与回滚

- T1 前失败:不产生 reservation,可直接返回拒绝。
- T1 后 proof 缺失、被修改或 owner 抛错:`unsettled`,禁止 generic T2 fallback。
- no-change / failed-no-effect:使用 Runtime-issued terminal event 原子释放 reservation。
- candidate 已产生但 SQLite 未接受:保持未接受派生物;如何 reopen、重新计算或 park 由后续 managed-recovery owner 明确定义。
- SQLite 已接受但 Git accepted ref 尚未投影:由后续 accepted-ref projection slice 直接采用 durable candidate evidence 幂等推进,不依赖当前 transform 实现。

## 5. 平台承诺

本切片只改变 Runtime/SQLite capability seam,不执行平台文件 mutation:

- Linux、macOS、Windows:同一 strict RuntimeEvent 与 SQLite transaction 合同。
- Git ref promotion、filesystem projection 和 crash reconciliation 由后续切片分别提供平台证据。
72 changes: 72 additions & 0 deletions packages/runtime/src/__tests__/managed-mutation-transform.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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.
*/

import assert from 'node:assert/strict';
import test from 'node:test';
import { transformManagedMutation } from '../managed-mutation-transform.js';

test('derives Write from the immutable Git base without touching a checkout', () => {
const result = transformManagedMutation({
toolName: 'Write',
canonicalPath: 'docs/hello.txt',
baseContent: 'before\n',
args: { path: 'docs/hello.txt', content: 'after\n' },
});
assert.equal(result.content, 'after\n');
assert.equal(result.changed, true);
assert.equal((result.providerResult as { kind: string }).kind, 'file_diff');
});

test('uses the production Edit matcher and rejects an absent target', () => {
const result = transformManagedMutation({
toolName: 'Edit',
canonicalPath: 'src/value.ts',
baseContent: 'const value = 1;\n',
args: {
path: 'src/value.ts',
old_string: 'const value = 1;',
new_string: 'const value = 2;',
},
});
assert.equal(result.content, 'const value = 2;\n');
assert.equal(result.changed, true);
assert.throws(
() =>
transformManagedMutation({
toolName: 'Edit',
canonicalPath: 'src/missing.ts',
baseContent: null,
args: { path: 'src/missing.ts', old_string: 'a', new_string: 'b' },
}),
/does not exist/u,
);
});

test('keeps the durable provider result bounded independently of file size', () => {
const content = `${'x'.repeat(2 * 1024 * 1024)}\n`;
const result = transformManagedMutation({
toolName: 'Write',
canonicalPath: 'artifacts/large.txt',
baseContent: 'before\n',
args: { path: 'artifacts/large.txt', content },
});

assert.equal(result.content, content);
assert.ok(Buffer.byteLength(JSON.stringify(result.providerResult), 'utf8') <= 512);
});
Loading
Loading