4148 Commits

Author SHA1 Message Date
suzmii 56a8c2c32c 驱逐仍可见的卡之后补一次可见性复核:图片不再凭空消失
- publishPreview 记录本轮驱逐条数,驱逐发生后在 previewsRef 落盘之后补一次 sweepVisiblePreviews;
- 被驱逐的 identity 状态正好回到 undefined,而 sweepVisiblePreviews 只对 undefined 的卡重新入队,此前只差不这一次调用;
- 调用点必须在 previewsRef.current = next 之后,否则扫描看到被驱逐卡仍是 loaded 而不做任何事;
- 注释写明重入有界:重新入队走 publishPreview({status:'loading'}),不进 loaded/failed 驱逐分支,递归深度恒为 1;
- 只在真的发生驱逐时补扫,普通 loading/loaded 发布不增加扫描开销;
- 新增用例:灌满 48 张缓存把仍可见的目标卡挤出(LRU 不看可见性),断言该卡被重新请求读成 loaded。
2026-09-11 19:28:47 +08:00
suzmii f88e6aa5fe 清单快照被拒收不再静默:可见提示 + 强制重读磁盘真相
- WorkspaceLauncher:applyManifestSnapshot 拒收分支此前直接 return,改为必须先留痕(console.warn 记 decision/source/两个 revision)再走恢复;
- 新增 manifestMergeNotice 状态与提示条,DOM 暴露 data-manifest-merge-decision / -stage / -source / -held-revision / -snapshot-revision 作为排障观察点;
- 新增 recoverRejectedManifestSnapshot:重读磁盘 revision + 清单并重建 merge 状态,把被拒快照漏掉的新资源真正带进项目上下文;
- 同一项目只允许一条恢复在飞,避免拒收成串到达时打满读取槽;
- 重读期间若有更新的快照已被接受,绝不回退 revision(宁可报未解决,不放宽 CAS);
- scope-mismatch 仍只记日志不弹提示:串项目的快照对用户没有可执行语义;
- projectResourceLiveUpdateModel:新增拒收判定、三阶段文案与 rereadAuthoritativeProjectManifestSnapshot(两次读 revision 夹一次读清单,撕裂就放弃);
- styles.css:新增 .launcher-manifest-merge-notices 绝对定位提示位,容器不吃点击,与 .game-resource-book-notices 同口径;
- 新增 apps/ai-game-creator-shell/tests/workspaceLauncherManifestMerge.test.tsx:拒收可见 + 重读采纳 + 重读失败报未解决 + 不回退 revision + 串项目快照保持静默;
- projectResourceLiveUpdateModel.test.ts 追加拒收可见性/重读三读/撕裂放弃/跨项目拒绝/revision 非法/三阶段文案可区分六条断言。
2026-09-11 19:23:25 +08:00
lhk229 1102b5af23 Merge remote-tracking branch 'origin/master' into design_agent_refactor
Project CI / Repository checks (pull_request) Successful in 2m24s
Project CI / Frontend tests (pull_request) Successful in 3m13s
Project CI / Backend tests (pull_request) Successful in 6m15s
Project CI / Native shell tests (pull_request) Successful in 18m32s
2026-09-11 11:22:29 +00:00
lhk229 fd5a4c3136 调整策划调试日志默认开关
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / Backend tests (pull_request) Failing after 13s
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
npm run agc 开发启动时默认开启 design debug

其他启动方式默认不创建 .debug 目录
2026-09-11 11:21:07 +00:00
suzmii ee8e12783e 校准读时重写的文档口径:写回一次 + 丢弃可见,并补一条口径变更决策
- decision-log 2026-09-10 那条把「不写迁移脚本、不删除、不重置」改成当前事实:读时会把 legacy 分区(art / code)坐标归并到新分区并写回一次 sidecar(revision +1);不写迁移脚本、不重置坐标位置;但无法归并的坐标会被跳过(跳过条数在画布提示条上可见)。

- 新增 2026-09-11 decision-log 条目:背景(审计查实「读时原地重写」112 条 + 27%(66 + 16)丢弃与旧文档字面冲突)、决策(用户选 A:保留重写、不静默、改文档)、影响范围、验证方式(含两处变异验证)、关联文档。

- 技术方案【GameAgent资源自由画板与快速编辑】:同一句改成读路径写回一次 + 无法归并的坐标被跳过且可在提示条 / data-resource-canvas-layout-* 上读到。

