91 Commits

Author SHA1 Message Date
lili
43a08624f8 feat(studio): S7c 采纳恒回传完整正文(所见即所写)+ 流健壮性
分支①第三步(纯前端,无需改后端):采纳恒以 merge_after_edit + modify_then_merge 语义上送用户在
候选面板审定的完整正文作 finalContent(改没改过都送、原样发),使 Canonical 由客户端回传正文写入,
而非后端存的 60/80 字摘要——修掉「原样采纳(accept_as_is)把摘要写进 Canonical」的潜伏缺陷。
后端契约已亲验:ContentSourceServiceImpl.resolveMergedContent 的 merge_after_edit 分支直接落
finalContent、只校验非空、不要求"必须改过";accept_as_is 才用摘要。

流健壮性:done 仅带 taskId/suggestionId/可选 summary、无完整性信号,故按前端可得信号三分——①流非空
(原子 SSE chunk 已收全)→happy;②流非空但短于 done.summary→疑似断连截断,提示重生成、绝不静默采纳;
③流为空→回源只得脱敏摘要,标 degraded 由候选面板明确警告、不当完整正文静默采纳。

验证:tsc -b / vitest 32 files 121 passed / vite build / eslint 均 EXIT=0;MSW-off e2e
accept-suggestion.spec 真后端48080+真 New-API 3 passed——采纳后 acceptMode=merge_after_edit、
revision 180→181、Canonical content_text===客户端回传 finalContent(所见即所写端到端证实)。
改动严格 8 文件全在 muse-studio。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 00:53:56 -07:00
lili
9af471289a fix(solo): 修复 2.0.0 单人版 live 后端启动(DB 口径对齐 + moderation 关停)
标准启动默认落陈旧的 muse_local(仅 V0 baseline、缺 yudao 基座、update_updated_at_column()
函数属第三个角色 muse)→ Flyway V1 CREATE OR REPLACE FUNCTION 报 "must be owner"。唯一健康
的 live 库是 root@muse_slice_live(已迁 V34、含基座+登录种子)。将 application-infra.yaml 与
start-muse-server-infra.sh 的默认库/用户改为 muse_slice_live/root(真实值仍由 infra.env 覆盖)。

S4 关停 spring.ai.model.* 时漏了 moderation;OpenAiModerationAutoConfiguration 默认
matchIfMissing=true → 全量 boot 实例化 openAiModerationModel、无 OpenAI key 直接抛
"OpenAI API key must be set" 使单体启动失败。在 monolith 真正加载的 muse-server/application.yaml
与 ai-server/application.yaml 两处补 moderation: none(单人形态输出合规走自研 MuseAiCandidateReviewService)。

workspace.spec 冒烟原缺 token 注入,被 S5 新增的 AuthGuard 拦重定向 /login → 补 test1 token 注入。
external-deps 记录 Dify 实例被游戏/Muse 共用、workspace 须隔离的约束。

