Files
mnote/harness-tasks.json
T

584 lines
31 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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 显式门控与首页 smoke3104 不可达时 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 idsidebar/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"
}