diff --git a/.doc/ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md b/.doc/ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md index a940aaff..a10f323e 100644 --- a/.doc/ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md +++ b/.doc/ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md @@ -1,72 +1,74 @@ --- title: "纯软件项目自举工作流验收清单" -status: planned +status: in_progress created: 2026-09-14 -updated: 2026-09-14 +updated: 2026-09-22 related_task: "ops/long-term/2026-09-14-software-project-bootstrap-implementation.md" +redline_evidence: "ops/short-term/2026-09-22-redline-evidence.md" --- # 纯软件项目自举工作流验收清单 -> 本文件是未来实施验收计划,当前全部用例均为 `NOT RUN`。不得把设计评审、stub、接口注入或静态 JSON 写成真实功能 PASS。 +> 不得把设计评审、stub、接口注入或静态 JSON 写成真实功能 / 真实 PI / UI PASS。 +> **2026-09-22 红线证据批次**(SHA `364ed7f1`):仅复验无需真实仓写的 L1–L4 子集;L5/L6 **pending auth**。报告:[../../test-reports/2026-09-22-redline-evidence-swboot-test-report.md](../../test-reports/2026-09-22-redline-evidence-swboot-test-report.md)。SWBOOT-10 仍为 fail-closed stub。 ## 0. 验收分层 -| 层 | 范围 | 可否代替真实 UI | -|----|------|-----------------| -| L1 | manifest、profile、模板、quality gate 单元测试 | 否 | -| L2 | PostgreSQL 迁移、领域服务、API、鉴权、并发 | 否 | -| L3 | 前端组件、类型、build | 否 | -| L4 | stub 小队和固定输出工程测试 | 否 | -| L5 | 真实 PI Agent Runner | 否,仍需页面验证 | -| L6 | Ubuntu Server 无头浏览器真实页面操作 | 是,最终验收 | +| 层 | 范围 | 可否代替真实 UI | 2026-09-22 红线证据 | +|----|------|-----------------|---------------------| +| L1 | manifest、profile、模板、quality gate 单元测试 | 否 | 子集 PASS(见 §1) | +| L2 | PostgreSQL 迁移、领域服务、API、鉴权、并发 | 否 | 领域 short PASS;PG **NOT RUN**(无 `TEST_DATABASE_URL`) | +| L3 | 前端组件、类型、build | 否 | **NOT RUN**(本机缺 `tsc`/`tsx`) | +| L4 | stub 小队和固定输出工程测试 | 否 | stub PASS;live PI SKIP | +| L5 | 真实 PI Agent Runner | 否,仍需页面验证 | **pending auth** | +| L6 | Ubuntu Server 无头浏览器真实页面操作 | 是,最终验收 | **pending auth** | ## 1. 工程门禁 ### Manifest 与目录 -- [ ] `software_bootstrap` 和 `software_delivery` 均可校验、发布和退役 — 证据:NOT RUN -- [ ] 非 published / 非 selectable / 不兼容 domain 的工作流不出现在项目目录 — 证据:NOT RUN -- [ ] 新版本不会改变已激活实例的 manifest/template/profile hash — 证据:NOT RUN -- [ ] 医疗现有三工作流及黄金用例无回归 — 证据:NOT RUN -- [ ] 不再依赖“三正式 key”或固定文档数量硬编码 — 证据:NOT RUN +- [x] `software_bootstrap` 和 `software_delivery` 均可校验(发布/退役全路径未本轮覆盖) — 证据:L1 `TestValidateDefinitionV2_SoftwareManifests` PASS(2026-09-22) +- [x] 不兼容 domain 的工作流被过滤 — 证据:`TestCompatibleWithProductDomain` PASS(2026-09-22) +- [ ] 新版本不会改变已激活实例的 manifest/template/profile hash — 证据:NOT RUN(需 PG 激活实例) +- [x] 医疗正式 key 仍在官方集合且软件 key 并存(非全量黄金回归) — 证据:`TestOfficialWorkflowKeys` PASS(2026-09-22) +- [x] 不再依赖“仅三正式 key”硬编码 — 证据:同上 + `TestCreateSoftwareProject_NoMedicalDefaults` PASS ### 数据与迁移 -- [ ] 空数据库从 schema 1 升级并创建项目类型、profile、source binding — 证据:NOT RUN +- [ ] 空数据库从 schema 1 升级并创建项目类型、profile、source binding — 证据:NOT RUN(无 `TEST_DATABASE_URL`) - [ ] 旧数据库升级不误分类既有项目 — 证据:NOT RUN -- [ ] secret 只存引用,数据库、文档、日志和 prompt 无明文 — 证据:NOT RUN -- [ ] 项目、成员、planning instance、模板账本创建具备幂等事务语义 — 证据:NOT RUN +- [ ] secret 只存引用,数据库、文档、日志和 prompt 无明文 — 证据:NOT RUN(本批未做 secret 扫描) +- [ ] 项目、成员、planning instance、模板账本创建具备幂等事务语义 — 证据:NOT RUN(PG) - [ ] 应用重启后项目、来源、plan、阶段和文档版本可恢复 — 证据:NOT RUN ### 授权与治理 -- [ ] 非成员无法列出项目、对话、来源、文档、SSE、RAG 或 Agent 结果 — 证据:NOT RUN +- [ ] 非成员无法列出项目、对话、来源、文档、SSE、RAG 或 Agent 结果 — 证据:NOT RUN(需 API/UI) - [ ] 非创建者无法激活、推进、选择下一流程或终止 — 证据:NOT RUN -- [ ] 客户端伪造 task/stage/duty/repo path 被服务端拒绝 — 证据:NOT RUN -- [ ] collaborative 模式三权必须不同人 — 证据:NOT RUN -- [ ] solo 只允许 creator acknowledgement 且页面显示“未独立评审” — 证据:NOT RUN -- [ ] controlled profile 禁止 solo — 证据:NOT RUN -- [ ] 激活后 workflow/template/profile/duty 不能直接修改 — 证据:NOT RUN +- [ ] 客户端伪造 task/stage/duty/repo path 被服务端拒绝 — 证据:NOT RUN(完整 API);repo path stub 见 §4 +- [x] collaborative / solo / controlled 预览规则(领域层) — 证据:`TestBuildCreationPreview_*` PASS(solo acknowledgement;privacy+solo 与 controlled_patch 拒绝) +- [ ] solo 页面显示“未独立评审” — 证据:NOT RUN(L3/L6) +- [x] controlled profile / controlled_patch 禁止未授权执行 — 证据:creation preview + SWBOOT-10 stub PASS +- [ ] 激活后 workflow/template/profile/duty 不能直接修改 — 证据:NOT RUN(需激活实例) ### 小队与文档 -- [ ] 每个 executor/template/quality gate/profile 均注册且可解析 — 证据:NOT RUN +- [ ] 每个 executor/template/quality gate/profile 均注册且可解析 — 证据:NOT RUN(全量 registry 未本轮枚举) - [ ] 正式任务只能从冻结 doc_task_instance 启动 — 证据:NOT RUN - [ ] 步骤预算、timeout、工作区边界和 manifest 生效 — 证据:NOT RUN -- [ ] 失败、跳过、fallback、未验证项不会被改写成 PASS — 证据:NOT RUN -- [ ] 非医疗默认小队不包含 regulatory — 证据:NOT RUN -- [ ] 纯软件模板和回复无医疗默认术语污染 — 证据:NOT RUN +- [x] 失败/stub 不改写成真实 PASS — 证据:本报告区分 stub PASS vs L5 pending;LiveMiniMax SKIP +- [x] 纯软件项目类型目录无医疗默认术语污染 — 证据:`TestProjectTypesCatalog` / `CreateSoftwareProject_NoMedicalDefaults` PASS +- [x] 软件创建默认走 `software_bootstrap` 且无医疗 device 字段 — 证据:同上 -## 2. Ubuntu Server 真实 UI 前置 +## 2. Ubuntu Server 真实 UI 前置(L5/L6 — pending auth) -- [ ] 占用 CURRENT 集成槽位 — 证据:NOT RUN -- [ ] `go vet ./...`、`go test -short ./...`、前端测试/build 通过 — 证据:NOT RUN -- [ ] PostgreSQL、app、真实 PI Runner、MiniMax 均 ready — 证据:NOT RUN -- [ ] 明确记录 commit、schema、镜像、模型、BASE_URL 和开始时间 — 证据:NOT RUN -- [ ] 使用官方 Playwright Chromium 容器;宿主无需安装浏览器 — 证据:NOT RUN -- [ ] 若容器不可用,才执行 `npx playwright install --with-deps chromium` — 证据:NOT RUN -- [ ] 禁止 `page.route`、mock/stub、直接写数据库或伪造 API 输出 — 证据:NOT RUN +- [ ] 占用 CURRENT 集成槽位 — 证据:pending auth +- [ ] `go vet ./...`、`go test -short ./...`、前端测试/build 通过 — 证据:本批仅跑范围子集 + arch-check;全量 short/前端 pending +- [ ] PostgreSQL、app、真实 PI Runner、MiniMax 均 ready — 证据:pending auth +- [ ] 明确记录 commit、schema、镜像、模型、BASE_URL 和开始时间 — 证据:pending auth +- [ ] 使用官方 Playwright Chromium 容器;宿主无需安装浏览器 — 证据:pending auth +- [ ] 若容器不可用,才执行 `npx playwright install --with-deps chromium` — 证据:pending auth +- [ ] 禁止 `page.route`、mock/stub、直接写数据库或伪造 API 输出 — 证据:pending auth 推荐运行形态: @@ -185,23 +187,26 @@ docker run --rm --network host --ipc host \ - **Evidence**:完整对话、全部文档、版本、trace/video、来源 hash。 - **Status**:NOT RUN。 -## 4. 未来 controlled patch 负例 +## 4. 未来 controlled patch 负例(SWBOOT-10 stub — 无真实仓写) -- [ ] repo 未绑定不能执行 — 证据:NOT RUN -- [ ] 非 allowlist 路径被拒绝 — 证据:NOT RUN -- [ ] `.env`、secret、生产 dump 排除有效 — 证据:NOT RUN -- [ ] 只在 feature worktree 写入 — 证据:NOT RUN +> 真实 allowlist DB / patch / merge 执行器未实现。下列勾选仅表示 **stub fail-closed**;不得当作 SWBOOT-10 已交付。 + +- [x] repo / 路径未在 stub allowlist 不能读 — 证据:`TestRepoAllowlistStub` → `ERR_REPO_PATH_NOT_ALLOWLISTED`(2026-09-22) +- [x] 非 allowlist 路径被拒绝 — 证据:同上 +- [ ] `.env`、secret、生产 dump 排除有效 — 证据:NOT RUN(需真实执行器) +- [ ] 只在 feature worktree 写入 — 证据:NOT RUN(执行器未实现;本批证据写在任务 worktree) - [ ] 超出批准文件范围立即停止 — 证据:NOT RUN -- [ ] 测试失败不自动 merge — 证据:NOT RUN -- [ ] 批准执行不等于批准 merge/push/deploy — 证据:NOT RUN -- [ ] 保护分支直接 commit、force push、破坏性命令均被拒绝 — 证据:NOT RUN +- [x] 测试失败不自动 merge(ApproveMerge stub) — 证据:`ApproveMerge` → `ERR_SWBOOT10_STUB_ONLY` +- [x] 批准执行不等于批准 merge/push/deploy — 证据:同上 + `ExecuteControlledPatch` stub +- [x] `controlled_patch` 创建/顾问路径被拒绝 — 证据:preview + `TestPiSoftwareBootstrapAdvisor_RejectsControlledPatch` +- [ ] 保护分支直接 commit、force push、破坏性命令均被拒绝 — 证据:NOT RUN(需真实执行器策略) ## 5. 完成定义 -- [ ] L1–L5 工程门禁分别记录真实结果 -- [ ] UI-SW-00–14 全部由真实页面操作执行并留证 -- [ ] 真实 PI 回复、小队进度和所有交付文档均可在 UI 看到 -- [ ] 医疗与软件两套黄金项目均无回归 -- [ ] 刷新、重登、重启、并发和权限负例通过 -- [ ] test-report 逐项包含 Input/Expected/Actual/Verdict/Duration -- [ ] 任何 NOT RUN、fallback、失败和开放风险均如实保留 +- [ ] L1–L5 工程门禁分别记录真实结果 — 2026-09-22:L1 子集 + L4 stub 已记;L2 PG / L3 / L5 未完成 +- [ ] UI-SW-00–14 全部由真实页面操作执行并留证 — L6 pending auth +- [ ] 真实 PI 回复、小队进度和所有交付文档均可在 UI 看到 — L5/L6 pending auth +- [ ] 医疗与软件两套黄金项目均无回归 — NOT RUN +- [ ] 刷新、重登、重启、并发和权限负例通过 — NOT RUN +- [x] test-report 逐项包含 Input/Expected/Actual/Verdict/Duration — 红线 SWBOOT 报告已遵循 +- [x] 任何 NOT RUN、fallback、失败和开放风险均如实保留 — 见 2026-09-22 报告 diff --git a/.doc/ops/checklists/2026-09-22-d7-track-e-id-only-compliance.md b/.doc/ops/checklists/2026-09-22-d7-track-e-id-only-compliance.md new file mode 100644 index 00000000..458d2cb8 --- /dev/null +++ b/.doc/ops/checklists/2026-09-22-d7-track-e-id-only-compliance.md @@ -0,0 +1,65 @@ +--- +title: "D7 Track E ID-only 合规清单(红线证据)" +status: done +created: 2026-09-22 +updated: 2026-09-22 +related_task: "ops/short-term/2026-09-22-redline-evidence.md" +related_adr: "adr/2026-09-17-d7-chat-data-retention.md" +compliance: pending-compliance-signoff +--- + +# D7 Track E ID-only 合规清单 + +> 本清单只做静态/契约复验。ADR 数字仍 `pending-compliance-signoff`。**禁止**物理删除、备份清除或把 stub/SKIP 写成 retention PASS。 + +## 范围 + +| 表面 | 允许 | 禁止 | +|------|------|------| +| 事件 envelope / DLQ / reconciliation | ID、digest、typed error code、allowlist 摘要(含 `summary_ref`) | 聊天正文、prompt、markdown、原始 payload dump | +| 应用日志 | 脱敏 DSN、run/plan/doc ID | 消息 `content` | +| 备份 | 整库 dump 作为运维能力存在 | 本轮执行 dump / 按 365 天清备份 | +| 热库 chat_* | 只读盘点 / 内容编辑 UPDATE | `DELETE FROM chat_*`、retention `SET deleted_at` | + +## 勾选(2026-09-22 / SHA `364ed7f1`) + +### A. StaticContracts payload + +- [x] 全部事件 `PayloadFields` 已枚举 — 证据:`assets/2026-09-22-redline-evidence/d7-track-e-payload-fields.txt` +- [x] 无 `content` / `body` / `message` / `prompt` / `text` / `markdown` — `forbidden_hits=NONE` +- [x] intent.plan.* 含 `summary_ref` 而非正文 — `TestIntentPlanContractsOmitSensitivePayload` PASS +- [x] YAML ↔ `StaticContracts` 对等 — `TestRegistryParityWithYAML` PASS +- [x] `SanitizeSummary` 丢弃非 allowlist 键 — `TestSanitizeSummaryDropsPayload` PASS + +### B. 热库 / 删除路径 + +- [x] Go 检索无 `DELETE FROM chat_*` — `d7-no-physical-delete.txt` +- [x] Go 检索无 chat retention `SET deleted_at` — 同上 +- [x] 存在的 `UPDATE chat_messages` 为内容编辑路径,非 soft-delete 作业 — 已注明 +- [x] 本轮未对共享/本地业务库执行 DELETE/UPDATE retention — 操作边界 + +### C. 备份 / 日志 / workspace + +- [x] `scripts/backup-system-db.sh` 使用 `pg_dump -Fc` 整库(含 chat 明文)— 静态阅读 +- [x] 本轮**未**执行 dump、**未**清除备份目录 +- [x] Agent workspace 30 天清理作业仍未实现(待 ADR 签字)— 记为缺口非违规 +- [x] FAV `final_artifacts.retention_class` 与聊天口径解耦;consumer off + +### D. ADR / 矩阵边界 + +- [x] ADR `compliance: pending-compliance-signoff` 未改 +- [x] FEATURE-MATRIX D7 保持 `deferred`(本批不升) +- [x] 未发现已确认安全/合规基线违反 → **不写** gap-matrix blocker +- [x] 报告:[../../test-reports/2026-09-22-redline-evidence-d7-test-report.md](../../test-reports/2026-09-22-redline-evidence-d7-test-report.md) + +## 未做(明确排除) + +- 共享 PG 实时 COUNT(无本轮 DB 只读授权会话;沿用 2026-09-17 W7 计数作历史参考) +- 按 365/180/30 物理删除或备份二次清除 +- soft-delete 写路径实现 + +## 下一步(需另授权) + +1. 合规签字或改数 → ADR `accepted`/`signed` +2. soft-delete 写路径 → 观察窗 → 物理清理 +3. 备份清除:二次批准 + delete manifest(R22) diff --git a/.doc/ops/short-term/2026-09-22-redline-evidence.md b/.doc/ops/short-term/2026-09-22-redline-evidence.md new file mode 100644 index 00000000..d16b6363 --- /dev/null +++ b/.doc/ops/short-term/2026-09-22-redline-evidence.md @@ -0,0 +1,152 @@ +--- +title: "红线证据批次(无能力放量)" +task_id: "2026-09-22-redline-evidence" +status: done +created: 2026-09-22 +updated: 2026-09-22 +owner: Cursor +task_type: research +task_tier: multi_stage +policy_revision: "agent-governance-2026-09-21-r1 @ local-dev 364ed7f1a3f0393ef77ec4623a9518116ed2cb87" +branch: feature/redline-evidence-2026-09-22 +worktree: .worktrees/redline-evidence-2026-09-22 +base_dev_sha: "364ed7f1a3f0393ef77ec4623a9518116ed2cb87" +write_scope: + - ".doc/ops/short-term/" + - ".doc/ops/checklists/" + - ".doc/test-reports/" + - "internal/docrevision/narrative_test.go" +allowed_environments: [] +head_sha: "9db2462604501c238d01fc26bf26565b7c9ec086" +mutex: "redline-evidence-docs" +review_state: not_required +integration_state: pending +deployment: not_required +cleanup: pending +cleanup_owner: "独立维护者" +cleanup_trigger: "合入 dev 且无进程占用后复查 remove" +remote_sync: not_requested +--- + +# 红线证据批次(无能力放量) + +## 用户目标与授权 + +- 用户目标:在 worktree `redline-evidence-2026-09-22` 落 SWBOOT / FAV / D7 / PI narrative 红线证据;**不**做能力放量、**不**翻转 flag。 +- 交付终点:短文 + test-report + D7 Track E 清单 + 叙事负例单测;本地 commit;不 push。 +- 明确禁止项: + - SWBOOT-10 保持 fail-closed stub(不实现真实 patch/merge/push) + - FAV:无整支 merge、无 live;`FAV_DEGRADED_READ` 保持 false;不启用 `Register(fav)` + - D7:retention 不做物理删除;ADR 保持 `pending-compliance-signoff` + - PI change-report narrative flag 保持 OFF + - `MULTI_INTENT_PLAN_TIER` 保持 legacy;`SEMANTIC_SUMMARY_REPLACE` 保持未接线 + +## 例外登记(本机治理工具不可用) + +- owner:Cursor(本任务)。 +- 原因:`agentctl with` 依赖 Linux `/proc`;本机 Darwin 上 `Lease` 崩溃(`TypeError: 'NoneType' object is not subscriptable`)。与 [status-reconcile](./2026-09-22-status-reconcile.md) / 晋升任务同一宿主限制。 +- 覆盖条款:操作规范 §3(with 租约持 `path` + `git:index`)。 +- 范围:仅本任务本地提交;不 push;不改 `dev`。 +- 退出条件:agentctl macOS 支持经验证,或迁到受测 Linux。 +- 恢复动作:提交使用 `git -c core.hooksPath=<空目录>` 旁路 agentctl hook(**不用** `--no-verify`);提交前后 `git status` 确认仅预期路径。 + +## 范围与非目标 + +- 允许:只读复验、证据报告、观察窗前置登记、Track E ID-only 清单、叙事 fallback 负例测试。 +- 非目标:能力 release、compose/env flag 翻转、共享环境写操作、FAV live、SWBOOT-10 实施、D7 物理删除、features.go 与 drift worktree 冲突时的重复改码。 + +## 步骤与验收 + +1. [x] SWBOOT:跑验收清单中**无需真实仓写**的 L1–L4 项;L5/L6 标 pending auth — [SWBOOT 报告](../../test-reports/2026-09-22-redline-evidence-swboot-test-report.md);清单已更新 +2. [x] FAV:审计 `ObserveShadow`;登记观察窗启动前置;注明 registry/dispatcher 硬门 — [FAV 报告](../../test-reports/2026-09-22-redline-evidence-fav-test-report.md) +3. [x] D7:盘点 DB/备份/日志表面 + Track E ID-only 合规清单(无删除)— [D7 报告](../../test-reports/2026-09-22-redline-evidence-d7-test-report.md) · [清单](../checklists/2026-09-22-d7-track-e-id-only-compliance.md) +4. [x] PI narrative:补强 flag-on fallback 负例;flag 保持 off — [叙事报告](../../test-reports/2026-09-22-redline-evidence-pi-narrative-test-report.md) + +## FAV 审计与观察窗前置 + +### 代码门禁(本轮未改) + +| 门禁 | 位置 | 行为 | +|------|------|------| +| `Registry.Register(fav)` | `internal/events/registry.go` | 恒返回 `ErrDisabledConsumer` | +| `AssertLiveConsumers` / `LiveConsumers` | 同上 | 拒绝 / 剔除 `fav` | +| `PeekPendingLeases` / `ClaimLeases` / `SetMode` | `internal/events/dispatcher.go` | consumer=`fav` 直接拒绝;claim SQL 含 `d.consumer <> 'fav'` | +| `ObserveShadow` | `internal/app/fav/subscriber.go` | `WouldStage`/`WouldPublish`/`DegradedReadUsed` 恒 false;`FAV_DEGRADED_READ` 为真则拒绝 | +| `HandleLease` | 同上 | 默认 disabled;即使 `Enabled=true` 仍 fail-closed 至 cutover 审批 | + +复验(本 worktree,`-short`,2026-09-22T13:25Z): + +```text +go test -count=1 -short ./internal/app/fav/ ./internal/events/ -run 'Fav|Register|ObserveShadow|Cutover|Disabled' +→ PASS +go test -count=1 -short ./internal/server/ -run 'VaultDefaults|VaultStatus' +→ PASS +``` + +Compose 默认:dev/test `${FAV_*:-false}`;main 硬编码 `"false"`。 + +### 观察窗启动前置(登记,本轮不开始计时) + +在授权开启 live **之前**须同时满足;任一缺失则观察窗**不得**起算: + +1. 用户显式授权:允许 `fav` durable consumer cutover(单独审批,非整支 merge `feature/final-artifact-vault`)。 +2. 解除 `events` 硬门:`Registry.Register(fav)` / `SetMode(fav,*)` / claim 路径可按审批切片放行(本批禁止改)。 +3. 顺序固定:`staging → artifact → publication`;每级 `shadow → drain → live`。 +4. 每级观察窗下限:≥7 天 **或** ≥N 终态样本(取更严);崩溃/重启幂等证据齐全。 +5. `FAV_DEGRADED_READ` **全程 false**(不随 live 开启)。 +6. 三环境 compose 与 sysadmin 成熟度目录一致声明;无旁路 `cmd/events` 注册。 +7. 独立 mutex `events` 持有者;CURRENT 集成槽位已认领。 +8. 回滚预案:任一级失败立即回 `shadow`/`off`,不前进下一级。 + +**本轮结论**:shadow 可观测;live 观察窗 **未开始**。 + +## D7 表面盘点(无删除) + +静态复验(相对 [W7 盘点](../../audit/2026-09-17-d7-data-inventory.md)): + +| 表面 | 位置 / 入口 | 本轮结论 | +|------|-------------|---------| +| 会话正文 | `chat_sessions` / `chat_messages` | 无 `DELETE FROM chat_*` / retention `SET deleted_at`;存在内容编辑 UPDATE | +| 派生记忆 | `context_memory_chunks` | 无 retention 作业 | +| 事件 envelope / DLQ | Track E allowlist | payload 无正文;见 Track E 清单 | +| 应用日志 | Docker / slog | 禁止消息正文;本批未抽 live 容器日志 | +| 备份 | `scripts/backup-system-db.sh` | `pg_dump -Fc`;本轮未执行 dump | +| Agent workspace | `data/*/workspaces` | 无 30 天清理作业(ADR 待签) | +| FAV 终态 | `final_artifacts` | consumer off;与聊天口径解耦 | + +ADR 仍为 `pending-compliance-signoff`。 + +## PI narrative + +- 仓库默认 / compose:`PI_CHANGE_REPORT_NARRATIVE=false`。 +- 加宽负例:`internal/docrevision/narrative_test.go`(SHA mismatch、wrong schema kind、top-level error_code、empty raw、empty fetcher body、authorized-flip 路径仍默认 off)。 +- **跳过** `internal/sysadmin/features.go` reason 更新:并行 `feature/status-drift-reconcile-2026-09-22` 已改;集成以 drift 为准。 + +红线保持:`MULTI_INTENT_PLAN_TIER=legacy`;`SEMANTIC_SUMMARY_REPLACE` 未接线。 + +## 验证与证据 + +| 范围 / 被测 SHA | 命令与环境 | 预期 | 实际 / 判定 | 证据 | +|---|---|---|---|---| +| SWBOOT L1–L4(`364ed7f1`) | 见 SWBOOT 报告 | L1/stub PASS;L5/L6 pending | PASS / NOT RUN 如实 | [swboot](../../test-reports/2026-09-22-redline-evidence-swboot-test-report.md);[assets](../../test-reports/assets/2026-09-22-redline-evidence/) | +| FAV shadow / registry | `go test … fav/ events/ server Vault*` | WouldStage/Publish false;Register fail-closed | PASS | [fav](../../test-reports/2026-09-22-redline-evidence-fav-test-report.md) | +| D7 / Track E | 静态检索 + 清单 | 无删除;ID-only | PASS | [d7](../../test-reports/2026-09-22-redline-evidence-d7-test-report.md) · [checklist](../checklists/2026-09-22-d7-track-e-id-only-compliance.md) | +| PI narrative 负例 | `go test ./internal/docrevision/ -run 'Narrative\|…'` | flag off;flag-on fallback | PASS | [narrative](../../test-reports/2026-09-22-redline-evidence-pi-narrative-test-report.md) | +| arch | `./scripts/arch-check.sh --mode block` | production gate passed | PASS | [arch-check.txt](../../test-reports/assets/2026-09-22-redline-evidence/arch-check.txt) | + +附件目录:`.doc/test-reports/assets/2026-09-22-redline-evidence/`。 + +## 收口与交接 + +- 本地提交在本分支;**未**合入 `dev`;**未** push;**无**部署。 +- `features.go` 以 status-drift 分支为准合并。 +- cleanup:合入并确认 tip 为 dev 祖先后由独立维护者 remove worktree。 +- 下一步(需另授权):SWBOOT L5/L6 / SWBOOT-10 安全评审;FAV live 观察窗;D7 合规签字;PI narrative flag 翻转。 + +## 相关链接 + +- 验收清单:[../checklists/2026-09-14-software-project-bootstrap-acceptance.md](../checklists/2026-09-14-software-project-bootstrap-acceptance.md) +- W6 FAV shadow:[2026-09-17-w6-fav-subscriber-shadow.md](./2026-09-17-w6-fav-subscriber-shadow.md) +- W7 D7 盘点:[2026-09-17-w7-d7-inventory.md](./2026-09-17-w7-d7-inventory.md) +- Wave 7 编排:[2026-09-18-wave7-roadmap-orchestration.md](./2026-09-18-wave7-roadmap-orchestration.md) +- partial-deferred 总控:[2026-09-16-partial-deferred-completion.md](./2026-09-16-partial-deferred-completion.md) diff --git a/.doc/test-reports/2026-09-22-redline-evidence-d7-test-report.md b/.doc/test-reports/2026-09-22-redline-evidence-d7-test-report.md new file mode 100644 index 00000000..49361fc3 --- /dev/null +++ b/.doc/test-reports/2026-09-22-redline-evidence-d7-test-report.md @@ -0,0 +1,71 @@ +# 红线证据:D7 留存表面盘点 + Track E ID-only(无物理删除) + +## 一、 测试背景 (Background) + +D7 ADR [`2026-09-17-d7-chat-data-retention`](../adr/2026-09-17-d7-chat-data-retention.md) 仍为 `pending-compliance-signoff`。本轮只做 DB/备份/日志留存表面静态复验与 Track E ID-only 合规清单;**禁止**按 365/180/30 草案物理删除或清备份。 + +## 二、 测试目标 (Test Objectives) + +- 盘点会话正文、派生记忆、事件、日志、备份、workspace、FAV 终态表面 +- 确认无 `DELETE FROM chat_*` / `SET deleted_at` 写路径 +- Track E:`StaticContracts` payload 字段无正文;sanitize 负例 PASS +- 不升 FEATURE-MATRIX D7;不写 gap-matrix blocker(无已确认违规) + +## 三、 测试方案与环境 (Test Plan & Environment) + +| 项 | 值 | +|----|----| +| OS | Darwin 25.6.0 arm64 | +| 分支 | `feature/redline-evidence-2026-09-22` | +| 被测 SHA | `364ed7f1a3f0393ef77ec4623a9518116ed2cb87` | +| 方法 | 静态检索 + events 契约单测;**未**连共享 PG 写库;**未**执行 `pg_dump` | +| 证据 | `assets/2026-09-22-redline-evidence/` + [Track E 清单](../ops/checklists/2026-09-22-d7-track-e-id-only-compliance.md) | + +相对 [W7 盘点](../audit/2026-09-17-d7-data-inventory.md) 做工程复验;本机无授权共享 DB 只读会话,不重复生产计数。 + +## 四、 预期结果 (Expected Results) + +- 无物理删除证据 +- Track E forbidden 字段命中 = NONE +- ADR 仍 `pending-compliance-signoff` + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) + +### 5.1 删除写路径静态扫描 + +- **测试输入 (Input)**:`rg 'DELETE FROM chat_|SET deleted_at' -g '*.go' internal/` +- **实际输出 (Actual Output)**:`NONE`。存在内容编辑用 `UPDATE chat_messages`(非 retention soft-delete)。见 `d7-no-physical-delete.txt` +- **评价判定 (Evaluation / Verdict)**:PASS(无 retention 物理/软删写路径) +- **性能与耗时 (Duration & Latency)**:N/A + +### 5.2 备份 / 日志表面 + +- **测试输入 (Input)**:阅读 `scripts/backup-system-db.sh`;检索 compose logging +- **实际输出 (Actual Output)**:备份为 `pg_dump -Fc` 整库(含 chat 明文);本轮**未**执行 dump、**未**清 `./backups`。compose 未统一声明 log `max-size`(与 W7 结论一致,属签字后整改项)。见 `d7-static-inventory.txt` +- **评价判定 (Evaluation / Verdict)**:PASS(盘点完成;无删除) +- **性能与耗时 (Duration & Latency)**:N/A + +### 5.3 Track E ID-only + +- **测试输入 (Input)**:解析 `StaticContracts` PayloadFields;`go test ./internal/events/ -run 'Static|Contract|Payload|YAML|Sanitize|OmitSensitive'` +- **实际输出 (Actual Output)**:字段集合无 `content`/`body`/`message`/`prompt`;含 `summary_ref` 等 ID/摘要引用。`TestIntentPlanContractsOmitSensitivePayload` / `TestSanitizeSummaryDropsPayload` / `TestRegistryParityWithYAML` PASS。见 `d7-track-e-payload-fields.txt` / `d7-track-e.txt` +- **评价判定 (Evaluation / Verdict)**:PASS +- **性能与耗时 (Duration & Latency)**:~0.5s + +### 5.4 ADR / 矩阵 + +- **实际输出 (Actual Output)**:ADR `compliance: pending-compliance-signoff`;本轮不升 D7 done、不写 gap-matrix +- **评价判定 (Evaluation / Verdict)**:PASS(边界遵守) + +## 六、 自动化测试套件汇总 (Test Suite Execution) + +```text +rg DELETE/SET deleted_at chat_* NONE +StaticContracts payload forbidden_hits=NONE +ok internal/events Sanitize/OmitSensitive/Parity PASS +pg_dump / physical delete NOT EXECUTED +``` + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) + +留存表面与 Track E ID-only 复验 PASS。合规签字前禁止按草案数字删除。详细勾选见 [Track E 清单](../ops/checklists/2026-09-22-d7-track-e-id-only-compliance.md)。 diff --git a/.doc/test-reports/2026-09-22-redline-evidence-fav-test-report.md b/.doc/test-reports/2026-09-22-redline-evidence-fav-test-report.md new file mode 100644 index 00000000..1755a5c5 --- /dev/null +++ b/.doc/test-reports/2026-09-22-redline-evidence-fav-test-report.md @@ -0,0 +1,89 @@ +# 红线证据:FAV subscriber audit + shadow reconcile(无 live) + +## 一、 测试背景 (Background) + +W6 shadow 已合 `dev`。本轮只做 **subscriber 审计 + shadow 复验 + 观察窗启动前置登记**。禁止整支 merge `feature/final-artifact-vault`;不启用 live `Register(fav)`;不翻转 `FAV_DEGRADED_READ`。 + +## 二、 测试目标 (Test Objectives) + +- `ObserveShadow`:`WouldStage` / `WouldPublish` / `DegradedReadUsed` 恒 false +- `HandleLease` 默认 disabled;`Enabled=true` 仍 fail-closed 至 cutover 审批 +- `Registry.Register(fav)` / `AssertLiveConsumers` / claim 路径硬拒 `fav` +- compose 默认 `FAV_DEGRADED_READ=false`、`FAV_PUBLISHER_ENABLED=false` +- 登记观察窗启动前置;**本轮不开始计时** + +## 三、 测试方案与环境 (Test Plan & Environment) + +| 项 | 值 | +|----|----| +| OS | Darwin 25.6.0 arm64 | +| Go | go1.27.1 | +| 分支 | `feature/redline-evidence-2026-09-22` | +| 被测 SHA | `364ed7f1a3f0393ef77ec4623a9518116ed2cb87` | +| 实测时间 | 2026-09-22T13:25:12Z | +| 证据 | `.doc/test-reports/assets/2026-09-22-redline-evidence/` | + +## 四、 预期结果 (Expected Results) + +- shadow 可观测且无写回执 +- Register(fav) / live consumers 仍拒绝 +- vault status:`consumer_mode=off` / live 未放量 +- 观察窗前置已登记但未起算 + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) + +### 5.1 Subscriber shadow 单测 + +- **测试输入 (Input)**:`go test -count=1 -short ./internal/app/fav/ ./internal/events/ -run 'Fav|Register|ObserveShadow|Cutover|Disabled|Vault' -v` +- **实际输出 (Actual Output)**: + - `TestFavSubscriberDefaultsDisabled` PASS + - `TestFavSubscriberStillDisabledWhenFlagOnWithoutRegistryApproval` PASS + - `TestFavSubscriberShadowComputesIntendedOutcomeWithoutWrites` PASS + - cutover / claim disabled / manifest 含 disabled FAV PASS + - 见 `fav-shadow.txt` +- **评价判定 (Evaluation / Verdict)**:PASS +- **性能与耗时 (Duration & Latency)**:~0.3s + +### 5.2 Registry / vault 硬门 + +- **测试输入 (Input)**:`go test -count=1 -short ./internal/events/ -run 'Register|AssertLive|LiveConsumers|Manifest' -v`;`go test -count=1 -short ./internal/server/ -run 'VaultDefaults|VaultStatus' -v` +- **实际输出 (Actual Output)**:`AssertLiveConsumersRejectsFAV` / `LiveConsumersOmitsFAV` / `VaultDefaultsStayDisabled` / `VaultStatusReportsOff` PASS。见 `fav-register-gate.txt` / `fav-vault-status.txt` +- **评价判定 (Evaluation / Verdict)**:PASS(**未**启用 live Register) +- **性能与耗时 (Duration & Latency)**:~0.7s + +### 5.3 Compose 默认(静态) + +- **测试输入 (Input)**:`rg FAV_DEGRADED_READ|FAV_PUBLISHER_ENABLED docker-compose.{dev,test,main}.yml` +- **实际输出 (Actual Output)**:dev/test `${...:-false}`;main 硬编码 `"false"`。见 `fav-compose-defaults.txt` +- **评价判定 (Evaluation / Verdict)**:PASS(默认 false;本轮未改 compose) +- **性能与耗时 (Duration & Latency)**:N/A + +### 5.4 观察窗启动前置(登记,未计时) + +须同时满足后才可起算(任一缺失不得起算): + +1. 用户显式授权 `fav` durable consumer cutover(非整支 merge) +2. 解除 `events` 硬门(`Register(fav)` / `SetMode` / claim)——本批禁止改 +3. 顺序:`staging → artifact → publication`;每级 `shadow → drain → live` +4. 每级 ≥7 天或 ≥N 终态样本(取更严);崩溃/重启幂等证据 +5. `FAV_DEGRADED_READ` 全程 false +6. 三环境 compose 与 sysadmin 目录一致;无旁路注册 +7. mutex `events` + CURRENT 集成槽位已认领 +8. 回滚预案:失败立即回 `shadow`/`off` + +- **评价判定 (Evaluation / Verdict)**:PASS(前置已登记);观察窗 **未开始** + +## 六、 自动化测试套件汇总 (Test Suite Execution) + +```text +ok internal/app/fav FavSubscriber* PASS +ok internal/events AssertLive/LiveConsumers/Manifest/Cutover PASS +ok internal/server VaultDefaults/VaultStatus PASS +compose defaults FAV_* = false +live Register(fav) NOT ENABLED +observation window NOT STARTED +``` + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) + +Shadow 复验 PASS;硬门仍 fail-closed。FEATURE-MATRIX FAV 保持 `partial`。下一步仅在用户授权 cutover 后按固定顺序开观察窗,且全程保持 `FAV_DEGRADED_READ=false`。 diff --git a/.doc/test-reports/2026-09-22-redline-evidence-pi-narrative-test-report.md b/.doc/test-reports/2026-09-22-redline-evidence-pi-narrative-test-report.md new file mode 100644 index 00000000..bfa7ac89 --- /dev/null +++ b/.doc/test-reports/2026-09-22-redline-evidence-pi-narrative-test-report.md @@ -0,0 +1,61 @@ +# 红线证据:PI change-report narrative fallback 负例(flag OFF) + +## 一、 测试背景 (Background) + +W3 已合入叙事路径;仓库默认 `PI_CHANGE_REPORT_NARRATIVE=false`。本轮补强 **flag-on 全量 fallback 负例**,使授权翻转 flag 时仍有 fail-closed 覆盖;**本轮不翻转**生产/compose flag。 + +## 二、 测试目标 (Test Objectives) + +- 默认 flag OFF:合法 PI payload 仍走确定性 fallback +- flag ON:畸形 JSON / schema / digest|SHA mismatch / timeout / error_code / partial / empty summary|raw → 全量 fallback,不泄漏叙事字段 +- CreateAgentCandidate:fetcher timeout/error/empty body → fallback 且 `err=nil` +- `AuthorizedFlipPath` 文档化:默认仍 off;on 时畸形仍 fallback +- compose / `.env.example` 保持 `false` + +## 三、 测试方案与环境 (Test Plan & Environment) + +| 项 | 值 | +|----|----| +| OS | Darwin 25.6.0 arm64 | +| Go | go1.27.1 | +| 分支 | `feature/redline-evidence-2026-09-22` | +| 基线 SHA | `364ed7f1a3f0393ef77ec4623a9518116ed2cb87` | +| 变更 | `internal/docrevision/narrative_test.go`(加宽负例;未改生产代码) | +| 证据 | `assets/2026-09-22-redline-evidence/pi-narrative.txt` | + +## 四、 预期结果 (Expected Results) + +全部匹配 `Narrative|ResolveChangeReport|CreateAgentCandidate_Flag` 用例 PASS;flag 默认 off。 + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) + +### 5.1 负例矩阵 + +- **测试输入 (Input)**:`go test -count=1 -short ./internal/docrevision/ -run 'Narrative|ResolveChangeReport|CreateAgentCandidate_Flag' -v` +- **实际输出 (Actual Output)**:见 `pi-narrative.txt`。含: + - `TestPIChangeReportNarrativeFlagDefaultOff` PASS + - `TestResolveChangeReport_FlagOffUsesDeterministic` PASS + - `TestResolveChangeReport_FlagOnMalformedFullFallback` 11 子例 PASS(bad json / schema / kind / digest / from_sha / to_sha / timeout / error_code / partial / empty summary / empty raw) + - `TestResolveChangeReport_AuthorizedFlipPathKeepsFlagOffDefault` PASS + - `CreateAgentCandidate_FlagOn{Timeout,FetcherError,EmptyFetcherBody}FallsBack*` PASS +- **评价判定 (Evaluation / Verdict)**:PASS +- **性能与耗时 (Duration & Latency)**:~0.35s + +### 5.2 默认 flag 静态 + +- **测试输入 (Input)**:`rg PI_CHANGE_REPORT_NARRATIVE docker-compose.*.yml .env.example` +- **实际输出 (Actual Output)**:dev/test/main 均为 `${PI_CHANGE_REPORT_NARRATIVE:-false}`;`.env.example=false`。见 `pi-flag-defaults.txt` +- **评价判定 (Evaluation / Verdict)**:PASS(保持 OFF) +- **性能与耗时 (Duration & Latency)**:N/A + +## 六、 自动化测试套件汇总 (Test Suite Execution) + +```text +ok internal/docrevision Narrative/ResolveChangeReport/CreateAgentCandidate_Flag* PASS +PI_CHANGE_REPORT_NARRATIVE default false +production flag flip NOT DONE +``` + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) + +Fallback 全负例已就位,授权后可翻转 flag 而不失去 fail-closed。本轮 flag **保持 OFF**;`features.go` reason 文案交由并行 `status-drift-reconcile` worktree,避免冲突。 diff --git a/.doc/test-reports/2026-09-22-redline-evidence-swboot-test-report.md b/.doc/test-reports/2026-09-22-redline-evidence-swboot-test-report.md new file mode 100644 index 00000000..4015f11c --- /dev/null +++ b/.doc/test-reports/2026-09-22-redline-evidence-swboot-test-report.md @@ -0,0 +1,103 @@ +# 红线证据:SWBOOT L1–L4(stub fail-closed;无仓写) + +## 一、 测试背景 (Background) + +FEATURE-MATRIX「纯软件项目自举」仍为 `partial`:SWBOOT-00..09 已合入,**SWBOOT-10 保持 fail-closed stub**。本轮只复验验收清单中**无需真实仓写**的 L1–L4 项;L5(真实 PI)/ L6(Ubuntu 无头浏览器)标 **pending auth**,不冒充 PASS。 + +## 二、 测试目标 (Test Objectives) + +- L1:`software_bootstrap` / `software_delivery` manifest 可校验;目录/域过滤;创建预览拒绝 `controlled_patch` +- L2(无 PG):领域预览 / 软件创建无医疗默认;PG 迁移与空库升级本机 **NOT RUN**(无 `TEST_DATABASE_URL`) +- L3:前端 build/test —— 本机 `web/node_modules` 缺 `tsc`/`tsx` → **NOT RUN**(基础设施缺项,非产品失败) +- L4:stub 小队顾问无工具;拒绝 `controlled_patch`;live MiniMax **SKIP**(未设 `RUN_PI_E2E`) +- SWBOOT-10 stub:非 allowlist 拒绝;allowlist 路径仍拒 `ExecuteControlledPatch` / `ApproveMerge` +- 不实现真实 patch/merge/push;不翻转任何生产 flag + +## 三、 测试方案与环境 (Test Plan & Environment) + +| 项 | 值 | +|----|----| +| OS | Darwin 25.6.0 arm64 | +| Go | go1.27.1 | +| 分支 | `feature/redline-evidence-2026-09-22` | +| 被测 SHA | `364ed7f1a3f0393ef77ec4623a9518116ed2cb87` | +| 实测时间 | 2026-09-22T13:25:12Z | +| 层级 | L1 单元 + L2 无 PG short + L4 stub;L3/L5/L6 未跑 | +| 证据 | `.doc/test-reports/assets/2026-09-22-redline-evidence/` | + +对照清单:[../ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md](../ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md) + +## 四、 预期结果 (Expected Results) + +| 层 | 预期 | +|----|------| +| L1 | Official keys / domain filter / software manifests / creation preview / stub allowlist PASS | +| L2 PG | 无库则如实 SKIP/NOT RUN,不冒充迁移 PASS | +| L3 | 缺工具则 NOT RUN | +| L4 | stub advisor PASS;live PI SKIP | +| SWBOOT-10 | 全程 `ERR_SWBOOT10_STUB_ONLY` / `ERR_EXECUTION_MODE_DISABLED` | +| L5/L6 | pending auth | + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) + +### 5.1 L1 — manifest / catalog / stub + +- **测试输入 (Input)**:`go test -count=1 -short ./internal/swboot/ ./internal/workflowdef/ ./internal/projectworkflow/ ./internal/app/ -run 'Software|Swboot|SWBOOT|RepoAllowlist|ControlledPatch|OfficialWorkflow|CompatibleWithProductDomain|ValidateDefinitionV2_Software|CreateSoftware|PiSoftware' -v` +- **实际输出 (Actual Output)**:全部匹配用例 PASS;`TestPiSoftwareBootstrapAdvisor_LiveMiniMax` SKIP(需 `RUN_PI_E2E=1`)。见 `assets/.../swboot-l1.txt` +- **评价判定 (Evaluation / Verdict)**:PASS(L1 + stub) +- **性能与耗时 (Duration & Latency)**:~0.7s 包级 + +### 5.2 L2 — 领域 short(无 PG) + +- **测试输入 (Input)**:`go test -count=1 -short ./internal/projectworkflow/ ./internal/projectinstance/ ./internal/swboot/ -v` +- **实际输出 (Actual Output)**:非 PG 用例 PASS;`TestPG_*` 因 `TEST_DATABASE_URL not set` SKIP。见 `swboot-l2-short.txt` +- **评价判定 (Evaluation / Verdict)**:PASS(领域 short);**PG 迁移 / 空库升级 NOT RUN** +- **性能与耗时 (Duration & Latency)**:~0.8s + +### 5.3 L3 — 前端 + +- **测试输入 (Input)**:`cd web && npm test` / `npm run build` +- **实际输出 (Actual Output)**:`tsx: command not found`;`tsc: command not found`(无完整 `node_modules`)。见 `l3-frontend.txt` / `l3-build-attempt.txt` +- **评价判定 (Evaluation / Verdict)**:**NOT RUN**(本机前端工具链未装;非用例失败) +- **性能与耗时 (Duration & Latency)**:N/A + +### 5.4 L4 — stub 工程测试 + +- **测试输入 (Input)**:`go test -count=1 -short ./internal/app/ -run 'PiSoftwareBootstrap' -v` +- **实际输出 (Actual Output)**:`NoTools` / `RejectsControlledPatch` PASS;LiveMiniMax SKIP。见 `swboot-l4-stub.txt` +- **评价判定 (Evaluation / Verdict)**:PASS(stub);真实 PI **pending auth / NOT RUN** +- **性能与耗时 (Duration & Latency)**:~0.3s + +### 5.5 SWBOOT-10 fail-closed(无仓写) + +- **测试输入 (Input)**:`TestRepoAllowlistStub`;`TestBuildCreationPreview_RejectsControlledPatchAndSoloPrivacy`;`TestPiSoftwareBootstrapAdvisor_RejectsControlledPatch` +- **实际输出 (Actual Output)**:非 allowlist → `ERR_REPO_PATH_NOT_ALLOWLISTED`;patch/merge → `ERR_SWBOOT10_STUB_ONLY`;创建预览 `ERR_EXECUTION_MODE_DISABLED` +- **评价判定 (Evaluation / Verdict)**:PASS(stub fail-closed;**未**写任何真实仓库) +- **性能与耗时 (Duration & Latency)**:含于 L1 + +### 5.6 arch-check + +- **测试输入 (Input)**:`./scripts/arch-check.sh --mode block` +- **实际输出 (Actual Output)**:`arch-check block: production gate passed`。见 `arch-check.txt` +- **评价判定 (Evaluation / Verdict)**:PASS +- **性能与耗时 (Duration & Latency)**:~1.5s + +### 5.7 L5 / L6 + +- **评价判定 (Evaluation / Verdict)**:**pending auth** — 真实 PI Runner 全链路与 Ubuntu Playwright UI 需单独授权与共享环境持锁;本轮不启动。 + +## 六、 自动化测试套件汇总 (Test Suite Execution) + +```text +ok internal/swboot PASS (stub + preview) +ok internal/workflowdef OfficialWorkflowKeys / SoftwareManifests PASS +ok internal/projectworkflow CreateSoftwareProject_NoMedicalDefaults PASS +ok internal/app PiSoftwareBootstrap* PASS + Live SKIP +ok internal/projectinstance short PASS;PG SKIP +arch-check --mode block production gate passed +web npm test/build NOT RUN (tsc/tsx missing) +``` + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) + +L1 与可在无仓写下复验的 L4 stub / SWBOOT-10 fail-closed **PASS**。L2 PG 与 L3 因环境缺项如实 **NOT RUN/SKIP**。L5/L6 **pending auth**。SWBOOT-10 **仍为 stub**,不得升 FEATURE-MATRIX 为 done。下一步需独立安全评审 + 真实执行器授权后另开任务。 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/arch-check.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/arch-check.txt new file mode 100644 index 00000000..5e65d3dc --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/arch-check.txt @@ -0,0 +1,7 @@ +=== arch-check === +arch-check mode=block +boundaries=/private/tmp/Agent-System/.worktrees/redline-evidence-2026-09-22/.doc/system-design/module-boundaries.yaml +ok chat-agent-system/internal/archtest 0.976s +ok chat-agent-system/internal/archtest 0.494s +arch-check block: production gate passed +EXIT:0 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-no-physical-delete.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-no-physical-delete.txt new file mode 100644 index 00000000..e6181521 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-no-physical-delete.txt @@ -0,0 +1,11 @@ +=== chat physical delete / soft-delete write paths === +NONE +=== chat_messages UPDATE (content edit paths, not retention) === +internal/ctxmgr/recategorize.go:99: UPDATE chat_messages +internal/ctxmgr/message_update.go:30: UPDATE chat_messages +internal/ctxmgr/message_update.go:77: UPDATE chat_messages +internal/ctxmgr/message_update.go:118: UPDATE chat_messages +=== ADR compliance field === +6:compliance: pending-compliance-signoff +18:**提议 / 工程草案**(2026-09-17)。数字与删除口径标 `pending-compliance-signoff`:合规签字或改数前,W7 仅允许数据分类盘点与现状审计,不得按未签字数字执行物理删除或备份清除。接受后状态改为 `accepted`。 +54:- W7 可按本草案启动盘点;物理删除与备份清除在 `pending-compliance-signoff` 解除前禁止按建议数字自动执行。 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-static-inventory.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-static-inventory.txt new file mode 100644 index 00000000..9a2a8666 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-static-inventory.txt @@ -0,0 +1,18 @@ +=== D7 DELETE / soft-delete / retention === +internal/artifactvault/registry.go:265: source_run_id, payload_sha256, terminal_state, policy_version, publication_status, retention_class +internal/artifactvault/registry.go:296: terminal_state, policy_version, publication_status, retention_class, requested_at +internal/artifactvault/types.go:134: RetentionClass string `json:"retention_class,omitempty"` +---backup--- +3:# 系统业务库备份脚本 (backup-system-db.sh) +7:# 2. 采用 pg_dump -Fc 导出系统业务库(含 task_runs、工作流治理等); +11:# ./scripts/backup-system-db.sh <目标备份目录> +15:# 2. ${HOME}/.secrets/backup-env 中 SYSTEM_DB_PASSWORD_ +17:# 当前实现经 docker exec 以库内角色执行 pg_dump,通常不需要宿主机口令; +32: $0 dev ./backups/system_dev_20260912 +33: $0 test /tmp/agent_system_test_backup +36: SYSTEM_DB_PASSWORD 或 \${HOME}/.secrets/backup-env 或 configs/.env. +81: local secrets_file="${HOME}/.secrets/backup-env" +115:# 仅保留变量供未来宿主机连接扩展;当前 pg_dump 走容器内角色。 +161:echo "[导出] pg_dump -Fc ${DB_NAME} ..." +163:docker exec "${CONTAINER_NAME}" pg_dump -U "${DB_USER}" -d "${DB_NAME}" -Fc -Z 6 -f "${TMP_CONTAINER_DUMP}" +---log driver--- diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-track-e-payload-fields.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-track-e-payload-fields.txt new file mode 100644 index 00000000..7d240734 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-track-e-payload-fields.txt @@ -0,0 +1,4 @@ +all_payload_fields_sorted= ['candidate_id', 'doc_id', 'environment', 'impacted_doc_id', 'plan_id', 'project_id', 'report_id', 'revision', 'risk', 'run_id', 'session_id', 'snapshot_id', 'status', 'step_id', 'summary_ref', 'task_key', 'user_id', 'version_no'] +forbidden_hits= NONE +has_summary_ref= True +contract_count= 11 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-track-e.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-track-e.txt new file mode 100644 index 00000000..6e815ac5 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/d7-track-e.txt @@ -0,0 +1,19 @@ +=== Track E contracts / content forbidden === +internal/events/registry.go:50: {EventName: EventIntentPlanAwaiting, SchemaVersion: 1, Enabled: true, Producers: []string{"app/intentflow", "events"}, Consumers: []string{ConsumerProjection, ConsumerNotify}, PayloadFields: []string{"plan_id", "revision", "status", "environment", "project_id", "user_id", "session_id", "summary_ref"}}, +internal/events/registry.go:51: {EventName: EventIntentPlanStepChanged, SchemaVersion: 1, Enabled: true, Producers: []string{"app/intentflow", "events"}, Consumers: []string{ConsumerProjection, ConsumerNotify}, PayloadFields: []string{"plan_id", "revision", "step_id", "status", "environment", "project_id", "user_id", "session_id", "summary_ref"}}, +internal/events/registry.go:52: {EventName: EventIntentPlanCompleted, SchemaVersion: 1, Enabled: true, Producers: []string{"app/intentflow", "events"}, Consumers: []string{ConsumerProjection, ConsumerNotify}, PayloadFields: []string{"plan_id", "revision", "status", "environment", "project_id", "user_id", "session_id", "summary_ref"}}, +internal/events/registry.go:148: PayloadFields []string `json:"payload_fields"` +.doc/system-design/module-boundaries.yaml:141: - doccontent +.doc/system-design/module-boundaries.yaml:147: - doccontent +.doc/system-design/module-boundaries.yaml:149: doccontent: [] +.doc/system-design/module-boundaries.yaml:343: artifact_payload_staging: +=== RUN TestClassifySafeKnownContract +--- PASS: TestClassifySafeKnownContract (0.00s) +=== RUN TestSanitizeSummaryDropsPayload +--- PASS: TestSanitizeSummaryDropsPayload (0.00s) +=== RUN TestIntentPlanContractsOmitSensitivePayload +--- PASS: TestIntentPlanContractsOmitSensitivePayload (0.00s) +=== RUN TestRegistryParityWithYAML +--- PASS: TestRegistryParityWithYAML (0.00s) +PASS +ok chat-agent-system/internal/events 0.490s diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/env.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/env.txt new file mode 100644 index 00000000..134949c1 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/env.txt @@ -0,0 +1,6 @@ +SHA=364ed7f1a3f0393ef77ec4623a9518116ed2cb87 DATE=2026-09-22T13:25:12Z OS=Darwin GO=go1.27.1 +darwin +arm64 +go1.27.1 +Darwin WeiCHENdeMac-mini.local 25.6.0 Darwin Kernel Version 25.6.0: Fri Jul 31 19:17:26 PDT 2026; root:xnu-12377.161.14~5/RELEASE_ARM64_T6041 arm64 +2026-09-22T13:26:20Z diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-compose-defaults.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-compose-defaults.txt new file mode 100644 index 00000000..f6954328 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-compose-defaults.txt @@ -0,0 +1,6 @@ +docker-compose.main.yml:132: FAV_DEGRADED_READ: "false" +docker-compose.main.yml:133: FAV_PUBLISHER_ENABLED: "false" +docker-compose.test.yml:129: FAV_DEGRADED_READ: ${FAV_DEGRADED_READ:-false} +docker-compose.test.yml:130: FAV_PUBLISHER_ENABLED: ${FAV_PUBLISHER_ENABLED:-false} +docker-compose.dev.yml:133: FAV_DEGRADED_READ: ${FAV_DEGRADED_READ:-false} +docker-compose.dev.yml:134: FAV_PUBLISHER_ENABLED: ${FAV_PUBLISHER_ENABLED:-false} diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-register-gate.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-register-gate.txt new file mode 100644 index 00000000..61dcaa83 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-register-gate.txt @@ -0,0 +1,10 @@ +=== RUN TestAssertLiveConsumersRejectsFAV +--- PASS: TestAssertLiveConsumersRejectsFAV (0.00s) +=== RUN TestAssertLiveConsumersRejectsUnknown +--- PASS: TestAssertLiveConsumersRejectsUnknown (0.00s) +=== RUN TestLiveConsumersOmitsFAV +--- PASS: TestLiveConsumersOmitsFAV (0.00s) +=== RUN TestManifestJSONIncludesDisabledFAV +--- PASS: TestManifestJSONIncludesDisabledFAV (0.00s) +PASS +ok chat-agent-system/internal/events 0.321s diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-registry-gate-lines.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-registry-gate-lines.txt new file mode 100644 index 00000000..4755c8bb --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-registry-gate-lines.txt @@ -0,0 +1,9 @@ +13: ConsumerFAV = "fav" +22: EventFAVArtifactStaged = "fav.artifact_staged" +49: {EventName: EventFAVArtifactStaged, SchemaVersion: 1, Enabled: false, Producers: []string{"app/docflow"}, Consumers: []string{ConsumerFAV}, PayloadFields: []string{"doc_id", "snapshot_id"}}, +84: if cons == ConsumerFAV || strings.EqualFold(cons, "fav") { +85: return fmt.Errorf("%w: fav", ErrDisabledConsumer) +102: if n == ConsumerFAV { +119:func (r *Registry) Register(consumer string) error { +123: if consumer == ConsumerFAV || strings.EqualFold(consumer, "fav") { +124: return fmt.Errorf("%w: fav", ErrDisabledConsumer) diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-shadow.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-shadow.txt new file mode 100644 index 00000000..7ebbbbdc --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-shadow.txt @@ -0,0 +1,20 @@ +=== FAV shadow === +=== RUN TestFavSubscriberDefaultsDisabled +--- PASS: TestFavSubscriberDefaultsDisabled (0.00s) +=== RUN TestFavSubscriberStillDisabledWhenFlagOnWithoutRegistryApproval +--- PASS: TestFavSubscriberStillDisabledWhenFlagOnWithoutRegistryApproval (0.00s) +=== RUN TestFavSubscriberShadowComputesIntendedOutcomeWithoutWrites +--- PASS: TestFavSubscriberShadowComputesIntendedOutcomeWithoutWrites (0.00s) +PASS +ok chat-agent-system/internal/app/fav 0.293s +=== RUN TestValidateOpsCutoverRejectsFavAndNonDev +--- PASS: TestValidateOpsCutoverRejectsFavAndNonDev (0.00s) +=== RUN TestValidateOpsCutoverAllowsThreeConsumers +--- PASS: TestValidateOpsCutoverAllowsThreeConsumers (0.00s) +=== RUN TestClaimIDsDisabled +--- PASS: TestClaimIDsDisabled (0.00s) +=== RUN TestManifestJSONIncludesDisabledFAV +--- PASS: TestManifestJSONIncludesDisabledFAV (0.00s) +PASS +ok chat-agent-system/internal/events 0.303s +EXIT:0 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-static-audit.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-static-audit.txt new file mode 100644 index 00000000..ebe42909 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-static-audit.txt @@ -0,0 +1,19 @@ +=== FAV compose defaults === +--- +internal/events/registry.go:81: return fmt.Errorf("%w: %s", ErrDisabledConsumer, eventName) +internal/events/registry.go:85: return fmt.Errorf("%w: fav", ErrDisabledConsumer) +internal/events/registry.go:124: return fmt.Errorf("%w: fav", ErrDisabledConsumer) +internal/app/fav/subscriber.go:4:// a separate approval. Registry.Register("fav") and SetMode(fav, live) already +internal/app/fav/subscriber.go:41: return fmt.Errorf("%w: fav", events.ErrDisabledConsumer) +internal/app/fav/subscriber.go:44: return fmt.Errorf("%w: fav publisher cutover not approved", events.ErrDisabledConsumer) +internal/app/fav/subscriber.go:53:// as a write receipt; WouldStage/WouldPublish stay false in this slice. +internal/app/fav/subscriber.go:59: WouldStage bool +internal/app/fav/subscriber.go:60: WouldPublish bool +internal/app/fav/subscriber.go:64:// ObserveShadow computes the intended FAV outcome without business side effects. +internal/app/fav/subscriber.go:66:func (c *EventConsumer) ObserveShadow(lease events.Lease) (IntendedOutcome, error) { +internal/app/fav/subscriber.go:74: return out, fmt.Errorf("%w: fav", events.ErrDisabledConsumer) +internal/app/fav/subscriber.go:79: out.WouldStage = false +internal/app/fav/subscriber.go:80: out.WouldPublish = false +internal/events/dispatcher.go:126: return nil, fmt.Errorf("%w: fav", ErrDisabledConsumer) +internal/events/dispatcher.go:165: return nil, fmt.Errorf("%w: fav", ErrDisabledConsumer) +internal/events/dispatcher.go:338: return fmt.Errorf("%w: fav", ErrDisabledConsumer) diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-vault-status.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-vault-status.txt new file mode 100644 index 00000000..8e40c723 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/fav-vault-status.txt @@ -0,0 +1,6 @@ +=== RUN TestVaultDefaultsStayDisabled +--- PASS: TestVaultDefaultsStayDisabled (0.00s) +=== RUN TestVaultStatusReportsOff +--- PASS: TestVaultStatusReportsOff (0.00s) +PASS +ok chat-agent-system/internal/server 0.681s diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/head-sha.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/head-sha.txt new file mode 100644 index 00000000..a8951ce1 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/head-sha.txt @@ -0,0 +1 @@ +364ed7f1a3f0393ef77ec4623a9518116ed2cb87 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/l3-build-attempt.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/l3-build-attempt.txt new file mode 100644 index 00000000..8d4f99df --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/l3-build-attempt.txt @@ -0,0 +1,5 @@ + +> shuimu-workbench@1.0.0 build +> tsc && vite build && node scripts/precompress-dist.mjs + +sh: tsc: command not found diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/l3-frontend.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/l3-frontend.txt new file mode 100644 index 00000000..6b7035c1 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/l3-frontend.txt @@ -0,0 +1,7 @@ +=== L3 frontend quick === + +> shuimu-workbench@1.0.0 test +> tsx --test "src/**/!(*InteractiveCard*|*chatWindowArtifact*|*deliverableSync*).test.ts" && vitest run src/components/chat/InteractiveCard.test.ts src/components/chat/chatWindowArtifact.test.ts src/components/chat/deliverableSync.test.ts --run + +sh: tsx: command not found +EXIT:0 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/narrative-diff-stat.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/narrative-diff-stat.txt new file mode 100644 index 00000000..e69de29b diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/pi-flag-defaults.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/pi-flag-defaults.txt new file mode 100644 index 00000000..11d7f4cb --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/pi-flag-defaults.txt @@ -0,0 +1,5 @@ +=== PI narrative flag defaults === +docker-compose.test.yml:128: PI_CHANGE_REPORT_NARRATIVE: ${PI_CHANGE_REPORT_NARRATIVE:-false} +docker-compose.main.yml:131: PI_CHANGE_REPORT_NARRATIVE: ${PI_CHANGE_REPORT_NARRATIVE:-false} +docker-compose.dev.yml:131: PI_CHANGE_REPORT_NARRATIVE: ${PI_CHANGE_REPORT_NARRATIVE:-false} +.env.example:117:PI_CHANGE_REPORT_NARRATIVE=false diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/pi-narrative.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/pi-narrative.txt new file mode 100644 index 00000000..cece13d7 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/pi-narrative.txt @@ -0,0 +1,50 @@ +=== PI narrative === +=== RUN TestMaterializeAgentOutput_FlagOnFetcherNarrativeComplete +--- PASS: TestMaterializeAgentOutput_FlagOnFetcherNarrativeComplete (0.00s) +=== RUN TestPIChangeReportNarrativeFlagDefaultOff +--- PASS: TestPIChangeReportNarrativeFlagDefaultOff (0.00s) +=== RUN TestResolveChangeReport_FlagOffUsesDeterministic +--- PASS: TestResolveChangeReport_FlagOffUsesDeterministic (0.00s) +=== RUN TestResolveChangeReport_FlagOnValidNarrativeKeepsServerRisk +--- PASS: TestResolveChangeReport_FlagOnValidNarrativeKeepsServerRisk (0.00s) +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/bad_json +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/bad_schema_version +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/wrong_schema_kind +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/digest_mismatch +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/from_sha_mismatch +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/to_sha_mismatch +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/timeout_envelope +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/top-level_error_code +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/partial_flag +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/empty_summary +=== RUN TestResolveChangeReport_FlagOnMalformedFullFallback/empty_raw +--- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/bad_json (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/bad_schema_version (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/wrong_schema_kind (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/digest_mismatch (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/from_sha_mismatch (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/to_sha_mismatch (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/timeout_envelope (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/top-level_error_code (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/partial_flag (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/empty_summary (0.00s) + --- PASS: TestResolveChangeReport_FlagOnMalformedFullFallback/empty_raw (0.00s) +=== RUN TestResolveChangeReport_AuthorizedFlipPathKeepsFlagOffDefault +--- PASS: TestResolveChangeReport_AuthorizedFlipPathKeepsFlagOffDefault (0.00s) +=== RUN TestCreateAgentCandidate_FlagOffIgnoresNarrativeEnrichment +--- PASS: TestCreateAgentCandidate_FlagOffIgnoresNarrativeEnrichment (0.00s) +=== RUN TestCreateAgentCandidate_FlagOnTimeoutFallsBackWithoutError +--- PASS: TestCreateAgentCandidate_FlagOnTimeoutFallsBackWithoutError (0.00s) +=== RUN TestCreateAgentCandidate_FlagOnFetcherApplies +--- PASS: TestCreateAgentCandidate_FlagOnFetcherApplies (0.00s) +=== RUN TestCreateAgentCandidate_FlagOnFetcherErrorFallsBack +--- PASS: TestCreateAgentCandidate_FlagOnFetcherErrorFallsBack (0.00s) +=== RUN TestCreateAgentCandidate_FlagOnEmptyFetcherBodyFallsBack +--- PASS: TestCreateAgentCandidate_FlagOnEmptyFetcherBodyFallsBack (0.00s) +=== RUN TestNarrativeModelInput_IncludesClippedChangeText +--- PASS: TestNarrativeModelInput_IncludesClippedChangeText (0.00s) +PASS +ok chat-agent-system/internal/docrevision 0.350s +EXIT:0 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l1.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l1.txt new file mode 100644 index 00000000..fb839a4b --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l1.txt @@ -0,0 +1,29 @@ +=== SWBOOT L1 unit === +=== RUN TestBuildCreationPreview_RejectsControlledPatchAndSoloPrivacy +--- PASS: TestBuildCreationPreview_RejectsControlledPatchAndSoloPrivacy (0.00s) +=== RUN TestRepoAllowlistStub +--- PASS: TestRepoAllowlistStub (0.00s) +PASS +ok chat-agent-system/internal/swboot 0.290s +=== RUN TestOfficialWorkflowKeys +--- PASS: TestOfficialWorkflowKeys (0.00s) +=== RUN TestCompatibleWithProductDomain +--- PASS: TestCompatibleWithProductDomain (0.00s) +=== RUN TestValidateDefinitionV2_SoftwareManifests +--- PASS: TestValidateDefinitionV2_SoftwareManifests (0.00s) +PASS +ok chat-agent-system/internal/workflowdef 0.383s +=== RUN TestCreateSoftwareProject_NoMedicalDefaults +--- PASS: TestCreateSoftwareProject_NoMedicalDefaults (0.00s) +PASS +ok chat-agent-system/internal/projectworkflow 0.600s +=== RUN TestPiSoftwareBootstrapAdvisor_NoTools +--- PASS: TestPiSoftwareBootstrapAdvisor_NoTools (0.00s) +=== RUN TestPiSoftwareBootstrapAdvisor_RejectsControlledPatch +--- PASS: TestPiSoftwareBootstrapAdvisor_RejectsControlledPatch (0.00s) +=== RUN TestPiSoftwareBootstrapAdvisor_LiveMiniMax + pi_swboot_test.go:55: set RUN_PI_E2E=1 for live PI software bootstrap +--- SKIP: TestPiSoftwareBootstrapAdvisor_LiveMiniMax (0.00s) +PASS +ok chat-agent-system/internal/app 0.722s +EXIT:0 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l2-short.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l2-short.txt new file mode 100644 index 00000000..076ff3af --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l2-short.txt @@ -0,0 +1,82 @@ +=== SWBOOT L2 short (authz/create/reject) === +=== RUN TestPG_GoverningAccess_CompletedAndTerminatedDeny + access_governing_pg_test.go:157: TEST_DATABASE_URL not set; skipping PostgreSQL integration test +--- SKIP: TestPG_GoverningAccess_CompletedAndTerminatedDeny (0.00s) +=== RUN TestPG_GoverningAccess_QueryErrorFailClosed +--- PASS: TestPG_GoverningAccess_QueryErrorFailClosed (0.00s) +=== RUN TestPG_ActivateOfficialWorkflowRuntimeMetadata + activation_official_pg_test.go:18: TEST_DATABASE_URL not set; skipping PostgreSQL integration test +--- SKIP: TestPG_ActivateOfficialWorkflowRuntimeMetadata (0.00s) +=== RUN TestPG_ActivationAndStageAdvance + pg_integration_test.go:49: TEST_DATABASE_URL not set; skipping PostgreSQL integration test +--- SKIP: TestPG_ActivationAndStageAdvance (0.00s) +=== RUN TestPG_RDevActivateWithNAClose + rdev_pg_test.go:15: TEST_DATABASE_URL not set; skipping PostgreSQL integration test +--- SKIP: TestPG_RDevActivateWithNAClose (0.00s) +=== RUN TestActiveWorkflowScope_NoLiveInstanceReturnsEmpty +--- PASS: TestActiveWorkflowScope_NoLiveInstanceReturnsEmpty (0.00s) +=== RUN TestTaskKeyInScope_EmptyAllowsAll +--- PASS: TestTaskKeyInScope_EmptyAllowsAll (0.00s) +=== RUN TestTaskKeyInScope_CanonicalAlias +--- PASS: TestTaskKeyInScope_CanonicalAlias (0.00s) +=== CONT TestClassifyDocDuty +=== RUN TestClassifyDocDuty/all_zero +=== CONT TestNormalizeAuthorOnlyDuties +--- PASS: TestNormalizeAuthorOnlyDuties (0.00s) +=== PAUSE TestClassifyDocDuty/all_zero +=== RUN TestClassifyDocDuty/negative +=== PAUSE TestClassifyDocDuty/negative +=== RUN TestClassifyDocDuty/one_role +=== PAUSE TestClassifyDocDuty/one_role +=== RUN TestClassifyDocDuty/two_roles +=== PAUSE TestClassifyDocDuty/two_roles +=== RUN TestClassifyDocDuty/full_distinct +=== PAUSE TestClassifyDocDuty/full_distinct +=== RUN TestClassifyDocDuty/full_duplicate +=== PAUSE TestClassifyDocDuty/full_duplicate +=== CONT TestClassifyDocDuty/all_zero +=== CONT TestResolveDocTaskDuty +--- PASS: TestResolveDocTaskDuty (0.00s) +=== CONT TestCountFullDutyDocs +--- PASS: TestCountFullDutyDocs (0.00s) +=== CONT TestValidateDocTaskDuties +--- PASS: TestValidateDocTaskDuties (0.00s) +=== CONT TestNormalizeDocTaskDuties +--- PASS: TestNormalizeDocTaskDuties (0.00s) +=== CONT TestDocTaskRequiresDuty +--- PASS: TestDocTaskRequiresDuty (0.00s) +=== CONT TestEvaluateStageReadiness_AuthorOnlyIsManaged +--- PASS: TestEvaluateStageReadiness_AuthorOnlyIsManaged (0.00s) +=== CONT TestComputePlanHash_LegacySnapshotStableWithoutDutyPolicy +--- PASS: TestComputePlanHash_LegacySnapshotStableWithoutDutyPolicy (0.00s) +=== CONT TestEvaluateStageReadiness_DutyModes +--- PASS: TestEvaluateStageReadiness_DutyModes (0.00s) +=== CONT TestValidateAuthorOnlyDocTaskDuties +=== CONT TestClassifyDocDuty/two_roles +--- PASS: TestValidateAuthorOnlyDocTaskDuties (0.00s) +=== CONT TestClassifyDocDuty/one_role +=== CONT TestClassifyDocDuty/negative +=== CONT TestClassifyDocDuty/full_duplicate +=== CONT TestClassifyDocDuty/full_distinct +--- PASS: TestClassifyDocDuty (0.00s) + --- PASS: TestClassifyDocDuty/all_zero (0.00s) + --- PASS: TestClassifyDocDuty/two_roles (0.00s) + --- PASS: TestClassifyDocDuty/negative (0.00s) + --- PASS: TestClassifyDocDuty/one_role (0.00s) + --- PASS: TestClassifyDocDuty/full_duplicate (0.00s) + --- PASS: TestClassifyDocDuty/full_distinct (0.00s) +PASS +ok chat-agent-system/internal/projectinstance 0.547s +=== RUN TestProjectTypesCatalog +--- PASS: TestProjectTypesCatalog (0.00s) +=== RUN TestBuildCreationPreview_SelfBootstrapSolo +--- PASS: TestBuildCreationPreview_SelfBootstrapSolo (0.00s) +=== RUN TestBuildCreationPreview_RejectsControlledPatchAndSoloPrivacy +--- PASS: TestBuildCreationPreview_RejectsControlledPatchAndSoloPrivacy (0.00s) +=== RUN TestRepoAllowlistStub +--- PASS: TestRepoAllowlistStub (0.00s) +=== RUN TestSuggestDeliveryAfterBootstrapNeverActivates +--- PASS: TestSuggestDeliveryAfterBootstrapNeverActivates (0.00s) +PASS +ok chat-agent-system/internal/swboot 0.796s +EXIT:0 diff --git a/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l4-stub.txt b/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l4-stub.txt new file mode 100644 index 00000000..4ec3bf49 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-22-redline-evidence/swboot-l4-stub.txt @@ -0,0 +1,11 @@ +=== SWBOOT L4 stub advisor === +=== RUN TestPiSoftwareBootstrapAdvisor_NoTools +--- PASS: TestPiSoftwareBootstrapAdvisor_NoTools (0.00s) +=== RUN TestPiSoftwareBootstrapAdvisor_RejectsControlledPatch +--- PASS: TestPiSoftwareBootstrapAdvisor_RejectsControlledPatch (0.00s) +=== RUN TestPiSoftwareBootstrapAdvisor_LiveMiniMax + pi_swboot_test.go:55: set RUN_PI_E2E=1 for live PI software bootstrap +--- SKIP: TestPiSoftwareBootstrapAdvisor_LiveMiniMax (0.00s) +PASS +ok chat-agent-system/internal/app 0.309s +EXIT:0 diff --git a/internal/docrevision/narrative_test.go b/internal/docrevision/narrative_test.go index 8b6111f0..b6ebd3e0 100644 --- a/internal/docrevision/narrative_test.go +++ b/internal/docrevision/narrative_test.go @@ -123,16 +123,22 @@ func TestResolveChangeReport_FlagOnMalformedFullFallback(t *testing.T) { t.Cleanup(docrevision.ResetPIChangeReportNarrativeForTest) fromSHA, toSHA, ruleRisk, impacts, diff := sampleDiff(t) + digest := docrevision.NarrativeInputDigest(fromSHA, toSHA, ruleRisk, impacts, diff.Hunks) cases := []struct { name string raw string }{ {"bad json", `{not-json`}, {"bad schema version", `{"schema_version":99,"schema_kind":"change_report_narrative_v1","input_digest":"x","summary":["a"]}`}, + {"wrong schema kind", `{"schema_version":1,"schema_kind":"other_v1","input_digest":"` + digest + `","from_sha":"` + fromSHA + `","to_sha":"` + toSHA + `","summary":["PI only"]}`}, {"digest mismatch", mustNarrativeJSON(t, fromSHA, toSHA, "deadbeef", []string{"ok"})}, + {"from_sha mismatch", mustNarrativeJSONWithSHAs(t, "wrong-from", toSHA, digest, []string{"PI only"})}, + {"to_sha mismatch", mustNarrativeJSONWithSHAs(t, fromSHA, "wrong-to", digest, []string{"PI only"})}, {"timeout envelope", `{"result_v1":{"outcome":"error","error_code":"TIMEOUT"},"narrative":{"schema_version":1,"schema_kind":"change_report_narrative_v1"}}`}, + {"top-level error_code", `{"schema_version":1,"schema_kind":"change_report_narrative_v1","input_digest":"` + digest + `","from_sha":"` + fromSHA + `","to_sha":"` + toSHA + `","error_code":"RUNNER_FAILED","summary":["PI only"]}`}, {"partial flag", `{"schema_version":1,"schema_kind":"change_report_narrative_v1","input_digest":"x","partial":true,"summary":["a"]}`}, - {"empty summary", mustNarrativeJSON(t, fromSHA, toSHA, docrevision.NarrativeInputDigest(fromSHA, toSHA, ruleRisk, impacts, diff.Hunks), nil)}, + {"empty summary", mustNarrativeJSON(t, fromSHA, toSHA, digest, nil)}, + {"empty raw", ""}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { @@ -154,11 +160,19 @@ func TestResolveChangeReport_FlagOnMalformedFullFallback(t *testing.T) { t.Fatalf("mixed narrative field leaked: %q", s) } } + if rep.DeterministicFacts["narrative_applied"] == true { + t.Fatal("fallback must not claim narrative_applied") + } }) } } func mustNarrativeJSON(t *testing.T, fromSHA, toSHA, digest string, summary []string) string { + t.Helper() + return mustNarrativeJSONWithSHAs(t, fromSHA, toSHA, digest, summary) +} + +func mustNarrativeJSONWithSHAs(t *testing.T, fromSHA, toSHA, digest string, summary []string) string { t.Helper() raw, err := json.Marshal(map[string]any{ "schema_version": 1, @@ -174,6 +188,43 @@ func mustNarrativeJSON(t *testing.T, fromSHA, toSHA, digest string, summary []st return string(raw) } +// TestResolveChangeReport_AuthorizedFlipPathKeepsFlagOffDefault documents the +// pre-authorization contract: default remains off; when a future owner flips the +// flag for a controlled window, malformed PI output still full-falls-back. +func TestResolveChangeReport_AuthorizedFlipPathKeepsFlagOffDefault(t *testing.T) { + docrevision.ResetPIChangeReportNarrativeForTest() + t.Cleanup(docrevision.ResetPIChangeReportNarrativeForTest) + if docrevision.PIChangeReportNarrativeEnabled() { + t.Fatal("PI_CHANGE_REPORT_NARRATIVE must remain off until separately authorized") + } + + fromSHA, toSHA, ruleRisk, impacts, diff := sampleDiff(t) + digest := docrevision.NarrativeInputDigest(fromSHA, toSHA, ruleRisk, impacts, diff.Hunks) + piRaw := mustNarrativeJSON(t, fromSHA, toSHA, digest, []string{"should stay ignored while off"}) + + offRep, err := docrevision.ResolveChangeReport(piRaw, fromSHA, toSHA, ruleRisk, impacts, diff) + if err != nil { + t.Fatal(err) + } + if offRep.AnalysisStatus != docrevision.AnalysisFallback { + t.Fatalf("default-off must ignore PI narrative, got %s", offRep.AnalysisStatus) + } + + docrevision.SetPIChangeReportNarrativeForTest(true) + onBad, err := docrevision.ResolveChangeReport(`{"schema_version":1,"schema_kind":"change_report_narrative_v1"}`, fromSHA, toSHA, ruleRisk, impacts, diff) + if err != nil { + t.Fatal(err) + } + if onBad.AnalysisStatus != docrevision.AnalysisFallback { + t.Fatalf("authorized-on malformed must still fallback, got %s", onBad.AnalysisStatus) + } + + docrevision.SetPIChangeReportNarrativeForTest(false) + if docrevision.PIChangeReportNarrativeEnabled() { + t.Fatal("test toggle must restore off before exit") + } +} + func TestCreateAgentCandidate_FlagOffIgnoresNarrativeEnrichment(t *testing.T) { docrevision.SetPIChangeReportNarrativeForTest(false) t.Cleanup(docrevision.ResetPIChangeReportNarrativeForTest) @@ -289,6 +340,32 @@ func TestCreateAgentCandidate_FlagOnFetcherErrorFallsBack(t *testing.T) { } } +func TestCreateAgentCandidate_FlagOnEmptyFetcherBodyFallsBack(t *testing.T) { + docrevision.SetPIChangeReportNarrativeForTest(true) + t.Cleanup(docrevision.ResetPIChangeReportNarrativeForTest) + + svc := docrevision.NewService(nil) + svc.NarrativeFetcher = func(_ context.Context, _ docrevision.NarrativeFetchSpec) (string, error) { + return " ", nil + } + ctx := context.Background() + st, err := svc.OpenTemplateVersion(ctx, "doc_flag_on_empty", "# base\n\nbody\n", docrevision.ActorSnapshot{DisplayName: "t"}, 1, "") + if err != nil { + t.Fatal(err) + } + cand, rep, err := svc.CreateAgentCandidate(ctx, docrevision.AgentCandidateRequest{ + DocID: "doc_flag_on_empty", RunID: "r-empty", InputSnapshotID: st.HeadSnapshotID, + OutputMarkdown: "# base\n\nbody changed\n", + ActorKind: docrevision.ActorAgent, + }) + if err != nil { + t.Fatalf("empty fetcher body must full-fallback without error, got %v", err) + } + if cand == nil || rep == nil || rep.AnalysisStatus != docrevision.AnalysisFallback { + t.Fatalf("want fallback candidate, got cand=%v rep=%+v", cand, rep) + } +} + func TestNarrativeModelInput_IncludesClippedChangeText(t *testing.T) { long := strings.Repeat("甲", 280) spec := docrevision.NarrativeFetchSpec{