---
phase: 03-dialog-feedback
plan: 03
type: execute
wave: 3
depends_on:
  - "03-01"
  - "03-02"
files_modified:
  - docs/修改记录.md
autonomous: true
requirements:
  - CRED-FE-04
  - CRED-FE-05
must_haves:
  truths:
    - "docs/修改记录.md 顶部存在 [2026-05-08] Phase 3 条目（在 Phase 2 条目之上）"
    - "条目按 CLAUDE.md L72-82 格式包含「文件路径 / 修改类型 / 修改内容 / 修改原因」四段"
    - "条目「修改内容」段明确列出 3 个改动文件（app/layout.tsx + components/ai-model/credential-slot-dialog.tsx + app/ai-model/page.tsx）"
    - "条目「修改原因」段显式说明 access_token 强制输入的权衡 + 候选下一周期 milestone（识别脱敏掩码保留旧值）"
    - "条目「跨项目联动」段写「无 — Phase 3 是前端 UI 收尾，access_token 强制输入语义为 Phase 1+2 已建立的前后端互引（commit 46d72b8）的延续；'留空保留旧值' 语义需后端识别脱敏掩码格式 + 保留旧值，已记入候选下一周期 milestone（不属于 v1.0 范畴）」"
    - "条目「服务端联动」字段同上「跨项目联动」"
    - "Plan 级双重验证（tsc 整体反向断言 + grep 13 条 specifics 全表 + lockfile diff 0 行）全部通过"
  artifacts:
    - path: "docs/修改记录.md"
      provides: "Phase 3 修改记录条目（在 Phase 2 [2026-05-08] 条目上方）"
      contains: "[2026-05-08] Phase 3"
  key_links:
    - from: "docs/修改记录.md Phase 3 条目"
      to: "Phase 2 [2026-05-08] 条目"
      via: "在其上方追加（CLAUDE.md「最新在最前」规则）"
      pattern: "Phase 3.*\\n.*Phase 2"
---

<objective>
Phase 3 收尾 plan：

1. 在 `docs/修改记录.md` 顶部追加 [2026-05-08] Phase 3 条目（在 Phase 2 条目上方），按 CLAUDE.md L72-82 格式 + Phase 2 条目作为同期模板
2. 跑 plan 级双重验证：tsc 反向断言 + 13 条 grep specifics 全表 + lockfile diff 0 行 + lint 跳过沿用 Phase 1+2 判定

**Purpose**：CLAUDE.md L70-94 强制每次代码改动同会话追加修改记录（自动执行），且 Phase 3 引入了一个**业务语义权衡**（access_token 强制输入 vs 「留空保留旧值」），必须显式记入「修改原因」便于未来开后端 patch milestone 时反查。

**Output**：`docs/修改记录.md` 顶部 +1 个完整条目；plan 级整体验证报告。
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-dialog-feedback/03-CONTEXT.md
@.planning/phases/03-dialog-feedback/03-01-SUMMARY.md
@.planning/phases/03-dialog-feedback/03-02-SUMMARY.md
@CLAUDE.md
@docs/修改记录.md
</context>

<tasks>

<task type="auto">
  <name>Task 1：docs/修改记录.md 顶部追加 Phase 3 条目</name>
  <files>docs/修改记录.md</files>
  <read_first>
    必读 `docs/修改记录.md` 头部：
    - L1-22：「修改格式说明」段（4 字段格式：文件路径 / 修改类型 / 修改内容 / 修改原因）
    - L24-26：「修改历史」标题 + 「<!-- 新的修改记录添加在此处下方，最新的在最前面 -->」标记
    - L28-58：上一条 [2026-05-08] Phase 2 条目（**作为格式模板**，特别注意「跨项目联动」与「服务端联动」两段写法）

    确认插入位置：L26（标记注释）之后、L28（Phase 2 条目）之前。
  </read_first>
  <action>
**逐字插入以下条目**到 `docs/修改记录.md` 的 L26 注释 `<!-- 新的修改记录添加在此处下方，最新的在最前面 -->` 之后、L28 `### [2026-05-08] Phase 2（前端）...` 之前。

