收口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:
@@ -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 或构建准入。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user