Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
12 commits
Select commit Hold shift + click to select a range
6e50476
chore(c2c3): placeholder — 40min wall guard, resume anchor (tickets #…
steponeerror Oct 25, 2026
44e60a4
wip(#202): C1 开工占位——工件名表单源 artifacts.mjs(防超时丢工)
steponeerror Oct 25, 2026
7813d89
#202 C1:工件名表单源 ops/agent/artifacts.mjs+selftest 清单面改单源+双向闭包哨(清单18固定名∪…
steponeerror Oct 25, 2026
86f57d2
#202 C1:gates.mjs 门读面/inputs 声明全改工件名表取值(~45 处裸字符串清零,inputs/reason 字节不…
steponeerror Oct 25, 2026
326fd2f
refactor(#203): C2 月度准入拒跑块收口 budget.mjs admitOrRefuse——双面(agent.mjs r…
steponeerror Oct 25, 2026
48826c9
#202 C1:steps.mjs 写出面/读面全改工件名表取值(~31 处裸字符串清零;DEEP 参数族走 deepArtifactNa…
steponeerror Oct 25, 2026
0e74eab
#202 C1:C1C3-C1-REPORT.md 落 worktree 根(验收门全绿数字+commit 链+自决清单+残余回声面)
steponeerror Oct 25, 2026
f89fd08
refactor(#204): C3 ctx 形状收口 pipeline.mjs ctxShape——mkCtx(校验后新值)与 runR…
steponeerror Oct 25, 2026
41c1141
docs(c2c3): C1C3-C23-REPORT 交卷报告+C1C3 批 CHANGELOG 双语条(C2+C3 面;C1 词条留其…
steponeerror Oct 25, 2026
ef48c7b
merge(#202): C1 工件名表单源(artifacts.mjs)+三层消费面+双向闭包哨
steponeerror Oct 25, 2026
35a658a
merge(#203 #204): C2 月度准入收口 admitOrRefuse + C3 ctxShape 唯一构造点
steponeerror Oct 25, 2026
066120e
docs(#201 伞收口): C1 CHANGELOG 双语条补账(工位未落,merger 移交)+第四写面并入名表(finding-e…
steponeerror Oct 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions C1C3-C1-REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# C1C3-C1-REPORT — 工件名表单源(#202 C1,伞票 #201)

工位:`.worktrees/c1c3-c1`(分支 `feature/c1c3-c1`,基 a7c0f150)。零 push;只动本 worktree。

## 交付物

1. **`ops/agent/artifacts.mjs`(新)** — 轮目录工件名单一真源:
- `ARTIFACTS`(Object.freeze,18 固定名:01-…/02-…×3/03-…×2/04-…/05-deep-verdicts/06-…/07-…×2/08-…×2/09-budget/gates.json/state.json)+ `ARTIFACT_NAMES` 派生名单(禁手抄)
- DEEP 逐假设参数族:`deepArtifactName(slug)` / `deepTranscriptName(slug)` 工厂 + `DEEP_ARTIFACT_RE` / `DEEP_TRANSCRIPT_RE` 匹配面 + `DEEP_TRANSCRIPT_GLOB`(仅 gates inputs 声明标签面)
- 范围注释:retro/<round>.json(opsRoot 级)、breaker.json(opsRoot 级)不在表;磁盘名改值=改磁盘名,须过重放/位等价门
2. **`ops/agent/pipeline/gates.mjs`** — 门读面/inputs 声明/reason 字符串全改 `A.*` 取值(十门 ~45 处裸字符串清零;G_DEEP 巡检 regex 改 `DEEP_TRANSCRIPT_RE`,appendGate 写 gates.json 改 `A.GATES`)。gates.json 落盘 inputs/reason 字节不变。
3. **`ops/agent/pipeline/steps.mjs`** — 写出面/读面全改 `A.*` 取值(31 处;DEEP 族走工厂,`modelItemComplete` 的 `${base}.json`/`${base}-transcript.jsonl` 拼接改工厂两查;ITEMIZE replay 回声跨轮读 `06-itemize-manifest.json` 亦改表值)。
4. **`ops/agent/selftest-pipeline.mjs:177`** — 17 名手抄清单退役,改 `ARTIFACT_NAMES` 遍历 + 双向闭包差集断言(名表外文件必须 ∈ DEEP 参数族;名表加项不更新写出面=红;步面新写工件不入表=红)。

## 验收门(全绿,实测数字)

| 门 | 基线 | 实测 |
|---|---|---|
| selftest-pipeline | 78/0 | **78/0** |
| selftest-t4 | 票面 58/0(集成分支已含 PR3b 增 5) | **63/0**(FAIL=0,零回归) |
| selftest-contract | 18/0 | **18/0** |
| golden(run-golden.mjs) | 9/0 | **9/0** |
| standard-check | 47-48 OK | **OK=47 FAIL=0**(条文14 金标3 建议10 挂点31) |
| pytest ops 子集(`tests/ -k "ops or store"`,cwd=worktree/backend,主仓 venv) | 271 passed | **271 passed / 1 skipped / 0 failed** |
| 罐装面工件集合位等价 | — | 见下 |

**位等价抽验**(驱动 `/tmp/c1-equiv-driver.mjs` = selftest R1 同型罐装 faux 轮,child 真跑 `pipeline.mjs health`,重构前/后各一次):
- 轮目录 23 文件名集合**逐字节同**(18 固定 + 2 假设 × (.json/-transcript.jsonl));20/23 md5 直接全等
- 3 异 = 09-budget.json / gates.json / state.json:差异**仅** generated_at/started_at 时戳、dur_ms、wall_s、驱动 TMP 根路径串(mkdtemp 后缀);gates.json 时戳规范化后逐字节同,budget/state 再 TMP 路径规范化后逐字节同 → 零语义漂移(inputs/reason/读数全同)
- `git diff a7c0f150 -- ops/agent/golden/ ops/agent/fixtures/` 空(cases.json 与 fixtures 逐字节未动)

**闭包哨真红验证**(TDD 红步):名表临时加 `TAMPER_PROBE: "10-c1-tamper.json"` → selftest **FAIL=1**(`工件缺:10-c1-tamper.json`)→ 还原 → 78/0 绿。

## Commit 链

```
44e60a4e wip(#202): C1 开工占位(防超时丢工)
7813d893 #202 C1:工件名表单源 artifacts.mjs + selftest 清单面改单源 + 双向闭包哨(78/0)
86f57d27 #202 C1:gates.mjs 门读面/inputs 声明全改名表取值(~45 处清零,字节不变;78/0)
48826c9c #202 C1:steps.mjs 写出/读面全改名表取值(~31 处清零;DEEP 参数族工厂;78/0)
<本报告 commit>
```

## 自决清单(实现者裁量,均留痕)

1. `DEEP_TRANSCRIPT_GLOB` 补进 artifacts.mjs:gates G_DEEP inputs 里的 `"05-deep-*-transcript.jsonl"` 标签族与工厂/正则同文件单源(标签漂移面收口)。
2. 表键名风格 `PROBE_SUMMARY` 等(值派生自文件名,不带扩展名后缀);`02-verify-rules.json` 入表键 `VERIFY_RULES`。
3. opsRoot 级文件(retro/<round>.json、breaker.json)不入表——非轮目录面,gates 里 retro 标签 `retro/${key}.json` 维持字面量(非 ctx.dir 工件);已在 artifacts.mjs 头注释声明边界。
4. ticket 写 t4 基线 58/0,实测集成分支基线 63/0(PR3b 已加 5 例);以 FAIL=0 + 实测数为准报告。
5. CHANGELOG 双语条:spec 验收门 5 是**整批一条覆盖 C1-C3**,留给伞收口(C2/C3 合入后一次写),不在 C1 单票内提前写半条。
6. pytest 运行法:cwd=worktree/backend(`python -m pytest` 把 cwd 入 sys.path;直接 cwd=worktree 会 `ModuleNotFoundError: No module named 'ipdb'/'main'`——venv 属主仓,无 editable 指向 worktree)。

## 残余回声面(spec 三层措辞之外,未动;闭包哨兜底)

- `ops/agent/pipeline/faux.mjs:37-39` `transcriptName`:3 处 DEEP/SYNTH/TRIAGE transcript 名字面量(faux 面,写出与 steps 同名;哨管磁盘集合,名字漂移会即时红,但字面量本身未单源)。
- `ops/agent/pipeline.mjs` HEALTH_PIPELINE def `out` 数组(~10 处工件名)、SKIP_WHEN 面 `04-dispatch-bundles.json`/`03-triage-hypotheses.json` 字面量、STAGE_PREFIX:spec C1 三层消费面=gates/steps/selftest,pipeline.mjs 定义表面不在票面;若收口建议随 C2/C3 或伞票顺手(等价改法已验证:`import { ARTIFACTS as A } from "./artifacts.mjs"` + `out: [A.X]`)。

## 余项

无阻塞项。C2(budget.mjs admitOrRefuse 提取)/C3(ctxShape 提取)由同批其他实现者承担;本分支 `feature/c1c3-c1` 待任务评审后并入 `feature/c1c3-artifacts-ctx`。
66 changes: 66 additions & 0 deletions C1C3-C23-REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# C1C3-C23-REPORT — C2(#203)+C3(#204) 实现者交卷报告

工位:`.worktrees/c1c3-c2c3`(分支 `feature/c1c3-c2c3`,基 = 集成分支 `feature/c1c3-artifacts-ctx` @ a7c0f150)。零 push。

## 交付 C2(#203):月度准入拒跑块单源化 ✅

**收口前现状**:拒跑块在 `agent.mjs runRound`(legacy 面)与 `pipeline.mjs runPipeline`(管线面)逐字复制——文案/`[admission]` log 行/台账留痕行三件全同(#200 Spec 轴已核),漂移只靠人记。

**落地**(`ops/agent/pipeline/budget.mjs`):
- `export const refusalOf(a)` — 纯文案面,单源产出 `code="budget_monthly"` + 拒跑 message(counted/skipped 读数嵌文)。
- `export async function admitOrRefuse({ledgerFile, capCny, estCny, env, log})` — 留痕外壳:`monthlyAdmission` 读 → 放行返回 `{refused:false, admission}`(读数对象原样回传,`state.monthly_admission`/09-budget.json 观察面字节不变);拒跑则 `[admission] budget_monthly refused month=… spend=… est=… cap=… skipped=…` log + `appendRefusalTrace` 台账行(写败只 log 不翻转裁决,宁拒不跑)→ `{refused:true, ...refusalOf(admission)}`。
- 双面改调用,只映射各自出口:agent.mjs `throw Object.assign(new Error(msg), {code})`(main 兜底信封 exit 1);pipeline.mjs `emitFail(code, message)`(信封 exit 1)。**两面行为/日志/台账行/exit code 逐字不变**。
- 容差口径(spec P2 附注项):`admitMonthly` 上方集中单点注释——精确比较无 ε(`spend+est>cap` 才拒,等号放行);gates.mjs/steps.mjs 轮预算面的 +1e-9 灰尘容差先例不入本面;将来若加月帽 ε,admitMonthly 是唯一合法落点。

**哨**(selftest-pipeline.mjs 新增 1 条,"A2-拒跑块单源"):真台账树(mkTree)断言 message 逐字=收口前文案、logs 逐字=[admission] 行、台账含 `budget_monthly refused est=0.05 cap=0.05`、放行面 `refused:false + admission.spend=0.04` 原样回传+零日志。

**红证**(真红,已录):①未实现期 `admitOrRefuse is not a function` → 78/1;②容差翻转 `<=`→`<` → 恰「A2-纯函数…等号(0.04+0.06=0.10=帽)放行」真红 78/1,还原后绿。

## 交付 C3(#204):ctx 形状单源化 ✅

**收口前现状**:`runResume`(pipeline.mjs ~:435-444)手工重建 ctx,与 `mkCtx`(~:101-125)字段清单两处维护,形状漂移靠人记(终审 smell)。

**落地**(`ops/agent/pipeline.mjs`):
- 新增 `export const ctxShape({type, roundId, opsRoot, env, log, fixturesDir, modelFace, budgetCny, budgetKnobs, breakerKnobs, state})` — ctx 字段清单唯一构造点(模块内函数,择浅):dir 自算 `path.join(opsRoot,"rounds",String(roundId))`、展开 `ctxPaths`(四键含 retroAuditKey)、ledgerFile 公式、`modelCalls:0 / dupRegistry:new Map() / usage:{input:0,output:0,totalTokens:0,cost:0}` 每次新建、state 传引用不克隆。
- `mkCtx` 尾部改 `return ctxShape({...})` — **旋钮校验(budgetCny 非负有限/budgetKnobs/breakerKnobs)全部留在 mkCtx 进 ctxShape 前,不前移不放松**;ctxShape 刻意零校验零补齐。
- `runResume` 改 `const ctx = ctxShape({...})` — 值面 = state 复原 + 缺旋钮补 env 读取(`state.budget_knobs ?? readBudgetKnobs(io.env)`、`state.model_face ?? "faux"` 不变;`budgetCny = state.budget_cny` 不校验不补,旧轮 undefined 原样保持)。前置读 state.json 的局部 dir 保留(ctxShape 自算等值)。runReplay 走 mkCtx 自动获益(未动)。

**哨**(selftest-pipeline.mjs 新增 2 条):
- "C3-ctx 形状单源:ctxShape 闭集键钉死" — 构造后 `Object.keys().sort()` deepEqual 23 键金集(含 ctxPaths 四键 rulesFile/itemsDir/retroFile/retroAuditKey;= gates/steps 两消费面所读闭集);附 dir 自算、usage/dupRegistry/modelCalls 新建、state 引用不克隆断言。
- "C3-ctx 唯一构造点" — 读 pipeline.mjs 源文本,`dupRegistry: new Map()`、`modelCalls: 0`、`usage: { input: 0` 各恰出现 1 次(手抄字段清单回潮=第 2 处出现即红)。

**红证**(真红,已录):临时删 ctxShape 返回体的 `breakerKnobs,` 字段 → 闭集哨真红 80/1,还原后绿。(期间自修一例:哨金键集手写序 "envelope"/"env" 与 JS 字典序相反致哨假红——两侧同 .sort() 修复,属测试自bug非产品面。)

## 验收门(全绿;除注明外均为 C3 完成态实测)

| 门 | 数字 | 判定 |
|---|---|---|
| selftest-pipeline | **81/0**(基线 78/0,+1 C2 哨+2 C3 哨) | ✅ 基线不降 |
| selftest-t4 | **63/0**(任务文 58/0 系旧数;改动前基线实测 63/0,不降) | ✅ |
| selftest-contract | **18/0** | ✅ |
| golden | **9/0**(罐装面 = 验收门④ 位等价抽验:工件集合与文件名不变) | ✅ |
| standard-check | **47 OK**(条文14/金标3/建议10/挂点31/原语22,已有12/半缺7/缺3) | ✅ |
| backend pytest ops 子集 | **271 passed, 1 skipped**(主仓 venv;`-k "ops or store"`) | ✅ |
| legacy smoke | `node agent.mjs` 无参 exit 2;`OPS_PIPELINE_BUDGET_CNY=abc node agent.mjs health x` exit 2 | ✅ 不炸 |

注:上表数字在 C3 代码完成态实测;其后仅改 markdown(CHANGELOG.md、本报告),零代码面重叠,门不受影响。基线对照(改动前,/tmp/c23-baseline.log):pipeline 78/0 · t4 63/0 · contract 18/0 · golden 9/0 · standard-check 47。

## 自决清单

1. CHANGELOG 双语条只写 C2+C3(本工位两票);C1(工件名表)词条留给其工位自落——不代写未验证工作。
2. C2 哨放 selftest-pipeline(A2 系旁,同台账树 fixture 复用);C3 择浅=模块内函数(pipeline.mjs export),未开独立模块。
3. t4 门数字以实测基线 63/0 为准(任务文 58/0 为旧基线,PR3b 后已 63),不降不追旧数。
4. C3 哨金键集手写序初版与 JS 字典序冲突("env"<"envelope")致假红——两侧同 .sort() 收口(哨自身修复,非放松)。

## Commit 链

```
f89fd08b refactor(#204): C3 ctx 形状收口 pipeline.mjs ctxShape——mkCtx/runResume 共用单一形状构造…(门:81/0 等)
326fd2ff refactor(#203): C2 月度准入拒跑块收口 budget.mjs admitOrRefuse——双面文案/log/台账行单源…(门:79/0 等)
6e50476b chore(c2c3): placeholder — 40min wall guard, resume anchor (tickets #203 #204)
```

## 残留风险

- resume 面行为等价靠既有 resume 测试组(三规则+负例)+ 全 faux 轮钉住;旧轮 `state.budget_cny === undefined` 字面路径无专属历史 fixture(行为「不补不校验」由 ctxShape 零校验设计+注释钉死),如需可后续补历史形状 fixture。
- `runModelStage` 的防御补 `ctx.budgetKnobs ??= …` 保留未动(非本次票面)。
Loading
Loading