**完整条目（直接复制粘贴）**：

```markdown
### [2026-05-08] Phase 3（前端）凭据槽位编辑对话框 + 提交反馈

配套服务端 Phase：本 phase **不**触达服务端；与服务端 v1.0 Phase 2「管理端读写接口」commit `46d72b8` 既有契约保持兼容（GET 脱敏掩码 + PUT 全字段覆写语义不变）
覆盖前端需求：CRED-FE-04、CRED-FE-05

- **文件路径**：
  - `app/layout.tsx`（修改）
  - `components/ai-model/credential-slot-dialog.tsx`（新增）
  - `app/ai-model/page.tsx`（修改）
- **修改类型**: 修改 + 新增（前端 UI 收尾；纯前端，无新依赖、不动 lockfile、不触达服务端）
- **修改内容**:
  - `app/layout.tsx`（修复仓库 pre-existing 死代码 bug）：
    - 顶部新增 `import { Toaster } from "@/components/ui/sonner"`
    - `<body>{children}</body>` 内 `{children}` 之后追加 `<Toaster />`
    - 修复仓库内 9 处 `toast(...)` 调用全部静默的 dead-code 状态（`components/ui/sonner.tsx` 早就存在 Toaster 包装但**从未在 RootLayout 挂载**）
  - `components/ai-model/credential-slot-dialog.tsx`（**新建** ~150 行）：
    - 顶部 `"use client"` 指令；具名导出 `CredentialSlotDialog`
    - 文件命名 **kebab-case**（与仓库 9 个现有业务对话框 `user-form-dialog.tsx` / `add-song-dialog.tsx` 等对齐）
    - 表单技术栈：React Hook Form + Zod + shadcn Form wrapper（1:1 模板自 `components/users/user-form-dialog.tsx`）
    - Zod schema：`appId` + `accessToken` 都 `min(1)`（access_token **强制输入**，见「修改原因」段权衡说明）
    - 受控接口：`{ open: boolean; onOpenChange: (open: boolean) => void }`
    - 打开时 `useEffect` 调 `getCredentialSlot()` 拉取 → `form.reset({ appId: data.appId, accessToken: "" })` —— **accessToken 永远默认空串**，绝不回填脱敏掩码
    - `<Input placeholder={slot?.accessTokenMasked} />` —— 仅作视觉提示
    - `<FormDescription>每次保存都需要重新输入 Access Token（不会显示原值，避免回写脱敏掩码）</FormDescription>`
    - `updatedAt` 以 `new Date(slot.updatedAt).toLocaleString("zh-CN")` 中文只读显示
    - 提交成功：`toast.success("凭据槽位已更新", { description: "配置已生效" })` + `handleOpenChange(false)`
    - 提交失败：`toast.error("保存失败", { description: handleApiError(e) })` + 对话框保持打开 + 表单值不丢
    - 关闭时 `form.reset({ appId: "", accessToken: "" })` + `setSlot(null)` —— 避免下次打开残留上次输入
    - useEffect cleanup `cancelled` flag 防止快速开关导致的 race condition
    - **关键 import 决策**（避免仓库内同名 dead code）：
      - `import { toast } from "sonner"` —— **不**走 `@/hooks/use-toast`（Radix Toast 实现，与 Sonner 不通信）
      - `import { handleApiError } from "@/lib/api/error-handler"` —— **不**走 barrel `@/lib/api`（barrel 内有同名重复定义）
  - `app/ai-model/page.tsx`：
    - 删除 L9-15 Dialog 系列命名导入整段（`Dialog / DialogContent / DialogDescription / DialogHeader / DialogTitle`）—— 占位 Dialog 删除后 page 不再直接使用 Dialog primitive
    - 在 lucide-react import 之后新增 `import { CredentialSlotDialog } from "@/components/ai-model/credential-slot-dialog"`
    - 删除 L473-485 占位 Dialog（含 `<DialogTitle>通用凭据槽位</DialogTitle>` + `<DialogDescription>对话框真实内容由 Phase 3 落地</DialogDescription>`）
    - 替换为 `<CredentialSlotDialog open={isCredentialDialogOpen} onOpenChange={setIsCredentialDialogOpen} />`
    - 保留 L1 `"use client"` / L20-25 mounted state + isCredentialDialogOpen state + useEffect 守卫 / L35-43「凭据槽位」Button 入口（含 `mounted && hasPermission("credential-slot")` 守卫）
    - Tabs / TabsContent / Card 等其余内容（L18-471）逐字不动
- **修改原因**:
  - 收尾 Milestone v1.0「通用凭据槽位前端集成」：让授权运营能查看脱敏的当前凭据、安全提交新值，且成功 / 失败两条路径都有清晰的中文 toast 反馈
  - 修复 `app/layout.tsx` 的 pre-existing dead code：仓库 `components/ui/sonner.tsx` 早已存在 Sonner Toaster 包装但**从未挂载到 RootLayout**，导致仓库内 9 处既有 `toast(...)` 调用全部静默；本 phase 顺手修复（否则 Phase 3 反馈不可见）
  - 拆出独立组件 `credential-slot-dialog.tsx` 而非把表单内联进 page.tsx：(a) 与仓库 9 个现有业务对话框抽离风格一致；(b) 让 page.tsx 保持简洁，不掺业务表单状态；(c) 关闭对话框时组件级 form.reset 隔离干净
  - **业务语义权衡（重要 — 候选下一周期 milestone 锚点）**：本 phase Zod schema 把 `accessToken: z.string().min(1)` —— **强制每次重输** access_token，**不实现** ROADMAP success criteria #2 中提到的「留空保留旧值」语义。原因：
    - 后端 PUT 是全字段覆写语义（qy_lty 后端 v1.0 Phase 2 已锁定 commit `46d72b8`）
    - 后端 GET 返回的 access_token 字段是脱敏掩码（末 4 位明文 + 前缀 `*`），前端永远拿不到真值
    - 「留空保留旧值」需后端配合识别 PUT body 中 access_token 的脱敏掩码格式并保留旧值（后端逻辑：`if access_token == mask_token(current.access_token): preserve old`）
    - 该后端识别逻辑不在 Milestone v1.0 范畴，**已记入候选下一周期 milestone**（参见 PROJECT.md / REQUIREMENTS.md 候选清单 + STATE.md 风险段）
    - 当前实现退化为「每次保存都要重输 access_token」—— UX 略差但语义正确（永远不会回写脱敏掩码导致后端清空真实凭据）
  - 沿用 Phase 1 已建立的「`accessTokenMasked` vs `accessToken` 类型层屏障」（前者是脱敏字符串、后者是明文）—— TS 编译期会拦截「把脱敏字符串赋给 accessToken 字段」的 bug 路径
  - Sonner（`components/ui/sonner.tsx`）+ `lib/api/error-handler.ts:handleApiError` 是 CONTEXT D-Toast / D-错误处理 锁定的双依赖；不引入新依赖、不混合 Radix Toast hook、不走 barrel 同名重复定义，避免仓库内 dead code 串扰
- **跨项目联动**: 无 — Phase 3 是前端 UI 收尾，access_token 强制输入语义为 Phase 1+2 已建立的前后端互引（commit `46d72b8`）的延续；'留空保留旧值' 语义需后端识别脱敏掩码格式 + 保留旧值，已记入候选下一周期 milestone（不属于 v1.0 范畴）
- **服务端联动**: 同上「跨项目联动」字段；后端 commit `46d72b8` 已建立互引闭环，本 phase 无需再次互引；未来若启动「识别脱敏掩码保留旧值」的后端 patch milestone，届时双端各写新一轮互引条目

```