验证:muse-server 干净启动(Started in 22.4s、Flyway up-to-date 零 owner error);MSW-off 创作主线
e2e 33 passed/0 failed/31 隔离(候选采纳/导入/导出/知识草稿/图谱/绑定/agent 生命周期/AI 真生成全绿);
run-p1r-verification.sh local 65 tests/0 fail BUILD SUCCESS。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 22:41:12 -07:00
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
lili
acd7f040a5 fix(studio): 补齐用户端登录入口
Some checks failed
Backend Maven CI / backend-local (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 09:29:07 -07:00
lili
5acb2503b5 feat(studio): 补齐深面入口
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 08:26:47 -07:00
lili
a5619a3566 feat(content): 补齐导入导出真链路
Some checks failed
Backend Maven CI / backend-local (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:40:10 -07:00
lili
8ae812ce6c feat(content): 补本文导入初始化正文
Some checks failed
Backend Maven CI / backend-local (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:54:47 -07:00
lili
3585219637 feat(mvp): 收束1.0.0线A交付闭环
Some checks failed
Backend Maven CI / backend-local (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 10:52:10 -07:00
lili
8b3258e22f test(market): U-verify D0-fork 端到端真验收(真 PG+真 RAGFlow、第四单元)
D0-fork 最后单元:真 PG17+真 RAGFlow 端到端验收、2 IT 真绿(独立复跑确认 57s)。P1rMarketKbForkMaterializationIT(muse-server、跨 knowledge+market 两 BC 须同 Spring 上下文):①fork→安装→物化 installed_ref→检索命中(no_dataset 消除、副本与活 dataset 物理分离);②发布者私有不泄露真证(发布者上架后往活 dataset 真传私有 magic、安装者检索副本拿 magic 当 query 仍只返公开 chunk 不含 magic→d0ForkIsolationProven、U0 spike 反向基线);③幂等+多安装者共享1副本;④AFTER_COMMIT 时序(committedAssetForked/rolledBackAssetForked false:提交才 fork 回滚不 fork);⑤_test 库铁律(muse_p1r_fork_mat_test 绝未指 muse_slice_live)。

market-install-kb-retrieval.spec.ts(studio e2e):检索命中+私有不泄露无独立 UI 入口由 IT 证;安装物化 e2e 标 test.fixme 待 global-setup 补 fork 就绪资产(不伪绿、骨架就位 tsc 过)。召回回滚(D9)如实标开放项:recallAsset 仍 writeSourceStatusBlocked、knowledge 无召回消费者→不自动停用 installed_ref;需新增 market→knowledge 召回传播才闭环(不伪造、不引用不存在的 muse_source_propagation_target)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 11:58:56 -07:00
lili
d1917b4f77 test(studio-e2e): 收窄 agent-slot-bind 断言到槽位面板容器,根治 strict mode 歧义 flaky
agent-slot-bind:94 之前 flaky(~64% 失败):getByText(当前:xxx v1)全局 strict 命中 2 元素(AgentPage 沙盒试用区 selectedAgent 回显 + SlotBindingPanel 槽位 boundAgentName、选中 agent==已绑时同文案),与槽位异步读时机竞速。收窄到 div.rounded-2xl filter 作品槽位绑定 槽位面板容器内断言(仿套件其他 spec 的 locator().filter() scope、不改产品)。

验证:10 次独立 playwright test 循环(每轮重跑 globalSetup 复位 revision=1、非 --repeat-each 避 fixture 漂移伪红)10/10 全绿、无 strict mode violation。预存 flaky(commit 1fbe7ae 引入、非本轮回归);至此 studio e2e 56/56。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:16:07 -07:00
lili
c77b0064be fix(ai): 修 AI 流 SSE 长任务候选丢失(后端死线可配≥上游+前端重连幂等)+A1 启动脚本固化 AI 凭据
studio e2e ai-generation 真红根因=SSE 协议/时序 bug:后端 SSE 死线 30s < LLM 真实时延(且<上游自己 180s 总窗口)+前端 connectAIStream 无重连→长 AI 生成候选永丢(ai-gen 真红/accept flaky 同此 bug)。按方案 A1+候选③(design-docs/临时-01)、人类 review 批准后执行。

A1 环境固化:start-muse-server-infra.sh 追加 source p1r-external-acceptance.env(仅 source 路径不硬编凭据、缺失告警不退出)。后端③死线可配:MuseAiTaskStreamServiceImpl 删 DEFAULT_TIMEOUT_MILLIS 硬编码、改 @Value muse.ai.sse.task-timeout-millis 默认 240000(≥上游 TOTAL_TIMEOUT 180s+轮询/回放余量),连接死线(:70)+poll deadline(:198)同引用;application.yaml 加配置项。前端③重连+幂等:sse.ts connectAIStream 非终态结束退避重连续 poll、按 SSE id 去重(后端每次 seq0 全量回放→lastSeenSequenceNo 丢弃已见)、done/error terminal 停、总超时 300s→onError 不静默卡死;返回 AbortController、AIPanel 零改动。

compatibility:connectAIStream 唯一调用方 AIPanel、streamTask 唯一入口 controller、events 模块 30s 死线独立不动;回滚 git checkout、无 DB 迁移。验证:后端 SSE 单测 14/14+前端 107/107(含 4 新重连去重用例)、活体 e2e ai-generation+accept 连跑 3 轮 6/6 全绿、DB 落 6 行真 LLM suggestion、重连幂等方法 A 活体证。残留:本机 LLM 6.8-19s 未自然跨 30s、慢路径靠 240s 数学覆盖+单测+重连活体证三重保证。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 19:51:41 -07:00
lili
0b152d9c6d fix(knowledge): 修 KB 绑 ≥2 作品停用/删除必 500 真后端 bug + 补真 PG IT(studio e2e 真连揪出)
studio e2e knowledge-disable-restore 真连揪出 mock 单测掩盖的生产 bug:任何用户把知识库绑到 ≥2 作品后无法停用/删除(disable POST HTTP 200 但 body code:500)。根因:updateStatusByKbId 给该 KB 所有未删 binding 写同一停用 commandId→违反 uk_muse_knowledge_binding_command(tenant_id,command_id)唯一索引→DuplicateKeyException。

command_id 语义=「创建/最后改写该 binding 的命令」行级幂等键(单行写路径 create/delete/updateInstalled 各写一行;对称 source projection 无 command_id、用 last_event_id 印证 KB 级 fan-out 不占行级幂等槽);KB 级停用是 KB 维度单命令(commandId 已记 muse_knowledge_base+source_event)、非 binding 创建命令。修(候选①传播不覆盖 command_id):updateStatusByKbId(Long,String,String)→(Long,String)删 setCommandId 只翻 binding_status;propagateKbBlocked 去 commandId 参传 sourceEventId;disableGlobalKnowledgeBase(:190)/changeUserStatus(:452 user disable+delete)2 调用点同步。

影响面=全局/用户 KB disable+用户 KB delete 三传播路径,行为变化仅不再改写 binding.command_id(binding_status/affectedBindings/source projection 不变);对外契约不变、纯修 500;回滚 git checkout。

mock 单测掩盖根因(mock updateStatusByKbId 返行数、不触发真唯一索引)。补真 PG IT P1rKnowledgeBaseDisableMultiBindingIT(真 PG+Flyway V14+真 service/mapper):KB 绑 2 作品 disable/delete 传播成功+两 binding 各保留 command_id;反假绿用例直写同 command_id 仍被唯一约束拒(SQLState 23505)。修后 3/3 绿;临时重引入 bug→2/3 DuplicateKeyException 证真回归门禁。独立核实:e2e 连跑 3 次 2 passed(修前红);psql 复核 KB1 2 binding(work1+work2)全 disabled、command_id 各异无冲突;global-setup 补 9b 多 binding 锚点(KB1+work2)令 e2e 真走 ≥2 binding 传播路径。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 18:20:50 -07:00
lili
ca0e04c9a9 test(studio-e2e): source-attribution 解耦到 pristine block3 根治测试间来源污染 flaky
source-attribution 只读 spec 期望 block1 来源=user_original,但全量串行时前序 accept-suggestion(写 ai_suggestion)/block-autosave/block-structure 按字母序先跑且都写 block1,block1 顶层 revision 来源在 user_original/ai_suggestion 漂移→偶发渲染"AI 生成"红;global-setup 每轮仅跑一次、无法撤销跑中途污染。修:spec 改读 pristine work3/block3(grep 确认无人导航 /workspace/3、无人写 block3)+global-setup §3 每轮删净 block3 归因并重建唯一 user_original rev1 行(幂等)。断言未放宽仍真断言 user_original。免疫验证:强灌 block1 顶层 ai_suggestion(旧 spec 必红条件)新 spec 仍绿;独立连跑 source-attribution 3 次全绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 14:35:19 -07:00
lili
de5f4d0bf9 test(studio-e2e): global-setup 补 asset1/work1 fixture 复位(环境污染致 7 spec 偶发红)
studio e2e 全量核查 run1 7 红,根因测试间环境污染、global-setup 复位不全:①asset1「活体市场资产·测试」被历史操作 delisted(应 listed/active)→bind-precheck 返 1044000003 资产不存在→连带 handoff-agent/content/knowledge+live-read 市场浏览+market-governance-impact+market-handoff-precheck 6 红;②work1 残留多余 writing.expansion active 槽位(spec 假设仅 continuation)→agent-slot-bind strict 命中 2 元素红。修:§17 复位 asset1→listed/active、§18 删 work1 非 continuation 槽位。验证:重新污染→自愈后 7 spec 全绿、全量回归持续绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 13:47:28 -07:00
lili
443a1f3414 fix(studio): 修新建章节双提交 + work 乐观锁版本兜底两处 bug(studio e2e 真连揪出)
studio e2e chapter-create-delete 偶发 code=1041000002,根因两个独立前端 bug:①ChapterPanel 双提交:input onKeyDown(Enter→submitCreate)+onBlur=submitCreate,Enter 提交成功后 setIsCreating(false)卸载 input→onBlur 二次触发,isCreatingPending(异步)+disabled 滞后挡不住→重复 POST(第 2 个同 reqRev→500)。修:submitCreate 加同步 useRef 守卫(提交中早返+置位+onSettled 复位),只挡同次重入、不挡首次/失焦补提交。②WorkspacePage expectedWorkRevision 兜底:原 workRevision(work)??1,work 详情异步未加载时兜成 1、但真实 revision 已 >1→乐观锁冲突。改传真实 revision(未加载 undefined→ChapterPanel 既有 ==null 早返挡过早提交)。

实证:单次新建 POST 修前 2(第 1 成功+第 2 1041000002)→修后 6 轮恒 1;chapter-create-delete 连跑 8 次全绿。相邻写路 spec 不回归、tsc 0 错、editor 单测 33/33。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 13:47:28 -07:00
lili
37e7a8dc27 fix(market): 修 install 用户可见假绿——isAcquired/isInstalled/canInstall 按真实授权安装态 enrich
三路盘点发现 market install 头号用户可见假绿:install 后端真实已验(P1rMarketLicenseInstallCompletedApprovalIT 批18 绿),但 MarketAssetQueryServiceImpl 把 isAcquired/isInstalled 裸硬编 false(toCard:181-182 列表 + userActions:386-387 详情 + canInstall:383),致 studio MarketBrowse(assetType!=work && isAcquired && !isInstalled)安装按钮在真后端永不渲染,mock 伪造状态位才现身;批17 IT 把 isAcquired=false 断言为正确→假绿固化。

后端 enrich(读模型、未碰 install 写逻辑/授权语义):仿 isFavorite 范式加 isAcquired(active 授权)/isInstalled(installation)/isInstallable(类型集),与 install 写端口 MarketInstallServiceImpl 严格同源(selectActiveByOwnerAndAsset + INSTALLABLE_ASSET_TYPES={agent,knowledge_base}),避免"显示可装但装不了"新假绿;canInstall=listed && isInstallable && acquired && !installed(对齐 studio assetType!=work 门);批量加载(整页 2 次 IN vs 3N)避免放大 isFavorite 既有 N+1;mapper 加 selectActiveByOwnerAndAssetIds/existsByUserAndAsset/selectByUserAndAssetIds;批17 IT 改三态断言+订正裸写注释。

前端 MarketBrowse 补 onError(install/acquire 失败内联可见提示,对齐 AgentCreateForm/SlotBindingPanel,不再静默吞 ApiError);e2e 新增 market-install.spec(MSW-off:purchase 前置→断安装按钮真渲染→install→psql 验,连跑 2 次)+ global-setup #16 market 表复位。

活体真验(muse_slice_live,重启新 jar 10:08):purchase→isAcquired=T/canInstall=T(修前恒 false)→install→isInstalled=T/canInstall=F;独立 psql+GET 复核 asset1/4(owner1)isAcquired/isInstalled=true。批17 IT 5/5 三态绿(首跑遇 .m2 stale jar 假红、mvn install 刷新转真绿)、market 单测 9/9+11/11+7/7、UI e2e 连跑 2 次 passed。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 10:28:33 -07:00
lili
2ede7cb384 test(studio): accept-suggestion 改真生成删 stub,清除 line176② 最后 AI 假绿(采纳断层已修)
采纳断层修复后(commit a16c596 ADR-020,真候选 authz 字符串 envelope 可采纳),accept-suggestion 正路删 /ai/tasks+/stream stub,复用 ai-generation 真链路:WorkspacePage→AIPanel→真 AI task→SSE done→CandidatePanel 采纳替换→真 suggestion-merges code=0+newRevision 自增。反假绿:authz 真 rpe-local 字符串(非种子数值)、sourceAttribution.parentSuggestionId==真生成 id(证非种子)、block revision 实读动态比对(漂移不影响重复跑)。连跑 2 次 2/2 绿(suggestionId 25→26 revision 72→74)+ ai-generation/agent-slot-bind 回归绿。line176② AI 生成 stub 假绿完全清除。flaky:真 SSE 冷启动偶慢(与 ai-generation 同源,CI retries:2)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 01:24:01 -07:00
lili
180181e4c7 docs(studio): 订正 accept-suggestion stub 根因为真生成候选 authorization_snapshot_id=null(反假绿调研)
正路仍桩 /ai/tasks 的根因经实测订正(非旧注释"AI 本机不可用/缺审字段"):真生成候选已产审三件套+content,唯一缺 authorization_snapshot_id=null→采纳被拒 1041001001"外部 owner 暂不可用"。根因=真 runtime envelope 是字符串 rpe-local-uuid,MuseAiRuntimeProjectionService.numericEnvelopeId Long.parseLong 失败落 null。**揭 P1rContentMergeGeneratedSuggestionIT 假绿**(注入数值 envelope 9001,真 New-API runtime 不产数值→IT 绿≠活体真候选可采纳)。注释 only 无逻辑改,stub 保留(桩生成段、采纳+负路乐观锁全真打后端反假绿),accept-suggestion 2/2 可重复 + agent-slot-bind/ai-generation 回归绿、tsc 0。后续主线:让真生成链产数值授权快照(numericEnvelopeId 解析 rpe-local-* 或列承载字符串 envelope,后端缺口)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 22:08:41 -07:00
lili
410322cbc0 fix(studio): AIPanel onDone 改用 ref 读流式正文,消除渲染期跨组件 setState
AIPanel onDone 此前在 setStreamContent 更新函数里调父组件 onCandidateGenerated→AIPanel 渲染期触发 WorkspacePage setState(React warn "Cannot update a component while rendering a different component")。改:streamContentRef 在 onChunk 与 streamContent 同步累计,onDone 直接读 ref 调回调,不再渲染期 setState。ai-generation e2e 再跑 React warning grep=0(消失)、仍 passed(26.2s)。顺带修 AgentPage.contract.test 多余 import React(JSX automatic runtime 不需→TS6133;此前写 test 只跑 vitest 漏跑 tsc、commit 4c069d4 带入)。tsc 全量 0、vitest 102/102。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 18:01:56 -07:00
lili
494c9e9b89 test(studio): 补 AIPanel AI 生成真后端 e2e + 修 connectAIStream 漏鉴权头(反假绿暴露真 bug)
补 ai-generation.spec(真后端不 stub,消除 accept-suggestion stub 假绿,进度总账 line176②):真浏览器 WorkspacePage→AIPanel 发送指令→真后端 AI task→SSE→真 New-API LLM→suggestion 落库。**反假绿暴露真 bug**:connectAIStream(src/lib/sse.ts)漏带 Authorization+tenant-id 头→活体 SSE 必 401/400→done 永收不到→候选永不渲染(被 accept-suggestion 的 stub 长期掩盖)。修:补头,与 connectEventStream/client.ts 同源 @/api/auth。SSE 真行为:后端"持久化事件回放+5s 轮询",运行时只落 done 不落 chunk(streamContent 真链路恒空),真 LLM 文本在 suggestion 记录→断言落 suggestion(API+DB 双证)。四断言反假绿:POST 2xx+code0+taskId / suggestion 真 LLM 文本(非空+阈值+主题宽集合不硬编码句子) / CandidatePanel 采纳按钮 / DB muse_ai_suggestion 新行。自验+子代理连跑 4 次绿(suggestionId 12→13→14→15 各不同真 LLM,11-21s 稳定);vitest 102/102(sse.test 16/16);"AI 本机不可用"旧判断已过时(New-API 在线真生成)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 17:59:10 -07:00
lili
1fbe7ae73c test(studio): 补 agent 槽位绑定 UI e2e(AgentPage→真后端替换槽位,反假绿)
承 02D 死锁修复(9115d4f)+ AgentPage 作品选择器(4c069d4),补端到端 UI e2e(进度总账 line176② 缺口)。agent-slot-bind.spec:真浏览器 goto /agents→selectOption work1→点 agent1 卡片→点"绑定选中智能体"→真后端 precheck→bind。三重反假绿:DB 起点 revision=1 + bind 响应 code=0/slotRevision=2 + UI"绑定已更新"提示 + DB 终态 revision 1→2 active agent1。global-setup §15 每轮复位 work1 writing.continuation 槽位(agent1 revision1 active)保证可重复(bind 成功 revision+1 漂移、不复位二次跑红)。MSW off 真连 muse_slice_live;自验 + 子代理各跑均 passed 可重复、tsc 零报错。诚实范围:只覆盖"替换已有槽位",首次创建 UI 仍缺槽位骨架(Override Slot Contract=方案 B,人类架构决策域未做)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 11:19:44 -07:00
lili
4c069d482d fix(studio): AgentPage 槽位绑定改用作品选择器,消除 workId 硬编码
承 02D 后端槽位首次创建死锁修复(9115d4f),前端 AgentPage 此前 SlotBindingPanel 用硬编码 WORK_ID_FOR_SLOT_PREVIEW=1(盘点 line176② workId 硬编码),槽位绑定无法用于真实作品。修:接入 useWorkList 作品列表 + 作品选择下拉,SlotBindingPanel 按所选作品 workId 查询/绑定槽位,空作品时提示先建作品。SlotBindingPanel 绑定流(precheck→bind)本就完整(盘点"无真正绑定流"过时:实为后端死锁挡着 bind 必失败,后端修复后真后端 curl 已验 precheck→bind→首次建 binding)。补 AgentPage.contract.test(作品选择→正确 workId 下传 + 非硬编码反向验证)。tsc/eslint 绿,vitest 101→102。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 10:56:01 -07:00
lili
9115d4f95f fix(ai): 修 02D 槽位绑定首次创建死锁,precheck/bind 改 upsert + 补 active 唯一约束
根因:precheck(line102)/bind(line182)都 requireSlotBinding(binding!=null)缺行抛 AI_RESOURCE_FORBIDDEN;但"替换"是设计中唯一创建入口(替换=首次写入,无独立创建端点是设计有意,见后端-04 line748/产品-02D line507),要求被替换行先存在→死锁,首次绑定永不可达。work4 seed binding 是 E2E 绕此 bug 手插非设计常态。修:precheck 缺行放行;bind 抽 persistBinding upsert(有行 updateById 沿用乐观锁 revision+1,无行 insert revision=1 避免首次 expectedSlotRevision null 拆箱 NPE);V29 补 active partial unique index(tenant+work+slot WHERE status=active,并发首次写兜底);前端 mock protected 槽位对齐后端 startsWith(protected:)口径。验证:MuseAgentSlotServiceTest 26/26 + AppMuseAgentSlotControllerAnnotationTest 4/4 + 前端 useAgents/AIPanel.contract 4/4;handoff/幂等/乐观锁不破坏。范围:不建 Override Slot Contract 主数据(B)/不碰默认 agent 来源/不动 runtime 授权。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 10:09:53 -07:00
lili
df063cbacd feat(studio): AI 生成提交补全上下文引用(workId/blockId/agentSlotKey),消除前端假绿
AIPanel 此前只传 commandId/intent/contextScope,残缺上下文被宽松 mock 掩盖(假绿)。补全:Props 接收 + payload 下传 workId(必填)/blockId/chapterId/agentSlotKey,WorkspacePage 透传真实 workId(useParams)+activeBlock.id+activeChapterId,agentSlotKey 续写默认 writing.continuation,接通槽位绑定↔生成断层。防假绿:mock /ai/tasks 收紧 workId 必填(40011);contract test 断言 body 含 workId/blockId/agentSlotKey(反向验证:删 workId 下传则测试变红)。范围:未做 agentOverrideRef UI/AgentPage 硬编码/EditorPage 重构。验证:全量单测 101/101 + tsc -b --noEmit exit 0。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 09:01:52 -07:00
lili
26425b1755 test(handoff): P3 content asset_use 真后端 e2e + global-setup #14
handoff-content.spec(48080+真 PG+V28 真表):正路 bind-precheck(content)→
createHandoff(content/asset_use)→asset-use-precheck(后端 verify+consume)→asset-uses
落使用事实(单表转 consumed、assetUseId=precheckId);负路伪造 token 被后端 verify 拒(0 写)。
global-setup #14 每轮清 work4 asset_use precheck(asset_use 不绑实体、无需 seed fixture)。

验证:handoff-content 2 passed、全量 e2e 50→52(1 flaky knowledge-disable-restore 单跑绿、非回归)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 23:48:40 -07:00
lili
7bb15a5cf4 feat(handoff): P3 content 兑现侧落地 + 02F 来源侧发起(完整闭环)
ContentHandoffLanding(P3 完整闭环):bind-precheck(targetOwner=content)拿可信 source →
assetUsePrecheck(market+token,后端 verify+consume)→ setPrecheck(token 用完即弃)→
读 work revision → createAssetUse(凭 precheckId)→ 完成。useContentHandoff hooks +
HandoffLandingPage content dispatch + MarketAssetDetailPage「用于作品(进入作品空间)」发起入口
(asset_use 不依赖物化、sourceAssetId 真实,故来源侧发起完整可用、比 P1/P2 更完整)。

验证:tsc OK、eslint 空、vitest 97→101(ContentHandoffLanding 4:就绪/闭环/核验拒绝/会话失效)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 22:52:16 -07:00
lili
2a7906c74e test(handoff): P2 agent 兑现真后端 e2e + seed market agent fixture
global-setup #13:seed market 类型 agent(固定 agent_key)+ active version + work4 槽位绑定,
每轮幂等复位(子表先删再重建);供 market→agent 跨空间 handoff e2e(market→agent 资产物化未接,
此处为预置 fixture)。

handoff-agent.spec(真后端,反假绿):
- 正路:bind-precheck(targetOwner=agent)→ createHandoff 签一次性 token → agent precheck
  (market_agent + token):后端 verify+consume+放宽接纳 market 类型 agent → bind 落槽位(slotRevision=2)
- 负路:伪造 token 调 agent precheck → 后端 verify 拒(code≠0),不放宽、0 写

验证:V27 已应用共享 muse_slice_live(flyway "now at version v27",用户拍板应用);handoff-agent
2/2 passed(真 PG + 真 token + V27 真列);全量 e2e 50 passed(唯一 flaky=knowledge-disable-restore
全量时序、单跑 2/2 绿、用 KB id=1 与 handoff 用 work4 无关,非 P2 回归)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 13:09:47 -07:00
lili
4c3e8bb905 feat(handoff): P2 agent 兑现侧前端落地组件(token 红线闭环)
AgentHandoffLanding(P2 兑现侧):从 store 取 token + URL params 取 agent 参数(slotKey/
sourceAgentId/version/revision)→ agentSlotPrecheck(market_agent + handoffToken,后端核验+核销)
→ setPrecheck(token 用完即弃)→ bindAgentSlot(只消费 precheckId)→ 绑定完成。
useAgentHandoff hooks + HandoffLandingPage owner dispatch +agent。

诚实范围:来源侧发起入口(MarketAssetDetailPage agent 按钮)依赖 market→agent 资产物化
(未接、列独立后续),做了会是半成品故暂不做;agent 参数经 URL 透传,e2e 用 seed market
agent + 直接构造落地 URL 验证兑现侧放宽红线。

验证:tsc -b OK、eslint 空、vitest 97/97(含 AgentHandoffLanding 4:就绪/闭环/核验拒绝/会话失效)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:38:45 -07:00
lili
a09bf9cda3 fix(handoff): P1 knowledge 落地闭环修复(ready 态 + returnUrl 契约)
KnowledgeHandoffLanding: token 用完即弃后(setPrecheck 清 handoffToken)以 precheckId
维持就绪态,兑现中不误退"会话失效"。
MarketAssetDetailPage: createHandoff 的 returnUrl 用绝对 URL(后端 validateReturnUrl
要求 scheme+host),前端 navigate 仍用相对 path。

均为 handoff-knowledge e2e 正路闭环验证依赖的修复(真后端 2 passed)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:35:38 -07:00
lili
86bdba7974 test(handoff): P1 knowledge 兑现端到端真后端 e2e + fixture 复位
handoff-knowledge.spec(真后端 48080, MSW off):
- 正路:市场资产→获取授权→bind-precheck 就绪→前往绑定(createHandoff token)→落地页(URL token 经 replaceState
  清除)→确认→kbBindPrecheck(后端核验+核销 token)→createBinding→绑定完成。证红线兑现闭环真生效。
- 负路:伪造 handoffToken 直打 kbBindPrecheck→后端 verify 拒(code 非 0)。证"不信客户端 token"红线后端真拦截。
- 用 work4(creator=test1、未占 uk);work1+kb1 已被 installed binding 占,避 uk_muse_knowledge_binding_work_kb 冲突。

global-setup #12:每轮清理 handoff 兑现产生的 market_kb 绑定(work4+kb1,按 source_snapshot_id 精准删),供闭环幂等重跑。

验证:handoff-knowledge 2 passed + 二次幂等绿;全量 48 passed。
(knowledge-disable-restore 全量时序 flaky——单跑 2 passed,预存在共享 fixture 时序、与本改动无关:handoff 不碰 KB id=1。)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:31:18 -07:00
lili
6a56524679 feat(handoff): P1 前端 knowledge 兑现闭环——发起+落地组件+mock+单测
P1 knowledge 端到端前端(纯前端,零后端改动——bind-precheck 已返回全部可信 source):
- 发起(MarketAssetDetailPage):bind-precheck 就绪→createHandoff 创建一次性 token→跳 /handoff/land/knowledge
  (token 走 URL query,落地页随即 replaceState 清除,防刷新重复消费)。
- 落地(KnowledgeHandoffLanding):3 步兑现闭环——来源侧 bind-precheck 拿后端可信 source(authorizationSummaryId/
  Snapshot/sourceVersion/sourceStatus,不信客户端自造)→目标侧 kbBindPrecheck(后端核验+核销 token,换 precheckId、
  token 用完即弃)→createKnowledgeBinding(读 work revision 防乐观锁,落 binding)→clearSession 返回来源。
- owner 分发(HandoffLandingPage):按 targetOwner=knowledge 渲染落地组件,agent/content 留 P2/P3。
- 兑现 hooks(useKnowledgeHandoff)+ 类型收口(MarketBindPrecheckResult.sourceVersion、CreateHandoffInput
  .authorizationSummaryId 对齐后端 Long,均 openapi 手写类型此前漏标的 drift)。
- mock handlers(market bind-precheck/handoffs/status + knowledge bindings/prechecks),支撑 dev 模式跑通闭环。

验证:tsc/eslint 绿;vitest 89→93(+KnowledgeHandoffLanding 4:就绪渲染/完整闭环/后端核验拒绝负路/会话失效)。
红线真生效(拒伪造/过期 token + 核销 + DB)待真后端 e2e(handoff-knowledge.spec)端到端覆盖。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 09:42:04 -07:00
lili
a3b45ae6b5 feat(handoff): P0 统一基座——Market token 核验/核销端口 + 前端 HandoffStore/落地路由
handoff 跨空间统一接入执行版 P0(基座,前后端共享):
- 后端 market-api 新增 MarketHandoffTokenApi(verify 只读核验 + consume CAS 核销)+ market-server
  实现:复用现有 selectByTokenHash/effectiveStatus/updateLifecycleByExpectedStatus + cancel 同款
  envelope 幂等;consume 沿用调用方事务保原子(绿地:completed 状态此前无生产写入路径)。出参脱敏不回 token。
- 前端:openapi 导出 Handoff 类型;HandoffStore(Zustand,token 一次性用完即弃 + precheck 会话态);
  通用 hooks(create/status/cancel);落地路由 /handoff/land/:targetOwner(红线:解析 token→
  replaceState 清 URL→存 store,防刷新重复消费)。

验证:market 编译+install+BcBoundaryArchTest 绿;前端 tsc/eslint 绿、vitest 82→89(+handoffStore 5
+HandoffLandingPage 2)。verify/consume 真实行为(拒伪造/过期/跨属主 token + CAS 核销 + DB)随 P1
knowledge 端到端真后端 e2e 覆盖。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 09:02:52 -07:00
lili
ab83735f6f feat(studio): 资产详情页治理影响接入真后端(A 类:消费者治理 C14 读端)
A 类(后端就绪、前端 0 消费):02F GET /marketplace/assets/{id}/governance-impact 就绪
(curl code:0 + 真实 governanceResult:resultType/reason/操作限制 + affectedAuthorizations/
suggestedActions),但 studio 详情页无展示(盘点 C14 消费者治理缺口)。接入:
- useGovernanceImpact hook + openapi 导出 GovernanceImpactResult
- MarketAssetDetailPage「治理影响」区:结果类型(下架/召回/吊销/可申诉)+ 操作限制(停止获取/安装/绑定/生成)+ 建议动作
- mock handler + vitest 契约 + market-governance-impact.spec.ts 真后端 e2e
- 修 spec 块注释内 affected*/ 的 */ 意外闭合(tsc 不覆盖 e2e、playwright esbuild 暴露)

验证:全量 e2e 46→47/0;vitest 81→82;tsc/eslint 绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 07:49:08 -07:00
lili
7408615037 feat(studio): 个人中心 New-API 绑定摘要接入真后端(A 类:接已就绪后端)
A 类(后端就绪、前端 0 消费):02G GET /account/new-api-binding 后端就绪(curl code:0、
未绑定时 fail-closed 返 bindingStatus=unbound),但 studio 无任何展示(盘点 02G  缺口)。接入:
- useAccountNewApiBinding hook + openapi 导出 NewApiBindingSummary
- PersonalCenter「New-API 绑定」区:bindingStatus 中文徽标(已绑定/未绑定/同步失败/同步中)+ 上次同步时间
- mock handler + vitest 契约 + account-newapi-binding.spec.ts 真后端 e2e

验证:全量 e2e 45→46/0;vitest 80→81;tsc/eslint 绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 07:37:22 -07:00
lili
cac3b8837f feat(studio): 市场推荐位接入真后端 recommendations(A 类:接已就绪后端)
A 类(缺口盘点:后端已就绪、前端 0 消费):02F GET /marketplace/recommendations 后端就绪
(curl code:0 + 真实推荐资产 + recommendationReason),但 studio 从不调用、推荐理由仅 mock
造、UI 未渲染(盘点 C3)。接入:
- useMarketRecommendations hook(返回 MarketAssetCard[],推荐失败不阻断主列表)
- MarketBrowse「为你推荐」区:渲染推荐资产 + recommendationReason,点击进详情
- mock handler + vitest 推荐契约;market-recommendations.spec.ts 真后端 e2e
- 连带修 live-read market 断言加 .first()(推荐位与列表可同时渲染同名资产→strict mode)

验证:全量 e2e 44→45/0;vitest 79→80;tsc/eslint 绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 07:29:14 -07:00
lili
a581fec913 fix(studio): 正文保存补真后端 e2e + 修 block/work revision 字段漂移(D 类反假绿)
D 类(缺口盘点最高优先):正文自动保存是写作台心脏却零 e2e、仅 MSW 掩盖。补
block-autosave.spec.ts 真打 PUT /works/{id}/blocks/{id} 暴露并修真 bug:
- block revision 漂移:WorkspacePage 裸读 activeBlock.version(真后端返 revision、无 version)
  → expectedRevision 恒为 1 → 真后端乐观锁必冲突(1041000002,curl 实证)。提 blockRevision()
  到 useBlockStructure 共享、WorkspacePage 复用。
- work revision 漂移(tsc -b 增量重检暴露):WorkVO 类型无 revision、真后端 detail 返 revision,
  chapter create/work delete 裸读致 TS 报错。加 workRevision() helper。
- MuseEditor saveBlock 返回 { revision }(非 openapi 标的 newVersion),L110 改 revision 优先兜底。
- market 申诉 deadline fixture 老化(纯时间推进、非代码):reviewedAt+7天过期致提交被拒
  1044000027,globalSetup 刷新被驳回 request.reviewed_at 到近期。

验证:block-autosave + block-structure/chapter/work 回归 4/4 绿;全量 e2e 44/0;tsc/eslint/vitest 79/79。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 07:02:13 -07:00
lili
a752626286 test(content): V26 应用后 chapter-create-delete e2e 转正(全量 43/0 全绿)
V26(章节/Block order_no uk 改 partial index WHERE deleted=false)已 flyway 应用(now at v26),
curl 实证建 order=2 章节(之前撞软删行 → 500)→ code:0。chapter-create-delete.spec.ts 由 test.fixme
转回 test(),建→删配对通过;全量 e2e 43/0(原 +1 fixme 现转正、0 skipped)。

content 写路 + 软删 uk 修复完整闭环:chapter create/work delete 前端契约 + chapter/block order_no
后端 schema 双修验证通过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:32:48 -07:00
lili
172261f540 fix(content): V26 修章节/Block 软删后 order_no uk 碰撞(partial index,待人类应用 flyway)+ 软删 uk 全仓审计
审计(用户授权):Explore 扫 177 uk,22 高危/137 中危/18 安全(yudao 软删 + ~99% uk 漏 WHERE deleted=false)。
精炼剔假阳(幂等/递增键不复用),真可复用业务键 uk = content order_no×2(确证)+ meta/ai/knowledge *_key×13。
全仓 ON CONFLICT 仅引用 command_id/id/asset/kb/validation/source,22 高危均不被引用→改 partial 安全。

V26 修 chapter+block order_no 改 partial index WHERE deleted=false(block create L294 确证同 selectCount+1 bug)。
应用需重启 48080 跑 flyway(DDL 改真 PG,auto-mode 归人类执行,未绕过)。chapter-create-delete e2e 保持
test.fixme、注释指向 V26,人类应用后转正。其余 13 业务键 uk 建议 V27 按模块逐步修(账本有清单)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:09:59 -07:00
lili
59d139637a fix(editor): 修删除作品缺契约字段致真后端 400(反假绿挖出,纯前端修复)
前端 useWorkDelete 此前 api.delete 不传 body,而后端 deleteWork 要 @Valid RevisionCommandReqVO
(commandId 幂等 + expectedRevision 作品乐观锁)→ 真后端删作品必 400(dev mock 不校验长期掩盖)。
又因列表 VO(GET /works)不含 revision 字段(仅 detail 有),无法直接取乐观锁版本;故 useWorkDelete
改为删除前先读 work 详情拿 revision,再带 commandId 提交删除(删除低频、额外一次 GET 可接受)。

补 work-create-delete.spec.ts(配对自清理 e2e:建作品→删作品,验 DELETE 200/code:0 + 列表无残留)。
curl 实证后端 work create→delete code:0(无 chapter 那类 order_no schema bug)。

tsc/eslint 0,vitest 79/79,全量 e2e 42/0(+1 chapter fixme)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 14:08:08 -07:00
lili
ca33c8e006 fix(editor): 修新建章节缺契约字段致真后端 400(反假绿挖出)+ 标注暴露的后端 order_no 软删 bug
前端 useChapterCreate 此前只传 {title},而后端 ChapterCreateReqVO 强制 commandId(幂等)+
expectedWorkRevision(作品乐观锁),缺失被 @Valid 拦成 400——dev mock 不校验、长期掩盖,真后端建章必败。
修:useChapterCreate 补 commandId + expectedWorkRevision;ChapterPanel 经 props 接 work.revision、
WorkspacePage 传入;建章后失效 workDetail 缓存避免后续写命令复用旧 revision。

补 chapter-create-delete.spec.ts(配对自清理 e2e),暂 test.fixme:前端修复后请求合法到达后端,
又暴露独立后端 bug——createChapter orderNo=selectCountByWorkId(active)+1,章节软删后行仍在、
uk_muse_content_chapter_work_order 不含 deleted(同文件 command uk 是 partial index 却此处遗漏)
→ 删章节后再建 order_no 冲突 500。属 schema/软删语义,需人类定 DDL 修法,fixme 待修。

tsc/eslint 0,studio vitest 79/79,全量 e2e 41/0(+1 fixme)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 13:54:34 -07:00
lili
1dbbfc78b5 test(account): 补权益配额/用量归属真后端 e2e(UsageStats,account 面收口)
GET /account/entitlements(套餐/配额/发布能力)+ /account/usage(Token 用量/归属分布)
此前无专门 e2e(live-read 仅断言 nickname、未覆盖 UsageStats);curl 证两端 code:0 就绪。
补 account-usage.spec.ts(验 200/code:0 + 「权益与配额」/「归属分布」区块渲染)。
全量 e2e 41/0。至此个人中心 account 面真后端 e2e 全闭环(profile 读写 + 权益配额 +
用量归属 + 购买/授权/发布三件套 + 安全事件 ack)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 13:31:00 -07:00
lili
3ffee3599a test(e2e): global-setup 清理 agent-create 累积污染(修 live-read ai 稳定红)
agent-create.spec uniqueName=`活体智能体-e2e-${Date.now()}` 不幂等,每跑新建一个自建 agent,
累积 22 条后按 updatedAt 倒序把种子「活体测试智能体」挤出后端默认分页第一页,致 live-read
「智能体列表渲染真实 Agent」断言 timeout(随历史跑次增多从绿变稳定红)。global-setup 加第 11 节
删 e2e 前缀 agent、保留种子。全量 e2e 39/0。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 13:19:34 -07:00
lili
f3ea06c154 fix(account): 修个人中心资料更新 jsonb 类型错致 update 500(反假绿挖出)
AccountProfileMapper.updateByAccountUserIdAndVersion 用 LambdaUpdateWrapper.set
写 profile_snapshot(PG jsonb 列),默认不走 DO 上 @TableField 的 JsonbStringTypeHandler,
按 varchar 绑定 →「column is jsonb but expression is character varying」→ update 500
(insert 走 typeHandler 故首次 create 侥幸 OK、对已存在 profile 的 update 必 500)。
set 显式指定 JsonbStringTypeHandler 与 insert 路径对齐。

新增 account-profile-update.spec.ts(真后端写路 e2e:改公开署名→PATCH /profile→
code:0+version 乐观锁自增+UI 回显;只改署名不动昵称以不破坏 live-read 的 nickname 断言)
正是它暴露此 bug——curl 实证旧 jar PATCH 500、rebuild 后 code:0。全量 e2e 39/0。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 13:19:16 -07:00
lili
db63b2d57e test(account): 补个人中心购买/授权记录真后端 e2e(市场记录三件套补完)
purchases(GET /account/purchases)/licenses(/account/licenses)与已有「我的发布」同源
(AccountMarketRecordService 读 muse_account_record_projection 投影表),此前有 UI+hook
但缺真后端 e2e 验证(假绿风险)。补两 test:验 200/code:0 + 「我的购买」/「我的授权」区
真后端读通渲染。全量 e2e 38/0(原 36/0)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 12:55:50 -07:00
lili
23953fb701 fix(market): 修提交审核后「我的发布记录」列表慢一拍(全量 e2e 转 36/0)
根因(深度诊断,逐层排除):
1. React Query dedup: save→submit 链上 save 的 invalidate 已触发一次 refetch,
   提交时它仍 in-flight,submit 的 invalidate 被 dedup 到该旧请求(返回提交前快照),
   致「我的发布记录」刷不到刚提交申请(列表慢一拍);
2. 浏览器缓存: vite dev proxy 未透传后端 Cache-Control: no-store,浏览器按默认
   启发式缓存 GET,refetch 命中旧缓存。

修复:
- submit onSuccess 改 cancelQueries 取消 in-flight + refetchQueries 强制发新请求;
- api client fetch 加 cache: no-store,数据新鲜度统一由 React Query 应用层管理。

验证: market-publish 提交审核全链 e2e 真后端转绿,全量 e2e 36/0(原 35/1)、
market vitest 4/4、tsc/eslint 0。决定性诊断: browserFetch(no-store page.evaluate
直查)拿 fresh 而 React Query refetch 返回 stale,证 refetch 被 dedup 未发新请求;
cancelQueries 后 refetch 转 fresh。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 12:47:44 -07:00
lili
d8ed40dc4d feat(market): 我的发布记录按发生时间统一倒序
PublishRecordItem 加 occurredAt(草稿=createTime/申请=submittedAt),
listMyPublishRecords 合并 draft+request 后按 occurredAt 倒序(nullsLast),
对齐 market 其它列表 orderByDesc;前端 MyPublishRecord 同步 occurredAt 契约。

验证:market 模块 test 绿(mock 时间 null,nullsLast 稳定保序不破坏断言)、
前端 tsc+vitest 绿、page.request 真后端直查证列表倒序生效(最新在首页)。

注:market-publish:65 e2e 仍 fail,真根因是前端提交后列表写后读慢一拍
(非排序,详见进度总账),属 market 工作线专项。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:44:21 -07:00
lili
d4c530524e feat(studio): 已安装知识库停用/恢复 UI(G)
- useInstalledKnowledgeDisable/Restore hook(POST installed-knowledge-bases/{installId}/disable|restore,CommandReqVO 仅 commandId)
- KnowledgePage「从市场安装的」卡片:按 binding_status 切换停用/恢复按钮,保留卸载
- mock + vitest(installed disable/restore status 翻转)
- e2e 真后端(muse_knowledge_binding.binding_status 切换;global-setup section10 复位 binding id=1)

#30 第4缺口。验证:vitest 6/6+全套79/79、tsc/eslint 0、e2e 1 passed(真后端)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 10:42:27 -07:00
lili
fa651682b4 test(studio): work-schema-binding e2e 修 flaky(waitForResponse 前置)
schema-options 由 CreateWorkModal(首页即挂载、staleTime 60s)预取,全量跑(后端热)请求常
早于 waitForResponse 注册→race→30s timeout;注册移到 goto 前,覆盖请求早发/晚发两种时机。
全量 e2e 复跑该 spec 转绿(单跑本就绿、仅全量 flaky)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 10:20:28 -07:00
lili
494f3b5fd6 feat(studio): 知识库停用/恢复 UI + e2e 真跑
F——补自建知识库停用/恢复端面(后端 disable/restore 端点已有,缺 UI):
- useKnowledge: useKnowledgeDisable/useKnowledgeRestore mutation hook
- KnowledgePage: 自建 KB 卡片按 status 切换「停用」(confirm)/「恢复」按钮
- mock: 补 restore handler(disable 已有)
- 核实真后端 SummaryRespVO.processingStatus = kb.getStatus(),启用状态(disabled/searchable)
  经其透出可观测,排除"RespVO 缺启用状态字段"误判,确认无需改后端
- vitest useKnowledge 5/5(disable→disabled→restore→active)+ 全套 78/78,tsc/eslint 0
- e2e knowledge-disable-restore 真后端 1 passed;global-setup section 9 复位 KB1 status='draft'

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 09:42:29 -07:00
lili
cc57c595d8 feat(studio): E 来源归因查看 - 数据层+UI+e2e 真跑[P1]
studio 缺 UI 端面补齐(第 2 个,可验证缺口)。openapi export SourceAttribution;useSourceAttribution hook(只读);content mock source-attribution handler;SourceAttributionPanel(来源类型/贡献中文标签+许可+谱系);WorkspacePage 右侧加「来源」Tab(block 级,需 activeBlock)。

验证:useSourceAttribution 2/2 + SourceAttributionPanel 2/2 + 全套 vitest 77/77(无回归) + tsc 0 + eslint 0 + playwright source-attribution 1 passed(真后端 user_original→用户原创)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 09:11:28 -07:00