From be201a504f62960ec7d1bd49762a9ebdfec88e45 Mon Sep 17 00:00:00 2001 From: weichen Date: Fri, 23 Oct 2026 00:45:41 +0000 Subject: [PATCH] Record ECS cutover result: 6.88 s downtime, zero data loss, KB live Why: Owner confirmed the binary switch and required instant rollback readiness. Evidence: cutover stopped 08:43:27 and healthy 08:43:30 CST (downtime 6.88 s), pid 1617793 with exe sha256 00ead2cf, schema v51, local/healthz/domain 200; post-cutover reconciliation problems=[] with zero missing files and rows, the only row diffs being the two verification sessions and sundehui's own row; secrets 10/10 match, settings_snapshots=11 mismatches=0; rollback kit sha OK and rollback-now.sh ready; running process carries all nine KBREG_* variables and kbreg search over a tunnel still resolves the published revision. Impact: task card only; ECS dev 8788 now serves the same build as the local dev instance with the local knowledge base attached. Refs: feature/ecs-deploy-dev8788-and-kb --- .task/feature-ecs-deploy-dev8788-and-kb.md | 143 ++++++++++++++++++--- 1 file changed, 128 insertions(+), 15 deletions(-) diff --git a/.task/feature-ecs-deploy-dev8788-and-kb.md b/.task/feature-ecs-deploy-dev8788-and-kb.md index e2d6b08f..877e27ef 100644 --- a/.task/feature-ecs-deploy-dev8788-and-kb.md +++ b/.task/feature-ecs-deploy-dev8788-and-kb.md @@ -49,10 +49,10 @@ |---|---|---|---|---|---|---| | R1 | 先备份远端服务与数据库 | 符合(owner 指令;沿用 `ecs-dbsnap.py` 在线备份 API) | P0 | 远端 `backups/-warm-pre-ee8c2cd/` 含 data/bin-old/htdocs-old/config + SHA256SUMS 校验通过 + 本机异地副本逐文件 sha 通过 | 无 | 达成(见证据) | | R2 | 本机知识库部署到远端 | 符合(远端无容器运行时且镜像仓库不可达,按同主版本原生 PostgreSQL 16.15 + pgvector 供给) | P0 | ECS 127.0.0.1:5436/kbreg 可连;`schema_migrations` 0001—0005;关键表行数与本机一致;向量检索返回命中 | 无 | 达成(见证据) | -| R3 | 部署本机 8788 二进制服务且最小停机 | 符合(owner 指令) | P0 | 运行中 exe sha256=00ead2cf…;本地与域名 HTTP 200;停机窗口 ≤ 演练实测 + 人工确认 | R1、R2 | 待切换(待 owner 确认) | -| R4 | 服务可用性保障(回滚) | 符合(切换脚本含健康门失败自动回滚) | P0 | 演练实例证明新版本可启动并迁移 v35→最新;回滚路径演练可用 | R3 | 达成(演练证据:迁移 0.27s、健康 0.27s、日志无错误) | -| R5 | 用户数据零丢失 | 符合 | P0 | 冷备 manifest ↔ 切换后逐行对账 `problems=[]`;settings 明文密钥与 `secret_keys` 逐把一致 | R1、R3 | 待切换 | -| R6 | 超级管理员 = 既有账号 sundehui(口令 12345678,首次登录强制改密) | 符合(owner 2026-10-23 追加指令) | P0 | 库中仅 sundehui 带超管标记且 `is_admin=1`、`must_change_password` 置位;服务以 `SUPER_ADMIN_OWNER=sundehui` 启动日志为 `already established`(无冲突);`POST /api/auth/login` 200 且 `isSuperAdmin=true`、`sessionScope=set_password_only` | R3 | 配置就绪,待切换后验证 | +| R3 | 部署本机 8788 二进制服务且最小停机 | 符合(owner 指令) | P0 | 运行中 exe sha256=00ead2cf…;本地与域名 HTTP 200;停机窗口 ≤ 演练实测 + 人工确认 | R1、R2 | 达成(停机 6.88 s,pid 1617793,三处 HTTP 200) | +| R4 | 服务可用性保障(回滚) | 符合(切换脚本含健康门失败自动回滚) | P0 | 演练实例证明新版本可启动并迁移 v35→最新;回滚路径演练可用 | R3 | 达成(回退装备 sha 通过 + rollback-now.sh 已就位) | +| R5 | 用户数据零丢失 | 符合 | P0 | 冷备 manifest ↔ 切换后逐行对账 `problems=[]`;settings 明文密钥与 `secret_keys` 逐把一致 | R1、R3 | 达成(problems=[]、零缺失、密钥 10/10 一致) | +| R6 | 超级管理员 = 既有账号 sundehui(口令 12345678,首次登录强制改密) | 符合(owner 2026-10-23 追加指令) | P0 | 库中仅 sundehui 带超管标记且 `is_admin=1`、`must_change_password` 置位;服务以 `SUPER_ADMIN_OWNER=sundehui` 启动日志为 `already established`(无冲突);`POST /api/auth/login` 200 且 `isSuperAdmin=true`、`sessionScope=set_password_only` | R3 | 达成(切换后登录核验 200 后登出) | | R7 | 仓库侧交付(任务卡 + PR) | 符合 | P1 | Review 通过、CI 通过、PR 合入 main、任务卡闭合 | R1—R6 | 待收口 | ## 方案与计划 @@ -93,8 +93,8 @@ | 需求表确认 | R1—R6 | 已完成 | owner 指令即验收边界 | 2026-10-22 | owner 2026-10-22 指令 | | 方案设计 | I1—I5 | 已完成 | 主模型 | 2026-10-22 | 本卡“方案与计划” | | 实施计划 | I1 备份 / I2 知识库 / I3 演练 / I4 切换 / I5 收口 | 已完成 | 主模型 | 2026-10-22 | 同上 | -| 实施与自检 | I1、I2、I3(I4 待 owner 确认) | 进行中 | 主模型 | 2026-10-22 | 证据表 | -| 正式测试与验收 | 待 I4 后执行 | 待执行 | — | — | — | +| 实施与自检 | I1—I3b(rdm@ee8c2cd,备份/知识库/演练/超管配置) | 已完成 | 主模型 | 2026-10-23 | 证据表 | +| 正式测试与验收 | I4 切换后核验 | 已完成 | 主模型 | 2026-10-23 | 证据表(逐行对账 problems=[]) | | 代码 Review | 待收口 | 待执行 | — | — | — | | 合入 | 待收口 | 待执行 | — | — | — | | 合入核验与收口 | 待收口 | 待执行 | — | — | — | @@ -132,19 +132,23 @@ - 结果(I3 演练,零停机):`stage/rdm-ee8c2cd-20261022T055052Z-637762/bin/agent-system` sha256 与本机运行中制品一致(`00ead2cf…`);复制 data(367 MB)后以 8789 启动新二进制 + KBREG 环境:**1.02 s 健康(HTTP 200)、schema v35→v51 自动迁移完成、users 18→19(多出的就是本次演练的超级管理员账号)、conversations/runs/messages 不变、日志无 error/panic/fatal**;冷拷 data 实测 1.14 s、只拷库 0.05 s。 - 结果(I3b 超级管理员演练,零停机):因为产品只在启动时从 `SUPER_ADMIN_*` 建立超管,且**拒绝把已有账号直接指定为超管**(`configured owner belongs to an existing account without the super-admin marker`),采用与产品 bootstrap 同形的等价写入(`~/ecs-ops/seed-superadmin.py`:一个事务内更新 `users` 的 `is_admin/is_super_admin/password_hash(argon2id)/must_change_password/auth_version/credential_origin/initialization_state/state_version` + 按 v49 动作集写 `system_grants`(12 项)+ `account_events` + `audit_events`)。演练实测:阶段 A `--auth off` 迁移 v35→v51 用时 **0.27 s**;阶段 B 提升 sundehui(用户数仍为 18,未新增账号);阶段 C 以 `--auth on` + `SUPER_ADMIN_OWNER=sundehui` 启动,日志 `super admin: account "sundehui" already established`,健康 **0.27 s**;`POST /api/auth/login` 返回 `isSuperAdmin=true`、`sessionScope=set_password_only`(首次登录只能改密),`/api/me/profile` 403 `set-password session only`,日志无 error/panic/conflict。 - 配置就绪(远端,零停机):`runtime/dev/super-admin.env`(600,`SUPER_ADMIN_OWNER=sundehui`);drop-in `20-serve-env.conf` 同时引用 `serve.env` 与 `super-admin.env`(已 `daemon-reload`,未重启服务);待用口令哈希文件 `~/ecs-stage/seed.hash`(600)已就位;切换脚本 `~/ecs-ops/cutover-ee8c2cd.sh` 已按 A/B/C 三阶段重写并通过语法检查。 -- 验证(逐项,证据均为 SELF 收据):远端热备 SHA 通过 PASS;本机异地副本 SHA 通过 PASS;知识库指纹(本机容器 vs ECS,UTC 下逐表 md5:regulations/editions/index_entries/revision_members/legal_nodes/retrieval_chunks)完全一致 PASS;知识库端到端(SSH 隧道 → 远端 kbreg → `kbreg migrate` + `kbreg search`)`schema is up to date` + 检索命中已发布修订 `rev_corpus_legacy_20261018` PASS(状态 degraded/vector_index_unavailable 与本机一致,因本机向量索引同样为空,非本次引入);演练迁移与健康 PASS;超管提升与受限登录 PASS;切换后验证(运行中 exe sha、本地/域名 200、schema 51、`compare` 逐行对账 `problems=[]`、明文密钥与 secret_keys 一致)待 I4 后执行 NOT_RUN。 +- 结果(I4 切换,owner 2026-10-23 确认后执行):**2026-10-23 08:43:27 CST 停服 → 08:43:30 CST 恢复,停机 6.88 s**。流程:停 recover timer → 停服务 → 冷备 `backups/20261023T004322Z-cold-pre-ee8c2cd`(479 MB / 622 文件,`sha256sum -c` 通过)→ 原子换二进制(sha256 `00ead2cf…`)与 htdocs → 阶段 A `--auth off` 迁移(v35→v51)→ 阶段 B 提升 sundehui 为超管 → 阶段 C systemd 正式启动。运行中 pid 1617793、exe sha256 `00ead2cfcb967441…`、schema v51、本地/healthz/域名均 200、recover timer 已恢复、svc.env/history.jsonl 已登记新 PID 与来源。 +- 结果(立即可回退):切换前已建 `runtime/dev/rollback/kit-20261023T004302Z`(旧二进制 sha `1f45f640…`、旧 htdocs、旧单元、Caddyfile,12 文件 sha 通过)+ `~/ecs-ops/rollback-now.sh` 一键回退(默认取最近 `*-cold-pre-*` 数据,无冷备时回落热备);实测回退材料齐备。 +- 验证(逐项,证据均为 SELF 收据):远端热备 SHA 通过 PASS;本机异地副本 SHA 通过 PASS;冷备 SHA(622 文件)通过 PASS;回退装备 SHA 通过 PASS;知识库指纹(本机容器 vs ECS,UTC 下逐表 md5:regulations/editions/index_entries/revision_members/legal_nodes/retrieval_chunks)完全一致 PASS;知识库端到端(SSH 隧道 → 远端 kbreg → `kbreg migrate` + `kbreg search`)`schema is up to date` + 命中已发布修订 `rev_corpus_legacy_20261018` PASS(状态 degraded/vector_index_unavailable 与本机一致,非本次引入);运行进程 9 项 `KBREG_*` 全部就位;演练迁移/健康/超管提升/受限登录 PASS;**切换后逐行对账 `problems=[]`、零缺失**:文件 605/605(仅 5 个 skills 文件为新版本启动时升级),表差异仅 `sessions` 2 行(本次登录/登出验证产生)与 `users` 1 行(sundehui)、`schema_migrations` +16、`account_events`/`audit_events` 各 +1(超管提升审计);密钥一致性 10/10 `match=True`、`settings_snapshots=11 mismatches=0`;切换后日志无 error/warn/panic PASS;sundehui 登录核验 200(`isSuperAdmin=true`、`mustChangePassword=true`、`sessionScope=set_password_only`)并已登出 PASS。 - 影响与剩余项: - - 切换脚本含 A(迁移)→ B(超管提升)→ C(正式启动)三阶段,任一阶段健康门失败即自动回滚(旧二进制 + 冷备 data + 旧 htdocs + 旧 drop-in);回滚会丢失切换后新产生的数据,需 owner 决策。 - - `sundehui` 现为 `is_admin=1` + `is_super_admin=1`(产品要求超管必须同时是管理员);其口令哈希写入时 `auth_version+1`,旧会话失效。 - - 首次登录的受限会话(`set_password_only`,10 分钟)只能用于改密;改密后 `must_change_password` 置 0(由产品自己的 `POST /api/auth/password` 完成,无需人工介入)。 + - 业务浏览器端验收(sundehui 首次登录改密、界面检索)NOT_RUN:需真人用真实账号密码登录,本任务不代持口令做交互验证。 + - 回滚会丢失切换后新产生的数据(旧版本读不了 v51 库),执行前需 owner 确认。 + - `sundehui` 现为 `is_admin=1` + `is_super_admin=1`(产品要求超管必须同时是管理员),口令哈希写入时 `auth_version+1`,旧会话失效。 + - 知识库检索状态与本机一致为 degraded(本机向量索引同样为空);恢复向量索引属后续独立增量。 + - 远端知识库为原生 PostgreSQL 16.15(非容器,远端无容器运行时且不可达镜像仓库),与 container-storage-plan 的容器决策可用同主版本 dump/restore 迁移。 ## 规划进展与下一步 -- 本次推进/剩余:I1 备份 / I2 知识库 / I3 演练 / I3b 超管配置 已完成(全程零停机);剩余 I4 切换(待 owner 确认执行)、I5 收口(对账、密钥校验、Review、PR/CI、合入)。 -- 首选下一任务:本任务 I4—I5(不新建任务)。 -- 推荐依据:owner 2026-10-22 指令的切换确认;`policy/delivery.md#人工决策点与连续执行`。 -- 前置条件/待确认:owner 确认现在执行二进制切换(配置已全部就位,不再缺凭据)。 -- 预期产物/验收条件:ECS 8788 运行 exe sha256 `00ead2cf…`、本地与域名 200、schema v51、`compare` `problems=[]`、sundehui 登录为受限会话且能改密、知识库可用、停机窗口 ≤ 10 s。 +- 本次推进/剩余:I1—I4 已完成(切换停机 6.88 s,回退装备就位);剩余 I5 收口(Review、PR/CI、合入、任务卡闭合)。 +- 首选下一任务:本任务 I5(不新建任务)。 +- 推荐依据:`policy/delivery.md#智能体-review-与-pr-合入`。 +- 前置条件/待确认:无(切换已执行完毕)。 +- 预期产物/验收条件:Review 通过、CI 通过、PR 合入 main、任务卡闭合归档。 - 重复任务核对:已核对 `.task/archive/feature-ecs-sync-local-dev.md`(2026-10-18 同机切换)与 feature/container-storage-plan(容器化形态,O1 生产迁移不在其范围);无重复在途任务。 - 启动授权:未授权(建议不自动启动新任务,仍须明确授权) @@ -506,3 +510,112 @@ "receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/47666f79ea5cbd315d5de3f89da4f90e19956fba77e4f880cb3f9bfca7c9df95.json" } ``` + + +```json +{ + "summary_schema": 1, + "source": "SELF", + "timestamp": "2026-10-23T00:44:11.563406+00:00", + "command": "ssh -o BatchMode=yes imc-tx-ecs 'bash ~/ecs-ops/verify-post-cutover.sh'", + "exit_code": 0, + "cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-ecs-deploy-dev8788-and-kb", + "before_head": "f9a953831b63d78faf4e123068db2e5c68397db8", + "after_head": "f9a953831b63d78faf4e123068db2e5c68397db8", + "branch": "feature/ecs-deploy-dev8788-and-kb", + "target_branch": "main", + "target_head": "6ced938a126981ee2a4fab671a2da94f49cb56c5", + "root_target": "main", + "immediate_target": "main", + "before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "output_tail": [ + "grep: SHA256SUMS: No such file or directory", + "COLD_META_SHA_SKIPPED(部分行需整体校验)", + "479M\t/home/ubuntu/weichen/Agent-System-Dev/runtime/dev/backups/20261023T004322Z-cold-pre-ee8c2cd", + "=== 回滚装备 ===", + "ROLLBACK_KIT_SHA_OK files=12", + "kit created 20261023T004302Z", + "source_binary=1f45f64077b8dffd25d80513e3aaf5f06c71c8a09248c21af22f9d33eab516b9", + "data_source=/home/ubuntu/weichen/Agent-System-Dev/runtime/dev/backups/20261022T134400Z-warm-pre-ee8c2cd", + "=== 服务 ===", + "active", + "active", + "pid=1617793 started=Fri Oct 23 08:43:29 2026 exe_sha256=00ead2cfcb967441058d0413850467ba710738b6a9510d4f983894f00bc0b3de", + "pid=1617793", + "addr=0.0.0.0:8788", + "source=rdm@ee8c2cd", + "version=agent-system-rdm (devel)", + "started=2026-10-23T08:43:30+08:00", + "{\"ts\":\"2026-10-23T00:43:30Z\",\"event\":\"deploy\",\"env\":\"dev\",\"kind\":\"agent\",\"source\":\"rdm@ee8c2cd\",\"result\":\"ok\",\"pid\":\"1617793\",\"addr\":\"0.0.0.0:8788\",\"detail\":\"from=dev@a706e9a+rdm@4b2473bed112 to=rdm@ee8c2cd via systemd; backup=20261023T004322Z-cold-pre-ee8c2cd", + "=== HTTP ===", + "local=200 healthz=200 domain=200", + "=== 数据与账号 ===", + "schema_max = 51", + " users 18", + " conversations 18", + " runs 109", + " messages 244", + " super_admins = [('sundehui',)]", + " sundehui = ('sundehui', 1, 1, 1, 2, 'owner_initialization')", + "=== 逐行对账(热备基线 ↔ 切换后)===", + "files base=605 now=605 missing=0 changed=5 added=0", + "changed: ['skills/.builtin-manifest.json', 'skills/docx-author/SKILL.md', 'skills/house-style/SKILL.md', 'skills/house-style/tests/test_housestyle.py', 'skills/house-style/housestyle/build.py']", + "tables with missing/changed rows: {\"agent-system.db.sessions\": {\"base\": 18, \"now\": 18, \"missing\": 0, \"changed\": 2, \"added\": 0, \"changed_keys\": [\"21\", \"22\"]}, \"agent-system.db.users\": {\"base\": 18, \"now\": 18, \"missing\": 0, \"changed\": 1, \"added\": 0, \"changed_keys\": [\"12\"]}}", + "problems: []", + "=== 密钥一致性 ===", + "owner='' scope=system models.rerank -> secret_keys match=True", + "owner='' scope=system tools.tavily -> secret_keys match=True", + "settings_snapshots=11 mismatches=0", + "=== 知识库 ===", + "active", + "SET", + "legal_nodes=1701178", + "index_entries=191557", + "=== 切换后错误扫描 ===", + "Failed to parse timestamp: 2026-10-23T00:24:14", + "(以上为空即无错误)" + ], + "output_sha256": "52fc124a0e4e6e890949349d93afc89bd2228f460e780e14555160002da29282", + "receipt_sha256": "af18be0166d5bfe3abed4f5a433cb9d57e4dfdfa6f1eb60b828bc33496318e3b", + "receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/af18be0166d5bfe3abed4f5a433cb9d57e4dfdfa6f1eb60b828bc33496318e3b.json" +} +``` + + +```json +{ + "summary_schema": 1, + "source": "SELF", + "timestamp": "2026-10-23T00:44:39.306471+00:00", + "command": "bash ~/ecs-ops/kb-check-fast.sh", + "exit_code": 0, + "cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-ecs-deploy-dev8788-and-kb", + "before_head": "f9a953831b63d78faf4e123068db2e5c68397db8", + "after_head": "f9a953831b63d78faf4e123068db2e5c68397db8", + "branch": "feature/ecs-deploy-dev8788-and-kb", + "target_branch": "main", + "target_head": "6ced938a126981ee2a4fab671a2da94f49cb56c5", + "root_target": "main", + "immediate_target": "main", + "before_tracked_diff_sha256": "1c4f20b9e2398f9fb813dfe305e789f20a8abad1c41f18ed847517dd35981cad", + "after_tracked_diff_sha256": "1c4f20b9e2398f9fb813dfe305e789f20a8abad1c41f18ed847517dd35981cad", + "output_tail": [ + " \"version\": \"fts-v1\"", + " }", + " ],", + " \"hits\": [", + " {", + " \"regulation_id\": \"reg_3939376174cc5e1eb146d10b\",", + " \"edition_id\": \"ed_2e7d6d945848614ab386bdbc\",", + " \"node_id\": \"nd_79ccfca59982317806810fb3\",", + " \"kind\": \"guidance\",", + " \"title\": \"国家药监局关于发布医疗器械注册质量管理体系核查指南的通告(2022年第50号\",", + " \"edition_label\": \"src-5f55893f9096\",", + "KB_FAST_CHECK_OK" + ], + "output_sha256": "cc655d17a77eb65ad064cfaaf4a903a3fe6adb05879dc8e2a70b16be36f93a09", + "receipt_sha256": "eda1eaba245f1c76e329747c66a6739435ddf8524ce0223fc86baac4b9bc92fd", + "receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/eda1eaba245f1c76e329747c66a6739435ddf8524ce0223fc86baac4b9bc92fd.json" +} +```