**严格约束**：
- 插入位置：在 L26 注释之后、L28 Phase 2 条目之前（CLAUDE.md L72「最新在最前面」规则）
- 不动 L1-22 的「修改格式说明」段
- 不修改 L28 之后已有的任何条目（Phase 2 / Phase 1 / [2026-05-07] 锁定契约）
- 「修改原因」段必须包含「access_token 强制输入」「留空保留旧值」「候选下一周期 milestone」三个关键短语，方便未来 grep 反查
- 「跨项目联动」字段值**逐字使用** CONTEXT.md / 上下文锁定的中文文本（注意标点、引号、破折号 `—`）
- 不引入跨项目互引条目（本 phase 不触达后端）
  </action>
  <verify>
    <automated>
      cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin

      # A 段：条目存在性 + 标题正确
      Select-String -Path 'docs/修改记录.md' -Pattern '### \[2026-05-08\] Phase 3'
      # 期望：1 行命中

      # B 段：插入位置正确（Phase 3 出现在 Phase 2 之上）
      $content = Get-Content 'docs/修改记录.md' -Raw
      $phase3Pos = $content.IndexOf('### [2026-05-08] Phase 3')
      $phase2Pos = $content.IndexOf('### [2026-05-08] Phase 2')
      if ($phase3Pos -ge 0 -and $phase2Pos -ge 0 -and $phase3Pos -lt $phase2Pos) { Write-Host 'OK: Phase 3 在 Phase 2 上方' } else { Write-Host 'FAIL' }
      # 期望：'OK: Phase 3 在 Phase 2 上方'

      # C 段：4 段格式齐全（CLAUDE.md L72-82）
      Select-String -Path 'docs/修改记录.md' -Pattern '^- \*\*文件路径\*\*' | Where-Object { $_.LineNumber -lt 60 }
      # 期望：在 Phase 3 段内（前 60 行）≥1 行命中
      Select-String -Path 'docs/修改记录.md' -Pattern '^- \*\*修改类型\*\*' | Where-Object { $_.LineNumber -lt 60 }
      # 期望：≥1 行命中
      Select-String -Path 'docs/修改记录.md' -Pattern '^- \*\*修改内容\*\*' | Where-Object { $_.LineNumber -lt 60 }
      # 期望：≥1 行命中
      Select-String -Path 'docs/修改记录.md' -Pattern '^- \*\*修改原因\*\*' | Where-Object { $_.LineNumber -lt 60 }
      # 期望：≥1 行命中

      # D 段：3 个改动文件全列
      Select-String -Path 'docs/修改记录.md' -Pattern '`app/layout\.tsx`'
      Select-String -Path 'docs/修改记录.md' -Pattern '`components/ai-model/credential-slot-dialog\.tsx`'
      Select-String -Path 'docs/修改记录.md' -Pattern '`app/ai-model/page\.tsx`.*修改' | Where-Object { $_.LineNumber -lt 80 }

      # E 段：业务权衡关键短语
      Select-String -Path 'docs/修改记录.md' -Pattern '强制每次重输|强制输入'
      # 期望：≥1 行
      Select-String -Path 'docs/修改记录.md' -Pattern '留空保留旧值'
      # 期望：≥1 行
      Select-String -Path 'docs/修改记录.md' -Pattern '候选下一周期 milestone|候选下一周期'
      # 期望：≥1 行
      Select-String -Path 'docs/修改记录.md' -Pattern '识别脱敏掩码'
      # 期望：≥1 行

      # F 段：「跨项目联动」+「服务端联动」字段都在
      Select-String -Path 'docs/修改记录.md' -Pattern '\*\*跨项目联动\*\*' | Where-Object { $_.LineNumber -lt 60 }
      Select-String -Path 'docs/修改记录.md' -Pattern '\*\*服务端联动\*\*' | Where-Object { $_.LineNumber -lt 60 }

      # G 段：CRED-FE-04 + CRED-FE-05 显式列出
      Select-String -Path 'docs/修改记录.md' -Pattern 'CRED-FE-04.*CRED-FE-05|CRED-FE-04、CRED-FE-05'
      # 期望：≥1 行
    </automated>
  </verify>
  <done>
    - `docs/修改记录.md` 顶部存在 `### [2026-05-08] Phase 3` 条目
    - Phase 3 条目位于 Phase 2 条目上方（IndexOf 比较通过）
    - 4 段格式（文件路径 / 修改类型 / 修改内容 / 修改原因）全齐
    - 3 个改动文件（app/layout.tsx / credential-slot-dialog.tsx / app/ai-model/page.tsx）全列
    - 业务权衡关键短语（强制输入 / 留空保留旧值 / 候选下一周期 milestone / 识别脱敏掩码）全部 ≥1 行命中
    - 「跨项目联动」+「服务端联动」字段都在
    - CRED-FE-04 + CRED-FE-05 显式列出
  </done>