- PRD【项目开发工作台】第 325 行同一句同样校准(避免权威文档里留着「不写迁移脚本、不删除、不重置」这句会误导排障)。

- 测试用例【AGC资源工作台V3端到端验收】S21 台账那格补上「存量项目第一次打开时读路径也会写回一次、并给一次性提示条」,避免把 revision 从 1 开始误判成异常。

- 行为、sidecar schema(v1)与跨端契约均未改动。
2026-09-11 19:19:51 +08:00
suzmii e15456ea14 读时丢弃的坐标不再静默:提示条带条数并在 DOM 上分开三类计数
- readReport 增加 droppedMissingResource(资源已不在 manifest)/ droppedSectionMismatch(分区与资源分类不匹配)/ dropped(两者之和),判据仍是 normalizeResourceCanvasPosition,未改 resourceCanvasLayoutModel 的丢弃语义。

- 文案补上跳过条数与两类原因:归并与丢弃同时发生时用「另有 N 条坐标无法对齐已跳过(…)」;只有丢弃时用「打开项目时有 N 条坐标无法对齐已跳过(…)」。

- 提示条暴露 data-resource-canvas-layout-normalized / -dropped / -dropped-missing-resource / -dropped-section-mismatch,供排障直接读 DOM;完全没丢时四个值都是 0。

- 读盘触发条件放宽为「有归并或有丢弃」,避免只有丢弃时什么都不提示。

- 断言:读盘统计用例覆盖三种情况分离;文案用例覆盖四形态(含真机 112 / 66 / 16 口径);appSurface 用例断言四个 data-* 与完整文案。

- 变异验证:把 dropped 计数改成恒 0 → 统计用例、读盘报告用例、提示条用例三处变红;去掉 data-resource-canvas-layout-dropped → 提示条用例变红。
2026-09-11 19:18:12 +08:00
suzmii 18361f8585 读时归并不再静默:打开项目归并旧分区坐标后给一次性提示
- useProjectResourceCanvasLayout 新增读盘只读统计 inspectProjectResourceCanvasLayoutRead 与文案 describeProjectResourceCanvasLayoutRead。

- 读盘判定 changed 时写入 readReport(项目作用域身份 + 排序模式 + 旧分区归并条数),判据复用 normalizeResourceCanvasPosition,只统计、不改写回与丢弃语义。

- index.tsx 在既有 game-resource-book-notices 提示层内渲染一次性提示条,复用 .game-resource-live-notice 样式与「知道了」关闭按钮;每个项目只提示一次,切换项目清空。

- 断言:useProjectResourceCanvasLayout.test.ts 覆盖归并时 readReport 与文案、无需归并且不写盘、只补新资源落位的写回不报读时统计;appSurface/project-development.suite.ts 覆盖提示条出现(data-resource-canvas-layout-normalized、可关闭)与无需归并时不出现。

- 变异验证:去掉 setReadReport → 上述读盘统计与提示条用例变红。
2026-09-11 19:14:44 +08:00
lhk229 63f5a1d49e 精简项目写锁历史型注释
Project CI / Backend tests (pull_request) Failing after 15s
Project CI / Repository checks (pull_request) Failing after 15s
Project CI / Frontend tests (pull_request) Successful in 2m51s
Project CI / Native shell tests (pull_request) Successful in 18m39s
移除 Issue 编号和旧实现叙述

