1195 lines
58 KiB
JSON
1195 lines
58 KiB
JSON
{
|
||
"version": 2,
|
||
"created": "2026-04-17T07:58:16Z",
|
||
"session_config": {
|
||
"concurrency_mode": "exclusive",
|
||
"max_tasks_per_session": 12,
|
||
"max_sessions": 120
|
||
},
|
||
"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"
|
||
},
|
||
{
|
||
"id": "task-021",
|
||
"title": "执行 TreeShell Phase A-1:产出共享 tree projection contract 文档,冻结 sidebar_tree/page_tree/file_tree 共用字段与差异字段",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-020"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "python3 - <<'PY'\nfrom pathlib import Path\npath = Path('/mnt/Data1T/mnote/design/tree-projection-protocol-contract-v1.md')\ntext = path.read_text(encoding='utf-8')\nfor needle in ['sidebar_tree', 'page_tree', 'file_tree', 'row_id', 'node_id', 'resource_meta']:\n assert needle in text, f'missing {needle}'\nprint('task-021-tree-projection-contract-ok')\nPY",
|
||
"timeout_seconds": 180
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已产出共享 tree projection contract 文档,并用文档断言冻结 sidebar_tree/page_tree/file_tree 的共享字段、row_id 与 resource_meta 口径。",
|
||
"timestamp": "2026-04-17T23:18:26Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-17T23:18:26Z",
|
||
"claimed_by": "SESSION-4"
|
||
},
|
||
{
|
||
"id": "task-022",
|
||
"title": "执行 TreeShell Phase A-2:落地前后端共享 projection 类型,并冻结 file_tree 扩展字段与 capability/icon/resource 语义",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-021"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p core-protocol -- --nocapture && cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/tree-protocol.test.ts && python3 - <<'PY'\nfrom pathlib import Path\nfrontend = Path('/mnt/Data1T/mnote/wolai-frontend/src/lib/tree-protocol.ts').read_text(encoding='utf-8')\nassert 'resourceKind' in frontend\nassert 'assetKind' in frontend\nassert 'iconHint' in frontend\nprint('task-022-tree-protocol-types-ok')\nPY",
|
||
"timeout_seconds": 1800
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已补齐前后端共享 projection 类型与 file_tree 扩展字段,并跑通 core-protocol 与 tree-protocol 目标测试。",
|
||
"timestamp": "2026-04-17T23:18:30Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-17T23:18:30Z"
|
||
},
|
||
{
|
||
"id": "task-023",
|
||
"title": "执行 TreeShell Phase A-3:固定树域 command protocol 长期命名面,并给出 documents.* 到 tree.* 的兼容迁移文档",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-022"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "python3 - <<'PY'\nfrom pathlib import Path\npath = Path('/mnt/Data1T/mnote/design/tree-command-protocol-cutover-stage2-v1.md')\ntext = path.read_text(encoding='utf-8')\nfor needle in ['tree.node.create', 'tree.node.rename', 'tree.subtree.move', 'tree.asset.attach', 'documents.create']:\n assert needle in text, f'missing {needle}'\nprint('task-023-tree-command-protocol-doc-ok')\nPY",
|
||
"timeout_seconds": 180
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已冻结 tree.* 长期命名面,并把 documents.* 到 tree.* 的兼容映射与 cutover 顺序写入设计文档。",
|
||
"timestamp": "2026-04-17T23:18:34Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-17T23:18:34Z"
|
||
},
|
||
{
|
||
"id": "task-024",
|
||
"title": "执行 TreeShell Phase A-4:明确 projection 状态与本地 UI 状态边界,并形成 Rust/前端共享的状态约束文档",
|
||
"status": "completed",
|
||
"priority": "P2",
|
||
"depends_on": [
|
||
"task-023"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "python3 - <<'PY'\nfrom pathlib import Path\npath = Path('/mnt/Data1T/mnote/design/tree-shell-ui-state-boundary-v1.md')\ntext = path.read_text(encoding='utf-8')\nfor needle in ['expanded', 'selected', 'focus', 'dragging', 'drop target', 'projection']:\n assert needle in text, f'missing {needle}'\nprint('task-024-tree-shell-ui-state-boundary-ok')\nPY",
|
||
"timeout_seconds": 180
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已固定 projection truth 与本地 UI state 的边界,并用文档断言锁定 expanded、selected、focus、dragging、drop target 不进入 projection。",
|
||
"timestamp": "2026-04-17T23:18:38Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-17T23:18:38Z"
|
||
},
|
||
{
|
||
"id": "task-025",
|
||
"title": "执行 TreeShell Phase A-5:补齐 projection/command protocol fixtures 与 contract tests,锁死后续 Phase B-D 的协议基线",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-024"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/tree-protocol.test.ts src/lib/tree-projection-contract.test.ts src/lib/documents/tree-command-client.test.ts && cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web tree_projection_contract -- --nocapture && python3 - <<'PY'\nfrom pathlib import Path\nfor rel in [\n 'wolai-frontend/src/lib/tree-protocol.test.ts',\n 'wolai-frontend/src/lib/tree-projection-contract.test.ts'\n]:\n assert Path('/mnt/Data1T/mnote', rel).exists(), rel\nprint('task-025-tree-contract-tests-ok')\nPY",
|
||
"timeout_seconds": 2400
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已新增 projection/command protocol contract tests,并跑通前端 fixtures 与 mnote-web tree_projection_contract 验证。",
|
||
"timestamp": "2026-04-17T23:18:42Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-17T23:18:42Z"
|
||
},
|
||
{
|
||
"id": "task-026",
|
||
"title": "执行 TreeShell Phase B-1:在 mnote-web 补正式 sidebar_tree/page_tree/file_tree projection route 族,退出“只靠 kernel sidebar 兼容入口”阶段",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-025"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web tree_projection_routes -- --nocapture && python3 - <<'PY'\nfrom pathlib import Path\ntext = Path('/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/mod.rs').read_text(encoding='utf-8')\nfor needle in ['/api/tree/projections/sidebar', '/api/tree/projections/page', '/api/tree/projections/file']:\n assert needle in text or needle.replace('/api', '') in text, needle\nprint('task-026-tree-projection-routes-ok')\nPY",
|
||
"timeout_seconds": 2400
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已补齐 mnote-web 的 sidebar/page/file projection route 族,并重新验证 tree projection routes。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-027",
|
||
"title": "执行 TreeShell Phase B-2:让 Rust 直接输出 file_tree projection,先覆盖 asset/mindmap/table,减少前端 adapter 拼装真相",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-026"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web file_tree_projection -- --nocapture && cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/file-tree/rows.test.ts && node - <<'NODE'\nconst fs = require('fs');\nconst rows = fs.readFileSync('/mnt/Data1T/mnote/wolai-frontend/src/lib/file-tree/rows.ts', 'utf8');\nif (/mindmap_assets|table_assets|media_assets/.test(rows)) {\n throw new Error('rows.ts 仍直接耦合旧资产数组主路径');\n}\nconsole.log('task-027-file-tree-rust-projection-ok');\nNODE",
|
||
"timeout_seconds": 2400
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "Rust 已直接输出 file_tree projection 的 document/index/asset 行语义,前端 rows 测试通过。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-028",
|
||
"title": "执行 TreeShell Phase B-3:扩展 Rust file_tree mapper 到 book/pdf/index/resource hint/capabilities,补齐更宽对象投影",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-027"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web file_tree_projection_resource_variants -- --nocapture && python3 - <<'PY'\nfrom pathlib import Path\ntext = Path('/mnt/Data1T/mnote/design/tree-projection-protocol-contract-v1.md').read_text(encoding='utf-8')\nfor needle in ['book', 'pdf', 'index', 'icon_hint', 'capabilities']:\n assert needle in text, f'missing {needle}'\nprint('task-028-file-tree-resource-variants-ok')\nPY",
|
||
"timeout_seconds": 2400
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "Rust file_tree mapper 已扩展到 book/pdf/index/iconHint/capabilities,并验证资源变体测试。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-029",
|
||
"title": "执行 TreeShell Phase B-4:把树域 command route 长期协议切到 tree.*,同时保留 documents.* 兼容 alias 与桥接回归",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-028"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web tree_commands -- --nocapture && cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/documents/tree-command-client.test.ts && node - <<'NODE'\nconst fs = require('fs');\nconst client = fs.readFileSync('/mnt/Data1T/mnote/wolai-frontend/src/lib/documents/tree-command-client.ts', 'utf8');\nif (!/tree\\./.test(client) && !/documents\\./.test(client)) throw new Error('tree command client 未体现 tree.* / documents.* 兼容层');\nconsole.log('task-029-tree-command-alias-ok');\nNODE",
|
||
"timeout_seconds": 2400
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "树域 command 主协议已切到 tree.*,同时保留 documents.* alias 与共享 client 回归通过。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-030",
|
||
"title": "执行 TreeShell Phase B-5:补齐树域 route 的鉴权、错误码、trace、workspace 解析与 compat fallback 契约",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-029"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web tree_route_contracts -- --nocapture && python3 - <<'PY'\nfrom pathlib import Path\nroot = Path('/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes')\njoined = '\\n'.join((root / name).read_text(encoding='utf-8') for name in ['compat.rs', 'kernel.rs', 'tree.rs'])\nfor needle in ['traceId', 'requestId', 'workspaceId', 'Authorization']:\n assert needle in joined, f'missing {needle}'\nprint('task-030-tree-route-contracts-ok')\nPY",
|
||
"timeout_seconds": 2400
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "树域 route 契约已补齐 trace/workspace/auth 边界,tree_route_contracts 测试通过。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-031",
|
||
"title": "执行 TreeShell Phase B-6:让 Next 侧树域只保留 transport/compat,删除残余结构真相拼装逻辑",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-030"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm eslint src/lib/server/sidebar-data.ts src/app/api/sidebar/route.ts src/components/sidebar/sidebar.tsx src/components/documents/move-embed-picker-dialog.tsx && node - <<'NODE'\nconst fs = require('fs');\nfor (const rel of [\n 'src/lib/server/sidebar-data.ts',\n 'src/app/api/sidebar/route.ts',\n 'src/components/sidebar/sidebar.tsx',\n 'src/components/documents/move-embed-picker-dialog.tsx'\n]) {\n const source = fs.readFileSync(`/mnt/Data1T/mnote/wolai-frontend/${rel}`, 'utf8');\n if (source.includes('buildDocumentTree(')) {\n throw new Error(`${rel} 仍残留 buildDocumentTree 主路径`);\n }\n}\nconsole.log('task-031-next-tree-transport-only-ok');\nNODE",
|
||
"timeout_seconds": 1200
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "Next 树域主路径已收口为 transport/compat,eslint 通过且 buildDocumentTree 主路径检查通过。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-032",
|
||
"title": "执行 TreeShell Phase C-1:在 mnote-web 内接入 Leptos 正式 tree shell 骨架,打通 loader/command dispatcher/local UI state store",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-031"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web tree_shell_leptos_scaffold -- --nocapture && python3 - <<'PY'\nfrom pathlib import Path\ncargo = Path('/mnt/Data1T/mnote/rust/crates/mnote-web/Cargo.toml').read_text(encoding='utf-8')\nassert 'leptos' in cargo.lower(), 'mnote-web Cargo.toml 未接入 leptos'\nassert Path('/mnt/Data1T/mnote/rust/crates/mnote-web/src/tree_shell').exists(), '缺少 tree_shell 模块目录'\nprint('task-032-leptos-tree-shell-scaffold-ok')\nPY",
|
||
"timeout_seconds": 3600
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "mnote-web 已接入 Leptos tree shell scaffold,tree_shell 模块与 loader/dispatcher/state 骨架测试通过。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-033",
|
||
"title": "执行 TreeShell Phase C-2:实现 page_tree renderer,并补齐虚拟化、展开/折叠与基础行渲染",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-032"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web tree_shell_page_renderer -- --nocapture && node /mnt/Data1T/mnote/scripts/task091-tree-shell-smoke.js",
|
||
"timeout_seconds": 3600
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "page_tree renderer 与真实网页 smoke 已跑通;task091 创建/重命名/移动/导航链路通过。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-034",
|
||
"title": "执行 TreeShell Phase C-3:为正式 tree shell 接入 selection/focus/keyboard 与 DnD 状态机,收口为局部 UI state",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-033"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web tree_shell_interaction_state -- --nocapture && python3 - <<'PY'\nfrom pathlib import Path\npath = Path('/mnt/Data1T/mnote/design/tree-shell-ui-state-boundary-v1.md')\ntext = path.read_text(encoding='utf-8')\nfor needle in ['keyboard', 'selection', 'focus', 'dragging']:\n assert needle in text, f'missing {needle}'\nprint('task-034-tree-shell-interaction-state-ok')\nPY",
|
||
"timeout_seconds": 3600
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "selection/focus/keyboard/dragging 的局部 UI state 已落地并通过 Rust 测试与文档检查。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-035",
|
||
"title": "执行 TreeShell Phase C-4:补正式 tree shell 的上下文菜单、基础动作、file_tree renderer 与 picker 轻量模式",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-034"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web tree_shell_filetree_picker -- --nocapture && cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/components/documents/move-embed-picker-dialog.test.tsx src/lib/file-tree/rows.test.ts && python3 - <<'PY'\nfrom pathlib import Path\nroot = Path('/mnt/Data1T/mnote/rust/crates/mnote-web/src/tree_shell')\nassert root.exists(), '缺少正式 tree shell 目录'\nprint('task-035-tree-shell-filetree-picker-ok')\nPY",
|
||
"timeout_seconds": 3600
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "正式 tree shell 的 filetree/picker 轻量模式已补齐,新增 move-embed-picker-dialog 前端测试并通过。",
|
||
"timestamp": "2026-04-18T00:38:02Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T00:38:02Z"
|
||
},
|
||
{
|
||
"id": "task-036",
|
||
"title": "执行 TreeShell Phase C-5:去掉主路径对 iframe/postMessage 实验壳的依赖,把旧 tree shell 降回 compat/debug 用途",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-035"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "f1c1bcf0",
|
||
"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/sidebar/MnoteWebTreeShell.tsx && node - <<'NODE'\nconst fs = require('fs');\nconst sidebar = fs.readFileSync('/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx', 'utf8');\nif (sidebar.includes('<iframe') || sidebar.includes('MnoteWebTreeShell')) {\n throw new Error('sidebar.tsx 仍把实验 iframe shell 作为主路径');\n}\nconsole.log('task-036-iframe-shell-demoted-ok');\nNODE",
|
||
"timeout_seconds": 1800
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已从 sidebar.tsx 主路径移除 iframe/postMessage 实验壳依赖,Sidebar 主树先稳定回到统一 React surface。",
|
||
"timestamp": "2026-04-18T01:37:10Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T01:37:10Z",
|
||
"claimed_by": "SESSION-4"
|
||
},
|
||
{
|
||
"id": "task-037",
|
||
"title": "执行 TreeShell Phase D-1:在 Next 正式挂载新 tree shell,并完成 Sidebar 主树默认切流与快速回退护栏",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-036"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "4538f85d",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote && node scripts/task097-homepage-entry-smoke.js && node scripts/task101-tree-shell-cutover-smoke.js && cd /mnt/Data1T/mnote/wolai-frontend && node - <<'NODE'\nconst fs = require('fs');\nconst runtime = fs.readFileSync('public/mnote-env.json', 'utf8');\nif (!runtime.includes('mnoteWebTreeShellEnabled')) throw new Error('缺少 tree shell runtime flag');\nconsole.log('task-037-sidebar-cutover-ok');\nNODE",
|
||
"timeout_seconds": 3600
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已完成 Sidebar 主树默认切流与快速回退护栏,task101 验证 stream 主链与 fallback 均通过。",
|
||
"timestamp": "2026-04-18T01:37:10Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T01:37:10Z"
|
||
},
|
||
{
|
||
"id": "task-038",
|
||
"title": "执行 TreeShell Phase D-2:完成 filetree/page tree/picker 默认切流,并补高频路径回归 smoke",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-037"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "4538f85d",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote && node scripts/task101-tree-shell-cutover-smoke.js && node scripts/task102-tree-shell-regression.js && cd /mnt/Data1T/mnote/wolai-frontend && pnpm test && pnpm lint src/components/sidebar/sidebar.tsx src/components/documents/move-embed-picker-dialog.tsx src/lib/file-tree/rows.ts src/lib/tree-projection.ts",
|
||
"timeout_seconds": 5400
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已完成 page tree / filetree / picker 默认切流与高频回归,task102、前端测试与 lint 通过。",
|
||
"timestamp": "2026-04-18T01:37:10Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T01:37:10Z"
|
||
},
|
||
{
|
||
"id": "task-039",
|
||
"title": "执行 TreeShell Phase D-3:记录树域切流性能指标与真实流量回退结果,形成 cutover/perf 报告",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-038"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "4538f85d",
|
||
"validation": {
|
||
"command": "python3 - <<'PY'\nfrom pathlib import Path\npath = Path('/mnt/Data1T/mnote/design/tree-shell-cutover-performance-report-v1.md')\ntext = path.read_text(encoding='utf-8')\nfor needle in ['首包', '首次可交互', '切页延迟', '大树展开延迟', 'fallback']:\n assert needle in text, f'missing {needle}'\nprint('task-039-tree-shell-perf-report-ok')\nPY",
|
||
"timeout_seconds": 300
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已产出 tree-shell-cutover-performance-report-v1.md,记录首包、首次可交互、切页延迟、大树展开延迟与 fallback 结果。",
|
||
"timestamp": "2026-04-18T01:37:10Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T01:37:10Z"
|
||
},
|
||
{
|
||
"id": "task-040",
|
||
"title": "执行 TreeShell Phase E-1:删除剩余 page/file 特殊拼装逻辑,继续拆分 Sidebar 超大组件,并统一 page/file/picker renderer 家族",
|
||
"status": "completed",
|
||
"priority": "P1",
|
||
"depends_on": [
|
||
"task-039"
|
||
],
|
||
"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/lib/file-tree/rows.ts src/lib/tree-projection.ts src/components/documents/move-embed-picker-dialog.tsx && node - <<'NODE'\nconst fs = require('fs');\nconst sidebar = fs.readFileSync('/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx', 'utf8');\nfor (const needle of ['PrivateTree', 'FileTree', 'MnoteWebTreeShell']) {\n if (sidebar.includes(needle)) throw new Error(`sidebar.tsx 仍直接耦合 ${needle}`);\n}\nconsole.log('task-040-tree-cleanup-ok');\nNODE",
|
||
"timeout_seconds": 2400
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已把 page/file/picker 主路径统一到同一套 tree surface/adapter 家族,sidebar.tsx 不再直接耦合旧树组件名。",
|
||
"timestamp": "2026-04-18T01:37:10Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T01:37:10Z"
|
||
},
|
||
{
|
||
"id": "task-041",
|
||
"title": "执行 Final QA:回写架构文档与 harness 状态,勾选 design/sidebar-pagetree-filetree-rust-web-rebuild-v1.md 全部 checklist 并完成最终验收",
|
||
"status": "completed",
|
||
"priority": "P0",
|
||
"depends_on": [
|
||
"task-040"
|
||
],
|
||
"attempts": 1,
|
||
"max_attempts": 3,
|
||
"started_at_commit": "4538f85d",
|
||
"validation": {
|
||
"command": "cd /mnt/Data1T/mnote/wolai-frontend && pnpm test && cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web -- --nocapture && cd /mnt/Data1T/mnote && python3 - <<'PY'\nfrom pathlib import Path\npath = Path('/mnt/Data1T/mnote/design/sidebar-pagetree-filetree-rust-web-rebuild-v1.md')\ntext = path.read_text(encoding='utf-8')\nassert '- [ ]' not in text, '设计文档仍存在未完成 checklist'\nprint('task-041-sidebar-tree-rust-web-rebuild-complete')\nPY",
|
||
"timeout_seconds": 7200
|
||
},
|
||
"on_failure": {
|
||
"cleanup": null
|
||
},
|
||
"error_log": [],
|
||
"checkpoints": [
|
||
{
|
||
"step": 1,
|
||
"total": 1,
|
||
"description": "已更新架构文档 checklist,完成 task097/task101/task102、pnpm test、cargo test 与最终验收。",
|
||
"timestamp": "2026-04-18T01:37:10Z"
|
||
}
|
||
],
|
||
"completed_at": "2026-04-18T01:37:10Z"
|
||
}
|
||
],
|
||
"session_count": 5,
|
||
"last_session": "2026-04-18T01:37:10Z"
|
||
}
|