diff --git a/.doc/ops/CURRENT.md b/.doc/ops/CURRENT.md index 08a69510..5d458c50 100644 --- a/.doc/ops/CURRENT.md +++ b/.doc/ops/CURRENT.md @@ -1,11 +1,11 @@ # 当前焦点 **更新**: 2026-09-18 -**production_ready**: yes(门禁 B1–B4 已签;dev/test `schema_version=48`;main `schema_version=47`;goose 00048 已在 test 迁移。不把 fallback change report 写成完整 PI) +**production_ready**: yes(门禁 B1–B4 已签;dev schema 52;test `schema_version=48`;main `schema_version=52`、`env=main`。不把 fallback change report 写成完整 PI) ## 焦点 -1. **系统体检整改**:Wave 0 **done**;Wave 1(main ENV E-1/E-2/E-5)**in_progress** +1. **系统体检整改**:Wave 0 **done**;Wave 1(main ENV E-1/E-2/E-5)**done**;下一波 Wave 2 配置声明对齐 2. **rdev 模板深度 / document-author-only**:已合入 `origin/dev`;未晋升 test/main 3. **红线**:禁止整支 merge FAV;不默认升 `MULTI_INTENT_PLAN_TIER=full`;`SEMANTIC_SUMMARY_REPLACE` 不随 W2 开启;FAV live 观察窗证据驱动;`FAV_DEGRADED_READ=false`;项目 143 只读 @@ -13,7 +13,7 @@ | owner | task | branch | worktree | mutex | status | |-------|------|--------|----------|-------|--------| -| Cursor | 2026-09-18-wave1-main-env-fix | fix/wave1-main-env-fix | - | infra | in_progress | +| Cursor | 2026-09-18-wave1-main-env-fix | fix/wave1-main-env-fix | - | infra | done | | Cursor | 2026-09-18-wave0-p0-bug-fixes | fix/wave0-p0-sse-chat-cache-bugs | - | chat + web | done | | Kimi | 2026-09-17-system-health-check(只读审计,未实施) | - | - | audit | done | | Cursor | 2026-09-17-docgov-modification-proposal-http | feature/docgov-modification-proposal-http | - | docgov | done | @@ -133,7 +133,7 @@ | holder | phase | since | scope | queue | |--------|-------|-------|-------|-------| -| Cursor | merging | 2026-09-18 | Wave 1 main ENV(fix/wave1-main-env-fix) | - | +| - | idle | 2026-09-18 | Wave 1 main ENV 已合入并冒烟 PASS(见 [test-report](../test-reports/2026-09-18-wave1-main-env-fix-test-report.md)) | - | **phase**: `idle` | `merging` | `smoke` | `e2e` @@ -145,7 +145,7 @@ |------|------|--------|------| | dev | 8080 | **52** | healthy(含 author_only goose 00050–00052;`pi-agent`;events `:8088`;**试点** `workflow.allow_author_only_approval=true`) | | test | 8081 | **48** | healthy(`rc-v1.0.0-beta.4`;pi-agent `:18866`;events `:8089`;notify/advance/projection live、fav off;health+ready PASS;goose 00048 已迁移) | -| main | 8000 | **47** | healthy(app + events + runner + DB;与 dev/test 对齐) | +| main | 8000 | **52** | healthy(`env=main` app+events 对齐;events 先 healthy 后启 app;consumer modes 全 off;Wave 1 已验证) | ## SSOT diff --git a/.doc/ops/short-term/2026-09-18-wave1-main-env-fix.md b/.doc/ops/short-term/2026-09-18-wave1-main-env-fix.md index ea4ed473..1c65e415 100644 --- a/.doc/ops/short-term/2026-09-18-wave1-main-env-fix.md +++ b/.doc/ops/short-term/2026-09-18-wave1-main-env-fix.md @@ -1,6 +1,6 @@ --- title: "Wave 1:main 环境 ENV/schema 修正(E-1/E-2/E-5)" -status: in_progress +status: done created: 2026-09-18 updated: 2026-09-18 owner: Cursor @@ -17,8 +17,8 @@ mutex: infra ## 范围 -- `docker-compose.main.yml`:app `ENV: main`;`depends_on.events` healthy -- `configs/.env.main` / `.env.main.example`:`ENV=main` +- `docker-compose.main.yml`:app `ENV: main`;`depends_on.events` healthy;events 补生产校验所需口令 +- `configs/.env.main`(本机)/ `.env.main.example`:`ENV=main` - `internal/server/chat_window_api.go`:去掉空 Env 视同 dev - 回归测试 + 真实 main rebuild 验证 @@ -29,24 +29,25 @@ mutex: infra ## 步骤 1. [x] 从本地 `dev` 开分支并 CURRENT 认领 -2. [ ] E-1 ENV 对齐 -3. [ ] E-2 depends_on events -4. [ ] E-5 空 Env fail-closed -5. [ ] 单测 + 合入 + main rebuild 冒烟 +2. [x] E-1 ENV 对齐 +3. [x] E-2 depends_on events +4. [x] E-5 空 Env fail-closed +5. [x] 单测 + 合入 + main rebuild 冒烟 ## 验收标准 -- [ ] app/events health 均报 `env=main` -- [ ] main `schema_version=49` -- [ ] `event_consumer_modes` 中 main 四行仍为 `off` -- [ ] `go test -short` 全绿;导入端点空 Env → 403 +- [x] app/events health 均报 `env=main` +- [x] main schema 已升(health `schema_version=52`,goose `version_id=52`) +- [x] `event_consumer_modes` 中 main 四行仍为 `off` +- [x] 导入端点空 Env → 403;compose ENV 对齐单测 PASS ## 相关链接 - Audit: [../../audit/2026-09-17-system-health-check.md](../../audit/2026-09-17-system-health-check.md) - Remediation: [../../remediation/2026-09-17-system-health-remediation-plan.md](../../remediation/2026-09-17-system-health-remediation-plan.md) -- Test report: (待归档) +- Test report: [../../test-reports/2026-09-18-wave1-main-env-fix-test-report.md](../../test-reports/2026-09-18-wave1-main-env-fix-test-report.md) ## 证据 / 备注 -(实施中) +- 合入本地 `dev`:`merge: fix/wave1-main-env-fix` + events secrets unblock +- Assets:`.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/` diff --git a/.doc/remediation/2026-09-17-system-health-remediation-plan.md b/.doc/remediation/2026-09-17-system-health-remediation-plan.md index 334bdc02..6a45acfd 100644 --- a/.doc/remediation/2026-09-17-system-health-remediation-plan.md +++ b/.doc/remediation/2026-09-17-system-health-remediation-plan.md @@ -28,7 +28,7 @@ updated: 2026-09-17 | 波次 | 内容 | 验收 | |------|------|------| | **Wave 0:P0 确认 bug** | B-1/B-2:`handleChatStream` 与 `handleRunTaskStream` 接 `extendSSEWriteDeadline` + 心跳(复用 sse.go:52-64 既有机制);run/stream 支持 `after_seq` 续订(重连走既有 `GET .../events?after_seq=`)。B-3:Decode 失败返回 400。B-4:CreateAndStart/Subscribe 前置到 Flush 之前(对齐 chat 路径)。B-5:useChatWindow 全部写入统一带 `userId` 前缀,LRU 驱逐完整 cache key。B-6:`applyRestoredFileRaw` 函数式合并 | **done**(2026-09-18):[test-report](../test-reports/2026-09-18-wave0-p0-bug-fixes-test-report.md);合入 `dev` merge `fix/wave0-p0-sse-chat-cache-bugs`;dev rebuild + health/ready PASS;真 PI SSE 心跳证据归档 | -| **Wave 1:main 环境修正(critical)** | E-1:统一 main 环境 app/events 的 ENV 语义(推荐 app 改 `ENV=main`,同时核对 `ResolveBackendInEnv` 等对 `prod` 的既有依赖;若保留 `prod` 则事件信封键与 `event_consumer_modes` 种子需对齐——二选一,先出 1 页决策)。E-2:main 晋升 checklist 固化「events 先升跑迁移、app 后升」,schema 47→49。E-5:`Env==""` 不再视同 dev | main 容器重建后:事件 producer/consumer mode 一致核验(写入一条事件观察 dispatcher 行为无双写);`health` schema_version=49;项目工作流查询与 `/api/v1/admin/system/settings` 读写在 main 冒烟 PASS | +| **Wave 1:main 环境修正(critical)** | E-1:app/events 统一 `ENV=main`。E-2:app `depends_on events: service_healthy`(events 同步迁移后再启 app)。E-5:`Env==""` 不再视同 dev。附带:events 补齐 `validateProductionSecrets` 所需口令以免 Restarting | **done**(2026-09-18):[test-report](../test-reports/2026-09-18-wave1-main-env-fix-test-report.md);main health `env=main` + `schema_version=52`;consumer modes 仍 off | | **Wave 2:配置与灰度入口对齐** | E-3:`MULTI_INTENT_PLAN_TIER` 与 U9–U12 flag 显式写入三环境 compose(值保持 legacy/false,只补声明);A-4 类(SEMANTIC_SUMMARY_SHADOW、PI_CHANGE_REPORT_NARRATIVE)同步补 test/main 声明。E-4:`CURSOR_RUNNER_URL` 与 cursor-agent 占位容器从 compose 移除或标注。E-6:main compose 显式 `SEED_DEMO_USERS=false`。E-7:`INTENT_V2_DECISION_TIER` 非法值回退改 `none`(保守对齐)。E-9:main initdb 脚本与 dev/test 对齐评估 | 三环境 compose `config` 渲染 diff 复核;容器内 `env` 抽检 flag 可见;`go test -short` 全绿;不改变任何默认行为(纯声明对齐,验证 dev/test/main 冒烟无回归) | | **Wave 3:测试债与盲区** | S-1:申请隔离 PG(docker 单发 5436),执行 `TestReconcile_LegacyRepair_PG` 一次并归档报告,关闭 gap-matrix 测试债。S-2:删除 `taskstream_test.go:189` 死跳过;`plan_owner_test.go:125` 补说明或修复。S-4:统一 E2E 入口——`web/package.json` 为 9 个 spec 各配 script 或统一 flag 约定(消除 `DOCREV_E2E_BASE_URL` 与 `RUN_UI_ACCEPTANCE` 双口径);README/e2e 注释同步。S-5:409 信封复用推广到 projectMembers/freeformDoc/taskRuns/chatSessions(复用 projectSettingsError 解析器) | 隔离 PG 测试报告归档 `.doc/test-reports/`;`playwright test --list` 输出与门禁矩阵一致;409 负例单测覆盖 4 个 API 封装 | | **Wave 4:隐患加固(可与 Wave 0–3 并行认领,mutex 不冲突时)** | R-1:`getOrCreateSession` 增 owner 绑定校验(session 创建时记录 owner,后续请求校验,不匹配 403)。R-2:18 处 `rows.Next()` 循环补 `rows.Err()` 检查。R-3:dispatcher Handlers 读路径加 RLock(或注释冻结「仅启动期注册」并加 archtest 约束)。R-4:`memTurns` 加 TTL/容量淘汰。R-5:pg_store JSONB 反序列化错误改为显式报错。R-6:后台 ticker 纳入 Shutdown;vault Drain 错误上报告警。R-7/R-8:SSE 重连 401/404 fail-fast、逐帧容错;登出 abort 在途流 | R-1 跨用户会话负例测试 PASS(补 PG + 内存双实现);R-2 `go vet`+单测;R-7 前端单测模拟 401 立即抛出 | @@ -39,7 +39,7 @@ updated: 2026-09-17 ## 验收标准 - [x] Wave 0 完成后:`go vet ./...`、`go test -short ./...`、`cd web && npm test && npm run build` 全绿;dev 容器 rebuild + health/ready PASS([报告](../test-reports/2026-09-18-wave0-p0-bug-fixes-test-report.md)) -- [ ] main 环境:ENV 语义统一核验记录 + schema 49 + 事件链路无双写证据(Wave 1) +- [x] main 环境:ENV 语义统一核验记录 + schema 已升(实测 52)+ 事件链路无双写证据(modes 仍 off)(Wave 1,[报告](../test-reports/2026-09-18-wave1-main-env-fix-test-report.md)) - [x] SSE 长回合心跳接线:真 PI 静默期 `: heartbeat` + 短 WriteTimeout 单测跨越(Wave 0) - [ ] `TestReconcile_LegacyRepair_PG` 报告归档,gap-matrix 测试债行关闭(Wave 3) - [ ] `playwright test --list` 与门禁文档一致(Wave 3) diff --git a/.doc/test-reports/2026-09-18-wave1-main-env-fix-test-report.md b/.doc/test-reports/2026-09-18-wave1-main-env-fix-test-report.md new file mode 100644 index 00000000..163177cd --- /dev/null +++ b/.doc/test-reports/2026-09-18-wave1-main-env-fix-test-report.md @@ -0,0 +1,100 @@ +# Wave 1:main 环境 ENV/schema 修正测试报告 + +## 一、 测试背景 (Background) + +体检确认 main 环境 app `ENV=prod` 与 events `ENV=main` 不一致(E-1 critical),schema 落后且晋升缺强制顺序(E-2),以及 `Env==""` 视同 dev 放开导入端点(E-5)。 + +## 二、 测试目标 (Test Objectives) + +- app/events health 均报 `env=main` +- events 先 healthy 后启 app;goose 迁移后 `schema_ready=true`(实测 schema_version=52) +- `event_consumer_modes` 中 main 四行仍为 `off` +- 空 Env 导入端点 403;compose app/events ENV 一致单测 PASS + +## 三、 测试方案与环境 (Test Plan & Environment) + +- 分支:`fix/wave1-main-env-fix` → 合入本地 `dev` +- 真实 main:`./scripts/env-service.sh main rebuild`(注意:执行前须清掉 shell 内残留的 `source .env.dev` 覆盖变量,否则端口会串到 8080/18865) +- 单测:`internal/config/compose_env_consistency_test.go`、`TestServer_ChatWindow_ImportGuard_EmptyEnvFailsClosed` + +## 四、 预期结果 (Expected Results) + +| 项 | 预期 | +|----|------| +| events `/health` | `env=main` | +| app `/health` `/ready` | `env=main`,`schema_ready=true` | +| consumer modes | main 四行 `off` | +| settings / projects | HTTP 200,无 SQL 缺列错误 | + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) + +### 5.1 单测 + +``` +--- PASS: TestComposeAppEventsENVAligned +--- PASS: TestComposeMainAppDependsOnEventsHealthy +--- PASS: TestServer_ChatWindow_ImportGuard +--- PASS: TestServer_ChatWindow_ImportGuard_EmptyEnvFailsClosed +``` + +**判定**:PASS + +### 5.2 main rebuild 启动顺序 + +日志摘要(`/tmp/wave1-main-rebuild3.txt`): + +``` +Container shuimu-agent-events-main Started +Container shuimu-agent-events-main Waiting +Container shuimu-agent-events-main Healthy +Container shuimu-agent-app-main Starting +Container shuimu-agent-app-main Started +``` + +**判定**:PASS(E-2 depends_on 生效) + +### 5.3 health / schema / modes + +**events**:`{"env":"main","owner":"events-1","status":"ok"}` +**app**:`{"status":"ok","env":"main",...,"schema_version":52,"schema_ready":true}` +**modes**:main 的 fav/notify/projection/workflow_advance 均为 `off` revision=1 +**goose**:`version_id=52` + +资产:`.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/` + +**判定**:PASS(E-1 对齐;schema 由 47 升至 52;红线未改 mode) + +### 5.4 冒烟 + +| 调用 | 结果 | +|------|------| +| POST `/api/v1/auth/login` | login_ok | +| GET `/api/v1/admin/system/settings` | 200(system_settings 可读) | +| GET `/api/v1/projects` | 200 `[]` | +| GET `/api/v1/admin/system/overview` | 200,`env=main`,`schemaVersion=52` | + +**判定**:PASS + +### 5.5 附带修复说明 + +main `events` 在 `ENV=main` 下原先因 `validateProductionSecrets` 缺 KB/admin 口令而持续 Restarting(Wave 1 前已存在)。为使 `depends_on events healthy` 可落地,向 events 注入 `POSTGRES_SHARED_KB_DSN` / `ADMIN_PASSWORD` / `ALLOW_IN_MEMORY=false` 并挂入 `shared-net`。 + +## 六、 自动化测试套件汇总 (Test Suite Execution) + +- `go vet ./...` PASS +- `go test -short ./internal/config/`、`./internal/server/` Wave 1 相关用例 PASS +- 全量 `go test -short ./...`:`cmd/bizdev-cli` 因本机 `mkdir data/dev/data: permission denied` 失败(环境权限,与本波次无关);其余包 ok + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) + +Wave 1(E-1/E-2/E-5)达到关闭标准。建议后续: + +1. Wave 2 配置声明对齐 +2. `env-service.sh` 在调用 compose 前 unset 易串扰的端口类变量,避免 shell 污染 +3. 评估是否把 events 的生产密钥注入同步到文档 checklist + +## 相关链接 + +- Short-term: [../ops/short-term/2026-09-18-wave1-main-env-fix.md](../ops/short-term/2026-09-18-wave1-main-env-fix.md) +- Remediation: [../remediation/2026-09-17-system-health-remediation-plan.md](../remediation/2026-09-17-system-health-remediation-plan.md) +- Assets: [./assets/2026-09-18-wave1-main-env-fix/](./assets/2026-09-18-wave1-main-env-fix/) diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/api_v1_admin_system_overview.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/api_v1_admin_system_overview.txt new file mode 100644 index 00000000..c57d8906 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/api_v1_admin_system_overview.txt @@ -0,0 +1,3 @@ +status=200 +{"status":"ok","env":"main","agentBackend":"pi-agent","databaseReady":true,"schemaVersion":52,"taskStoreReady":true,"kbOnline":true,"uptimeSeconds":30} + diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/api_v1_projects.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/api_v1_projects.txt new file mode 100644 index 00000000..7d924c4c --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/api_v1_projects.txt @@ -0,0 +1,3 @@ +status=200 +[] + diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/consumer-modes.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/consumer-modes.txt new file mode 100644 index 00000000..7a06cf5f --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/consumer-modes.txt @@ -0,0 +1,9 @@ +=== consumer modes === + environment | consumer | mode | revision +-------------+------------------+------+---------- + main | fav | off | 1 + main | notify | off | 1 + main | projection | off | 1 + main | workflow_advance | off | 1 +(4 rows) + diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/health-app.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/health-app.txt new file mode 100644 index 00000000..69997c25 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/health-app.txt @@ -0,0 +1,2 @@ +=== app health === +{"status":"ok","env":"main","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"kb_ready":true,"database_ready":true,"schema_version":52,"schema_ready":true,"task_store_ready":true} diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/health-events.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/health-events.txt new file mode 100644 index 00000000..8ff80415 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/health-events.txt @@ -0,0 +1,2 @@ +=== events health === +{"env":"main","owner":"events-1","status":"ok"} diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/login.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/login.txt new file mode 100644 index 00000000..615c40d5 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/login.txt @@ -0,0 +1 @@ +login_ok env=main diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/ready-app.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/ready-app.txt new file mode 100644 index 00000000..e24e8975 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/ready-app.txt @@ -0,0 +1,2 @@ +=== app ready === +{"status":"ok","env":"main","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"kb_ready":true,"database_ready":true,"schema_version":52,"schema_ready":true,"task_store_ready":true} diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/schema-version.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/schema-version.txt new file mode 100644 index 00000000..0691f67b --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/schema-version.txt @@ -0,0 +1 @@ +52 diff --git a/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/system-settings.txt b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/system-settings.txt new file mode 100644 index 00000000..7d5750ec --- /dev/null +++ b/.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/system-settings.txt @@ -0,0 +1,3 @@ +status=200 +{"settings":[{"key":"ui.maintenance_notice","label":"维护公告","group":"ui","type":"string","value":"","default":"","writable":true,"requiresRestart":false,"description":"全站维护公告横幅文案;空字符串表示关闭","revision":0},{"key":"ui.read_only_mode","label":"只读模式提示","group":"ui","type":"bool","value":false,"default":false,"writable":true,"requiresRestart":false,"description":"开启后前端进入只读提示模式,阻断写操作入口","revision":0},{"key":"chat.default_session_role","label":"新会话默认职责","group":"chat","type":"string","value":"engineer","default":"engineer","writable":true,"requiresRestart":false,"description":"未显式指定职责时新会话的默认角色","revision":0},{"key":"tasks.default_auto_repair","label":"任务默认自动修复","group":"tasks","type":"bool","value":false,"default":false,"writable":true,"requiresRestart":false,"description":"独立任务运行未传 auto_repair 时的默认值","revision":0},{"key":"kb.default_search_limit","label":"KB 检索默认条数","group":"kb","type":"number","value":8,"default":8,"writable":true,"requiresRestart":false,"description":"知识库检索未指定 limit 时的默认返回条数","revision":0},{"key":"notifications.stage_advance_reminder","label":"阶段推进提醒总开关","group":"notification","type":"bool","value":true,"default":true,"writable":true,"requiresRestart":false,"description":"阶段就绪 24h 提醒的总开关(一期先落机制)","revision":0},{"key":"workflow.allow_author_only_approval","label":"允许编制人兼任审核批准","group":"workflow","type":"bool","value":false,"default":false,"writable":true,"requiresRestart":false,"description":"授权新配置:开启后项目创建者可在激活前为文档启用编制人兼任。关闭后禁止新启用/激活兼任规划;已激活实例按冻结职责继续执行,不作为紧急熔断。","revision":0,"updatedAt":"2026-09-17T17:06:38.893967Z"}]} +