feat: align local-first workspace direction

Document the VSCode-like local-first product shape, demote Convex to a control-plane role, and retire stale architecture drafts.

Add local workspace migration/export references plus smoke coverage for no-Convex managed workspace startup, local markdown title/body/options persistence, asset upload behavior, and Convex fixture export.

Verification: git diff --cached --check; node scripts/check-local-first-convex-guard.js --staged; node scripts/task444-convex-workspace-export-local-fixture-smoke.js; node scripts/task166-local-first-managed-workspace-no-convex-smoke.js; node scripts/task167-local-markdown-title-body-options-no-convex-smoke.js
This commit is contained in:
lix-2026
2026-05-19 08:11:58 +08:00
parent 68d321e297
commit cdff672aa5
67 changed files with 5242 additions and 932 deletions
@@ -0,0 +1,64 @@
# 7-31 [done][bug] 页面 AI block_edit_workflow 丢弃读取类回答摘要 v1
> 发现时间:2026-05-18
>
> 状态:`[done]`
>
> 关联主线:`07-ai`
## 1. 用户可见症状
在页面 AI 使用 `ACP · Reasonix` 输入:
```text
检查你是否能读取到本页第一段,同时请修改第二段为:测试123
```
`block_edit_workflow` 即使完成写入,前端也只显示固定文案:
```text
已通过页面 markdown 编辑快路径完成写入。
```
用户要求中的“是否能读取到第一段”没有被回答。
## 2. 根因
`page_ai_workflow.rs` 的模型提示已经要求模型输出:
```json
{"operations": [...], "summary": "..."}
```
但路由只提取 `operations`,丢弃了 `summary`,并在成功响应中固定返回“已通过页面 markdown 编辑快路径完成写入。”。
这会让读写混合请求退化为纯写入反馈。
## 3. 修复
- 新增 `MarkdownEditPlan`,同时解析模型输出中的 `operations``summary`
- `block_edit_workflow` 成功响应优先返回模型 `summary`,缺失时才使用固定 fallback。
- 系统提示明确要求:如果用户要求读取某段,`summary` 必须包含从 `page_text` 读取到的原文。
- 新增回归测试 `block_edit_workflow_surfaces_model_summary_for_read_and_edit_request`,覆盖“读取第一段 + 修改第二段”的真实快路径响应。
## 4. 验证
RED
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web block_edit_workflow_surfaces_model_summary_for_read_and_edit_request -- --nocapture
```
旧实现失败,`payload.message` 不包含 `已读取第一段:第一段`
GREEN
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_workflow -- --nocapture
```
结果:`5 passed`
## 5. 剩余边界
本修复只保证 fast workflow 成功响应不丢模型摘要;复杂多步推理、review session、流式 apply 仍属于 Phase C 冻结范围。
@@ -0,0 +1,50 @@
# 7-32 [done][bug] markdown_edit 直接 page.body.save 时丢失 revision / conflictDetectionKey v1
> 发现时间:2026-05-18
>
> 状态:`[done]`
>
> 关联主线:`07-ai`
## 1. 问题定义
7-27 后,在线 `mnote.doc.markdown_edit` 不再通过空 `block_ops` 写回,而是以最终 Markdown 生成 `content` 后直接执行 `page.body.save`
旧实现构造的写入 payload 只包含:
- `documentId`
- `workspaceId`
- `content`
- `mode`
没有携带当前 Page Aggregate 的 `revision``conflictDetectionKey`
## 2. 影响
AI markdown 主路径可能基于旧快照覆盖用户并发编辑,绕过 7-22 已补到 `apply_block_ops` 的写前置条件。
## 3. 修复
- 在线 `markdown_edit` 写回前读取当前 Page Aggregate。
- 构造 `page.body.save` payload 时带入:
- `/body/revision`
- `/body/conflictDetectionKey`
- 新增回归测试检查 command artifact payload 中真实携带这两个字段。
## 4. 验证
RED
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit_online_page_body_save_carries_revision_conflict_key -- --nocapture
```
旧实现失败,artifact payload 中 `revision``Null`
GREEN
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit_online_page_body_save_carries_revision_conflict_key -- --nocapture
```
结果:`1 passed`
@@ -0,0 +1,41 @@
# 7-33 [done][bug] markdown_edit 全部 search 失败仍返回成功 v1
> 发现时间:2026-05-18
>
> 状态:`[done]`
>
> 关联主线:`07-ai`
## 1. 问题定义
`mnote.doc.markdown_edit` 逐条执行 search/replace 时,如果所有 search 都失败,旧实现仍会继续进入写回阶段,并返回:
```json
{"ok": true, "operationsApplied": 0}
```
这会让页面 AI fast workflow 把“没有改动”误报为编辑成功。
## 2. 修复
-`applied == 0` 时立即返回 `mnote_markdown_edit_no_operations_applied`
- 不再执行本地文件写入或在线 `page.body.save`
- 新增回归测试 `hermes_tools_markdown_edit_rejects_no_applied_operations`
## 3. 验证
RED
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit_rejects_no_applied_operations -- --nocapture
```
旧实现返回 `200`
GREEN
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit_rejects_no_applied_operations -- --nocapture
```
结果:`1 passed`
@@ -0,0 +1,45 @@
# 7-34 [done][bug] 页面 AI ACP Runtime 默认值回跳 Hermes v1
> 发现时间:2026-05-18
>
> 状态:`[done]`
>
> 关联主线:`07-ai`
## 1. 用户可见症状
页面 AI 面板中选择 `ACP · Reasonix` 后,会自动回跳到 `ACP · Hermes`
用户期望:
- 默认 runtime 为 `ACP · Reasonix`
- 下拉仍可手动切换到 `ACP · Hermes`
## 2. 根因
页面 AI 的历史 runtime 语义仍把空 `acpRuntime` 当成旧 `Hermes HTTP` 默认值。当前主线已经退役 HTTP Hermes,但前端 session/localStorage 恢复、后端空 runtime 推导、以及 `/profiles` 尚未返回时的下拉渲染仍可能产生空 runtime。
空 runtime 进入旧逻辑后会被解释成 Hermes 路径,导致用户刚选择 Reasonix 后又被历史 session 或空 select value 覆盖。
## 3. 修复
- 前端 `pageAiAcpRuntime` 初始值改为 `reasonix`
- localStorage 版本提升到 `3`,避免旧缓存把 active runtime 覆盖回 Hermes。
- session 创建、持久化、停止 run、发送 run 默认都写入 `reasonix`
- 前端内置 `Reasonix / Hermes` 两个 ACP runtime fallback`/profiles` 慢或失败时也不会渲染空 select。
- 后端空 `acpRuntime` 默认归入 ACP 默认 runtime,默认值为 `reasonix`;旧 HTTP proxy 只保留在显式兼容开关后。
## 4. 验证
新增回归约束:
```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_acp_runtime_defaults_to_reasonix_and_keeps_hermes_switch -- --nocapture
```
覆盖:
- `pageAiAcpRuntime` 默认是 `reasonix`
- 下拉 options 固定包含 `reasonix` / `hermes`
- 不再包含旧的 `默认 (Hermes HTTP)` 空选项
- change handler 空值 fallback 到 `reasonix`