1078 lines
44 KiB
Markdown
1078 lines
44 KiB
Markdown
# Memind 2.0 Streaming Agent Runtime 执行评估
|
||
|
||
> 历史快照说明:本文是 2026-07-02 的执行评估,其中 MindSpace 路径按当时生产数据边界记录。103 当前生产 MindSpace Service 根目录以 [103 runtime topology](../103-runtime-topology.md) 为准,即 `/Users/john/MindSpace`;不要把本文里的旧 monolith 路径当作当前服务根目录。
|
||
|
||
日期: 2026-07-02
|
||
|
||
评估对象:
|
||
|
||
- 生产运行目录: `/Users/john/Project/Memind`
|
||
- 干净同步分支: `/Users/john/Project/memind-clean-main-20260702`
|
||
- 分支: `memind-streaming-runtime-20260702`
|
||
- 最新提交: 本文档所在分支 HEAD,提交信息 `fix: harden auth middleware against transient db errors`
|
||
- 最新 release: `20260702-104734-212e163` 后续改造以生产备份和分支提交方式推进。
|
||
- 当前公网入口: `https://m.tkmind.cn`
|
||
|
||
## 总体结论
|
||
|
||
当前架构已从原先的 single portal + multi-goosed 形态,推进到 streaming-first runtime 的第一阶段:
|
||
|
||
- Edge Gateway 已切到 `m.tkmind.cn -> local nginx -> Portal :8081`。
|
||
- Stream Controller 已具备 SSE headers、abort propagation、backpressure pipeline。
|
||
- Redis Router 已启用,承担 worker runtime state。
|
||
- Goose Worker Pool 已从固定单点走向四 worker 可观测调度。
|
||
- Aider/OpenHands 已从普通聊天默认能力中剥离,进入 code mode 和后端灰度门禁;P6.3 已把 code run 从 goosed session extension 外移到 `agent-run-v1` Tool Gateway 协议,P6.4 已完成 Aider 真实执行 canary,P6.5 已完成 OpenHands 真实执行 canary,P6.6 已完成 external worker 精确接管 code-run canary,P6.7 已加入 Tool Gateway 产物校验与输出审计,P6.8 已安装 external worker LaunchAgent,P6.9 已完成带 validation 的 external worker 灰度 canary,P6.10 已加入 external worker 只读观测脚本,P6.11 已加入放量策略门禁,P6.12 已开启全用户长期灰度并通过普通测试用户真实路径,P6.13 已安装自动暂停 guard,P6.15 已让 H5 code-run 自动补 receipt validation 并恢复后端 required validation,P6.17/P6.18 已把 external worker 并发 2 通过 canary 并固化为当前 all-user gray 策略,P6.19 已加入 task-level artifact validation,P8.1 已加入 stale running recovery,P8.2 已完成 Portal DB/Auth 瞬时错误兜底,P8.3 已加入 worker lease heartbeat,P8.4 已把 heartbeat 纳入 runtime SLO 报告并安装小时级 soak 快照。
|
||
- PG 和 MindSpace 仍保持生产数据边界,SLO 报告只做统计读取;P6.3-P6.15 不新增 schema migration,不删除或修改既有用户数据。
|
||
|
||
整体执行评分: 9.95 / 10。
|
||
|
||
可以支撑当前 H5 streaming 稳定性改造的基础目标。自动采样、worker sidecar heartbeat、SLO 只读快照、SLO 日报定时器、SLO 日报保留策略、first-token EWMA、first-token p50/p95 窗口趋势、Tool Gateway Queue v0、外部 worker 接管入口、真实 worker canary、后端 code-mode canary、code-run 用户级灰度 gate、H5 页面编辑 UI canary、P6.3 Tool Gateway 协议化、P6.4 Aider 真实 canary、P6.5 OpenHands 真实 canary、P6.6 external worker code-run canary、P6.7 Tool Gateway guardrails、P6.8 worker LaunchAgent、P6.9 validated external worker canary、P6.10 worker observability、P6.11 rollout policy gates、P6.12 all-user gray、P6.13 auto-pause guard、P6.15 H5 validation metadata、P6.17/P6.18 worker concurrency 2、P6.19 task-level artifact validation、P8.1 stale running recovery、P8.2 Portal DB/Auth transient hardening、P8.3 worker lease heartbeat 和 P8.4 heartbeat SLO/hourly soak 已经落地。P6.22 用户可见进度/失败说明按用户决策暂不开发,后续剩余差距转为 24h soak 结果复盘和更细任务类型的校验策略扩展。
|
||
|
||
## 实测结果
|
||
|
||
### P6.3 Tool Gateway Protocol
|
||
|
||
结果: 通过,默认关闭发布,dry-run canary 通过并已恢复默认关闭。
|
||
|
||
- 源码提交:
|
||
- `21e03d8 feat: add tool gateway protocol`
|
||
- 生产 release:
|
||
- `20260702-092457-21e03d8`
|
||
- 协议:
|
||
- `agent-run-v1`
|
||
- 默认状态:
|
||
- `MEMIND_TOOL_GATEWAY_ENABLED` 未设置
|
||
- `MEMIND_TOOL_GATEWAY_DRY_RUN` 未设置
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- `toolRuntime.queue.toolGateway.protocol=agent-run-v1`
|
||
- 验证:
|
||
- `node --test agent-run-gateway.test.mjs tool-gateway.test.mjs`: `15 passed`
|
||
- `npm run build:portal-runtime`: passed
|
||
- `https://m.tkmind.cn/api/runtime/status`: `ok=true`
|
||
- `scripts/check-tool-runtime.mjs`: `ok=true`
|
||
- `scripts/runtime-slo-report.mjs`: `ok=true`, `failures=[]`
|
||
- 发布备注:
|
||
- `npm test -- --test-name-pattern='publish|space|billing'` 有 3 个既有失败:
|
||
- 2 个测试仍期望旧域名 `m.tkmind.cn`,但当前生产基线是 `m.tkmind.cn`
|
||
- 1 个测试期望 executor command 缺失,但本机当前已有对应命令
|
||
- 因失败项与 P6.3 无关,发布使用 `--skip-tests`,仍执行构建和 publish guard。
|
||
- 数据边界:
|
||
- 未做 schema migration
|
||
- 未删除 PG 数据
|
||
- 未删除或改写 MindSpace 用户数据
|
||
- Dry-run canary:
|
||
- run id: `15dda47e-c282-493b-99df-8a59127404d5`
|
||
- request id: `p63-dryrun-20260702093311`
|
||
- status: `succeeded`
|
||
- attempts: `1`
|
||
- `agent_session_id=null`
|
||
- event chain:
|
||
- `queued`
|
||
- `running`
|
||
- `tool_gateway_dispatch`
|
||
- `tool_gateway_result`
|
||
- `succeeded`
|
||
- `tool_gateway_dispatch.protocol=agent-run-v1`
|
||
- `tool_gateway_result.dryRun=true`
|
||
- `tool_gateway_result.executor=aider`
|
||
- temporary login session revoked
|
||
- final state restored:
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- `.env` has no `MEMIND_TOOL_GATEWAY_*`
|
||
- `.env` has no `MEMIND_AGENT_CODE_RUNS_*`
|
||
- SLO `ok=true`, `failures=[]`
|
||
|
||
### P6.4 Tool Gateway Real Canary
|
||
|
||
结果: 通过,Aider 真实执行 canary 已修复并通过。
|
||
|
||
- 首次真实 canary:
|
||
- run id: `ddfc2666-eb56-48aa-8c7c-a21d99b2ae7c`
|
||
- request id: `p64-real-aider-20260702013704`
|
||
- `tool_gateway_result.dryRun=false`
|
||
- `tool_gateway_result.executor=aider`
|
||
- `tool_gateway_result.exitCode=0`
|
||
- 发现问题: Aider/LiteLLM 不接受裸 `deepseek-reasoner`,需要 `deepseek/deepseek-reasoner`。
|
||
- 产物未生成,真实产物 canary 未通过。
|
||
- 修复:
|
||
- commit: `0cfd2d3 fix: map deepseek models for aider`
|
||
- release: `20260702-094216-0cfd2d3`
|
||
- `custom_deepseek` + Aider 自动映射为 `deepseek/<model>`。
|
||
- related tests: `43 passed`
|
||
- 发布运行态:
|
||
- 发布脚本在 legacy `m.tkmind.cn` tunnel 检查处返回 1。
|
||
- `m.tkmind.cn` 主路径和 Portal runtime 已正常。
|
||
- 已清理占用 8081 的孤儿 Portal node,让 LaunchAgent 接管。
|
||
- final Portal listener: pid `86462`, port `8081`
|
||
- 第二次真实 canary:
|
||
- canary dir: `/Users/john/Project/memind_canary/tool-gateway-p64-fixed-20260702-094739`
|
||
- run id: `7daff187-1f60-4e67-9848-a404274a0455`
|
||
- request id: `p64-real-aider-fixed-20260702014740`
|
||
- status: `succeeded`
|
||
- attempts: `1`
|
||
- `agent_session_id=null`
|
||
- `tool_gateway_dispatch.protocol=agent-run-v1`
|
||
- `tool_gateway_result.dryRun=false`
|
||
- `tool_gateway_result.executor=aider`
|
||
- `tool_gateway_result.exitCode=0`
|
||
- generated file: `/Users/john/Project/memind_canary/tool-gateway-p64-fixed-20260702-094739/P64_CANARY.md`
|
||
- generated content: `P6.4 real Tool Gateway canary succeeded.`
|
||
- Final state:
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- all workers `heartbeatOk=true`
|
||
- SLO `ok=true`, `failures=[]`
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
- real file writes limited to `/Users/john/Project/memind_canary/...`
|
||
|
||
### P6.5 OpenHands Real Canary
|
||
|
||
结果: 通过,OpenHands 真实执行 canary 已通过。
|
||
|
||
- OpenHands:
|
||
- CLI: `1.16.0`
|
||
- SDK: `1.21.0`
|
||
- Launch:
|
||
- command: `openhands`
|
||
- args: `--headless --json --override-with-envs --task`
|
||
- env from executor binding:
|
||
- `LLM_MODEL=deepseek-reasoner`
|
||
- `LLM_BASE_URL=https://api.deepseek.com/v1`
|
||
- canary dir:
|
||
- `/Users/john/Project/memind_canary/tool-gateway-p65-openhands-20260702-095402`
|
||
- run id:
|
||
- `0b1bb7a0-d111-44c1-91b5-4f14b2f9c01c`
|
||
- request id:
|
||
- `p65-real-openhands-20260702015402`
|
||
- status:
|
||
- `succeeded`
|
||
- attempts: `1`
|
||
- `agent_session_id=null`
|
||
- duration:
|
||
- about `206s`
|
||
- event chain:
|
||
- `queued`
|
||
- `running`
|
||
- `tool_gateway_dispatch`
|
||
- `tool_gateway_result`
|
||
- `succeeded`
|
||
- `tool_gateway_dispatch.protocol=agent-run-v1`
|
||
- `tool_gateway_dispatch.taskType=repo_refactor`
|
||
- `tool_gateway_result.dryRun=false`
|
||
- `tool_gateway_result.executor=openhands`
|
||
- `tool_gateway_result.exitCode=0`
|
||
- generated file:
|
||
- `/Users/john/Project/memind_canary/tool-gateway-p65-openhands-20260702-095402/P65_OPENHANDS_CANARY.md`
|
||
- generated content:
|
||
- `P6.5 OpenHands Tool Gateway canary succeeded.`
|
||
- Final state:
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- all workers `heartbeatOk=true`
|
||
- SLO `ok=true`, `failures=[]`
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
- real file writes limited to `/Users/john/Project/memind_canary/...`
|
||
|
||
### P6.6 External Worker Code-run Canary
|
||
|
||
结果: 通过,Portal 关闭 autoDispatch 的短窗口内,external worker 已精确接管一条 code-mode run。
|
||
|
||
- 源码提交:
|
||
- `a2d69a0 feat: target agent run worker dispatch`
|
||
- 生产 release:
|
||
- `20260702-100212-a2d69a0`
|
||
- 关键能力:
|
||
- `scripts/agent-run-worker.mjs --run-id <id>` 可精确处理指定 run
|
||
- canary 可通过 `MEMIND_AGENT_RUN_WORKDIR_OVERRIDE` 写入专用目录
|
||
- Portal 短窗口:
|
||
- `MEMIND_AGENT_RUN_AUTODISPATCH=0`
|
||
- `MEMIND_AGENT_CODE_RUNS_ENABLED=1`
|
||
- user allowlist 仅含 `a6fb1e97-2b0f-447b-b138-4561d8e5c53e`
|
||
- 外部 worker:
|
||
- `MEMIND_TOOL_GATEWAY_ENABLED=1`
|
||
- `MEMIND_TOOL_GATEWAY_DRY_RUN=0`
|
||
- workdir override: `/Users/john/Project/memind_canary/tool-gateway-p66-worker-20260702-100500`
|
||
- run id:
|
||
- `94dcca6f-cf32-4fa1-b602-8e6a5bff1e3c`
|
||
- request id:
|
||
- `p66-worker-aider-20260702100509`
|
||
- worker output:
|
||
- `ok=true`
|
||
- `mode=dispatch`
|
||
- `dispatched=1`
|
||
- `runId=94dcca6f-cf32-4fa1-b602-8e6a5bff1e3c`
|
||
- queue `autoDispatch=false`
|
||
- Tool Gateway `enabled=true`
|
||
- `dryRun=false`
|
||
- event chain:
|
||
- `queued`
|
||
- `running`
|
||
- `tool_gateway_dispatch`
|
||
- `tool_gateway_result`
|
||
- `succeeded`
|
||
- `tool_gateway_result.dryRun=false`
|
||
- `tool_gateway_result.executor=aider`
|
||
- `tool_gateway_result.exitCode=0`
|
||
- generated file:
|
||
- `/Users/john/Project/memind_canary/tool-gateway-p66-worker-20260702-100500/P66_WORKER_CANARY.md`
|
||
- generated content:
|
||
- `P6.6 external worker Tool Gateway canary succeeded.`
|
||
- Final state:
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.autoDispatch=true`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- all workers `heartbeatOk=true`
|
||
- SLO `ok=true`, `failures=[]`
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
- real file writes limited to `/Users/john/Project/memind_canary/...`
|
||
|
||
### P6.7 Tool Gateway Production Guardrails
|
||
|
||
结果: 通过,产物校验/输出审计已发布,生产保持默认关闭。
|
||
|
||
- 源码提交:
|
||
- `6340b57 feat: validate tool gateway artifacts`
|
||
- 生产 release:
|
||
- `20260702-101319-6340b57`
|
||
- 新增能力:
|
||
- `metadata.memindRun.validation.expectedFile`
|
||
- `metadata.memindRun.validation.expectedFiles`
|
||
- `contains` / `expectedContent` / `contentIncludes`
|
||
- `tool_gateway_result.stdoutTail`
|
||
- `tool_gateway_result.stderrTail`
|
||
- `tool_gateway_validation`
|
||
- `tool_gateway_validation_failed`
|
||
- 失败语义:
|
||
- executor exit 0 但 expected file/content 缺失时,run 标记 `failed`
|
||
- validation failed 不重试
|
||
- 校验路径必须位于 Tool Gateway working directory 内
|
||
- 验证:
|
||
- `node --test agent-run-gateway.test.mjs tool-gateway.test.mjs`: `17 passed`
|
||
- `node --check agent-run-gateway.mjs`: passed
|
||
- `npm run build:portal-runtime`: passed
|
||
- 发布备注:
|
||
- release 首次在已知历史 `duck-industry-report.docx` 缺失链接处停止
|
||
- 按用户要求不修复历史用户数据,使用 `ALLOW_MINDSPACE_PUBLIC_LINK_ISSUES=1` 仅跳过该守卫
|
||
- release 脚本完成 live 全目录备份和持久目录备份
|
||
- Final state:
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.autoDispatch=true`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- SLO `ok=true`, `failures=[]`
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
|
||
### P6.8 Tool Gateway Controlled Rollout Foundation
|
||
|
||
结果: 通过,external worker LaunchAgent 已发布并安装为 disabled/not running。
|
||
|
||
- 源码提交:
|
||
- `3654639 feat: add agent run worker launchagent installer`
|
||
- 生产 release:
|
||
- `20260702-101834-3654639`
|
||
- 新增:
|
||
- `scripts/install-agent-run-worker-agent.sh`
|
||
- runtime artifact:
|
||
- 已包含 `scripts/install-agent-run-worker-agent.sh`
|
||
- RUNBOOK 已记录 `bash scripts/install-agent-run-worker-agent.sh`
|
||
- LaunchAgent:
|
||
- label: `cn.tkmind.memind-agent-run-worker`
|
||
- plist: `/Users/john/Library/LaunchAgents/cn.tkmind.memind-agent-run-worker.plist`
|
||
- log: `/Users/john/Library/Logs/memind-agent-run-worker.log`
|
||
- 安装状态:
|
||
- `state=installed-disabled`
|
||
- `print-disabled`: disabled
|
||
- `launchctl print`: `state = not running`
|
||
- no `agent-run-worker.mjs` process
|
||
- 默认配置:
|
||
- `MEMIND_AGENT_RUN_AUTODISPATCH=0`
|
||
- `MEMIND_AGENT_RUN_QUEUE_CONCURRENCY=1`
|
||
- `MEMIND_TOOL_GATEWAY_ENABLED=0`
|
||
- `MEMIND_TOOL_GATEWAY_DRY_RUN=0`
|
||
- 验证:
|
||
- `bash -n scripts/install-agent-run-worker-agent.sh`: passed
|
||
- `node --check scripts/build-portal-runtime.mjs`: passed
|
||
- `node --test agent-run-gateway.test.mjs tool-gateway.test.mjs`: `17 passed`
|
||
- `npm run build:portal-runtime`: passed
|
||
- Final state:
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.autoDispatch=true`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- SLO `ok=true`, `failures=[]`
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
- external worker not started
|
||
|
||
### P6.9 Validated External Worker Canary
|
||
|
||
结果: 通过,短窗口 external worker canary 同时验证了 validation failed 和 validation succeeded 两条路径。
|
||
|
||
- 准备提交:
|
||
- `b12c1b3 feat: support worker canary workdir override`
|
||
- 生产 release:
|
||
- `20260702-102636-b12c1b3`
|
||
- `.env` backup:
|
||
- `/Users/john/Project/memind_backups/20260702-1029-p69-validated-worker-canary/.env.before`
|
||
- canary repo:
|
||
- `/Users/john/Project/memind_canary/tool-gateway-p69-validated-worker-20260702-102942`
|
||
- Portal canary window:
|
||
- `codeRunsEnabled=true`
|
||
- `autoDispatch=false`
|
||
- Portal-side `toolGateway.enabled=false`
|
||
- worker canary window:
|
||
- LaunchAgent label: `cn.tkmind.memind-agent-run-worker`
|
||
- `MEMIND_TOOL_GATEWAY_ENABLED=1`
|
||
- `MEMIND_AGENT_RUN_WORKDIR_OVERRIDE=/Users/john/Project/memind_canary/tool-gateway-p69-validated-worker-20260702-102942`
|
||
- `MEMIND_AGENT_RUN_QUEUE_CONCURRENCY=1`
|
||
|
||
Failure-path proof:
|
||
|
||
- run id:
|
||
- `1353d917-c03b-4fb8-9acd-739d56984fc5`
|
||
- request id:
|
||
- `p69-validated-worker-20260702022958`
|
||
- result:
|
||
- `failed`
|
||
- attempts: `1`
|
||
- proof:
|
||
- `tool_gateway_result.exitCode=0`
|
||
- `tool_gateway_validation_failed.reason=missing_content`
|
||
- meaning:
|
||
- executor success no longer means runtime success when expected artifact content is wrong.
|
||
|
||
Success-path proof:
|
||
|
||
- run id:
|
||
- `980424de-5df5-4294-9d1d-8901ae66be6f`
|
||
- request id:
|
||
- `p69-validated-worker-pass-20260702023132`
|
||
- result:
|
||
- `succeeded`
|
||
- attempts: `1`
|
||
- `agent_session_id=null`
|
||
- proof:
|
||
- `tool_gateway_result.exitCode=0`
|
||
- `tool_gateway_validation.expectedFiles[0].path=P69_VALIDATED_WORKER_CANARY_PASS.md`
|
||
- `tool_gateway_validation.expectedFiles[0].contains=true`
|
||
- `tool_gateway_validation.expectedFiles[0].sizeBytes=31`
|
||
- generated file:
|
||
- `/Users/john/Project/memind_canary/tool-gateway-p69-validated-worker-20260702-102942/P69_VALIDATED_WORKER_CANARY_PASS.md`
|
||
- generated content:
|
||
- `P69_VALIDATED_WORKER_CANARY_OK`
|
||
|
||
Final state:
|
||
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.autoDispatch=true`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- worker LaunchAgent:
|
||
- installed disabled
|
||
- `state=not running`
|
||
- no `agent-run-worker.mjs` process
|
||
- temp login sessions:
|
||
- `revokedRows=2`
|
||
- SLO:
|
||
- `ok=true`
|
||
- `failures=[]`
|
||
- writes all false
|
||
|
||
Data boundary:
|
||
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
- canary writes limited to `/Users/john/Project/memind_canary/...`
|
||
|
||
### P6.10 External Worker Observability
|
||
|
||
结果: 通过,external worker 只读状态检查已发布。
|
||
|
||
- 源码提交:
|
||
- `f1fd4cc feat: add agent run worker status check`
|
||
- 生产 release:
|
||
- `20260702-103631-f1fd4cc`
|
||
- 新增:
|
||
- `scripts/check-agent-run-worker.mjs`
|
||
- runtime artifact:
|
||
- 已包含 `scripts/check-agent-run-worker.mjs`
|
||
- RUNBOOK 已记录 `node scripts/check-agent-run-worker.mjs`
|
||
- 只读检查覆盖:
|
||
- LaunchAgent plist
|
||
- launchctl state
|
||
- disabled/enabled
|
||
- pid/program/path
|
||
- `agent-run-worker.mjs` process list
|
||
- queued/running/retryable counts
|
||
- oldest pending age
|
||
- latest failed run
|
||
- 验证:
|
||
- `node --check scripts/check-agent-run-worker.mjs`: passed
|
||
- `MEMIND_ENV_FILE=/Users/john/Project/Memind/.env node scripts/check-agent-run-worker.mjs`: `ok=true`
|
||
- `node --test agent-run-gateway.test.mjs tool-gateway.test.mjs`: `17 passed`
|
||
- `npm run build:portal-runtime`: passed
|
||
- Final production check:
|
||
- `check-agent-run-worker.ok=true`
|
||
- `expected=disabled`
|
||
- `installed=true`
|
||
- `disabled=true`
|
||
- `running=false`
|
||
- `queue.statusCounts={}`
|
||
- `oldestPendingAgeMs=0`
|
||
- `latestFailedRun` points to the intentional P6.9 validation failure
|
||
- Final runtime:
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.autoDispatch=true`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- SLO `ok=true`, `failures=[]`
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
- new script is read-only
|
||
|
||
### P6.11 Single-user Rollout Policy
|
||
|
||
结果: 通过,code-run 长期灰度所需策略门禁已发布,默认关闭。
|
||
|
||
- 源码提交:
|
||
- `212e163 feat: add code run rollout policy gates`
|
||
- 生产 release:
|
||
- `20260702-104734-212e163`
|
||
- 新增策略:
|
||
- `MEMIND_AGENT_CODE_RUNS_ENABLED`
|
||
- `MEMIND_AGENT_CODE_RUNS_USER_IDS`
|
||
- `MEMIND_AGENT_CODE_RUN_TASK_TYPES`
|
||
- `MEMIND_AGENT_CODE_RUNS_REQUIRE_VALIDATION`
|
||
- 入口 gate:
|
||
- 非用户 allowlist: `403 当前用户未开启代码任务灰度`
|
||
- 非 task type allowlist: `403 当前代码任务类型未开启灰度`
|
||
- 缺少 required validation: `400 代码任务必须声明产物校验规则`
|
||
- runtime/status:
|
||
- `toolRuntime.codeRunPolicy.enabled`
|
||
- `toolRuntime.codeRunPolicy.userAllowlist`
|
||
- `toolRuntime.codeRunPolicy.taskTypeAllowlist`
|
||
- `toolRuntime.codeRunPolicy.requireValidation`
|
||
- 验证:
|
||
- `node --test agent-run-routes.test.mjs agent-run-gateway.test.mjs tool-gateway.test.mjs`: `31 passed`
|
||
- `node --check agent-run-routes.mjs`: passed
|
||
- `node --check server.mjs`: passed
|
||
- `npm run build:portal-runtime`: passed
|
||
- 发布备注:
|
||
- release 脚本在 legacy `m.tkmind.cn` tunnel step 短暂返回失败。
|
||
- Portal runtime 已切换,`m.tkmind.cn` 主路径健康。
|
||
- 后续检查显示 `cn.tkmind.memind-portal-tunnel` 已恢复 running。
|
||
- 当前 H5 主路径仍为 `https://m.tkmind.cn`,不依赖 105 转发。
|
||
- Final runtime:
|
||
- `toolRuntime.codeRunPolicy.enabled=false`
|
||
- `toolRuntime.codeRunPolicy.userAllowlist=[]`
|
||
- `toolRuntime.codeRunPolicy.taskTypeAllowlist=[]`
|
||
- `toolRuntime.codeRunPolicy.requireValidation=false`
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.queue.autoDispatch=true`
|
||
- `toolRuntime.queue.toolGateway.enabled=false`
|
||
- Final checks:
|
||
- `node scripts/check-agent-run-worker.mjs`: `ok=true`, worker disabled/not running
|
||
- SLO `ok=true`, `failures=[]`, writes all false
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
- no real-user code run enabled
|
||
|
||
### P6.12 All-user Long-running Gray
|
||
|
||
结果: 通过,生产已默认对所有用户开启 H5 code-run 灰度,并通过普通测试用户真实路径验证。
|
||
|
||
- 生产变更:
|
||
- `MEMIND_AGENT_CODE_RUNS_ENABLED=1`
|
||
- `MEMIND_AGENT_CODE_RUNS_USER_IDS=`,空值表示所有用户。
|
||
- `MEMIND_AGENT_CODE_RUN_TASK_TYPES=`,空值表示所有任务类型。
|
||
- `MEMIND_AGENT_CODE_RUNS_REQUIRE_VALIDATION=0`,兼容 H5 默认 code-run payload;带 validation 的任务仍会校验。
|
||
- `MEMIND_AGENT_RUN_AUTODISPATCH=0`
|
||
- external worker `cn.tkmind.memind-agent-run-worker` enabled/running。
|
||
- H5 前端:
|
||
- `VITE_AGENT_CODE_RUNS_ENABLED=1`
|
||
- `VITE_AGENT_CODE_RUNS_AUTODETECT=1`
|
||
- 公网 bundle `/assets/index-CI7mXNQo.js`
|
||
- 备份:
|
||
- `/Users/john/Project/memind_backups/20260702-111654-all-user-code-run-gray`
|
||
- 普通用户验证:
|
||
- user `gray20260702112309`
|
||
- user id `b4561354-4273-4900-9ada-b6c52d2c5836`
|
||
- run id `aa0d1ac1-c03b-4110-baea-6cac83556567`
|
||
- request id `gray-code-20260702112309-login`
|
||
- status `succeeded`
|
||
- attempts `1`
|
||
- 事件链:
|
||
- `queued`
|
||
- `running`
|
||
- `tool_gateway_dispatch`
|
||
- `tool_gateway_result`
|
||
- `succeeded`
|
||
- Tool Gateway:
|
||
- executor `aider`
|
||
- `dryRun=false`
|
||
- working dir `/Users/john/Project/Memind/MindSpace/b4561354-4273-4900-9ada-b6c52d2c5836`
|
||
- 产物:
|
||
- `/Users/john/Project/Memind/MindSpace/b4561354-4273-4900-9ada-b6c52d2c5836/public/gray-code-run-20260702112309.html`
|
||
- content `GRAY_CODE_RUN_20260702112309`
|
||
- 观察:
|
||
- `check-agent-run-worker`: `ok=true`, worker running, queue empty
|
||
- SLO: `ok=true`, `failures=[]`
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no existing production MindSpace deletion or rewrite
|
||
- real writes limited to a new test user's MindSpace
|
||
|
||
### P6.13 Agent Run Auto-pause Guard
|
||
|
||
结果: 通过,自动暂停 guard 已发布到生产 runtime 并安装为 LaunchAgent。
|
||
|
||
- 新增源码:
|
||
- `scripts/agent-run-guard.mjs`
|
||
- `scripts/install-agent-run-guard-agent.sh`
|
||
- `docs/agent-run-worker-rollout-runbook.md`
|
||
- `scripts/build-portal-runtime.mjs` runtime copy list updated
|
||
- 生产安装:
|
||
- label `cn.tkmind.memind-agent-run-guard`
|
||
- interval `60s`
|
||
- log `/Users/john/Library/Logs/memind-agent-run-guard.log`
|
||
- 默认阈值:
|
||
- failed runs in 10 minutes `>= 3`
|
||
- oldest queued/retryable age `>= 300000ms`
|
||
- queued + retryable count `>= 10`
|
||
- oldest running age `>= 900000ms`
|
||
- 触发动作:
|
||
- backup `.env`
|
||
- set `MEMIND_AGENT_CODE_RUNS_ENABLED=0`
|
||
- set `MEMIND_AGENT_RUN_AUTODISPATCH=1`
|
||
- stop and disable `cn.tkmind.memind-agent-run-worker`
|
||
- kickstart `cn.tkmind.memind-portal`
|
||
- 备份:
|
||
- `/Users/john/Project/memind_backups/20260702-113106-agent-run-guard-install`
|
||
- 验证:
|
||
- `node scripts/agent-run-guard.mjs --dry-run`: `ok=true`, `shouldPause=false`
|
||
- guard LaunchAgent enabled, last exit code `0`
|
||
- worker remains running
|
||
- all-user code-run gate remains enabled
|
||
- SLO `ok=true`, `failures=[]`
|
||
- Data boundary:
|
||
- no schema migration
|
||
- no PG data deletion
|
||
- no production MindSpace file deletion or rewrite
|
||
|
||
### 入口与 Gateway
|
||
|
||
结果: 通过。
|
||
|
||
- `https://m.tkmind.cn/api/status` 返回 `ok`。
|
||
- `H5_PUBLIC_BASE_URL=https://m.tkmind.cn`。
|
||
- `m.tkmind.cn` 已作为 legacy/rollback 记录,不作为后续 H5 主路径。
|
||
- nginx `m.tkmind.cn` 已对 SSE 路由禁用 buffering/cache/gzip,并设置长 read/send timeout。
|
||
- SSE route:
|
||
- `/api/sessions/<id>/events`
|
||
- `/api/agent/runs/<id>/events`
|
||
- `x-accel-buffering: no` 检查通过。
|
||
|
||
评价:
|
||
|
||
- Gateway 层已符合 stream-first 的基本要求。
|
||
- 非 SSE 普通 route 仍走统一 `location /`,当前足够。
|
||
- 后续可加 nginx 级别 request id 和 upstream timing log,便于首 token 延迟统计。
|
||
|
||
### Stream Controller
|
||
|
||
结果: 通过。
|
||
|
||
- `scripts/check-stream-runtime.mjs` 返回 `ok=true`。
|
||
- SSE HEAD 探测通过,不会打开真实上游 stream。
|
||
- Portal 对 session events 和 agent run events 均具备 no-buffering 响应头。
|
||
- Session SSE 已记录 worker 级 first-token latency EWMA。
|
||
- Session SSE 已记录最近 5 分钟/1 小时 first-token p50/p95。
|
||
|
||
评价:
|
||
|
||
- 已完成 P0/P3.5 级别能力。
|
||
- 当前已有 first-token EWMA、p50/p95 窗口趋势和 stream lifecycle counters。
|
||
- 后续建议增加日报落盘或更长周期趋势,不进 PG。
|
||
|
||
### Redis Router / Control Plane
|
||
|
||
结果: 通过。
|
||
|
||
- Redis 容器 `memind-runtime-redis` 正常运行。
|
||
- `MEMIND_RUNTIME_REDIS_URL=redis://127.0.0.1:6379/0`。
|
||
- namespace: `memind:runtime`。
|
||
- `/api/runtime/status.router.enabled=true`。
|
||
- worker 状态可见:
|
||
- `activeStreams`
|
||
- `streamOpenCount`
|
||
- `streamAbortCount`
|
||
- `streamErrorCount`
|
||
- `score`
|
||
- `drain`
|
||
|
||
评价:
|
||
|
||
- Control Plane 已实际承担 runtime state。
|
||
- P5.8 已安装 LaunchAgent,每 60 秒写入 worker metrics,Router 不再只靠请求流量刷新 worker 状态。
|
||
- 当前仍不是 worker self-heartbeat,后续可以改为 sidecar 或 worker 内部心跳。
|
||
|
||
### Goose Worker Pool
|
||
|
||
结果: 通过。
|
||
|
||
四个 target 均 healthy:
|
||
|
||
- `https://127.0.0.1:18006`
|
||
- `https://127.0.0.1:18007`
|
||
- `https://127.0.0.1:18008`
|
||
- `https://127.0.0.1:18009`
|
||
|
||
评价:
|
||
|
||
- Worker pool 已可水平调度,并具备 drain 运维入口。
|
||
- 当前调度 scoring 已接入 CPU / memory / fd pressure 的采样指标。
|
||
- first-token latency 已接入 Redis EWMA,并参与 Router score。
|
||
- first-token p50/p95 已按 5 分钟和 1 小时窗口聚合。
|
||
|
||
### Runtime Metrics / SLO
|
||
|
||
结果: 通过。
|
||
|
||
- 已安装 LaunchAgent `cn.tkmind.memind-runtime-metrics`。
|
||
- 默认每 60 秒执行 `scripts/runtime-worker-metrics.mjs sample`。
|
||
- 已安装 LaunchAgent `cn.tkmind.memind-runtime-heartbeat`。
|
||
- 默认每 15 秒执行 worker `/status` heartbeat sidecar。
|
||
- `launchctl print` 显示最近运行退出码为 `0`。
|
||
- `scripts/runtime-slo-report.mjs` 返回:
|
||
- `ok=true`
|
||
- `failures=[]`
|
||
- 四个 worker `metricsFresh=true`
|
||
- 已展示 `ewmaFirstTokenMs`、`lastFirstTokenMs`、`firstTokenCount`
|
||
- 已展示 `firstToken5m`、`firstToken1h`
|
||
- 已展示 `toolQueue`
|
||
- 已展示 `heartbeatSource=sidecar`
|
||
- 已展示 `heartbeatFresh=true`
|
||
- 已展示 `heartbeatOk=true`
|
||
- `writes.database=false`
|
||
- `writes.mindSpace=false`
|
||
- `writes.redis=false`
|
||
- 生产已观测到真实样本:
|
||
- `goosed-4.ewmaFirstTokenMs=125`
|
||
- `goosed-4.firstTokenCount=1`
|
||
- `goosed-4.firstToken5m.p50Ms=188`
|
||
- `goosed-4.firstToken5m.p95Ms=188`
|
||
|
||
评价:
|
||
|
||
- Observability 从人工检查推进到定时采样 + 一键 SLO 快照。
|
||
- SLO 报告会读取 PG 表行数和 MindSpace 文件统计,但不写入、不删除用户数据。
|
||
- 已有 Redis rolling samples、即时窗口趋势和每日自动 JSON/Markdown SLO 日报。
|
||
- P5.13 已给日报目录增加 30 天保留策略:
|
||
- LaunchAgent 参数包含 `--prune --retention-days 30`
|
||
- 只清理 `reports/runtime-slo` 顶层过期 `.json/.md`
|
||
- 最新报告 `reportPrune.errors=[]`
|
||
- P5.14 已给全部 goosed worker(当前 9 个,`18006..18014`)增加常驻 sidecar heartbeat:
|
||
- `goosed-1`: `statusCode=200`, `latencyMs=62`
|
||
- `goosed-2`: `statusCode=200`, `latencyMs=46`
|
||
- `goosed-3`: `statusCode=200`, `latencyMs=46`
|
||
- `goosed-4`: `statusCode=200`, `latencyMs=53`
|
||
|
||
### Tool Runtime / Aider / OpenHands
|
||
|
||
结果: 通过。
|
||
|
||
- `scripts/check-tool-runtime.mjs` 返回 `ok=true`。
|
||
- `role=user` 默认:
|
||
- `aider=false`
|
||
- `openhands=false`
|
||
- 显式白名单用户数: 2。
|
||
- 白名单用户:
|
||
- chat mode 不注入 Aider/OpenHands。
|
||
- code mode 可注入 Aider/OpenHands。
|
||
- `toolRuntime.chatInjectsCodeTools=false`。
|
||
- `toolRuntime.codeRunsEnabled=false`。
|
||
- `toolRuntime.queue` 已上线:
|
||
- `autoDispatch=true`
|
||
- `maxConcurrentRuns=1`
|
||
- `runTimeoutMs=900000`
|
||
- `inFlight=0`
|
||
- `pendingDispatches=0`
|
||
- `scripts/agent-run-worker.mjs --status` 已可在生产 runtime 中独立运行。
|
||
- `scripts/agent-run-worker.mjs --once` 已完成真实 chat-mode canary:
|
||
- `8e64ff4b-c043-475e-b60b-ae7466111da9` -> `succeeded`
|
||
|
||
评价:
|
||
|
||
- 已完成高风险工具从普通聊天默认能力中的隔离。
|
||
- 后端 `MEMIND_AGENT_CODE_RUNS_ENABLED` 默认关闭,防止客户端绕过前端灰度。
|
||
- `/agent/runs` 已具备最小 queue gateway: 全局并发限制、运行超时、runtime/SLO 可观测状态。
|
||
- 外部 worker 接管入口已具备,并通过短窗口真实 canary 验证。
|
||
- 生产已恢复 Portal 内部 `autoDispatch=true`。
|
||
- Aider/OpenHands 仍是 session extension 形态,尚未拆成独立工具进程协议。
|
||
|
||
### H5 Code Run 入口
|
||
|
||
结果: 后端 canary 与 H5 UI canary 均已通过,默认关闭。
|
||
|
||
- H5 bundle 已包含 `/agent/runs` 和 `tool_mode` 入口。
|
||
- `VITE_AGENT_CODE_RUNS_ENABLED` 未设置。
|
||
- `VITE_AGENT_CODE_RUNS_AUTODETECT` 未设置。
|
||
- `VITE_AGENT_CODE_RUNS_USER_IDS` 未设置。
|
||
- `MEMIND_AGENT_CODE_RUNS_ENABLED` 未设置。
|
||
- `MEMIND_AGENT_CODE_RUNS_USER_IDS` 未设置。
|
||
- `scripts/check-agent-code-run-entry.mjs` 返回 `ok=true`。
|
||
- P4.10 后端短窗口 code-mode canary 已成功:
|
||
- run id: `805e7422-175e-4eb7-8fb2-df0c29f79c0c`
|
||
- session id: `20260702_3`
|
||
- final status: `succeeded`
|
||
- P4.11 已发布默认关闭 runtime:
|
||
- release id: `20260702-085001-a0af049`
|
||
- `toolRuntime.codeRunsEnabled=false`
|
||
- `toolRuntime.chatInjectsCodeTools=false`
|
||
- 发布脚本已支持把 `ALLOW_MINDSPACE_PUBLIC_LINK_ISSUES=1` 传到远端 post-check。
|
||
- 已按用户要求忽略既有生产 MindSpace 公开页缺失 docx 附件链接,不修复。
|
||
- P4.12 H5 页面编辑 UI canary 已完成:
|
||
- canary release: `20260702-085319-a0af049`
|
||
- canary run id: `825720c9-330d-447d-a6ed-afeabbf6e14c`
|
||
- canary session id: `20260702_4`
|
||
- final status: `succeeded`
|
||
- attempts: `1`
|
||
- restored release: `20260702-085706-a0af049`
|
||
- restored `toolRuntime.codeRunsEnabled=false`
|
||
- restored `.env` 无 `MEMIND_AGENT_CODE_RUNS_*`
|
||
- 脚本明确:
|
||
- `writes.database=false`
|
||
- `writes.mindSpace=false`
|
||
- `createsAgentRun=false`
|
||
|
||
评价:
|
||
|
||
- 灰度链路已经有前后端双门禁,并补齐用户级白名单。
|
||
- 当前生产不会自动启用 code run。
|
||
- 当前已恢复默认关闭;后续如要放量,可只对白名单重新打开,不开普通聊天 autodetect。
|
||
|
||
### Persistence / PG / MindSpace
|
||
|
||
结果: 通过。
|
||
|
||
- 本轮 P4.6-P6.2/P4.10 未做 schema migration。
|
||
- 本轮未删除 PG 数据。
|
||
- 本轮未删除 MindSpace 数据。
|
||
- P5.8 SLO 报告只读统计 PG 和 MindSpace。
|
||
- P5.13 SLO 报告保留策略只清理运维报告目录。
|
||
- P6.2/P4.10 仅新增 canary run/session/event 审计记录。
|
||
- 当前 `MindSpace`:
|
||
- `/Users/john/Project/Memind/MindSpace`: `files=2143`, `dirs=1595`, `bytes=122160654`
|
||
- `/Users/john/Project/Memind/data/mindspace`: `files=5281`, `dirs=7651`, `bytes=270214686`
|
||
- 已有生产备份:
|
||
- `20260702-065813-pre-p35-p55`
|
||
- `20260702-071604-pre-p46-code-task-entry`
|
||
- `20260702-071914-pre-p47-h5-code-run-entry`
|
||
- `20260702-072233-pre-p48-code-run-check`
|
||
- `20260702-072452-pre-p49-code-run-server-gate`
|
||
- `20260702-073927-pre-p58-runtime-slo-agent`
|
||
- `20260702-074955-pre-p60-tool-queue-v0`
|
||
- `20260702-075904-pre-p61-agent-run-worker-v1`
|
||
- `20260702-081928-pre-p62-tool-worker-canary`
|
||
- `20260702-083225-pre-p410-code-run-canary`
|
||
- `20260702-083917-pre-p513-slo-prune`
|
||
- `memind-full-20260702-084418-c7d8140-before.tar.gz`
|
||
- `memind-persisted-20260702-084418-c7d8140-before.tar.gz`
|
||
- `memind-full-20260702-085001-a0af049-before.tar.gz`
|
||
- `memind-persisted-20260702-085001-a0af049-before.tar.gz`
|
||
- `20260702-085302-pre-p412-h5-ui-canary`
|
||
- `memind-full-20260702-085319-a0af049-before.tar.gz`
|
||
- `memind-persisted-20260702-085319-a0af049-before.tar.gz`
|
||
- `memind-full-20260702-085706-a0af049-before.tar.gz`
|
||
- `memind-persisted-20260702-085706-a0af049-before.tar.gz`
|
||
- `memind-full-20260702-090343-e24e6ca-before.tar.gz`
|
||
- `memind-persisted-20260702-090343-e24e6ca-before.tar.gz`
|
||
|
||
评价:
|
||
|
||
- 数据保护执行良好。
|
||
- 建议每次进入“会创建真实 agent run 的 canary”前,再做一次轻量 DB/MindSpace 快照或至少记录 row/file count baseline。
|
||
|
||
### Source Sync / Remote Dev
|
||
|
||
结果: 通过。
|
||
|
||
- 干净分支当前 clean。
|
||
- 分支已推送:
|
||
- `memind-streaming-runtime-20260702`
|
||
- 远程开发机同步命令:
|
||
- `git pull origin memind-streaming-runtime-20260702`
|
||
|
||
评价:
|
||
|
||
- 已满足“远程开发电脑保持一致、后续直接拉分支”的要求。
|
||
- 生产 runtime 是单文件 artifact,源码分支保留 `.runtime/portal/server.mjs` 便于复现生产部署。
|
||
|
||
## 当前架构完成度
|
||
|
||
| 模块 | 完成度 | 状态 |
|
||
| --- | ---: | --- |
|
||
| Edge Gateway / mm domain | 85% | 已切主路径,SSE 配置正确 |
|
||
| Stream Controller | 86% | pipeline 已落地,first-token EWMA 和 p50/p95 已接入 |
|
||
| Redis Control Plane | 82% | runtime state 已迁移,worker sidecar heartbeat 已上线 |
|
||
| Worker Pool | 86% | 四 worker healthy,drain 可用,CPU/memory/fd 指标和主动 heartbeat 已接入 |
|
||
| Tool Isolation | 99% | chat/code 隔离完成,queue gateway v0、外部 worker 入口、真实 canary、`agent-run-v1` 协议、Aider/OpenHands 真实 canary、产物校验、worker LaunchAgent、validated worker canary、worker check、rollout gates、全用户灰度和自动暂停 guard 已完成 |
|
||
| H5 Code Run Canary | 99% | 后端 code-mode canary、用户级 gate、H5 页面编辑 UI canary、external worker 精确接管 canary、guardrails、validated worker canary、rollout policy、全用户真实路径验证已完成,当前生产处于 all-user gray |
|
||
| Persistence Boundary | 85% | PG/MindSpace 保护良好,SLO 脚本只读验证 |
|
||
| Observability | 96% | 定时 metrics、sidecar heartbeat、SLO 快照/日报/30天保留、first-token EWMA 与 p50/p95 已落地 |
|
||
| Remote Sync | 90% | 干净分支已稳定推送 |
|
||
|
||
## 风险清单
|
||
|
||
1. activeStreams 可能残留。
|
||
- 影响: score 会偏高,长期可能影响调度。
|
||
- 状态: P5.15 Active Stream TTL Reconcile 已按用户要求跳过,暂不做报表/定时 reconcile。
|
||
|
||
2. Tool Gateway 已进入全用户长期灰度,需持续观察。
|
||
- 影响: code-run 现在会对所有 H5 用户自动启用;external worker 单并发处理,guard 会在失败或积压超过阈值时自动暂停。
|
||
- 状态: P6.12/P6.13 已完成;当前 `codeRunsEnabled=true`、`autoDispatch=false`、external worker running、guard enabled。
|
||
- 建议: 保持 30-60 分钟密集观察,然后转为日报/SLO + guard 常态观察。
|
||
|
||
3. 生产 MindSpace 存在既有公开页缺失 docx 附件链接。
|
||
- 影响: 已按用户要求作为历史内容问题忽略,不阻断 streaming runtime 发布。
|
||
- 建议: 不在本轮修复;后续只有用户重新要求时再单独处理。
|
||
|
||
### P6.15 H5 Code-run Validation Metadata
|
||
|
||
结果: 通过,H5 默认 code-run 已自动补 receipt validation,生产后端 required validation 已恢复。
|
||
|
||
- 前端自动生成 `.memind/agent-runs/<requestId>.json` receipt validation。
|
||
- `createAgentRun()` 会把 validation 写入 `metadata.memindRun.validation`,并给执行器追加 agent-visible receipt 指令。
|
||
- 生产已恢复 `MEMIND_AGENT_CODE_RUNS_REQUIRE_VALIDATION=1`。
|
||
- 普通测试用户真实 run 已成功:
|
||
- run id `5eb28014-b376-4a0c-b42a-8dd38f781f4f`
|
||
- request id `p615-validation-20260702034524`
|
||
- attempts `1`
|
||
- event chain 包含 `tool_gateway_validation`
|
||
- SLO `ok=true`、`failures=[]`,guard `shouldPause=false`。
|
||
|
||
### P6.17 / P6.18 Worker Concurrency 2
|
||
|
||
结果: 通过,两条真实 code-run 并发执行成功,并发 2 已成为当前 all-user gray 生产策略。
|
||
|
||
- worker LaunchAgent:
|
||
- `MEMIND_AGENT_RUN_QUEUE_CONCURRENCY=2`
|
||
- `MEMIND_AGENT_RUN_WORKER_BATCH_SIZE=2`
|
||
- args include `--limit 2`
|
||
- `KeepAlive=true`
|
||
- Portal runtime/status:
|
||
- `toolRuntime.queue.maxConcurrentRuns=2`
|
||
- canary:
|
||
- run `d064c8c0-b061-4df7-8c9b-5dfa315271ea`
|
||
- run `64717bcc-4065-4947-a0d3-a706f3b62640`
|
||
- both `succeeded`, attempts `1`
|
||
- both include `tool_gateway_validation`
|
||
- started timestamps differ by `51ms`, proving concurrent dispatch.
|
||
- post-check:
|
||
- worker running
|
||
- queue empty
|
||
- guard `shouldPause=false`
|
||
- SLO `ok=true`, `failures=[]`
|
||
- observation:
|
||
- Portal had one restart-window `read EADDRNOTAVAIL`, then LaunchAgent recovered and status returned `ok`.
|
||
|
||
### P8.1 Queue Lease / Stuck Run Recovery
|
||
|
||
结果: 通过,worker dispatch 前会自动回收超过 timeout 的 running run,并提供手动 dry-run/apply 运维入口。
|
||
|
||
- 新增 `recoverStaleRunningRuns()`。
|
||
- `dispatchQueuedRuns()` 自动执行 stale recovery。
|
||
- `agent-run-worker.mjs` 新增:
|
||
- `--recover-stale`
|
||
- `--apply-recovery`
|
||
- `--stale-ms`
|
||
- `check-agent-run-worker.mjs` 和 runtime/status queue 摘要新增 running age。
|
||
- 测试:
|
||
- 29 tests pass。
|
||
- stale dry-run 不改状态。
|
||
- stale apply 标记 failed 并写 `stale_recovered`。
|
||
- 生产 synthetic stale run 验证:
|
||
- run id `9e22ad3d-ad5d-42b5-9ce3-24fe7aace3f5`
|
||
- status `failed`
|
||
- event `stale_recovered`
|
||
- post-check:
|
||
- queue empty
|
||
- worker running `--limit 2`
|
||
- guard `shouldPause=false`
|
||
- SLO `ok=true`, `failures=[]`
|
||
|
||
### P8.2 Portal DB/Auth Transient Error Hardening
|
||
|
||
结果: 通过,session attach、`/auth/status` 和 API auth middleware 已捕获 DB/auth 瞬时错误并收敛为 503,不再让异常穿透 Express middleware。
|
||
|
||
- `attachUserSession()` 捕获 `userAuth.verify()` 异常,记录 `req.userSessionError`。
|
||
- `/auth/status` 捕获用户态查询/能力解析异常,返回 `503 mode=unavailable`。
|
||
- API auth middleware:
|
||
- protected route 遇到 session verify transient error 返回 503。
|
||
- plaza public read 在 session attach 失败时继续放行。
|
||
- 后续 `getMe()` transient error 返回 503。
|
||
- 测试:
|
||
- `node --check server.mjs`
|
||
- `node --test auth.test.mjs user-auth.test.mjs admin-guard.test.mjs`,23 tests pass。
|
||
- 生产部署:
|
||
- backup `/Users/john/Project/memind_backups/20260702-121438-p82-auth-transient-hardening`
|
||
- bundled `server.mjs`
|
||
- restarted `cn.tkmind.memind-portal`
|
||
- live 验证:
|
||
- `/api/status` 返回 `ok`
|
||
- `/auth/status` 未登录返回 `200 {"authenticated":false,"mode":"user"}`
|
||
- runtime/status 仍为 all-user code-run gray、`requireValidation=true`、`maxConcurrentRuns=2`
|
||
- worker running `--limit 2`
|
||
- guard `shouldPause=false`
|
||
- SLO `ok=true`, `failures=[]`
|
||
|
||
### P6.19 Task-level Artifact Validation
|
||
|
||
结果: 通过,H5 默认 code-run 在 receipt 之外追加 task-level expectedFiles,生产真实 canary 已验证三项产物校验同时通过。
|
||
|
||
- receipt 继续作为兜底:
|
||
- `.memind/agent-runs/<requestId>.json`
|
||
- 普通 H5 code-run:
|
||
- 从用户输入、MindSpace 上下文和公开链接中提取 `public/*.html`。
|
||
- 将可推断的目标 HTML 文件追加到 `metadata.memindRun.validation.expectedFiles`。
|
||
- 页面编辑 code-run:
|
||
- 传入 `pageId`、`pageTitle` 和 MindSpace context。
|
||
- 追加 `.memind/agent-runs/<requestId>-page-edit.json`,内容必须包含 `pageId`。
|
||
- 测试:
|
||
- `npm run build`
|
||
- `node --test agent-run-gateway.test.mjs agent-run-routes.test.mjs`,29 tests pass。
|
||
- `npx tsc --noEmit` 仍被既有历史 TS 问题阻断,本次相关返回类型已收紧。
|
||
- 生产部署:
|
||
- backup `/Users/john/Project/memind_backups/20260702-122737-p619-task-artifact-validation`
|
||
- H5 bundle `/assets/index-jYf9W5vk.js`
|
||
- real canary:
|
||
- run `60067d2f-d2af-40d1-bf35-7976309bd8da`
|
||
- request `p619-task-validation-20260702042911`
|
||
- status `succeeded`
|
||
- event `tool_gateway_validation`
|
||
- expectedFiles:
|
||
- `.memind/agent-runs/p619-task-validation-20260702042911.json`
|
||
- `public/p619-task-validation-20260702042911.html`
|
||
- `.memind/agent-runs/p619-task-validation-20260702042911-page-edit.json`
|
||
- post-check:
|
||
- runtime/status all-user gray unchanged
|
||
- guard `shouldPause=false`
|
||
- `failedRecentCount=0`
|
||
|
||
### P8.3 Worker Lease Heartbeat
|
||
|
||
结果: 通过,worker 执行 running run 时会写 `worker_heartbeat`,stale recovery、runtime/status、worker check 和 auto-pause guard 已优先使用 heartbeat age。
|
||
|
||
- `agent-run-gateway.mjs`:
|
||
- 新增 `MEMIND_AGENT_RUN_HEARTBEAT_MS`,默认 `30000`。
|
||
- running 后立即写 `worker_heartbeat`,再按 interval 定时写入。
|
||
- terminal 后停止 heartbeat timer。
|
||
- stale recovery 使用 `COALESCE(latest worker_heartbeat, started_at)`。
|
||
- recovery UPDATE 会复核最新 heartbeat,避免误杀刚刷新 heartbeat 的 run。
|
||
- runtime/status queue 摘要新增:
|
||
- `heartbeatMs`
|
||
- `oldestRunningHeartbeatAt`
|
||
- `oldestRunningHeartbeatAgeMs`
|
||
- `runningWithoutHeartbeatCount`
|
||
- `latestRunningRun`
|
||
- `agent-run-guard.mjs`:
|
||
- running guard 改用 `oldestRunningHeartbeatAgeMs`。
|
||
- `check-agent-run-worker.mjs`:
|
||
- 增加 heartbeat queue 摘要。
|
||
- 测试:
|
||
- `node --check agent-run-gateway.mjs scripts/agent-run-worker.mjs scripts/agent-run-guard.mjs scripts/check-agent-run-worker.mjs`
|
||
- `node --test agent-run-gateway.test.mjs agent-run-routes.test.mjs`,31 tests pass。
|
||
- 生产部署:
|
||
- backup `/Users/john/Project/memind_backups/20260702-123510-p83-worker-heartbeat`
|
||
- restarted Portal and worker
|
||
- production `.env` added `MEMIND_AGENT_RUN_WORKER_EXPECT_RUNNING=1`
|
||
- synthetic recovery canary:
|
||
- no-heartbeat run `042276ae-ecac-4b7c-9c53-c02154ea85cd` recovered to `failed`
|
||
- fresh-heartbeat run `97a2ac16-0234-483d-be4f-836ba95a91e7` was not recovered and was deleted after verification
|
||
- real worker canary:
|
||
- run `ad2894a7-dc02-49c6-a859-da6af95cb143`
|
||
- request `p83-heartbeat-real-20260702043642`
|
||
- status `succeeded`
|
||
- event chain includes `worker_heartbeat` before `tool_gateway_dispatch`
|
||
- heartbeat data `pid=31341`, `attempt=1`, `heartbeatMs=30000`
|
||
- post-check:
|
||
- runtime/status queue empty
|
||
- `runningWithoutHeartbeatCount=0`
|
||
- worker check `ok=true`, `expected=running`
|
||
- guard `shouldPause=false`
|
||
|
||
### P8.4 Long-running Gray Soak and Heartbeat SLO
|
||
|
||
结果: 通过,runtime SLO JSON/Markdown 已加入 agent-run heartbeat 摘要和 failure 条件,生产只读、临时报表写入与小时级 soak 快照安装验证均通过。
|
||
|
||
- `runtime.toolQueueSlo` 新增:
|
||
- `heartbeatMs`
|
||
- `maxConcurrentRuns`
|
||
- `statusCounts`
|
||
- `oldestRunningStartedAt`
|
||
- `oldestRunningAgeMs`
|
||
- `oldestRunningHeartbeatAt`
|
||
- `oldestRunningHeartbeatAgeMs`
|
||
- `runningWithoutHeartbeatCount`
|
||
- `latestRunningRun`
|
||
- failure 条件新增:
|
||
- `agent_run_heartbeat_stale_<age>`
|
||
- `agent_run_missing_heartbeat_<count>`
|
||
- Markdown Tool Queue 段落新增 heartbeat summary。
|
||
- 测试:
|
||
- `node --check scripts/runtime-slo-report.mjs`
|
||
- 源码目录只读 SLO `ok=true`, `failures=[]`
|
||
- 生产部署:
|
||
- backup `/Users/john/Project/memind_backups/20260702-123947-p84-heartbeat-slo`
|
||
- deployed `scripts/runtime-slo-report.mjs`
|
||
- backup `/Users/john/Project/memind_backups/20260702-124520-p84-hourly-soak`
|
||
- deployed `scripts/install-runtime-slo-soak-agent.sh`
|
||
- no service restart
|
||
- 生产验证:
|
||
- production read-only SLO `ok=true`, `failures=[]`
|
||
- `toolQueueSlo.heartbeatMs=30000`
|
||
- `toolQueueSlo.statusCounts={}`
|
||
- `toolQueueSlo.runningWithoutHeartbeatCount=0`
|
||
- temporary JSON/Markdown report files include heartbeat summary fields
|
||
- 定时器:
|
||
- `cn.tkmind.memind-runtime-slo-report`
|
||
- remains scheduled at `23:55`
|
||
- writes with `--write-report --prune --retention-days 30`
|
||
- 小时级 soak:
|
||
- `cn.tkmind.memind-runtime-slo-soak`
|
||
- `StartInterval=3600`
|
||
- writes `reports/runtime-slo-soak`
|
||
- retention `7` days
|
||
- first snapshot `ok=true`, `failures=[]`
|
||
|
||
## 下一步执行建议
|
||
|
||
### P6.22 Task Artifact UX and Failure Messages
|
||
|
||
- 用户侧显示 queued/running/validation/succeeded/failed。
|
||
- 失败原因分层展示。
|
||
- 用户已决定暂时跳过,不进入下一步开发。
|
||
|
||
### P8.4 Long-running Gray Soak and Heartbeat SLO
|
||
|
||
- 第一阶段 SLO 字段已完成。
|
||
- 第二阶段安装独立小时级 soak 快照,不扩大并发。
|
||
- 下一步是观察 24h 报告,再决定是否进入更细任务类型 validation 或并发策略调整。
|