保留写锁等待与排障契约说明
2026-09-11 11:10:57 +00:00
k88936 53008959c5 修正自动切分结果的类型收窄
在异步闭包赋值后明确已完成结果的非空类型。
2026-09-11 19:09:22 +08:00
k88936 57dbb3de52 替换已有组件前增加确认
使用独立确认弹窗避免一次点击覆盖已配置组件。
2026-09-11 19:07:12 +08:00
k88936 e189aff485 更新设计基础提示词契约测试
将测试断言同步到当前按需图片生成与动态产物合同。
2026-09-11 19:05:57 +08:00
k88936 248c094da9 清理合并命令测试中的无用导入
移除组件类型未再使用的测试模块导入。
2026-09-11 19:05:03 +08:00
k88936 e66eb2fb55 切换预览图片时自动适配画布
在活动图片变化后重新按完整画布边界计算视口。
2026-09-11 19:04:33 +08:00
k88936 d455dc18a9 按实际保存快照更新脏状态签名
保存成功后直接记录持久化快照签名,避免闭包中的旧编辑器状态阻止清脏。
2026-09-11 19:03:51 +08:00
k88936 04a0d21351 避免原始 PNG 的重复解析
使用解码后的颜色类型校验位深,将读取限制统一留在 image 解码器。
2026-09-11 19:03:03 +08:00
k88936 a9358bf3ce 防止字体前置校验访问空值
对外部状态中的空字体引用返回正常校验结果而不是抛出异常。
2026-09-11 19:00:49 +08:00
k88936 c3de2ce958 为自动切分命令增加项目写权限校验
在启动分离工作流前复用 asset.register 权限门禁。
2026-09-11 19:00:19 +08:00
k88936 287d2f94da 限制自动切分恢复状态读取大小
在解析 sidecar state 前检查文件大小,避免异常分配。
2026-09-11 18:59:51 +08:00
k88936 1343f487d0 为自动切分工作流增加忙碌保护
统一直接调用入口的并发防护,避免状态锁冲突。
2026-09-11 18:59:10 +08:00
k88936 73fb89a8f4 阻止本地素材登记结果错位回填
资源导入返回数量与请求路径不一致时立即中止位置映射。
2026-09-11 18:58:35 +08:00
k88936 bf2ffd2bf9 拒绝保存无可见像素的切分区域
透明裁切区域直接返回可恢复错误,避免登记空素材。
2026-09-11 18:58:13 +08:00
lhk229 811abdd375 修复策划 Agent 四个审查问题
Project CI / Repository checks (pull_request) Failing after 15s
Project CI / Backend tests (pull_request) Failing after 15s
Project CI / Frontend tests (pull_request) Successful in 2m40s
Project CI / Native shell tests (pull_request) Successful in 17m42s
修复 Retry 流式回合身份与阶段审批 transient 清理