</task>

<task type="auto">
  <name>Task 2：Plan 级整体双重验证（沿用 Phase 1+2 模式）</name>
  <files></files>
  <read_first>
    回顾 STATE.md L84-85 Plan 02-02 落地说明，本 task 沿用相同验证模式（A 段 tsc 反向断言 + B 段 14 条 grep 全表 + C 段 4 个 lockfile diff + D 段 lint 跳过判定）。
  </read_first>
  <action>
**执行 4 段验证脚本，逐段记录结果到 SUMMARY.md**：

**A 段：tsc 整体 + 反向断言（必须 0 条指向本 phase 改动文件）**

```powershell
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin

# 整体（含 67 条存量错误，与本 phase 无关）
$tscOutput = npx tsc --noEmit 2>&1
$totalErrors = ($tscOutput | Select-String -Pattern '\.tsx?\(\d+,\d+\):' -AllMatches).Matches.Count
Write-Host "tsc 整体错误总数: $totalErrors（应在 60-70 之间，与 Phase 1+2 持平）"

# 反向断言：本 phase 3 个改动文件应 0 条命中
$tscOutput | Select-String -Pattern 'app/layout\.tsx|app\\layout\.tsx|components/ai-model/credential-slot-dialog\.tsx|components\\ai-model\\credential-slot-dialog\.tsx|app/ai-model/page\.tsx|app\\ai-model\\page\.tsx'
# 期望：无任何输出
```

