收口design组展示名,改为设计实现Agent

分组字典、manifest默认名与分组头像字一并改掉

个体Agent名兜底跟进,玩法策划Agent与内部id不动

跟改16处由label派生的断言

第 18.2 节要求 design 组用户名称改为「设计实现组」,与新阶段「立项策划」区分。
bf2185fba 只改了 taskGroupLabels 一本字典,另两本同概念字典没动,于是同一个
design 组在开发者面板/文本汇总里叫「设计实现组」、在工作台状态栏里叫
「策划 Agent」——这个语义不一致是该提交引进来的。

先更正一条此前的判断:曾把这条的严重度建立在「新项目默认主路径上『立项策划』
与『策划 Agent』同屏共存」上。该说法未经验证且不成立——用 appSurface harness
实测策划路径,子 Agent 状态栏根本不渲染,策划 Agent 出现 0 次。结构上二者确在
launcherView === 'project-development' 分支的同一棵树里,但未能把用例驱动到该
分支,故不作为事实主张。若真会撞,也是批准后进入完整制作那一段,比原描述窄
得多。改这条的理由与撞不撞名无关,只是第 18.2 节的要求 + 上述不一致。

口径取最小方案:保持兄弟项的「X Agent」体系,design 取「设计实现 Agent」。
不把 taskGroupLabels 直接塞进 groupConfigs——两本字典命名体系不同(「X组」对
「X Agent」,且音乐组/音频 Agent、运营组/发布 Agent 连词都不一样),直接替换
会连带改掉另外五个分组名;消灭重复字典属视觉改版,单独立项。

改动:agentPresentation.ts 的 groupConfigs、view/project-development/index.tsx
的 summarizeAgent 默认名与同文件分组头像字(策→设)、model.ts 中
agentId.includes('design') 的个体名兜底(design-director 走这里)。
design-foundation 的「玩法策划 Agent」单列在前,不变;内部 agent id 与 design
分组键均未动。

测试量原估「3 处断言」严重低估,实跑发现 project-development.suite.ts 有 16 处
派生断言需跟改——「X 文本回执」由 App.tsx 的 `${candidate.label} 文本回执` 拼出、
「历史成果 · X」由 resourceProjectionModel.ts 拼出、dock 的 article accessible
name 亦然。替换用后行否定守住「玩法策划 Agent」(它含「策划 Agent」子串),
替换前后该串恒为 6 处。agentRuntimeModel.test.ts 与
projectResourceProjectionModel.test.ts 里剩余 4 处是测试自造的输入 fixture、
不由字典派生,保持不动。