拒绝无效 write_file 内容并补齐顾问阶段导轨
2026-09-11 10:57:49 +00:00
suzmii 27be57bf68 修正上一条提交里错位的别名表用例行
- 现象:提交 3082c3e85 把两条新增的 `decided` 表行(`'UI'`、`'font'`)插到了 `test.each(decided)` 的实参位置,`test.each` 拿到的是对象而不是回调,原来 7 条 `decided` 用例全部报 `fn2 is not a function`
- 成因:pre-commit 的 lint-staged 对**部分暂存**文件做「隐藏未暂存改动 → 跑 prettier → 还原未暂存改动」时会重新落位 hunk,本次两条新增行落错了位置;该文件当时是部分暂存(提交 ① 只暂存了其中 3 个 hunk),因此被波及
- 修法:把两条行移回 `decided` 数组内的正确位置,`test.each(decided)` 恢复成「表 + 单回调」形态
- 本提交只暂存这一个文件(不部分暂存),避开同一成因
2026-09-11 18:57:42 +08:00
k88936 3f55f043a1 拒绝切分产物路径中的非法节点标识
在写入 cut 图片前限制节点 ID 字符并确认路径仍位于 sidecar 内。
2026-09-11 18:57:19 +08:00
k88936 26677b193c 复用界面树组件计数值
在同一行中复用组件数量,避免重复计算。
2026-09-11 18:56:13 +08:00
k88936 b8691add3a 移除区域归一化日志路径中的恐慌
直接记录归一化结果,避免诊断日志调用 expect。
2026-09-11 18:55:28 +08:00
k88936 bfe010a192 让视觉绑定调试预览写入失败可降级
调试 PNG 写入失败时记录警告并继续绑定流程。
2026-09-11 18:55:06 +08:00
k88936 6db6de5b99 同步检查器组件面板展开状态
切换节点或组件时重置展开状态,避免复用旧节点的折叠状态。
2026-09-11 18:54:39 +08:00
k88936 87a7294a04 细化组件绑定载荷形状校验
在反序列化前拒绝空值和无效的节点组件外部枚举。
2026-09-11 18:54:21 +08:00
k88936 3774d7c1e1 移除修复重试流程中的隐式恐慌
在循环意外结束时返回可恢复错误而不是触发 unreachable。
2026-09-11 18:53:34 +08:00
k88936 8d15125f12 限制切分提示词中的节点备注
对用户备注清理控制字符和围栏符号并限制长度。
2026-09-11 18:52:59 +08:00
k88936 cf68b8212d 让提取提示词序列化错误可恢复
将提取提示词生成改为返回带上下文的错误。
2026-09-11 18:52:10 +08:00
k88936 8d7ccc0d75 简化工作流操作卡状态映射
使用步骤映射替代嵌套三元表达式。
2026-09-11 18:51:30 +08:00
k88936 2af3d9a965 修正结构识别步骤的前置校验
将结构识别活动步骤改为校验素材切分前置条件。
2026-09-11 18:50:59 +08:00
suzmii d9822eca05 同步资源分类口径的文档:读显示 / 写回两个口径、别名表大小写不敏感
- PRD 的分类取值段落改为「读显示 / 写回两个口径」:写清跨端同构的两个函数名、Agent 投影不许再透传落盘 `category`、面板保存回传落盘原值、别名表大小写不敏感(`"UI"`、`font`)
- 技术方案(AI游戏创作智能体App实施计划)的 manifest `category` 段落同步:`"UI" → ui-interaction`、`font → document`,其余映射不到的 kind 才落 `unclassified`;补上两侧口径函数名
- `pitfalls.md`:把「补别名只影响新登记,不重算 `category`」这条坑更新为已修形态,并写明「同 kind 重登记禁止动 `category`」这条必须保留的不变量;「读时重派生」条目补上两个口径不能混用与跨端必须同构两条
- `pitfalls.md` 新增条目「大写 `UI` / `font` 不在 alias 表 → 8 条真机 UI 资产永远落「待归类」,且自愈救不回」,记录成因链与三层守卫
- `decision-log.md` 新增决策条目:口径拆两半、自愈不下沉到反序列化、别名表大小写不敏感、重登记重派生但不抹掉显式分类,含变异验证与影响范围
- 端到端验收用例文档的 S5 栏目归属补一句:判定「编辑标签后分类有没有被改」必须比 manifest 文件,不能拿自愈后的显示值当落盘值
2026-09-11 18:49:32 +08:00
suzmii f476eb89e5 同路径重登记:kind 变化时重派生 category,同 kind 时保留落盘分类
- `register_local_asset_entry`(`assets.rs`)命中同 `localPath` 的既有资产时,旧实现只覆盖 `kind` / `media_type` / `source`,**从不重算 `category`**:`kind` 变了而 `category` 停在旧值,且陈旧的非 `unclassified` 值会被读侧无条件信任(自愈只在落盘值是 `unclassified` 时才触发),该资产就永远停在错误栏目
- 修法:只在 `existing.kind != kind` 时重派生 `category`;`kind` 未变时刻意不动 `category`——落盘分类是权威值,同 kind 重登记不得抹掉它
- `register_local_asset_records_existing_asset_with_canvas_source` 补上 `category` 断言:首次登记 `kind:"character"` 落 `character`,重登记改成 `kind:"ui"` 后必须变 `ui-interaction`(旧用例只断言 `kind` 与 `source.kind`,正好走更新分支却漏掉 `category`,所以这条错位一直没被抓住)
- 新增用例 `register_local_asset_keeps_explicit_category_when_kind_is_unchanged`:显式设成 `audio` 后同 kind 重登记,`category` 与 `tags` 必须原样保留,把「不能无条件重派生」这条不变量钉死
- 新增用例 `register_local_asset_derives_category_from_real_write_side_kinds`:用与现役写入侧逐字一致的字面量(`"UI"` / `"font"`)走真实 `register_local_asset_at`,断言落到 `ui-interaction` / `document`;它属于同一套 `register_local_asset_*` 写 API 的派生行为,因此与上面的更新分支断言放在同一个提交
2026-09-11 18:48:03 +08:00
suzmii 3082c3e854 kind 别名表大小写不敏感并收口 font:堵住 8 条 UI 资产永远落「待归类」
- `canonical_game_creation_app_asset_kind`(Rust)与 `canonicalGameCreationAppAssetKind`(TS)改为对 trim 后的小写值查别名表与 canonical 目录,修正「UI 设计资产的现役写入侧写的是大写 `"UI"`」这条真机事实
- 别名表补 `font → document`:字体上传(`ttf / otf / woff / woff2`)登记的 manifest `kind` 就是 `font`
- 为什么必须在别名表收口、读时自愈救不回来:`"UI"` 与 `"font"` 的派生结果本身就是 `unclassified`,自愈规则「派生值不是 unclassified 才触发」永不成立;真机 8 条 `kind:"UI"` + `mediaType:"application/json"` + `localPath:"ui/UI 设计 N.json"` 与写入路径逐字段吻合
- 改写 Rust 断言 `game_creation_app_asset_category_for_kind("UI") == Unclassified` → `UiInteraction`,并补 `canonical_...("UI") == "ui-design"` 与 `font == Document`:旧断言把这条 bug 钉成了「期望行为」,新形态才是唯一真源——写入侧真实写出的 kind 必须能落进明确栏目,否则真机资产永远归不了类
- 改写 TS 断言 `gameCreationAppAssetCategoryForKind('UI') == 'unclassified'` → `'ui-interaction'`,理由同上
- `game_creation_app.rs` 里「现役写入侧仍会写出这些非 canonical 值,必须在这里收口」的注释此前只收口了小写 `ui`,与大写写入侧矛盾,现按注释本意收口
- 新增写侧→分类的端到端契约用例:`resource_bridge.rs` 的 `bridge_is_idempotent_and_installs_source_image` 走真实生产函数 → 真实 `register_local_asset_at(..., "UI", ...)` → 断言落盘 `category` 为 `ui-interaction`
- 新增 `assetKindCanonicalMapping.test.ts` 的「写侧 kind 字面量 → 分类」用例组:直接解析 UI 编辑器写侧源码第 3 个实参,写点换个新字面量就会红,防下次再漏
2026-09-11 18:46:58 +08:00
suzmii 576786324f 编辑标签面板回传落盘原值:堵住「只改标签」静默改分类
- 新增 `gameCreationAppAssetPersistedCategory`:写回口径,只做「缺失或非法 → 按 kind 派生」兜底,不套用读时自愈;它必然等于 Rust 反序列化后的落盘 `category`
- `ResourceClassificationPanel` 的分类初值从 `gameCreationAppAssetCategory`(读显示口径、会把落盘 `unclassified` 自愈成派生值)改为 `gameCreationAppAssetPersistedCategory`,保存时回传落盘原值
- 修掉真机上「同一 `kind:"ui"` 资产同时存在 55 条 `unclassified` 与 2 条 `ui-interaction`」的漂移签名——后者正是自愈值被回写持久化的结果
- 面板注释更正:原注释写「保证『只改标签』不会顺带改动分类」,但那行读的是自愈后的值,这个保证是假的
- `gameCreationAppAssetCategory` 的文档补上「这是读显示口径,回写必须用 `gameCreationAppAssetPersistedCategory`」,避免下次再混用
- 新增面板用例「保存标签不改动落盘 category:自愈值不得被回写」:夹具 `{kind:'ui', category:'unclassified'}`,断言写入命令收到的 `category` 仍是 `unclassified`
- 既有面板夹具 `{kind:'character', category:'character'}` 是自愈 no-op,永远测不出漂移,因此保留它作为对照、另加自愈夹具
- 新增契约用例「写回口径保留落盘 unclassified,读显示口径才自愈」,把两个口径的差集钉死
2026-09-11 18:45:38 +08:00
suzmii 458a65cb5e 资源分类读显示口径下沉到 Rust:Agent 投影与 UI 同构
- 新增 `game_creation_app_asset_effective_category`:读显示口径的唯一实现——落盘 `category` 权威,仅在落盘值为 `unclassified` 且该资产 `kind` 能派生出明确的非 `unclassified` 分类时采用派生值,其余信任落盘值
- `GameCreationAppAssetManifestEntry` 的反序列化刻意不做自愈:反序列化结果就是落盘原值,「编辑标签」面板要靠它原样回写;自愈只属于读显示口径
- Agent 资源投影 `bridge_registered_resource` 不再直接透传 `asset.category`,改走有效分类,修掉真机 122 条资产里 55 条「UI 显示 UI 交互、Agent 读到待归类」的跨端口径分歧
- 新增 Rust 决策矩阵 `EFFECTIVE_CATEGORY_CONTRACT` 与用例 `asset_effective_category_follows_the_shared_contract_matrix`,矩阵是「落盘值 / kind 派生 / 读时自愈」三个口径的唯一真源
- 新增跨语言契约:`assetKindCanonicalMapping.test.ts` 解析 Rust 源码里的决策矩阵与 canonical kind→栏目表,逐条喂给 TS `gameCreationAppAssetCategory` 对照,任一侧改口径都会红
- `direct_tool_bridge` 新增 Agent 侧回归用例:`kind:"ui" + category:"unclassified"` 必须投影成 `ui-interaction`
- 既有用例 `..._projects_manifest_classification_verbatim` 更名为 `..._keeps_explicit_manifest_classification`:逐字透传只在落盘值不是 `unclassified` 时成立,旧名字会与新的有效分类语义矛盾
2026-09-11 18:43:39 +08:00
suzmii c527c19bf8 校准 DirectProject 历史兼容口径的技术方案与共享决策记录
- 技术方案:把「不迁移旧 {role,content} 行 / 不会对旧格式做迁移或兼容」改成当前状态——读侧白名单兼容 legacy 行(含 tool 行只识别不注入)、写侧 DirectProject 自己的旧行写点已收口
- 技术方案:修正「Rust 是该历史文件的唯一写入方」,写清 project.jsonl 同时被通用对话链(agent_id=None 的项目主对话与 Runtime 公开状态消息)读写,并记录两条链互读兼容的规则
- 技术方案:说明为什么故意不给通用对话写入器加「Direct-owned 就拒写」的硬报错(会把旧行噪声换成任务起不来),以及这类失败为何按不可重试处理
- 技术方案:更新时间改 2026-09-11
- decision-log:新增 2026-09-11 条目,记录格式切换当年「唯一写入方 + 测试手动清理」的前提在存量用户项目上不成立、现改为「读侧白名单兼容 + 写侧统一」,以及为什么不做数据迁移
2026-09-11 18:36:29 +08:00
suzmii 2b44b62599 DirectProject 历史格式类失败给出专门提示并按不可重试处理
- direct_runtime.rs:新增 direct_project_history_shape_failure 白名单(历史记录类型无效 / 缺少 payload / 解析历史失败)
- direct_codex_failure_recovery_hint 增加专门 hint,指向真实现象与动作:该类旧格式已被读侧兼容,仍失败说明记录不在白名单内,请检查项目诊断后修复该历史文件
- direct_codex_failure_is_retryable 对该类失败返回 false,前端不再显示「可直接重试」(同一份历史每次读得到同一结论)
- 打开/读取类 IO 失败不在白名单内,仍按可重试处理
- 补断言:hint 文案、IO 失败边界、诊断 message 里的 retryable=false 与 sidecar 的 "retryable": false
2026-09-11 18:36:19 +08:00
suzmii 5ac26b99c9 显式 Codex 返回不再往项目主对话投影旧格式行
- direct_tools_mcp.rs:删除 conversation.record_codex_response 末尾往 project.jsonl 追加 legacy 行的投影,它写的是 {schemaVersion:game-creator-conversation.v1,...} 旧行,会毒化共用该文件的 DirectProject 历史
- 顺带删掉只为那条投影存在的 key/message_id 计算与描述它的注释,不留墓碑
- 该工具的事实来源仍是自己的只读 journal .agent/conversations/codex-responses.jsonl,返回内容与 conversation.list/read 行为不变
- 补断言:record_codex_response 只写 codex-responses.jsonl,project.jsonl 保持为空
2026-09-11 18:36:16 +08:00
suzmii f0d5687ab7 共享的 project.jsonl 让两条对话链互读对方的行,混合历史不再双向失败关闭
- project/conversation.rs:read_persisted_local_conversation_records_unlocked 跳过 type=response_item 且带 payload 的行(DirectProject 写给同一份「项目主对话」的行),其余解析失败仍按「解析对话记录失败」失败关闭
- 新增 is_direct_project_history_row 做行信封白名单,只认对方那一种明确枚举的形状,不放宽成「什么都跳过」
- 不把 response_item 行二次投影成 LocalConversationMessageRecord:DirectProject 侧已经拥有那份 Responses item → 聊天内容的投影,再造一份平行投影会与它漂移
- 不加「文件已属于 DirectProject 就拒绝追加旧行」的硬报错:runtime_driver/task_start.rs 在 ensure_..._accepted_public_status_at 返回 Err 时会中止后台任务(「后台任务启动确认落盘失败,任务未执行」),runtime_protocol/steering.rs:572/604/1300 也用 ? 上抛,加硬报错会把旧行噪声换成任务起不来;毒化本身已由读侧白名单堵住
- 补断言:混合文件里通用链只读自己的 legacy 行且坏行仍失败关闭、混合文件从两条链都能读(DirectProject 把两种行都读出来)、纯旧格式文件的写入行为不变
2026-09-11 18:36:07 +08:00
suzmii bfb928295e DirectProject 读侧白名单兼容格式切换前的旧行,存量项目不再全部读不动
- direct_project_history.rs:两处行信封判定收敛到 direct_project_history_item_from_parsed_line,response_item 与白名单化的 legacy 行走同一条判定路径
- 新增 direct_project_legacy_row:只认 schemaVersion=game-creator-conversation.v1、无 type、role 落在该写入器自己的角色集合(user/assistant/tool)内、content 为非空字符串的行,其余形状继续按损坏失败关闭
- user/assistant 旧行投影成与 direct_project_local_message_item 同形状的 message item:role 与 content 逐字节保留、不 trim、不改写、未知字段忽略,有 messageId 才带 id
- tool 旧行已识别但不进 Codex 上下文:它不是 Responses item,无法还原成真正的工具 item,混入会造出假的工具消息;聊天投影本来也只展示 user/assistant
- 抽出 direct_project_message_item 供本地补写与 legacy 投影共用,保证两种来源的 item 形状一致
- 补断言:旧行投影(role/content 逐字节、无 messageId 时无 id)、旧行与新行交替的混合文件按行顺序读取、tool 行被识别且不进上下文、非白名单异常行(role=system/developer、content 非字符串或为空、缺 role、缺 payload、坏 JSON)仍失败关闭、通用对话写入器产出的旧行形状落在白名单内
- 变异验证:去掉 legacy 兼容分支→投影/混合文件/通用写入器形状 3 个用例变红;把白名单放宽成「任意行都接受」→失败关闭用例变红
2026-09-11 18:35:26 +08:00
lhk229 712f28e207 策划工作区改名为design_artifacts
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 3m20s
Project CI / Native shell tests (pull_request) Successful in 17m35s
更新策划文件工具和阶段产物检查路径