**B 段：13 条 grep specifics 全表（CONTEXT.md L253-268 表）**

```powershell
# 编号沿用 CONTEXT.md L253-268 表
$file = 'components/ai-model/credential-slot-dialog.tsx'

# spec #1 文件存在 + 导出
Select-String -Path $file -Pattern 'export function CredentialSlotDialog'
# spec #2 RHF + Zod
Select-String -Path $file -Pattern 'useForm'
Select-String -Path $file -Pattern 'zodResolver'
Select-String -Path $file -Pattern 'z\.object'
# spec #3 useEffect 调 getCredentialSlot
Select-String -Path $file -Pattern 'useEffect'
Select-String -Path $file -Pattern 'getCredentialSlot'
# spec #4 反向：accessToken 默认空串、不是 accessTokenMasked
Select-String -Path $file -Pattern 'defaultValues.*accessTokenMasked'
# 期望：0 行
Select-String -Path $file -Pattern "accessToken: \`"\`""
# 期望：≥1 行（"accessToken": ""）
# spec #5 placeholder 用 accessTokenMasked
Select-String -Path $file -Pattern 'placeholder.*accessTokenMasked'
# spec #6 提示文字
Select-String -Path $file -Pattern '每次保存都需要重新输入'
# spec #7 updatedAt 只读显示
Select-String -Path $file -Pattern 'slot\.updatedAt'
# spec #8 submit 调 updateCredentialSlot
Select-String -Path $file -Pattern 'updateCredentialSlot'
# spec #9 toast.success 中文
Select-String -Path $file -Pattern 'toast\.success.*凭据槽位已更新'
# spec #10 handleApiError
Select-String -Path $file -Pattern 'handleApiError'

# spec #11 page.tsx 占位删除 + 替换
Select-String -Path 'app/ai-model/page.tsx' -Pattern 'import \{ CredentialSlotDialog \} from "@/components/ai-model/credential-slot-dialog"'
Select-String -Path 'app/ai-model/page.tsx' -Pattern '<CredentialSlotDialog'
Select-String -Path 'app/ai-model/page.tsx' -Pattern '对话框真实内容由 Phase 3 落地'
# 期望：0 行（已删干净）

# spec #12 tsc 过滤（A 段已覆盖）

# spec #13 修改记录条目（Task 1 已覆盖）

# Layout Toaster 挂载（Plan 03-01 落地）
Select-String -Path 'app/layout.tsx' -Pattern 'from "@/components/ui/sonner"'
Select-String -Path 'app/layout.tsx' -Pattern '<Toaster\s*/>'

# 反向（防回归）：不走 Radix Toast hook + 不走 barrel handleApiError
Select-String -Path $file -Pattern 'from\s+"@/hooks/use-toast"'
# 期望：0 行
Select-String -Path $file -Pattern '^"use client"'
# 期望：1 行（首行）
```