验证:appSurface.test.ts 383 passed / 0 failed;agentRuntimeModel、
agentTraceSummary、projectResourceProjectionModel、projectResourceLiveUpdateModel
合计 39 passed;agc:typecheck、ESLint --max-warnings 0、check:encoding、
git diff --check 通过。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 12:20:01 +00:00
parent 7ca82ba7aa
commit d44f930d1f
7 changed files with 36 additions and 23 deletions
@@ -1553,7 +1553,7 @@ export function projectProfessionalAgentLabel(agentId: string) {
return '数值 Agent';
}
if (agentId.includes('design')) {
return '策划 Agent';
return '设计实现 Agent';
}
if (agentId.includes('art')) {
return '美术 Agent';
@@ -268,7 +268,7 @@ export function projectAgentRuntimeSummaries(
: []
: null;
const groupConfigs = [
{ group: 'design' as const, label: '策划 Agent' },
{ group: 'design' as const, label: '设计实现 Agent' },
{ group: 'art' as const, label: '美术 Agent' },
{ group: 'code' as const, label: '程序 Agent' },
{ group: 'balance' as const, label: '数值 Agent' },
@@ -1244,7 +1244,7 @@ export default function ProjectDevelopmentView({
asset.kind === 'art-spritesheet' && asset.mediaType.startsWith('image/'),
);
const allAgentSummaries = [
summarizeAgent(manifest, 'design', '策划 Agent'),
summarizeAgent(manifest, 'design', '设计实现 Agent'),
summarizeAgent(manifest, 'art', '美术 Agent'),
summarizeAgent(manifest, 'code', '程序 Agent'),
summarizeAgent(manifest, 'balance', '数值 Agent'),
@@ -3806,7 +3806,7 @@ export default function ProjectDevelopmentView({
<span className="game-agent-avatar">
{
{
design: '',
design: '',
art: '美',
code: '程',
balance: '数',
@@ -1339,7 +1339,7 @@ export function registerProjectConversationTests() {
expect(await screen.findByText('刷新后外部记录')).not.toBeNull();
expect(
await screen.findByText(
'策划 Agent 模型上下文已超限,请缩小任务范围后重试',
'设计实现 Agent 模型上下文已超限,请缩小任务范围后重试',
),
).not.toBeNull();
expect(agentDialog.textContent).not.toContain('fingerprint');
@@ -766,7 +766,9 @@ export function registerProjectWorkbenchFoundationTests() {
expect(screen.getByLabelText('陶泥儿 Agent 对话')).not.toBeNull();
expect(screen.getByLabelText('测试项目总控')).not.toBeNull();
expect(screen.getByLabelText('子 Agent 状态栏')).not.toBeNull();
expect(screen.getByRole('article', { name: /策划 Agent/ })).not.toBeNull();
expect(
screen.getByRole('article', { name: /设计实现 Agent/ }),
).not.toBeNull();
expect(screen.getByRole('article', { name: /美术 Agent/ })).not.toBeNull();
expect(screen.getByRole('article', { name: /程序 Agent/ })).not.toBeNull();
@@ -10082,7 +10084,9 @@ export function registerProjectSupervisorSurfaceTests() {
);
expect(professionalRuntimeReadCount).toBeGreaterThan(readCountBeforeExpose);
expect(
within(professionalList).getByText('策划 Agent 服务连接失败,请稍后重试'),
within(professionalList).getByText(
'设计实现 Agent 服务连接失败,请稍后重试',
),
).not.toBeNull();
expect(professionalList.textContent).not.toContain('fingerprint');
expect(professionalList.textContent).not.toContain('chars=545');
@@ -10122,7 +10126,7 @@ export function registerProjectSupervisorSurfaceTests() {
}),
).not.toBeNull();
const designReceiptCard = within(documentResources).getByRole('button', {
name: '打开资源详情:文档 策划 Agent 文本回执',
name: '打开资源详情:文档 设计实现 Agent 文本回执',
});
expect(designReceiptCard).not.toBeNull();
expect(
@@ -10140,10 +10144,10 @@ export function registerProjectSupervisorSurfaceTests() {
);
fireEvent.click(designReceiptCard);
const designReceiptFocus = await screen.findByRole('region', {
name: '策划 Agent 文本回执',
name: '设计实现 Agent 文本回执',
});
expect(
within(designReceiptFocus).getByText('历史成果 · 策划 Agent'),
within(designReceiptFocus).getByText('历史成果 · 设计实现 Agent'),
).not.toBeNull();
fireEvent.click(
within(designReceiptFocus).getByRole('button', { name: '收起资源' }),
@@ -10164,7 +10168,7 @@ export function registerProjectSupervisorSurfaceTests() {
);
expect(
within(screen.getByLabelText('文档')).getByRole('button', {
name: '打开资源详情:文档 策划 Agent 文本回执',
name: '打开资源详情:文档 设计实现 Agent 文本回执',
}),
).not.toBeNull();
expect(
@@ -10193,7 +10197,7 @@ export function registerProjectSupervisorSurfaceTests() {
);
const updatedDesignCard = await waitFor(() => {
const card = within(screen.getByLabelText('文档')).getByRole('button', {
name: '打开资源详情:文档 策划 Agent 文本回执',
name: '打开资源详情:文档 设计实现 Agent 文本回执',
});
expect(card.getAttribute('data-resource-id')).toContain(
'agent-finalization-33333333333333333333333333333333',
@@ -10202,7 +10206,7 @@ export function registerProjectSupervisorSurfaceTests() {
});
fireEvent.click(updatedDesignCard);
const updatedDesignDialog = await screen.findByRole('region', {
name: '策划 Agent 文本回执',
name: '设计实现 Agent 文本回执',
});
expect(
within(updatedDesignDialog).getByText(
@@ -10217,8 +10221,8 @@ export function registerProjectSupervisorSurfaceTests() {
await waitFor(() => {
expect(
within(
within(dock).getByRole('article', { name: /策划 Agent/ }),
).getByText('策划 Agent 服务连接失败,请稍后重试'),
within(dock).getByRole('article', { name: /设计实现 Agent/ }),
).getByText('设计实现 Agent 服务连接失败,请稍后重试'),
).not.toBeNull();
expect(
within(
@@ -10271,8 +10275,8 @@ export function registerProjectSupervisorSurfaceTests() {
);
expect(
within(
within(dock).getByRole('article', { name: /策划 Agent/ }),
).getByText('策划 Agent 服务连接失败,请稍后重试'),
within(dock).getByRole('article', { name: /设计实现 Agent/ }),
).getByText('设计实现 Agent 服务连接失败,请稍后重试'),
).not.toBeNull();
expect(
within(
@@ -10291,7 +10295,7 @@ export function registerProjectSupervisorSurfaceTests() {
fireEvent.click(retryButton);
expect(
await within(retryButton.closest('article')!).findByText(
'策划 Agent 服务连接失败,请稍后重试',
'设计实现 Agent 服务连接失败,请稍后重试',
),
).not.toBeNull();
expect(retryButton.closest('article')?.textContent).not.toContain(
@@ -10326,10 +10330,10 @@ export function registerProjectSupervisorSurfaceTests() {
'重试请求已受理,正在同步新一轮状态',
);
const retriedDesignCard = within(professionalList)
.getByText('策划 Agent')
.getByText('设计实现 Agent')
.closest('article')!;
expect(retriedDesignCard.textContent).not.toContain(
'策划 Agent 服务连接失败,请稍后重试',
'设计实现 Agent 服务连接失败,请稍后重试',
);
expect(retriedDesignCard.textContent).toContain('执行中');
expect(
@@ -10349,12 +10353,12 @@ export function registerProjectSupervisorSurfaceTests() {
expect(screen.queryByLabelText('专业 Agent 实时状态')).toBeNull();
expect(
within(
within(dock).getByRole('article', { name: /策划 Agent/ }),
within(dock).getByRole('article', { name: /设计实现 Agent/ }),
).getByText('等待中'),
).not.toBeNull();
expect(
within(screen.getByLabelText('文档')).getByRole('button', {
name: '打开资源详情:文档 策划 Agent 文本回执',
name: '打开资源详情:文档 设计实现 Agent 文本回执',
}),
).not.toBeNull();
},
@@ -1,5 +1,14 @@
# 决策记录
## 2026-08-18 M1D 收口:design 组展示名改完
- **背景更正(先于结论)**:此前把这条的严重度建立在「新项目默认主路径上『立项策划』与『策划 Agent』同屏共存」上,**该说法未经验证且不成立**。用 appSurface harness 实测策划路径:`子 Agent 状态栏` 根本不渲染,`策划 Agent` 出现 0 次、`立项策划` 出现 2 次。结构上二者确在 `launcherView === 'project-development'` 分支的同一棵树里(`ProjectDevelopmentView` 的 dock + 作为 `supervisor` 传入的 `ProjectSupervisorView`),但未能把用例驱动到该分支,故不作为事实主张。若真会撞,也是**批准后进入完整制作**那一段(此时 `state=approved`,阶段进度卡守卫仍放行),比原描述窄得多。
- **仍然要改的理由**:与撞不撞名无关。`bf2185fba` 只把 `taskGroupLabels.design` 改成「设计实现组」,另两本同概念字典没动,于是同一个 design 组在开发者面板/文本汇总里叫「设计实现组」、在工作台状态栏里叫「策划 Agent」——**这个语义不一致是该提交引进来的**。第 18.2 节要求本就是「design 组用户名称改为设计实现组」,与新阶段区分只是其动机之一。改完比回退便宜(回退还需挑拣 `c6a08ef98` 里混着的按钮改名与 prettier 重排,并反改第 18.2 节)。
- **口径选择**:采最小方案,保持兄弟项的「X Agent」体系(美术 Agent / 程序 Agent / …),design 取「设计实现 Agent」。**不**把 `taskGroupLabels` 直接塞进 `groupConfigs`——两本字典命名体系不同(「X组」对「X Agent」,且音乐组/音频 Agent、运营组/发布 Agent 连词都不一样),直接替换会连带改掉另外五个分组名。消灭重复字典属视觉改版,单独立项。
- **改动**`agentPresentation.ts``groupConfigs``view/project-development/index.tsx``summarizeAgent` 默认名与同文件分组头像字(`策``设`)、`model.ts``agentId.includes('design')` 的个体名兜底(`design-director` 走这里;`design-foundation` 的「玩法策划 Agent」单列在前,不变)。内部 agent id 与 `design` 分组键均未动。
- **测试**:原估「3 处断言」严重低估。实跑发现 `project-development.suite.ts` 有 16 处派生断言需跟改——「X 文本回执」由 `App.tsx``${candidate.label} 文本回执` 拼出、「历史成果 · X」由 `resourceProjectionModel.ts` 拼出、dock 的 article accessible name 亦然。替换时用后行否定守住 `玩法策划 Agent`(它含 `策划 Agent` 子串),替换前后该串恒为 6 处。`agentRuntimeModel.test.ts``projectResourceProjectionModel.test.ts` 里剩余 4 处是测试自造的输入 fixture、不由字典派生,保持不动。
- **验证**`appSurface.test.ts` **383 passed / 0 failed**`agentRuntimeModel` / `agentTraceSummary` / `projectResourceProjectionModel` / `projectResourceLiveUpdateModel` 合计 39 passed`agc:typecheck`、ESLint `--max-warnings 0``check:encoding``git diff --check` 通过。
## 2026-08-18 M1D 审查修复补充:锁错误脱敏与澄清轮次口径
- **锁错误回传绝对路径**`acquire_project_write_lock` 的 Err 内嵌 `.agent/project.lock` 真实绝对路径,违反第 18.3 节「返回值不包含绝对路径……或内部诊断」。补 `redact_agent_runtime_project_paths` 的三处是前端审批卡真正会显示的那条链:`reconcile_plan_gdd_approval_projections_at`(hydrate 在取自己的锁之前调它)、hydrate 自己的锁、`decide_plan_gdd_at`(其错误与 hydrate 的错误渲染在同一个错误区)。planning 另有 14 个取锁点沿用未脱敏写法,属 M1B/M1C 既有模式,本次不扩面。脱敏不破坏 `项目正在被其他写操作占用:` 前缀,`project_gates.rs` / `provider_recovery.rs` 两处按前缀分类的判据不受影响。
@@ -2027,7 +2027,7 @@ M0 完成不表示完整策划闭环已经上线。`M1A-1``M1A-4`、`M1B-1`
| `M1D-2` | 入口分流与阶段进度 | `M1D-1` | **已完成并以 `bf2185fba` 合入 `feat/five_min_design`**:游戏新项目默认 `standard + project-supervisor-plan`,显式“直接开建”保持 `autonomous-game-build`;阶段进度显示轮次 x/3、当前版本和状态徽章;实际项目总控页面挂载 hydrate/审批卡,并将 `project-planning` / 设计组展示名收口。未接 M2 approved-GDD 构建绑定或完整构建按钮。 |
| `M1E` | 端到端与故障注入收口 | `M1D-2` | 第 21 节测试矩阵中跨层场景 |
**2026-08-18 M1D 审查修复快照**:对 `14c00017c..bf2185fba` 做规格对照审查后,修复三条决定链路缺陷并补齐回归。① `decidePlanGdd` 的失败分支原来不 hydrate,命中后端任一 `PLAN_STALE_APPROVAL` 分支后卡片会停在已失效的 pending 身份上、`recoveryPending` 永不翻真导致「重试恢复」入口不渲染,现已按第 18.3 节在失败分支同样重灌(顺序钉死:`hydratePlanGddState` 入口会清空错误,必须先 hydrate 再写决定错误)。② responseId 复用键原为 `approvalRequestId:action`,不含 comment,违反第 13.2 节「改变 action/comment 必须换新 responseId」,现改为比对 `{action, comment}` 完整意图,判据方向为宁可多换不可少换。③ 第 18.2 节「`recoveryPending` 时不允许提交决定」原来只作用于三个触发按钮,已打开的评论弹层仍可提交,现已同门控并保留用户已输入内容。回归位于 `tests/appSurface/plan-gdd.suite.ts`,三条均经变异验证(逆转对应修复即变红);`appSurface.test.ts` 381 passed`agc:typecheck`、ESLint、编码检查通过。其中锁错误回传绝对路径阶段进度轮次差一格条已于同日补修(见 decision-log 同日「M1D 审查修复补充」条);hydrate 身份校验与落盘投影修复的顺序、design 组展示名剩余两处字典两条单列后续,未并入。
**2026-08-18 M1D 审查修复快照**:对 `14c00017c..bf2185fba` 做规格对照审查后,修复三条决定链路缺陷并补齐回归。① `decidePlanGdd` 的失败分支原来不 hydrate,命中后端任一 `PLAN_STALE_APPROVAL` 分支后卡片会停在已失效的 pending 身份上、`recoveryPending` 永不翻真导致「重试恢复」入口不渲染,现已按第 18.3 节在失败分支同样重灌(顺序钉死:`hydratePlanGddState` 入口会清空错误,必须先 hydrate 再写决定错误)。② responseId 复用键原为 `approvalRequestId:action`,不含 comment,违反第 13.2 节「改变 action/comment 必须换新 responseId」,现改为比对 `{action, comment}` 完整意图,判据方向为宁可多换不可少换。③ 第 18.2 节「`recoveryPending` 时不允许提交决定」原来只作用于三个触发按钮,已打开的评论弹层仍可提交,现已同门控并保留用户已输入内容。回归位于 `tests/appSurface/plan-gdd.suite.ts`,三条均经变异验证(逆转对应修复即变红);`appSurface.test.ts` 381 passed`agc:typecheck`、ESLint、编码检查通过。其中锁错误回传绝对路径阶段进度轮次差一格与 design 组展示名收口三条已于同日补修(见 decision-log 同日条);hydrate 身份校验与落盘投影修复的顺序条单列后续,未并入。
**2026-08-14 `M1B-1` 合入验收快照**:已合入实现集中在 `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/planning_storage.rs`,并由 `runtime_protocol.rs` 注册。已具备 `plan-gdd.v1``plan-gdd-index.v1``plan-session.v1``plan.submit_gdd` input 的 strict serde 形状校验、文本/ID/时间/枚举边界、typed serde fingerprint、canonical JSON(重复键、BOM、尾空白、字段顺序)解析、GDD 连续版本链、session `revision + 1` / `previousFingerprint` 链、create-only durable writer、session 原子替换与受限 recovery,以及 `project-planning / agent-delegate / standard / project-supervisor` writer identity。通用 `file.write``file.patch``file.delete``project.patchset` 与 checkpoint restore 对 `.agent/planning/**``game/fast_gdd.md` 只挡写,planning 的 `file.read` / `file.list` 仍可读;M1B-1 合入时没有注册或执行 `plan.submit_gdd`,也没有实现 approval pending、receipt、UI 或构建准入。