同步测试夹具与生产迁移方案文档
2026-09-11 10:16:15 +00:00
suzmii b1377572d6 校准资源替换的 PRD、验收文档、技术方案与项目记忆
- PRD §5.3 补实现口径:替换落盘 = 改绑定 + 追加新版本、子版本绑定 = 源绑定去掉源素材并保证替换素材在集合里、前后身份用推导记录、三项兼容性逐条判据与 sizeSpecEqual 的降级声明、失败即拒绝、入口与可见效果;同时标注 :364-373 的 ProjectResourceDescriptor 是历史四分类形状(其 width/height/durationMs 在 manifest 里并不存在)
- PRD §5.4 前的版本章节与 §6 P1、§7.4 第 4 条按当前状态校准:替换已实施,但版本聚焦态仍不提供创建/替换/切换/回滚按钮,资源替换入口在资源卡工具条
- PRD 新增 §7.8 P1 资源替换验收六条(入口放行判据、候选禁用与原因、只追加写入形状、两条绑定路径、拒绝零副作用、成功后切版本但不重载预览)
- 【测试用例】AGC资源工作台V3端到端验收:删掉「PRD L387 兼容性三项属 C6 取消范围」那句(改为明确不属于),更新 §7.3 工具条 opt-in 清单,补三条已知边界(运行画面不因改绑定而变、候选弹窗不加载缩略图、picker 在 AGC 首次使用),§8 覆盖与不覆盖范围补资源替换
- 【技术方案】AI游戏创作智能体App实施计划::669 的「本阶段不提供版本创建、替换、切换」与 :641 的布局切片范围按当前状态校准,并在文末新增「2026-09-11 AGC 资源工作台 V3:版本级资源替换」一节,写全命令、写入语义、前后身份推导口径、三项兼容性判据与降级声明、入口、成功后行为与验证数字
- decision-log 新增一条(背景 / 决策 / 恒等绑定硬约束 / 判据 / 降级 / 边界 / 影响范围 / 验证方式 / 关联文档):说明本次按 PRD §3.2 / §5.3 恢复「替换后创建下一迭代版本」,与 2026-09-10 那条「不创建新版本、替换功能整条取消」的口径关系,以及 C6 的候选/队列/审核仍不做
- Issue #309 的三处口径(C1 决策、贯穿性决策 6、验收总纲的「不创建新版本 / 不产生新版本」)按远程写确认规则**未擅自改动**,需要在用户确认后再改
2026-09-11 18:12:41 +08:00
kdletters fafe6b63cd 修复AGC模型请求与对话登录态自动续期 (#329)
Project CI / Repository checks (push) Successful in 2m40s
Project CI / Frontend tests (push) Successful in 3m23s
Project CI / Backend tests (push) Successful in 5m46s
Project CI / Native shell tests (push) Successful in 18m30s
## 变更说明

- AGC 客户端配套后端 API 在 401 时自动刷新登录态并重试一次,覆盖模型目录请求。
- DirectProject 对话鉴权失效时刷新平台会话、同步 Rust/Runner 凭据并重试同一 clientTurnId。
- 403 权限拒绝不触发续期;账号切换后不重发旧请求。
- 补充并发续期、失败保留原错误、权限边界和 Direct 对话重试测试。

## 验证

- npm run test -- apps/ai-game-creator-shell/tests/appSurface.test.ts apps/ai-game-creator-shell/tests/clientApi.test.ts apps/ai-game-creator-shell/tests/clientHttp.test.ts apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx
- npm run agc:typecheck
- npm run check:encoding
- git diff --check

Reviewed-on: #329
Co-authored-by: kdletters <kdletters@qq.com>
Co-committed-by: kdletters <kdletters@qq.com>
2026-09-11 18:09:48 +08:00
k88936 4749339bad 补齐图片字节类型导出与转换
Project CI / Repository checks (pull_request) Failing after 31s
Project CI / Backend tests (pull_request) Failing after 13s
Project CI / Frontend tests (pull_request) Successful in 3m56s
Project CI / Native shell tests (pull_request) Failing after 3m33s
导出共享 GPT 图片尺寸阈值常量。

修复编辑器参考图 Bytes 与 Vec 边界转换。
2026-09-11 18:02:04 +08:00
k88936 3e85c71060 整理图片代理代码格式
按 Rust 格式化规范整理 multipart 与响应解析代码。
2026-09-11 17:55:50 +08:00
suzmii f5b381dbd8 视图切换时只取消上一视图排队中的可见性预取
用户离开某个视图后,继续为它排队读图没有任何收益,而这些排队的预取会**排在新视图按需请求的前面**(3 槽跨视图共享),把"进入总览后等图"变成纯等待。这是"进总览要等图"的主因,单张读取本身只有 5–15ms。

- `cancelQueuedVisiblePrefetches()`:只下掉**还在队列里**的 `visible` 理由任务。语义边界刻意收窄 ——
  - `detail` / `play` 理由的排队**保留**;
  - **在途请求不打断**(只占 3 槽中的 1 个,打断它拿不回已花的读盘成本,且切回来要重读);
  - **缓存与身份不失效**(不触发 `disposeAllCachedPreviews`),切回原视图不重读已拿到的图。
- 修法 4 一并收口:视图切换 effect 在取消后**立即按几何复核一次**(`sweepVisiblePreviews`),仍然可见的卡重新入队、不可见的自然不再请求 —— 因此不存在"取消后永不重试"的死角。
- 依赖使用**派生后的** `prefetchScopeKey`(不是可能为 `undefined` 的 `input.prefetchScopeKey`)。这修掉了本轮自查发现的一个真 bug:早期写法在调用方未传该 prop 时直接 `return`,整段取消逻辑成了**永不执行的死代码**;由下面的断言暴露。

断言(`tests/useProjectResourceCardPreviews.test.ts` 新增 2 条):
1. 「切视图只取消上一作用域排队中的可见性预取」:登记 6 张(3 在途占满槽 + 3 排队,其中 1 张为 `detail`),切视图后断言队列从 3 → 1、**留下的正是 `detail`**、且 `activeReadCount` 仍为 3(在途不被取消)、新视图 identity 立刻可用;
2. 「取消后再次可见会重新入队」:切走再切回,卡片重新注册且几何可见后,断言该卡**重新进入队列** —— 直接守住"不留永不重试死角"这条硬要求。

变异验证:把取消那一步去掉(effect 内只保留复核)→ 第 1 条断言立即失败(`expected [ …(3) ] to have a length of 1 but got 3`);恢复后 24/24 通过。

验证(同一时刻、同一命令的前后对照;当时树上有并发改动:`src-tauri/.../direct_project_history.rs`):
- 改动前(只 stash 我的两个文件):`86 files / 1236 passed / 4 skipped / 0 failed`
- 改动后:`86 files / 1238 passed / 4 skipped / 0 failed`(多出的 2 条为本提交新增用例)
- `src/components/image-editor` 1387 passed;typecheck exit 0;check:encoding 4388 文件;prettier 与 eslint 干净;`git diff --check` 干净。
2026-09-11 17:55:22 +08:00