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 198e216..a930e7d 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 @@ -702,16 +702,21 @@ Expected: FAIL —— `Failed to resolve import "../internal/domain/auto-source. * 嵌套**两层封顶**:两层(某几颗料 × 该类型的参数字段)是已知业务的上限; * 超出就别 auto —— 退回模型,或者把那一段切出去。 */ -import type { AutoSource } from '@contracts'; +import type { AutoExpr, AutoSource } from '@contracts'; import { evalExpr, rowsAt, type ExprCtx, type Row } from './auto-expr.ts'; export type ExpandedRow = { readonly row: Row; readonly outer?: Row }; /** where 是等值过滤;比值按字符串(台账里数字与文本混着存) */ -function matches(row: Row, where: Readonly> | undefined, ctx: ExprCtx, outer?: Row): boolean { +function matches( + row: Row, + where: Readonly> | undefined, + ctx: ExprCtx, + outer?: Row, +): boolean { if (where === undefined) return true; return Object.entries(where).every(([column, valueExpr]) => { - const want = evalExpr(valueExpr as never, { ...ctx, row, ...(outer === undefined ? {} : { outer }) }); + const want = evalExpr(valueExpr, { ...ctx, row, ...(outer === undefined ? {} : { outer }) }); const got = row[column]; return (got === null || got === undefined ? '' : String(got)) === (want === null || want === undefined ? '' : String(want)); }); @@ -816,11 +821,23 @@ export type AnalyzeGateway = { 以及在该文件顶部的 import 里补上 `AnalyzeGateway`(与 `AgentPort` 同一行 import)。 -> 这一步会让 `apps/api/src/app/wiring/engines.ts` 装配处**类型报错**(少传一个依赖)—— -> 这是对的,Task 5 会补上。为了让本任务能独立跑测,先在 `engines.ts` 里传一个**当场抛错**的占位: -> ```ts -> analyze: { run: () => Promise.reject(new Error('analyze 尚未装配(Task 5)')) }, -> ``` +这一步会让**两个地方**少一个必填属性,两处都要在本任务里补上,否则 `typecheck` 当场红: + +**① 装配层占位**(`apps/api/src/app/wiring/engines.ts`,Task 5 换成真实现): + +```ts +analyze: { run: () => Promise.reject(new Error('analyze 尚未装配(Task 5)')) }, +``` + +**② 测试脚手架的桩**(`apps/api/src/modules/loop-engine/__tests__/turn-runner-acceptance.test.ts`, +在 `const deps: TurnRunnerDeps = {` 里、`agent: { … } as never,` 之后加一行): + +```ts + analyze: { run: async () => ({ object: {} }) } as never, +``` + +补完先跑一遍确认既有用例没被碰坏: +`pnpm exec vitest run apps/api/src/modules/loop-engine/__tests__/turn-runner-acceptance.test.ts` - [ ] **Step 2: 写失败的测试** @@ -2029,7 +2046,10 @@ Expected: 全绿(这一步只是提纯,行为一个字不变) /* 卡发出去了 = 这一步真动过世界 —— 标 worldTouched,自动收步那道门才诚实 */ const touched = markWorldTouched(stateRuntime, current.item); await deps.state.save(taskId, model, parsed, touched); - await showView(taskId, undefined, touched, current.view); + /* 这一步声明了画面才推 —— `showView` 的第二参不可选,没声明就沿用上一帧(与既有行为一致) */ + if (current.view !== undefined && current.view !== '') { + await showView(taskId, current.view, touched, current.view); + } return { runtime: touched, enabled: stateEnabled, navigation: { kind: 'converged' }, status: 'awaiting' }; } if (auto.wrote > 0 || auto.dropped > 0) { @@ -2056,7 +2076,7 @@ Expected: 全绿(这一步只是提纯,行为一个字不变) > 三个你要照该文件既有写法对齐的名字: > - `markWorldTouched` —— 用 `grep -n "worldTouched" apps/api/src/modules/loop-engine/internal/domain/lifecycle.ts` 找那个把项标成「动过世界」的函数;它已存在(`human`/`decide`/`entry` 三条路都在用)。 -> - `showView` —— 该文件里推帧那一段用的函数,签名照它。 +> - `showView` —— 第 559 行定义,签名 `(taskId, template: string, runtime, preferred?)`;**第二参不可选**。 > - `raiseAcceptance` —— 第 1500 行定义,签名 `(taskId, runtime, rationale, fields?)`。 - [ ] **Step 9: 在 `createTurnRunner` 里造出 `autoRunner`** @@ -2079,17 +2099,16 @@ Expected: 全绿(这一步只是提纯,行为一个字不变) import { createAutoRunner } from './auto-runner.ts'; ``` -- [ ] **Step 10: 给 turn-runner 的测试脚手架补 `analyze` 端口** +- [ ] **Step 10: 确认测试脚手架的 `analyze` 桩已经在** -`TurnRunnerDeps` 多了一个依赖,`turn-runner-acceptance.test.ts` 的 `harness()` 要跟上。 -在 `const deps: TurnRunnerDeps = {` 里,`agent: { … } as never,` 之后插入: +Task 4 已经在 `turn-runner-acceptance.test.ts` 的 `const deps: TurnRunnerDeps = {` 里加过这一行: ```ts analyze: { run: async () => ({ object: {} }) } as never, ``` -Run: `pnpm exec vitest run apps/api/src/modules/loop-engine/__tests__/turn-runner-acceptance.test.ts` -Expected: 现有用例全绿(这一步只是补一个没人调的端口) +Run: `grep -n "analyze:" apps/api/src/modules/loop-engine/__tests__/turn-runner-acceptance.test.ts` +Expected: 有这一行。**没有就现在补上** —— 少了它下面的用例连编译都过不去。 - [ ] **Step 11: 写接线的五个失败用例**