From 80e9b01f84d1554021a05be2049962b766f0a478 Mon Sep 17 00:00:00 2001 From: xcs Date: Sat, 29 Aug 2026 04:42:54 +0800 Subject: [PATCH] =?UTF-8?q?docs(plan):=20R8=20=E2=80=94=E2=80=94=20?= =?UTF-8?q?=E5=85=A8=20auto=20=E7=9A=84=E6=AD=A5=E8=A6=81=E8=83=BD?= =?UTF-8?q?=E5=A3=B0=E6=98=8E=E3=80=8C=E6=B2=A1=E6=9C=89=20guide=E3=80=8D,?= =?UTF-8?q?=E5=B9=B6=E8=BF=9B=20Task=209?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 7 的评审挖出来的:manifest.ts 的 guide 是 z.string().min(1)(必填非空), 而全 auto 的步按设计就没有 guide —— 引擎正是按 guide.trim() === '' 分半 auto 与全 auto。 照现在的 schema,第二份计划里四步全 auto 的活动会在装包那一刻被拒。 改成 superRefine:声明了 auto 才允许 guide 为空;没有 auto 的照旧拦 ——「作者忘了写做法」是个老错,那道门要留着。 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet --- ...6-08-29-deterministic-steps-auto-recipe.md | 87 ++++++++++++++++++- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/plans/2026-08-29-deterministic-steps-auto-recipe.md b/docs/superpowers/plans/2026-08-29-deterministic-steps-auto-recipe.md index a930e7d..1966371 100644 --- a/docs/superpowers/plans/2026-08-29-deterministic-steps-auto-recipe.md +++ b/docs/superpowers/plans/2026-08-29-deterministic-steps-auto-recipe.md @@ -2622,6 +2622,86 @@ export function autoRecipeFindings(manifest: ActivityManifest): StaticAuditFindi } ``` +- [ ] **Step 4(R8):让全 auto 的步能声明「没有 guide」** + +**这一条是 Task 7 的评审挖出来的,不在原计划里。** `packages/contracts/src/manifest.ts:122` 现在写着 +`guide: z.string().min(1)` —— 必填且非空。而**全 auto 的步按设计就没有 guide**(引擎按 +`guide.trim() === ''` 分「半 auto」与「全 auto」,见 Task 7 插入的那一段)。照现在的 schema, +第二份计划里四步全 auto 的活动会**在装包那一刻被拒**。 + +先写失败的测试,追加到 `packages/contracts/src/__tests__/auto-recipe.test.ts` 末尾: + +```ts +import { planStepSchema } from '../manifest.ts'; + +describe('全 auto 的步可以没有 guide', () => { + const base = { item: 'S1', guide: '', writes: [], reads: [], tools: [] }; + + it('声明了 auto 就允许 guide 为空 —— 那一步压根不问模型', () => { + const parsed = planStepSchema.safeParse({ + ...base, + auto: { do: [{ kind: 'say', text: '办完了' }] }, + }); + expect(parsed.success).toBe(true); + }); + + it('没有 auto 又不写 guide → 拒 —— 「作者忘了写做法」这个老错照旧要拦', () => { + const parsed = planStepSchema.safeParse(base); + expect(parsed.success).toBe(false); + }); + + it('有 auto 但 guide 写了内容 → 照收(半 auto:确定的先做完,剩下的仍问模型)', () => { + const parsed = planStepSchema.safeParse({ + ...base, + guide: '把结论写实', + auto: { do: [{ kind: 'say', text: 'x' }] }, + }); + expect(parsed.success).toBe(true); + }); +}); +``` + +Run: `pnpm exec vitest run packages/contracts/src/__tests__/auto-recipe.test.ts -t "全 auto"` +Expected: 第一条 FAIL(`guide` 被 `.min(1)` 拒),后两条 PASS。 + +改法:把 `packages/contracts/src/manifest.ts:122` 的 + +```ts + guide: z.string().min(1), +``` + +改成 + +```ts + guide: z.string(), +``` + +并在 `planStepSchema` 的 `});` 之后接一段 `superRefine`(注意:`planStepSchema` 从此是 `ZodEffects`, +不能再 `.extend()` / `.omit()` —— 改之前先 `grep -rn "planStepSchema\." packages apps` 确认没有这类用法): + +```ts + .superRefine((step, ctx) => { + /* + * **全 auto 的步没有 guide 是正常形态**(2026-08-29):引擎按 `guide.trim() === ''` + * 分「半 auto(确定的先做完,剩下的仍问模型)」与「全 auto(这一步一次都不问模型)」。 + * 而 `.min(1)` 让后者压根写不出来 —— 四步全 auto 的活动会在装包那一刻被拒。 + * 非空这条要求仍留给没有 auto 的步:**「作者忘了写做法」是个老错,照旧要拦**。 + */ + if (step.auto === undefined && step.guide.trim() === '') { + ctx.addIssue({ + code: 'custom', + path: ['guide'], + message: '这一步的做法不能为空 —— 只有声明了 auto 配方的步才允许没有 guide', + }); + } + }); +``` + +Run: `pnpm exec vitest run packages/contracts/src/__tests__/auto-recipe.test.ts` +Expected: 全绿。 + +契约变更四步照走:`pnpm api:check --update && git add api-report`。 + - [ ] **Step 4: 挂进 `staticAudit`** 在 `staticAudit(manifest, external)` 函数体里,找到它 `out.push(...loopFindings(manifest))` 那一行(或等价写法), @@ -2631,19 +2711,20 @@ export function autoRecipeFindings(manifest: ActivityManifest): StaticAuditFindi out.push(...autoRecipeFindings(manifest)); ``` -- [ ] **Step 5: 跑测试与全量门禁** +- [ ] **Step 6: 跑测试与全量门禁** Run: ```bash pnpm exec vitest run apps/api/src/modules/activity-registry +pnpm exec vitest run packages/contracts pnpm gates ``` Expected: 全绿。**现有三个活动包(E04 / I01 / W05)必须照装不误** —— 它们没有 `auto`,这一段整个不进。 -- [ ] **Step 6: 提交** +- [ ] **Step 7: 提交** ```bash -git add apps/api/src/modules/activity-registry +git add apps/api/src/modules/activity-registry packages/contracts api-report git commit -m "$(cat <<'EOF' feat(activity-registry): 配方静态审 —— 写错地址在装包那一刻就拒