{ "version": 2, "created": "2026-04-17T07:58:16Z", "session_config": { "concurrency_mode": "exclusive", "max_tasks_per_session": 20, "max_sessions": 50 }, "tasks": [ { "id": "task-001", "title": "执行 Stage A-1:固定首页与 /api/sidebar 主路径只走 Convex/Rust 主链,禁止默认回落到 mnote-web compat/sidebar,并把 tree shell 默认运行态切成显式开关", "status": "completed", "priority": "P0", "depends_on": [], "attempts": 1, "max_attempts": 3, "started_at_commit": "4538f85d", "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/app/api/sidebar/route.ts src/lib/runtime-config.ts src/components/sidebar/sidebar.tsx src/components/sidebar/MnoteWebTreeShell.tsx && node - <<'NODE'\nconst fs = require('fs');\nconst route = fs.readFileSync('src/app/api/sidebar/route.ts', 'utf8');\nconst runtime = fs.readFileSync('src/lib/runtime-config.ts', 'utf8');\nconst sidebar = fs.readFileSync('src/components/sidebar/sidebar.tsx', 'utf8');\nconst shell = fs.readFileSync('src/components/sidebar/MnoteWebTreeShell.tsx', 'utf8');\nconst envJson = JSON.parse(fs.readFileSync('public/mnote-env.json', 'utf8'));\nif (/fetchSidebarDatasetFromMnoteWeb|getMnoteWebBaseUrl\\(/.test(route)) throw new Error('route.ts 仍残留 mnote-web compat 主路径');\nif (!runtime.includes('parseRuntimeBoolean(cfg.mnoteWebTreeShellEnabled) ?? false')) throw new Error('runtime-config.ts 未把 tree shell 默认值固定为 false');\nif (!sidebar.includes('mnoteWebTreeShellEnabled === true')) throw new Error('sidebar.tsx 未收紧为显式开关');\nif (!shell.includes('mnoteWebTreeShellEnabled === true')) throw new Error('MnoteWebTreeShell.tsx 未收紧为显式开关');\nif (envJson.mnoteWebTreeShellEnabled !== false) throw new Error('public/mnote-env.json 未默认关闭 tree shell');\nconsole.log('task-001-boundary-ok');\nNODE", "timeout_seconds": 300 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [], "completed_at": "2026-04-17T08:03:15Z" }, { "id": "task-002", "title": "执行 Stage A-2:收紧 move/embed picker 的实验壳边界,tree shell 关闭时不再额外请求 viewer/tree-shell 依赖,空查询路径继续只消费稳定 projection 数据", "status": "completed", "priority": "P0", "depends_on": [ "task-001" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "4538f85d", "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/components/documents/move-embed-picker-dialog.tsx src/components/documents/move-embed-picker-host.tsx && node - <<'NODE'\nconst fs = require('fs');\nconst dialog = fs.readFileSync('src/components/documents/move-embed-picker-dialog.tsx', 'utf8');\nif (!dialog.includes('const treeShellEnabled =')) throw new Error('picker 未显式计算 treeShellEnabled');\nif (!dialog.includes('enabled: Boolean(workspaceId) && isEmptyQuery && treeShellEnabled')) throw new Error('viewerQuery 仍会在 tree shell 关闭时触发');\nconsole.log('task-002-picker-boundary-ok');\nNODE", "timeout_seconds": 300 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [], "completed_at": "2026-04-17T08:06:06Z" }, { "id": "task-003", "title": "执行 Stage A-3:新增并跑通 3000 首页入口 smoke,验证在 3104 不可用时首页主链仍可进入 /auth 或已登录文档页,不因实验壳阻塞", "status": "completed", "priority": "P0", "depends_on": [ "task-001", "task-002" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "4538f85d", "validation": { "command": "cd /mnt/Data1T/mnote && node scripts/task097-homepage-entry-smoke.js", "timeout_seconds": 600 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [], "completed_at": "2026-04-17T08:12:27Z" }, { "id": "task-004", "title": "执行 Stage B-1:继续收缩前端树域真相泄漏,确认主路径 consumer 只消费 kernel projection,兼容 helper 不再回到运行时主链", "status": "completed", "priority": "P1", "depends_on": [ "task-001", "task-002" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "4538f85d", "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/components/sidebar/sidebar.tsx src/components/documents/move-embed-picker-dialog.tsx src/components/documents/move-embed-picker-host.tsx && node - <<'NODE'\nconst fs = require('fs');\nconst sidebar = fs.readFileSync('src/components/sidebar/sidebar.tsx', 'utf8');\nconst picker = fs.readFileSync('src/components/documents/move-embed-picker-dialog.tsx', 'utf8');\nconst host = fs.readFileSync('src/components/documents/move-embed-picker-host.tsx', 'utf8');\nfor (const [name, source] of [['sidebar', sidebar], ['picker', picker], ['host', host]]) {\n if (source.includes('buildDocumentTree(')) throw new Error(name + ' 仍残留 buildDocumentTree 主路径依赖');\n}\nconsole.log('task-004-tree-truth-mainpath-ok');\nNODE", "timeout_seconds": 300 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [], "completed_at": "2026-04-17T08:11:55Z" }, { "id": "task-005", "title": "执行 Stage B-2:梳理 sidebar/page/filetree 的 create/rename/move 命令入口,给出并落第一批 Rust command envelope 收口边界,避免前端继续扩散树语义", "status": "completed", "priority": "P1", "depends_on": [ "task-004" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "4538f85d", "validation": { "command": "python3 - <<'PY'\nfrom pathlib import Path\nroot = Path('/mnt/Data1T/mnote')\npath = root / 'design/tree-command-envelope-cutover-stage1-v1.md'\ntext = path.read_text(encoding='utf-8')\nassert 'sidebar.tsx' in text\nassert 'create / rename / move' in text or 'create/rename/move' in text\nprint('task-005-command-cutover-doc-ok')\nPY", "timeout_seconds": 120 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 2, "description": "已审计 sidebar/document-content/CustomSideMenu 与 create/title/move route,确认第一批 tree command 已接入 envelope,但入口与部分树策略仍散落在前端组件层。", "timestamp": "2026-04-17T08:32:00Z" }, { "step": 2, "total": 2, "description": "已新增共享 tree command client,并产出 design/tree-command-envelope-cutover-stage1-v1.md 固定第一批 cutover 边界与顺序。", "timestamp": "2026-04-17T08:40:10Z" } ], "completed_at": "2026-04-17T08:40:10Z" }, { "id": "task-006", "title": "执行 Stage C-1:为 Rust Web 正式实时树事件流补方案与接缝说明,明确 Convex substrate 与 Rust semantic owner 的订阅职责划分", "status": "completed", "priority": "P2", "depends_on": [ "task-003", "task-005" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "4538f85d", "validation": { "command": "python3 - <<'PY'\nfrom pathlib import Path\nroot = Path('/mnt/Data1T/mnote')\npath = root / 'design/rust-web-tree-realtime-event-stream-v1.md'\ntext = path.read_text(encoding='utf-8')\nassert 'Convex substrate' in text or 'Convex' in text\nassert 'Rust semantic owner' in text or 'Rust' in text\nprint('task-006-realtime-doc-ok')\nPY", "timeout_seconds": 120 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已产出 design/rust-web-tree-realtime-event-stream-v1.md,明确 Convex substrate、Rust semantic owner、Rust Web SSE/WS transport 与前端 projection consumer 的职责划分。", "timestamp": "2026-04-17T08:42:00Z" } ], "completed_at": "2026-04-17T08:42:00Z" }, { "id": "task-007", "title": "执行 Stage C-2:回写新的 harness 批次状态、阶段完成度与长期口径,明确哪些已进入稳定主链,哪些仍属于实验壳/后续阶段", "status": "completed", "priority": "P1", "depends_on": [ "task-003", "task-004", "task-005", "task-006" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "4538f85d", "validation": { "command": "python3 - <<'PY'\nfrom pathlib import Path\nroot = Path('/mnt/Data1T/mnote')\nassert (root / 'harness-tasks.json').exists()\nassert (root / 'harness-progress.txt').exists()\nprint('task-007-harness-sync-ok')\nPY", "timeout_seconds": 120 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已回写 harness 状态与进度,并验证修复 dev server 的 Convex HTTP 代理后,3000 首页基线恢复:/auth 返回 200,/ 根路径稳定进入 /auth。", "timestamp": "2026-04-17T08:56:30Z" } ], "completed_at": "2026-04-17T08:56:30Z" }, { "id": "task-008", "title": "执行 Stage P0-1:补首页/sidebar/tree shell 主链回归护栏,固化 3000 首屏、Convex live 优先与实验壳显式开关约束", "status": "completed", "priority": "P0", "depends_on": [ "task-007" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "aa6ee384", "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/hooks/use-sidebar-data.ts src/hooks/use-convex-sidebar-data.ts src/components/sidebar/sidebar.tsx src/components/sidebar/MnoteWebTreeShell.tsx && node - <<'NODE'\nconst fs = require('fs');\nconst useSidebarData = fs.readFileSync('src/hooks/use-sidebar-data.ts', 'utf8');\nconst useConvexSidebarData = fs.readFileSync('src/hooks/use-convex-sidebar-data.ts', 'utf8');\nconst sidebar = fs.readFileSync('src/components/sidebar/sidebar.tsx', 'utf8');\nconst shell = fs.readFileSync('src/components/sidebar/MnoteWebTreeShell.tsx', 'utf8');\nif (!useSidebarData.includes('!convexSidebar.hasLiveSubscription && convexSidebar.canUseHttpFallback')) throw new Error('use-sidebar-data.ts 丢失 Convex live 优先护栏');\nif (!useConvexSidebarData.includes('const hasLiveSubscription = shouldFetch')) throw new Error('use-convex-sidebar-data.ts 丢失 live subscription 判定');\nif (!sidebar.includes('runtimeConfig.mnoteWebTreeShellEnabled === true')) throw new Error('sidebar.tsx 未显式门控 tree shell');\nif (!shell.includes('readyTimerRef.current = window.setTimeout')) throw new Error('MnoteWebTreeShell.tsx 缺少超时 fallback 护栏');\nconsole.log('task-008-guardrails-ok');\nNODE\ncd /mnt/Data1T/mnote && node scripts/task097-homepage-entry-smoke.js", "timeout_seconds": 900 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已验证 Convex live 优先、tree shell 显式门控与首页 smoke;3104 不可达时 3000 仍稳定回到 /auth。", "timestamp": "2026-04-17T15:54:10Z" } ], "completed_at": "2026-04-17T15:54:10Z", "claimed_by": "SESSION-3", "lease_expires_at": "2026-04-17T16:22:02Z" }, { "id": "task-009", "title": "执行 Stage P1-1:把 delete/restore/purge 收口到 shared tree command client,并让 Sidebar/DocumentContent 退出对应直调 route", "status": "completed", "priority": "P1", "depends_on": [ "task-008" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "aa6ee384", "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/lib/documents/tree-command-client.ts src/components/sidebar/sidebar.tsx src/components/editor/document-content.tsx && node - <<'NODE'\nconst fs = require('fs');\nconst client = fs.readFileSync('src/lib/documents/tree-command-client.ts', 'utf8');\nconst sidebar = fs.readFileSync('src/components/sidebar/sidebar.tsx', 'utf8');\nconst documentContent = fs.readFileSync('src/components/editor/document-content.tsx', 'utf8');\nfor (const name of ['deleteDocumentCommand', 'restoreDocumentCommand', 'purgeDocumentCommand']) {\n if (!client.includes(`export async function ${name}`)) throw new Error(`tree-command-client.ts 缺少 ${name}`);\n}\nfor (const [name, source] of [['sidebar', sidebar], ['document-content', documentContent]]) {\n if (source.includes('fetch(\"/api/documents/delete\"') || source.includes(\"fetch('/api/documents/delete'\")) throw new Error(name + ' 仍直调 /api/documents/delete');\n if (source.includes('fetch(\"/api/documents/restore\"') || source.includes(\"fetch('/api/documents/restore'\")) throw new Error(name + ' 仍直调 /api/documents/restore');\n if (source.includes('fetch(\"/api/documents/purge\"') || source.includes(\"fetch('/api/documents/purge'\")) throw new Error(name + ' 仍直调 /api/documents/purge');\n}\nconsole.log('task-009-tree-command-client-delete-restore-purge-ok');\nNODE", "timeout_seconds": 600 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已补 shared tree command client 的 delete/restore/purge,并移除 Sidebar/DocumentContent 对应 route 直调。", "timestamp": "2026-04-17T15:58:30Z" } ], "completed_at": "2026-04-17T15:58:30Z", "claimed_by": "SESSION-3", "lease_expires_at": "2026-04-17T16:24:10Z" }, { "id": "task-010", "title": "执行 Stage P1-2:处理 pageReference 删除路径,移除 CustomSideMenu 中对 /api/documents/delete 的直调", "status": "completed", "priority": "P1", "depends_on": [ "task-009" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "aa6ee384", "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/components/editor/menus/CustomSideMenu.tsx src/lib/documents/tree-command-client.ts && node - <<'NODE'\nconst fs = require('fs');\nconst menu = fs.readFileSync('src/components/editor/menus/CustomSideMenu.tsx', 'utf8');\nif (menu.includes('fetch(\"/api/documents/delete\"') || menu.includes(\"fetch('/api/documents/delete'\")) throw new Error('CustomSideMenu.tsx 仍直调 /api/documents/delete');\nif (!menu.includes('deleteDocumentCommand(')) throw new Error('CustomSideMenu.tsx 未切到 shared tree command client');\nconsole.log('task-010-page-reference-delete-ok');\nNODE", "timeout_seconds": 300 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已让 CustomSideMenu 的 pageReference 删除改走 shared tree command client。", "timestamp": "2026-04-17T15:58:30Z" } ], "completed_at": "2026-04-17T15:58:30Z", "claimed_by": "SESSION-3", "lease_expires_at": "2026-04-17T16:28:30Z" }, { "id": "task-011", "title": "执行 Stage P1-3:为 embed 定义独立 Rust page-tree command,并让 Sidebar/DocumentContent 改走 shared embed client", "status": "completed", "priority": "P1", "depends_on": [ "task-010" ], "attempts": 1, "max_attempts": 3, "started_at_commit": "aa6ee384", "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/lib/documents/tree-command-client.ts src/lib/documents/page-command-adapter.ts src/app/api/documents/embed/route.ts src/components/sidebar/sidebar.tsx src/components/editor/document-content.tsx && node - <<'NODE'\nconst fs = require('fs');\nconst client = fs.readFileSync('src/lib/documents/tree-command-client.ts', 'utf8');\nconst adapter = fs.readFileSync('src/lib/documents/page-command-adapter.ts', 'utf8');\nconst sidebar = fs.readFileSync('src/components/sidebar/sidebar.tsx', 'utf8');\nconst documentContent = fs.readFileSync('src/components/editor/document-content.tsx', 'utf8');\nif (!client.includes('export async function embedDocumentCommand')) throw new Error('tree-command-client.ts 缺少 embedDocumentCommand');\nif (!adapter.includes('name: \"documents.embed\"')) throw new Error('page-command-adapter.ts 未定义独立 documents.embed 命令');\nif (adapter.includes('name: \"documents.save\"') && adapter.includes('executeDocumentEmbedBridgeCommand')) throw new Error('embed 仍停留在 documents.save 过渡语义');\nfor (const [name, source] of [['sidebar', sidebar], ['document-content', documentContent]]) {\n if (source.includes('fetch(\"/api/documents/embed\"') || source.includes(\"fetch('/api/documents/embed'\")) throw new Error(name + ' 仍直调 /api/documents/embed');\n}\nconsole.log('task-011-embed-command-ok');\nNODE", "timeout_seconds": 600 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已把 embed 从 documents.save 过渡语义切成独立 documents.embed 命令,并补齐 TS/Rust 映射与回归测试。", "timestamp": "2026-04-17T16:15:19Z" } ], "completed_at": "2026-04-17T16:15:19Z", "claimed_by": "SESSION-3", "lease_expires_at": "2026-04-17T16:28:30Z" }, { "id": "task-012", "title": "执行 Stage P1-4:把 copy-tree 收口到 shared tree command client,移除 Sidebar 中文档复制的直调 route", "status": "completed", "priority": "P1", "depends_on": [ "task-011" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/lib/documents/tree-command-client.ts src/components/sidebar/sidebar.tsx src/app/api/documents/copy-tree/route.ts && node - <<'NODE'\nconst fs = require('fs');\nconst client = fs.readFileSync('src/lib/documents/tree-command-client.ts', 'utf8');\nconst sidebar = fs.readFileSync('src/components/sidebar/sidebar.tsx', 'utf8');\nconst route = fs.readFileSync('src/app/api/documents/copy-tree/route.ts', 'utf8');\nif (!client.includes('export async function copyTreeCommand')) throw new Error('tree-command-client.ts 缺少 copyTreeCommand');\nif (sidebar.includes('fetch(\"/api/documents/copy-tree\"') || sidebar.includes(\"fetch('/api/documents/copy-tree'\")) throw new Error('sidebar.tsx 仍直调 /api/documents/copy-tree');\nif (!route.includes('name: \"documents.copy_tree\"')) throw new Error('copy-tree route 未保持 Rust bridge command 主链');\nconsole.log('task-012-copy-tree-client-ok');\nNODE", "timeout_seconds": 600 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已确认 copy-tree 继续走 shared tree command client 与 Rust bridge command 主链,Sidebar 不再直调 route。", "timestamp": "2026-04-17T16:15:19Z" } ], "completed_at": "2026-04-17T16:15:19Z" }, { "id": "task-013", "title": "执行 Stage P2-1:把 targetParentId / sortOrder / subtree move legality 收口到 Rust/bridge 主链,并补回归测试", "status": "completed", "priority": "P2", "depends_on": [ "task-012" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/documents/page-lifecycle-command-adapter.test.ts src/lib/file-tree/dnd.test.ts && cd /mnt/Data1T/mnote/rust && cargo test -p bridge-runtime kernel_project_view_query_executes_into_sidebar_projection -- --nocapture && cargo test -p bridge-runtime kernel_subtree_query_executes_into_unified_subtree -- --nocapture", "timeout_seconds": 1200 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已补 page-lifecycle-command-adapter 测试并收口 move/copy-tree 的 targetParentId、sortOrder 与 subtree move legality 归一化。", "timestamp": "2026-04-17T16:35:06Z" } ], "completed_at": "2026-04-17T16:35:06Z" }, { "id": "task-014", "title": "执行 Stage P2-2:统一 sidebar/page/file 的 kernel projection 契约,逐步移除前端本地 synthetic projection/fallback 真相", "status": "completed", "priority": "P2", "depends_on": [ "task-013" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/sidebar-data.test.ts src/lib/tree-projection.test.ts src/lib/file-tree/rows.test.ts && node - <<'NODE'\nconst fs = require('fs');\nconst sidebarData = fs.readFileSync('src/lib/sidebar-data.ts', 'utf8');\nconst pageSubtree = fs.readFileSync('src/lib/documents/page-subtree.ts', 'utf8');\nif (sidebarData.includes('result.kernel_sidebar_projection ??')) throw new Error('sidebar-data.ts 仍在主路径本地补 projection 真相');\nif (pageSubtree.includes('projectionId: `page_subtree:')) throw new Error('page-subtree.ts 仍本地合成 page_tree projection');\nconsole.log('task-014-kernel-projection-contract-ok');\nNODE", "timeout_seconds": 900 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已移除主路径 projection fallback/synthetic projection id,sidebar/page/file 的 projection 契约改为只认上游 kernel 输出。", "timestamp": "2026-04-17T16:35:06Z" } ], "completed_at": "2026-04-17T16:35:06Z" }, { "id": "task-015", "title": "执行 Stage P2-3:清理 compat/fallback 与实验壳重复树拼装,确保主路径 consumer 只消费统一 projection", "status": "completed", "priority": "P2", "depends_on": [ "task-014" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/components/sidebar/sidebar.tsx src/components/documents/move-embed-picker-dialog.tsx src/components/documents/move-embed-picker-host.tsx src/lib/sidebar-data.ts && node - <<'NODE'\nconst fs = require('fs');\nconst sidebar = fs.readFileSync('src/components/sidebar/sidebar.tsx', 'utf8');\nconst picker = fs.readFileSync('src/components/documents/move-embed-picker-dialog.tsx', 'utf8');\nconst host = fs.readFileSync('src/components/documents/move-embed-picker-host.tsx', 'utf8');\nconst sidebarData = fs.readFileSync('src/lib/sidebar-data.ts', 'utf8');\nfor (const [name, source] of [['sidebar', sidebar], ['picker', picker], ['host', host]]) {\n if (source.includes('buildDocumentTree(')) throw new Error(name + ' 仍残留旧树拼装主路径');\n}\nif (sidebarData.includes('buildKernelSidebarProjection(')) throw new Error('sidebar-data.ts 仍保留主路径 synthetic kernel projection');\nconsole.log('task-015-mainpath-projection-only-ok');\nNODE", "timeout_seconds": 600 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已确认 Sidebar/picker/host 主路径不再残留旧树拼装,sidebar-data 主路径不再本地合成 kernel projection。", "timestamp": "2026-04-17T16:35:06Z" } ], "completed_at": "2026-04-17T16:35:06Z" }, { "id": "task-016", "title": "执行 Stage P3-1:把 Rust Web SSE/WS 从 placeholder 升级为 workspace/subtree snapshot stream", "status": "completed", "priority": "P2", "depends_on": [ "task-015" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web -- --nocapture && python3 - <<'PY'\nfrom pathlib import Path\nroot = Path('/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes')\nsse = (root / 'sse.rs').read_text(encoding='utf-8')\nws = (root / 'ws.rs').read_text(encoding='utf-8')\nassert 'sse_placeholder' not in sse, 'sse.rs 仍是 placeholder'\nassert 'ws_placeholder' not in ws, 'ws.rs 仍是 placeholder'\nassert 'workspace' in sse or 'subtree' in sse, 'sse.rs 未体现 workspace/subtree stream'\nprint('task-016-rust-web-snapshot-stream-ok')\nPY", "timeout_seconds": 1800 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已把 Rust Web SSE/WS 升级为 workspace/subtree snapshot stream,并复用统一 snapshot/stream support。", "timestamp": "2026-04-17T16:35:06Z" } ], "completed_at": "2026-04-17T16:35:06Z" }, { "id": "task-017", "title": "执行 Stage P3-2:接入 snapshot + delta + resync 协议与前端 tree stream consumer,逐步切 Sidebar/filetree/page subtree", "status": "completed", "priority": "P2", "depends_on": [ "task-016" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/tree-stream/tree-stream.test.ts src/lib/tree-stream/tree-delta.test.ts && node - <<'NODE'\nconst fs = require('fs');\nconst sidebar = fs.readFileSync('src/components/sidebar/sidebar.tsx', 'utf8');\nif (!/useTreeStream|useSidebarTreeStream|snapshot|delta|resync/.test(sidebar)) throw new Error('sidebar.tsx 未接入正式 tree stream consumer');\nconsole.log('task-017-tree-stream-consumer-ok');\nNODE", "timeout_seconds": 1200 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已接入 useSidebarTreeStream 正式 consumer,并补齐 snapshot/delta/resync 协议与 reducer 测试。", "timestamp": "2026-04-17T16:35:06Z" } ], "completed_at": "2026-04-17T16:35:06Z" }, { "id": "task-018", "title": "执行 Stage P4-1:让 Rust Web 接住正式 SSR 页面壳与 server-first projection 分发,前端退回必要 islands", "status": "completed", "priority": "P3", "depends_on": [ "task-017" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web kernel_projection_route_returns_sidebar_projection -- --nocapture && cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/lib/server/sidebar-data.ts src/app/(app)/documents/[id]/page.tsx src/components/editor/document-shell.tsx && cd /mnt/Data1T/mnote && node scripts/task097-homepage-entry-smoke.js", "timeout_seconds": 1800 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已验证 Rust Web kernel projection SSR 路由、前端 server data lint 与首页 smoke,主链仍不依赖 3104 可用。", "timestamp": "2026-04-17T16:35:06Z" } ], "completed_at": "2026-04-17T16:35:06Z" }, { "id": "task-019", "title": "执行 Stage QA-1:统一跑前端测试并修复必须修复的 bug,确保架构收口后的主链交互与关键回归稳定", "status": "completed", "priority": "P0", "depends_on": [ "task-018" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm test && pnpm lint src/hooks/use-sidebar-data.ts src/hooks/use-convex-sidebar-data.ts src/lib/documents/tree-command-client.ts src/components/sidebar/sidebar.tsx src/components/editor/document-content.tsx src/components/editor/menus/CustomSideMenu.tsx src/lib/sidebar-data.ts src/lib/tree-projection.ts src/lib/file-tree/rows.ts && cd /mnt/Data1T/mnote && node scripts/task097-homepage-entry-smoke.js", "timeout_seconds": 2400 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已跑通前端全量测试并修复必须修复 bug:AiAgentPanel 过期断言与 tree stream 连接错误路由。", "timestamp": "2026-04-17T16:35:06Z" } ], "completed_at": "2026-04-17T16:35:06Z" }, { "id": "task-020", "title": "执行 Stage P4-2:回写长期架构文档与 harness 状态,勾选 design/tree-first-graph-convex-rust-long-term-architecture-v1.md 全部 checklist", "status": "completed", "priority": "P1", "depends_on": [ "task-019" ], "attempts": 0, "max_attempts": 3, "started_at_commit": null, "validation": { "command": "python3 - <<'PY'\nfrom pathlib import Path\nroot = Path('/mnt/Data1T/mnote')\narch = (root / 'design/tree-first-graph-convex-rust-long-term-architecture-v1.md').read_text(encoding='utf-8')\nassert '- [ ]' not in arch, '长期架构文档仍有未完成 checklist'\nassert (root / 'harness-tasks.json').exists(), 'harness-tasks.json 缺失'\nassert (root / 'harness-progress.txt').exists(), 'harness-progress.txt 缺失'\nprint('task-020-architecture-checklist-complete')\nPY", "timeout_seconds": 180 }, "on_failure": { "cleanup": null }, "error_log": [], "checkpoints": [ { "step": 1, "total": 1, "description": "已回写长期架构文档并清空全部 checklist,harness 状态已完成收尾。", "timestamp": "2026-04-17T16:36:54Z" } ], "completed_at": "2026-04-17T16:36:54Z" } ], "session_count": 3, "last_session": "2026-04-17T08:56:30Z" }