diff --git a/.doc/ops/short-term/2026-09-26-sysadmin-maturity-refresh.md b/.doc/ops/short-term/2026-09-26-sysadmin-maturity-refresh.md new file mode 100644 index 00000000..119ce91f --- /dev/null +++ b/.doc/ops/short-term/2026-09-26-sysadmin-maturity-refresh.md @@ -0,0 +1,40 @@ +# sysadmin 功能目录成熟度刷新(short-term) + +- **task_id**: sysadmin-maturity-refresh-2026-09-26 +- **owner**: pi +- **status**: in_progress +- **授权来源**: 用户会话反馈「重新看了 dev 功能特性页面,这些还都是降级状态」——页面徽标未反映 2026-09-26 放量后的接线事实,构成对目录刷新的即时授权(承接 degraded-flags-enable-2026-09-26-r4)。 +- **write_scope**: internal/sysadmin, .doc/ops/CURRENT.md, .doc/ops/short-term +- **mutex**: sysadmin-maturity +- **base_dev_sha**: 1d13a892fcd7b6676346502bb236a440efbf46c8 +- **capabilities**: git:dev, env:dev, docs:publish +- **policy_revision**: AGENTS 2026-09 / agent-worktree-workflow r1 / validation-contract 2026-09-21 + +## 一、问题 + +`featureMaturityCatalog`(internal/sysadmin/features.go)自述为"源码接线事实,不随环境变量翻转",但其内容停留在 2026-09-24 I2 时代;degraded-flags-enable 放量后页面"值"已翻转(confirm/true/*)而"适配"列仍显示降级,用户判断页面失真。逐项核对: + +| 键 | 旧目录断言 | 当前事实与证据 | +|---|---|---| +| MULTI_INTENT_PLAN_TIER | degraded,"默认仍 legacy" | I2/I3/P8 合入并验收(I2 报告 5.1–5.4;P8 报告);dev 现行 confirm+* | +| MULTI_INTENT_U11_DOCGOV | degraded,"其余 key 仍 dry-run" | P8 后全部键接真实引擎(matrix intent-plan-u9u12 行),剩余键由逐键 flag 控制 | +| MULTI_INTENT_U12_RUN_CONTROL | 同上 | 同上 | +| SEMANTIC_SUMMARY_SHADOW | shadow/degraded,"默认关闭、可见集 digest 仍空" | 影子链路生产化(D3 收口);job#18 visibility_digest 已落盘非空;dev 已开 | +| SEMANTIC_SUMMARY_REPLACE | shadow/degraded,"默认关" | 双开关全量接线含 `*` 通配(dev 6b317181);真实链路命中新会话 | +| PI_CHANGE_REPORT_NARRATIVE | shadow/degraded,"待放量授权" | 2026-09-23 收口真 MiniMax 复测 PASS;dev 已按授权开启 | + +FAV 两项(红线)不动。 + +## 二、修改 + +- 目录六项改 `live+ready`,reason 改写为带证据日期的当前事实;U11/U12 reason 保留"逐键 flag(默认关)"提示,防止误读为可 full 放量。 +- service_test.go:narrative/五键断言改 live+ready;保留 chat_summaries 与防回退断言(不得再出现"尚未在运行环境执行/尚未切到");新增 U11/U12 reason 必须含"逐键"。 + +## 三、验证计划 + +1. `go test ./internal/sysadmin/` + arch-check block + `go test -short ./...` +2. 集成后重启 dev 单二进制(env:dev),GET /api/v1/admin/system/features 复核六项 `adapter=ready`、值不变。 + +## 四、结果登记 + +(待填) diff --git a/internal/sysadmin/features.go b/internal/sysadmin/features.go index 6f1ae026..aa85f355 100644 --- a/internal/sysadmin/features.go +++ b/internal/sysadmin/features.go @@ -51,8 +51,8 @@ var featureMaturityCatalog = map[string]featureMaturity{ reason: "降级读保持关闭", }, "MULTI_INTENT_PLAN_TIER": { - state: implLive, adapter: adapterDegraded, - reason: "I2 接线就绪:shadow 持久不可执行计划 + 项目 allowlist + 指标;默认仍 legacy,升档需 allowlist 与阈值验收", + state: implLive, adapter: adapterReady, + reason: "I2/I3/P8 已合入并按 allowlist 验收(shadow→auto_read→confirm,项目 6579);dev 现行 confirm+*(2026-09-26 授权放量);U11/U12 逐键 live flag 默认关,禁止 full 一次放量", }, "INTENT_PLAN_PROJECT_ALLOWLIST": { state: implLive, adapter: adapterReady, @@ -67,24 +67,24 @@ var featureMaturityCatalog = map[string]featureMaturity{ reason: "project.fact.supplement 经 MutateOwner 写项目黑板(ctxmgr 端口);需 ExpectedResourceVersion", }, "MULTI_INTENT_U11_DOCGOV": { - state: implLive, adapter: adapterDegraded, - reason: "document.claim / document.review.submit 接 docgov 引擎;其余 docgov key 仍 dry-run;项目 143 只读", + state: implLive, adapter: adapterReady, + reason: "P8 后全部 docgov 键已接真实引擎:claim/review.submit 随域名 flag,review/final/proposal 三组逐键 flag(默认关)另控;项目 143 只读", }, "MULTI_INTENT_U12_RUN_CONTROL": { - state: implLive, adapter: adapterDegraded, - reason: "workflow.run / run.resume 接 projectworkflow 与 taskrun;其余 run-control key 仍 dry-run", + state: implLive, adapter: adapterReady, + reason: "P8 后全部 run-control 键已接真实引擎:workflow.run/run.resume 随域名 flag,switch/restart 逐键 flag(默认关)另控", }, "SEMANTIC_SUMMARY_SHADOW": { - state: implShadow, adapter: adapterDegraded, - reason: "影子组件默认关闭;dev/test schema 61 已含 chat_summaries。摘要请求已用 reasoning profile,pi-agent 经 bind-mount 的 pi-args.mjs 带 --no-tools。授权可见集 digest 仍空", + state: implLive, adapter: adapterReady, + reason: "影子链路生产化(durable jobs/租约/watermark/provenance,dev schema 75 含 chat_summaries);可见集 digest 已随 provenance 落盘;dev 已开启(2026-09-26)", }, "SEMANTIC_SUMMARY_REPLACE": { - state: implShadow, adapter: adapterDegraded, - reason: "fail-closed 灰度已接线(2026-09-26):验证 OK 后仅替换白名单会话 served Narrative(支持 * 全部会话,含后续新建);Facts/计数保持 deterministic;digest 仍 advisory;默认关", + state: implLive, adapter: adapterReady, + reason: "fail-closed 双开关已全量接线(master+SESSIONS,支持 * 全部会话含后续新建;四重校验;Facts/digest 保持 deterministic);dev 已开 *(2026-09-26)", }, "PI_CHANGE_REPORT_NARRATIVE": { - state: implShadow, adapter: adapterDegraded, - reason: "只读事实已含截断差异;reasoning/--no-tools 目标落盘与真实 MiniMax 链路已复测。开关默认关闭,待放量授权前保持 shadow", + state: implLive, adapter: adapterReady, + reason: "2026-09-23 收口真实 MiniMax 复测 PASS(截断差异+reasoning 落盘);dev 已按授权常驻开启(2026-09-26);test/main 保持默认关", }, } diff --git a/internal/sysadmin/service_test.go b/internal/sysadmin/service_test.go index 68c1a9ff..fd24030b 100644 --- a/internal/sysadmin/service_test.go +++ b/internal/sysadmin/service_test.go @@ -148,8 +148,8 @@ func TestFeatures_CoversCatalogAndInjectedValues(t *testing.T) { t.Fatalf("catalog must cover %s", key) } } - if byKey["PI_CHANGE_REPORT_NARRATIVE"].ImplementationState != "shadow" || byKey["PI_CHANGE_REPORT_NARRATIVE"].AdapterReadiness != "degraded" { - t.Fatalf("narrative readiness must stay degraded while the flag is off (shadow default), even though pi-agent already mounts --no-tools: %+v", byKey["PI_CHANGE_REPORT_NARRATIVE"]) + if byKey["PI_CHANGE_REPORT_NARRATIVE"].ImplementationState != "live" || byKey["PI_CHANGE_REPORT_NARRATIVE"].AdapterReadiness != "ready" { + t.Fatalf("narrative must read live+ready after the 2026-09-26 dev rollout (real MiniMax retest PASS; dev flag on): %+v", byKey["PI_CHANGE_REPORT_NARRATIVE"]) } if !strings.Contains(byKey["SEMANTIC_SUMMARY_SHADOW"].AdapterReason, "chat_summaries") { t.Fatalf("semantic summary reason must reflect schema 61 chat_summaries: %+v", byKey["SEMANTIC_SUMMARY_SHADOW"]) @@ -159,8 +159,16 @@ func TestFeatures_CoversCatalogAndInjectedValues(t *testing.T) { t.Fatalf("readiness reasons must not claim missing migration or missing --no-tools: summary=%+v narrative=%+v", byKey["SEMANTIC_SUMMARY_SHADOW"], byKey["PI_CHANGE_REPORT_NARRATIVE"]) } - if !strings.Contains(byKey["PI_CHANGE_REPORT_NARRATIVE"].AdapterReason, "待放量授权") { - t.Fatalf("narrative reason must note retest-complete and awaiting rollout auth: %+v", byKey["PI_CHANGE_REPORT_NARRATIVE"]) + if !strings.Contains(byKey["PI_CHANGE_REPORT_NARRATIVE"].AdapterReason, "2026-09-26") { + t.Fatalf("narrative reason must note the dev rollout date: %+v", byKey["PI_CHANGE_REPORT_NARRATIVE"]) + } + for _, key := range []string{"MULTI_INTENT_PLAN_TIER", "MULTI_INTENT_U11_DOCGOV", "MULTI_INTENT_U12_RUN_CONTROL", "SEMANTIC_SUMMARY_SHADOW", "SEMANTIC_SUMMARY_REPLACE"} { + if byKey[key].AdapterReadiness != "ready" || byKey[key].ImplementationState != "live" { + t.Fatalf("%s must read live+ready after I2/I3/P8 wiring and the 2026-09-26 dev rollout: %+v", key, byKey[key]) + } + } + if !strings.Contains(byKey["MULTI_INTENT_U11_DOCGOV"].AdapterReason, "逐键") || !strings.Contains(byKey["MULTI_INTENT_U12_RUN_CONTROL"].AdapterReason, "逐键") { + t.Fatalf("U11/U12 reasons must keep the per-key rollout gate visible: %+v %+v", byKey["MULTI_INTENT_U11_DOCGOV"], byKey["MULTI_INTENT_U12_RUN_CONTROL"]) } } @@ -171,6 +179,7 @@ func TestFeatures_ConfiguredValueDoesNotImplyReadiness(t *testing.T) { "SEMANTIC_SUMMARY_REPLACE": "true", "MULTI_INTENT_PLAN_TIER": "confirm", "MULTI_INTENT_U9_SEGMENT": "true", + "FAV_PUBLISHER_ENABLED": "true", } }, }) @@ -189,10 +198,11 @@ func TestFeatures_ConfiguredValueDoesNotImplyReadiness(t *testing.T) { } replace := byKey["SEMANTIC_SUMMARY_REPLACE"] // 2026-09-26 fail-closed gray wiring: the master bit alone replaces - // nothing (session allowlist required); configured=true must not read as - // rollout-ready. - if replace.Value != "true" || replace.ImplementationState != "shadow" || replace.AdapterReadiness != "degraded" { - t.Fatalf("replace must report shadow/degraded under fail-closed gray: %+v", replace) + // nothing (session allowlist required); after the dev rollout the catalog + // reads live+ready while the empty SESSIONS value still shows the + // defense-in-depth default (replaces nothing until an allowlist is set). + if replace.Value != "true" || replace.ImplementationState != "live" || replace.AdapterReadiness != "ready" { + t.Fatalf("replace must read live+ready after full fail-closed wiring: %+v", replace) } if !strings.Contains(replace.Description, "白名单") { t.Fatalf("replace description must surface the allowlist requirement: %+v", replace) @@ -201,9 +211,15 @@ func TestFeatures_ConfiguredValueDoesNotImplyReadiness(t *testing.T) { if allow.Value != "" { t.Fatalf("replace sessions allowlist must default to empty (replaces nothing): %+v", allow) } + // Static wiring facts must not flip with configured values: FAV stays + // dry_run/unavailable even when configured true (red line, no live yet). + fav := byKey["FAV_PUBLISHER_ENABLED"] + if fav.Value != "true" || fav.ImplementationState != "dry_run" || fav.AdapterReadiness != "unavailable" { + t.Fatalf("FAV must keep dry_run/unavailable regardless of configured value: %+v", fav) + } tier := byKey["MULTI_INTENT_PLAN_TIER"] - if tier.Value != "confirm" || tier.ImplementationState != "live" || tier.AdapterReadiness != "degraded" { - t.Fatalf("confirm tier value must not imply rollout-ready: %+v", tier) + if tier.Value != "confirm" || tier.ImplementationState != "live" || tier.AdapterReadiness != "ready" { + t.Fatalf("confirm tier value with I2/I3/P8 wiring must read live+ready: %+v", tier) } u9 := byKey["MULTI_INTENT_U9_SEGMENT"] if u9.Value != "true" || u9.ImplementationState != "live" || u9.AdapterReadiness != "ready" {