zizi 6dcabf69fb feat(solo): 收口治理入口并裁剪 studio 表面
完成 2.0.0 S4 的外部 AI、admin、account 与 solo SQL 收口,并推进 S5 studio 市场/handoff/旧编辑器入口裁剪。S5 的前端单测、构建与 route-only e2e 已留证;MSW-off 创作主线 e2e 仍因本地后端活体启动口径待修正,已在总账标为未完成验收。
2026-07-08 11:45:26 +08:00

20 lines
17 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# .agent — muse-module-ai(AI 编排 BC)
> 模块跨会话记忆。真实现状权威见 [现状基线 §5.1](../../docs/agent-specs/2026-06-13-项目目标与模块现状基线.md);进度见 [总账](../../docs/mvp/进度总账.md)。本文件只记目标/边界/out-of-scope/现状指针/TODO,过时即更。
- **目标(owner 职责)**:链路编排 / 上下文组装 / 生成 / 分析 / 全书解析 / 质量门控 / AI 候选(Suggestion)/ 规划候选 / 风险标记 / Quality Result / 运行记录;承载 Protection Node(grant)与 Quality Policy。
- **边界(不可违反)**:**只产 Shadow,绝不直写 Canonical**;只消费服务端签发的 Runtime Permission Envelope,不能自授权;runtime/任务执行侧不得直连 `ToolGrant` 写模型(`AiGrantRuntimeBoundaryArchTest` 最小门禁已守住);grant 与 runtime 完整物理包隔离仍后置;守 BC 边界不碰他域 `.dal`([bc-boundaries](../../.agents/rules/bc-boundaries.md);历史违例 `ContentMuseWorkOwnerFacade` **已整改消除**——改消费 content `MuseContentWorkOwnerApi`,门禁已收紧、无豁免)。
- **out-of-scope**:Accept Suggestion(归 content BC)、正文写入。
- **现状**:只读评估 80%;后端真实较高质量(无 stub),`RealNewApiMuseAiRuntimeClient` 真打 New-API,SSE 已脱占位;studio `/agents` 已补自建智能体生命周期活体证(2026-06-27:`agent-create.spec.ts` MSW-off 真单体 1/1,覆盖创建初始版本、编辑生成 v2、版本切换、归档非当前版本、归档 AgentDB 证 `current_version_id` 与版本 status)。
- **E4 market agent 物化(2026-06-27)**:market agent handoff 不再信任客户端 `sourceAgentId/sourceAgentVersion`;AI 目标 owner 按 market asset `source_id` 解析发布者 agent并物化为安装者本地 user agent槽位绑定指向本地副本。MSW-off Playwright `handoff-agent.spec.ts` 2/0F/0E正路物化后真实创建 AI task 并完成 New-API runtime负路伪造 token 被拒。注意e2e 前置种入 Security 已批准 runtime grant生产 runtime 不自授权。
- **E5 account 用量/配额接线(2026-06-27)**:AI task 创建前经 Account owner 预占配额,成功投影时记录 usage 并累加 quota used,非可重试失败终态释放预占;AI 只消费 member-api 端口,不碰 member DAL。`P1rAiRuntimeEndToEndLiveAcceptanceIT` 显式 live 3/0F/0E/0S,反查 Account usage record=1、quota used=1、reserve audit=1、release audit=0、attribution job/item completed。targeted AI 单测中 `MuseAiTaskServiceTest` 40/0F/0E、`MuseAiRuntimeProjectionServiceTest` 6/0F/0E。
- **E6 admin AI 配置接线(2026-06-27)**:Muse Admin AI 配置页 Prompt 激活、质量评估启动、质量策略版本创建、system Agent 创建/版本发布/归档停用、Tool Grant 登记/调整已调用真实 admin API不再展示硬编码评估分数。后端 `adminArchiveAgent` 只允许 system scope归档 Agent 时同步归档 active 槽位绑定,避免运行时继续消费已停用系统能力;质量策略回滚仍保持 preview-only/线 B。RC 后已补 Quality eval 本地确定性执行器:默认 worker 领取 `evaluation` queued job合成/脱敏 dataset 才可执行,写 sample result/聚合 metricSummary 并推进 run/job 终态;不调用外部 LLM、不读取私有正文审计只落 dataset hash/聚合摘要。验证:`muse-admin` AI 配置目标 Vitest 2 files / 9 tests passed`@vben/web-antd typecheck` 通过;后端 `MuseAgentServiceTest`+`AdminMuseAgentControllerAnnotationTest` 31/0F/0E/0S`MuseToolGrantServiceTest`+`LocalSecurityToolGrantApprovalFacadeTest` 13/0F/0E/0S`MuseQualityEvaluationWorkerTest`+`MuseAiJobMapperTest`+`MuseQualityPolicyServiceTest` 18/0F/0Eserver 契约/覆盖门 27/0F/0E/0S。
- **2.0.0 S0 覆盖门基线(2026-07-07)**:`adminArchiveAgent` 已作为 AI completed operation 纳入覆盖 JSONAI 域计数为 48总 completed 为 242。已同步修正 Market/Knowledge/Events legacy gate 中仍停留在 `AI 47 / completedOperations 241` 的陈旧断言;`run-p1r-verification.sh local` 复跑 61/0F/0E/0S、BUILD SUCCESS。后续不要把 AI 覆盖口径回退到 47/241。
- **Dify Adapter 最小闭环(2026-06-29)**:系统 Agent 版本配置新增 `runtimeProvider` / `providerRef.dify` / `outputContract`;新发布版本必须显式 provider旧版本缺省 runtime 仅兼容为 `new-api`。`RoutingMuseAiRuntimeClient` 按 provider 失败关闭路由,`RealDifyMuseAiRuntimeClient` 支持 Dify blocking chat/workflow 调用、错误分类、timeout、脱敏、无隐式 fallbackDify 内部知识上下文标记 `untraceable_provider_context`,当输出合同要求 Muse source refs 时直接失败关闭。Dify 密钥不入库,只通过 `credentialRef` 从后端配置取Admin 发布页只保存 Dify app/workflow/credentialRef 引用,`consoleUrl` 由后端按 allowlist 拼装。验证:`MuseAgentServiceTest`+`MuseAiRuntimeClientTest` 51/0F/0EAdmin AI 目标 Vitest 2 files / 9 tests passed。后续仍需真实 Dify live 验证与用量进入 New-API/Member 归属链路后再宣称生产级可计费。
- **2.0.0 S1 Dify live 验证(2026-07-07)**:Dify 1.15.0 已在 `mini-infra` 独立部署,写作 chat app `75f105e8-dbca-4aa6-a296-2113a65ad005` 通过 `P1rDifyChatLiveAcceptanceIT` 真跑;默认不设置 `MUSE_P1R_EXTERNAL_ACCEPTANCE=true` 时 honest skipped显式 opt-in 后真实 `POST /v1/chat-messages` 返回 `status=success`、`messageIdPresent=true`、`summarySha256Prefix=565339bc4d33`。后端配置新增 `muse.ai.dify.*` env 占位,密钥仍只走 `credentialRef`/env不进 DBS1 只证明 Dify app 可调用New-API attribution 仍显示 `requires_new_api_attribution`,后续接 Dify runtime 归属/计费前不得宣称 Member 用量已闭环。
- **2.0.0 S3 market 摘装配影响(2026-07-07)**:默认单体无 market-server历史 E4 market agent handoff 物化链路进入 dormantAI owner 自建 Agent、槽位、生成、SSE、Dify/New-API runtime 不依赖 market-server仍按自身门禁验证。恢复 market agent 安装/物化验收时用 `muse-server -Pmarket-assembled`。
- **2.0.0 S4 单人版外部 AI 脚手架关停(2026-07-08)**:`muse-module-ai-server` 与 `muse-server` 两处 `application.yaml` 已把 yudao 继承的 gemini/doubao/hunyuan/siliconflow/xinghuo/baichuan/midjourney/suno/web-search 九类 provider `enable` 关为 false并把历史明文 key/base-url/notify-url 改为 env 占位Spring AI 示例 `qianfan/zhipuai/openai/anthropic/stabilityai/dashscope/minimax/moonshot/deepseek` key 也改为 env 占位以满足全仓 application yaml grep 门。新增 `SoloExternalAiProviderGateTest` 并纳入 `run-p1r-verification.sh local`,断言默认 ApplicationContext 不注册九类外部 provider Bean仅保留 Dify/New-API runtime router 壳。验收:`run-p1r-verification.sh local` 64/0F/0E/0S`grep -rn "api-key: sk-\|api-key: AIza" muse-cloud/**/application*.yaml` 零命中。注意:已入 git 历史的旧 key 仍需人工轮换Midjourney/Suno 的 DB 模型驱动路径不是本步范围,后续只在显式配置下可用。
- **2.0.0 S4 单人版外部 AI 脚手架关停(2026-07-08)**:`muse-module-ai-server` 与 `muse-server` 两处 `application.yaml` 已把 yudao 继承的 gemini/doubao/hunyuan/siliconflow/xinghuo/baichuan/midjourney/suno/web-search 九类 provider `enable` 关为 false并把历史明文 key/base-url/notify-url 改为 env 占位Spring AI 示例 `qianfan/zhipuai/openai/anthropic/stabilityai/dashscope/minimax/moonshot/deepseek` key 也改为 env 占位以满足全仓 application yaml grep 门。S5 起栈追补已显式关闭 Spring AI Alibaba DashScope agent并把 `spring.ai.model.chat/embedding/image/rerank/video/audio.*` 置为 `none`,避免 DashScope 自动配置因 matchIfMissing 在无 API key 时阻断单体启动。新增 `SoloExternalAiProviderGateTest` 并纳入 `run-p1r-verification.sh local`,断言默认 ApplicationContext 不注册九类外部 provider Bean、DashScope Spring AI 自动配置 Bean仅保留 Dify/New-API runtime router 壳。验收:`run-p1r-verification.sh local` 65/0F/0E/0S追补 targeted gate `SoloExternalAiProviderGateTest,SoloAccountDefaultsGateTest` 5/0F/0E/0S`grep -rn "api-key: sk-\|api-key: AIza" muse-cloud/**/application*.yaml` 零命中。注意:已入 git 历史的旧 key 仍需人工轮换Midjourney/Suno 的 DB 模型驱动路径不是本步范围,后续只在显式配置下可用。
- **RC 后完整导入解析 owner(2026-06-28)**:新增 `MuseAiImportParseApi` 与 `MuseAiImportParseService`,由 AI owner 持久化 `muse_ai_parse_job` / `muse_ai_chapter_parse_result`,读取 Content 传入的稳定 storageRef 后支持 txt/markdown/docx/epub 文本抽取;默认按 Markdown/CN/EN 标题做确定性章节拆分,`parseConfig.mode=full_book` 或 `strategy=llm_full_book` 时调用 New-API LLM 全书解析,并对 timeout/429/5xx/连接失败做可重试处理。解析只输出 pending-review Shadow 章节并支持确认/驳回/replay不写 Content Canonical不写 Knowledge Local KB。验证:`MuseAiImportParseServiceTest`、`NewApiMuseAiImportLlmParserTest`、`P1rImportLlmNewApiLiveAcceptanceIT` live 与完整导入链路 real-PG/live 测试通过。
- **关键风险 / TODO**:**AI runtime 生成 e2e 已端到端真验(2026-06-24)**——方案1(d647f0c 剥离 sourceSnapshotId 解授权死结)+ D(4dadc7b `DefaultDBFieldHandler` 无登录兜底 `system`,根治 scheduled worker 写 creator/updater null 违约 NOT NULL;BaseDO 带 jdbcType 强制入列致 insert/update 同病)+ agent_version config 补 modelKey=MiniMax-M2.5 + 启动 source `scripts/dev/p1r-external-acceptance.env`(New-API/RAGFlow 配置)→ task5 completed+suggestion+MiniMax-M2.5 真 LLM 生成(P-B envelope/approved、P-C contextAssembly 固化 ✓)。**P-A/P-B/P-C 完整 e2e 已端到端真验打通(2026-06-24,task7)**:P-A 检索命中根因=knowledge 模块 bug——`HttpRagFlowKnowledgeRuntimeClient.retrieveChunks` 把 `document_ids` 以 null 入 retrieval body,RAGFlow 要求其为 list 故拒(code 102 "documents should be a list")→检索 fail-closed→chunkCount=0(task3/4/5/6 全 0 即此 bug,非 RAGFlow 数据/凭据/timeout)。已修(commit 86c6dba:null 时不入 body + 回归测试)。task7 contextAssembly `chunkCount=1/retrievedKbIds=[2]/authorizationSnapshotIds=[authsnap-e2e-1]`,LLM(MiniMax-M2.5)基于 grounding 续写。**02D 槽位首次创建死锁已修+真验(2026-06-24,commit 9115d4f)**:根因=precheck/bind 都 `requireSlotBinding`(缺行抛 forbidden),而"替换"是设计中唯一创建入口("替换"=首次写入、无独立创建端点是设计有意,见后端-04 line748/产品-02D line507)→死锁,首次绑定永不可达(work4 seed binding 实为 E2E 绕此 bug 手插)。修:precheck 缺行放行 + bind 抽 `persistBinding` upsert(无行 insert revision=1/有行 updateById 沿用乐观锁)+ V29 `uk_muse_agent_slot_binding_active` partial unique index(同 work+slot 仅一条 active 并发兜底)+ 前端 mock protected 口径对齐 `protected:` 前缀。真验(muse_slice_live):work1 `writing.continuation` precheck(不再 forbidden)→bind 首次建 binding(slotRevision=1 active)→GET 槽位显示 agent1→AI task 用 `agentSlotKey`(非 agentOverrideRef)→agent1 解析 + runtime 授权过门 → completed + suggestion7(MiniMax-M2.5 真 LLM"星环大陆魔法体系"续写、finishReason stop)。**前端 MVP(df063cb)agentSlotKey 路径真后端端到端走通**;单测 `MuseAgentSlotServiceTest` 26/26 + Controller 4/4 + 前端 4/4;V29 由 Flyway 启动日志证 applied。**E2 智能体生命周期与候选拒绝已补并真验(2026-06-27)**:用户自建 Agent create 会同步建 v1 active version;update 创建下一 active version并更新 `current_version_id`;版本面板支持 list/activate/archive 非当前版本;archive Agent 同步 archive active 槽位绑定;slot unbind 将 binding revision+1、status=`archived`、响应 `sourceStatus=unbound`;WorkspacePage reject 调 AI owner `POST /suggestions/{id}/reject` 写 `rejected` 与 decision archive。验证:AI targeted 单测+Controller 63/0F/0E,Studio `tsc`/目标 ESLint/targeted Vitest 29/0F/0E,MSW-off Playwright 真后端 5/0F/0E(采纳真生成 suggestionId=80、拒绝真生成 suggestionId=81、Agent 生命周期 DB 核验、Slot unbind DB 核验)。**仍缺/线 B**:Override Slot Contract 主数据(方案 B:合法 slot 校验/系统默认 agent/listWorkAgentSlots 预设骨架未做,slotKey 暂自由字符串、listSlots 缺行仅返回已绑定);前端 agent "运行试用"等深链;Quality eval 真实评估集管理/外发授权/LLM judge 仍后置;grant/runtime 完整物理包拆分仍未做。SSE `event:` 解析漂移已修复并有 targeted Vitest 证据(2026-06-19:`sse.test.ts` + `AIPanel.contract.test.tsx` 17/17);`muse-module-ai-contract-server` 空壳孤儿 submodule 已清理(2026-06-19:从 AI reactor 移除并删除唯一 pom,`P1rAiRouteOwnershipTest` 加回潮门禁)。**2026-06-25:AI 生成候选采纳断层已修(ADR-020 方案 A,commit a16c596)**——`MuseAiRuntimeProjectionService` 此前用 `numericEnvelopeId(Long.parseLong)` 落 authz 快照,但真 runtime envelope 是字符串 `rpe-local-uuid`→解析失败落 null→suggestion 恒不可采纳(merge 1041001001);改直落字符串 envelope(删 numericEnvelopeId)、`MuseAiSuggestionDO.authorizationSnapshotId` 改 String、`AiSuggestionMergeProjectionFacade.getSuggestion` 校验改 hasText、V30 列 BIGINT→VARCHAR(128)。揭 `P1rContentMergeGeneratedSuggestionIT` 假绿(注入数值 9001、真 runtime 不产数值),改真字符串 envelope 转真绿。活体真验:真生成 suggestion authz=rpe-local 字符串→采纳 merge code=0+block revision 自增,生成→采纳→Canonical 全链通。详见总账 2026-06-25 / ADR-020 / memory muse-ai-accept-authz-snapshot-fix。**2026-06-27:E1 accepted decision owner 归档已补**——`AiSuggestionMergeProjectionFacade.markSuggestionAccepted` 作为 AI owner 写 `muse_ai_suggestion_decision`、更新 suggestion `status=accepted/decision_archive_id`、记录 AI command 与 business audit幂等 replay 不重复写,非 pending 候选返回 conflict 且不预占 command。注意边界:AI 仍只归档 Shadow 决策与审计,不写 Canonical 正文,不保存 `finalContent` 或 provider 原文。P1r 真 PG 切片 6/0F/0E/0S。**2026-06-25(同日续):槽位绑定授权快照孪生收口(C1,commit 854f18c)**——三路盘点发现 `muse_agent_slot_binding.authorization_snapshot_id` 是采纳断层唯一漏网 binding 表(列 BIGINT、DO Long,bind 时 parseLong 对字符串 envelope `rpe-local-<uuid>` 返 null→授权快照静默丢失、绑定溯源链断);V31 两列(authz+source)BIGINT→VARCHAR(128)、DO Long→String、bind 两处(insert/updateById)直透传删 parseLong(`sameAuthorizationSnapshot` 的 parseLong 保留,字符串 envelope 走 fallback 字符串比较正确)。活体真验(muse_slice_live):真 envelope 经 precheck→bind,binding authz 列存非空 rpe-local(insert id=51+updateById id=50 两路径),列类型 varchar(128)、flyway V31 success;修前恒 null。**此前模块"仍缺"只列方案 B/深链/物理拆分,从未记此类型错配——盘点补上的盲区**。至此 ADR-020 全部 binding 表(knowledge V14 + suggestion/attribution V30 + slot V31)收口完成。 **2026-06-25(同日续):AI 流 SSE 长任务候选丢失已修(commit c77b006、A1+候选③、design-docs/临时-01 review 批准后执行)**——studio e2e ai-generation 真红根因=后端 `MuseAiTaskStreamServiceImpl` SSE 死线 30s 硬编码 < LLM 真时延(MiniMax 11-60s)、更 < 上游自己 `MUSE_AI_NEW_API_TOTAL_TIMEOUT_SECONDS=180`,poll 30s 后 `emitter.complete()` 静默关连接不补 done;前端 `connectAIStream` 一次性连接无重连(重连只在 connectEventStream)→LLM>30s 候选永丢(ai-gen 真红/accept flaky 是同 bug 时延两侧)。修:① 后端删 `DEFAULT_TIMEOUT_MILLIS` 常量→`@Value("${muse.ai.sse.task-timeout-millis:240000}")`(连接死线:70+poll deadline:198 同引用、application.yaml 配置项);② 前端退避重连续 poll + 按 SSE id 去重(后端不读 lastEventId、每次 seq0 全量回放→`lastSeenSequenceNo` 丢弃 id≤已见,避免重复渲染候选)+总超时 300s `onError(SSE_TIMEOUT)` 不静默卡死(返回仍 AbortController、AIPanel 零改动);③ A1 `scripts/dev/start-muse-server-infra.sh` 固化追加 source acceptance env(防漏 `MUSE_AI_NEW_API_*`→`UnavailableMuseAiRuntimeClient` 兜底秒失败 `AI_NEW_API_UNAVAILABLE`)。验证:后端 SSE 单测 14/14+前端 107/107(含重连去重用例)、活体 e2e ai-generation+accept 连跑 3 轮 6/6、重连幂等方法 A 活体证;残留=本机 LLM 6.8-19s 未自然>30s、慢路径靠「240s 数学覆盖上游 180s+单测+方法 A 重连活体证」三重保证。**通则(避免重踩"后端比上游先关门")**:SSE 长任务死线须 ≥ 上游 TOTAL_TIMEOUT;AI 流重连必须以 SSE id 幂等去重(后端 seq0 全量回放、无 lastEventId)。详见 memory muse-ai-generation-sse-timeout-bug。