**C 段：4 个 manifest+lockfile 在工作区 + HEAD~3 比较均 0 行 diff**

```powershell
# 工作区 diff（应已被 git add 且 commit 后查 HEAD）
git diff --stat HEAD -- package.json yarn.lock package-lock.json pnpm-lock.yaml
# 期望：0 行

# 跨 Phase 3 三个 plan 的累计 diff（HEAD~3 = 03-01 之前）
# 注意：父仓库 Lila-Server 视角，路径需含子目录前缀
git diff --stat HEAD~3 HEAD -- 'qy-lty-admin/package.json' 'qy-lty-admin/yarn.lock' 'qy-lty-admin/package-lock.json' 'qy-lty-admin/pnpm-lock.yaml'
# 期望：0 行（Phase 3 全程不引入新依赖）
```

**D 段：lint 跳过判定（沿用 Phase 1+2）**

仓库 `package.json` 的 `"lint": "next lint"` 在执行时若无 `.eslintrc*` / `eslint-config-next` 会触发交互式 prompt（非自动通过）；本 phase 沿用 Phase 1 + Phase 2 已建立的判定（参见 STATE.md L83-85）：
- 不主动跑 `npm run lint`
- 在 SUMMARY.md「lint 状态」段写：「无 .eslintrc* / eslint-config-next → next lint 进入 interactive prompt 不可自动判定 → 沿用 Phase 1+2 判定（不阻塞）；ESLint bootstrap 留待候选 #3 milestone」

**记录验证报告**：把 A/B/C/D 四段全部输出 + 解读写到 `.planning/phases/03-dialog-feedback/03-03-SUMMARY.md`「Plan 级双重验证」段。
  </action>
  <verify>
    <automated>
      cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin

      # 整 phase 工作区在 commit 后净状态：本 task 不改任何代码 / lockfile（仅查询验证）
      # 验证 SUMMARY.md 已生成
      Test-Path '.planning/phases/03-dialog-feedback/03-03-SUMMARY.md'
      # 期望：True

      # SUMMARY 内含 4 段标题
      Select-String -Path '.planning/phases/03-dialog-feedback/03-03-SUMMARY.md' -Pattern 'A 段|B 段|C 段|D 段'
      # 期望：4 段都命中
    </automated>
  </verify>
  <done>
    - A 段：tsc 整体错误数 60-70 之间（沿用 67 条存量水位） + 反向断言对 3 个改动文件（layout.tsx / credential-slot-dialog.tsx / page.tsx）输出 0 行
    - B 段：13 条 grep specifics 全表跑过；正向 ≥1 行命中、反向 0 行命中全部满足；Layout Toaster 挂载验证通过
    - C 段：工作区 + HEAD~3 比较均 0 行 lockfile diff
    - D 段：lint 跳过判定文字化记入 SUMMARY
    - SUMMARY.md 已生成并包含 A/B/C/D 段完整报告
  </done>
</task>

</tasks>

<verification>
**Phase 3 整体收尾验证**（本 plan 已涵盖，此处汇总 Milestone v1.0 收尾态）：

1. **修改记录闭环**：CLAUDE.md L70-94 强制规则满足 —— Phase 1 / Phase 2 / Phase 3 三条条目按时间倒序排列在 docs/修改记录.md 顶部
2. **5 条 ROADMAP success criteria 对应**（ROADMAP.md L58-63）：
   - #1 打开自动 GET + appId 明文 + accessToken 掩码 placeholder + updatedAt 只读 ✓ Plan 03-02 Task 1
   - #2 RHF + Zod 校验 + 不回写脱敏掩码（强制输入语义；权衡说明已写入修改记录「修改原因」）✓ Plan 03-02 Task 1 + Plan 03-03 Task 1
   - #3 提交成功 toast.success + 自动关闭 + 重新打开自动 reload ✓ Plan 03-02 Task 1
   - #4 提交失败 handleApiError 映射 + toast.error + 对话框保持 + 表单不丢 ✓ Plan 03-02 Task 1
   - #5 端到端串联（依赖后端 Phase 2，commit 46d72b8 已落地）—— 程序化验证通过；浏览器 E2E 推迟（无 E2E 框架，CONTEXT 已声明）
3. **不引入新依赖**：4 个 lockfile 在 HEAD~3..HEAD 范围 0 行 diff
4. **不破坏 Phase 1+2**：Phase 1 落地的 `lib/api/credential-slot.ts` + `lib/api/index.ts` 未改 / Phase 2 落地的 `lib/permissions.ts` + `app/ai-model/page.tsx` Button 入口与 mounted 守卫未改

**Milestone v1.0 收尾态**：本 plan 完成后，Milestone v1.0「通用凭据槽位前端集成」全部 5 条前端需求（CRED-FE-01~05）100% 交付；后端 v1.0（CRED-01~06）已于 commit 46d72b8 收尾。Milestone 进度 100%（3/3 phase）。
</verification>

<success_criteria>
- [ ] `docs/修改记录.md` 顶部含 [2026-05-08] Phase 3 条目（位于 Phase 2 之上）
- [ ] 条目 4 字段格式齐全 + 3 改动文件全列 + 4 个关键权衡短语全命中
- [ ] 「跨项目联动」+「服务端联动」字段含 CONTEXT 锁定文本
- [ ] CRED-FE-04 + CRED-FE-05 显式列出
- [ ] A 段 tsc 反向断言 0 行（layout.tsx / credential-slot-dialog.tsx / page.tsx）
- [ ] B 段 13 条 grep specifics 全表通过
- [ ] C 段 lockfile 工作区 + HEAD~3 双比较均 0 行 diff
- [ ] D 段 lint 跳过判定文字化记入 SUMMARY
- [ ] `.planning/phases/03-dialog-feedback/03-03-SUMMARY.md` 已生成并含 4 段完整报告
- [ ] Milestone v1.0 5 条 success criteria 全部确认通过（#1-#4 完整 / #5 程序化验证通过 + 浏览器 E2E 已声明推迟）
</success_criteria>

<output>
完成后创建 `.planning/phases/03-dialog-feedback/03-03-SUMMARY.md`，按 `$HOME/.claude/get-shit-done/templates/summary.md` 格式记录：

- 改动文件清单（1 个：docs/修改记录.md）
- 修改记录条目预览（含 4 段 + 跨项目联动 + 服务端联动）
- 「Plan 级双重验证」段：A/B/C/D 四段输出 + 解读
- 「Milestone v1.0 收尾确认」段：5 条 success criteria 状态表
- 「下一步」段：
  - Milestone v1.0 已 100% 交付，可执行 `/gsd-retrospective` 总结本 milestone
  - 候选下一周期 milestone（已记入清单）：
    1. 后端「识别脱敏掩码保留旧值」patch（解锁 ROADMAP success criteria #2 完整语义）
    2. PERM-06 后端独立校验闭环
    3. ESLint bootstrap（候选 #3）
    4. 其他 brownfield 候选优先级
</output>
