Keep the mechanism fixture aligned with source-once input

Why: The existing browser fixture parses the trailing source index that the approved source-once layout removes.

Evidence: A zero-paid parser probe matched the old format and rejected the planned inline format; the plan now owns a failing fixture test and adaptation.

Impact: Preserve real HTTP browser coverage without changing product contracts or model acceptance.

Refs: Agent-System-Documents#95; Agent-System-Dev#512
This commit is contained in:
2026-10-13 09:33:43 +00:00
parent 0827b81026
commit 76651f6798
@@ -31,9 +31,9 @@
### Task 1:一次呈现原文和可引用来源(Backend)
**Files:** Modify `modules/backend/internal/runmgr/material_sources.go`、`material.go`、`material_sources_test.go`、`material_test.go`;不改 `modules/core/task_snapshot.go`。
**Files:** Modify `modules/backend/internal/runmgr/material_sources.go`、`material.go`、`material_sources_test.go`、`material_test.go`;update the live-tag, zero-paid mechanism fixture in `modules/backend/internal/server/work_checkpoint_eval_test.go` and its regression in `work_checkpoint_eval_budget_test.go`;不改 `modules/core/task_snapshot.go`。
**Interfaces:** `materialSources(docs, perDoc)` 继续产出唯一授权注册表。给内部 `materialSource` 增加 `Start, End int`(相对于 `strings.TrimSpace(d.PlainText())` 的 byte offset),新增 `annotateProvidedMaterial(d core.ParsedDocument, provided string, sources materialSourceRegistry) string`。`buildMaterialTask` 仅渲染各文档提供的前缀与紧邻的 `sourceId/blockIndex`,删除末尾重复索引;`validate` 原语义不动。
**Interfaces:** `materialSources(docs, perDoc)` 继续产出唯一授权注册表。给内部 `materialSource` 增加 `Start, End int`(相对于 `strings.TrimSpace(d.PlainText())` 的 byte offset),新增 `annotateProvidedMaterial(d core.ParsedDocument, provided string, sources materialSourceRegistry) string`。`buildMaterialTask` 仅渲染各文档提供的前缀与紧邻的 `sourceId/blockIndex`,删除末尾重复索引;`validate` 原语义不动。测试专用 `mechanismCheckpointSources(text string) [][]string` 仍返回正则组 `[full,id,blockIndex,providedLine]`,只适配新内联格式。
- [ ] **Step 1: 在既有测试写 RED。** `material_sources_test.go` 用含重复段落、截断段落、缺 Origin 和表格的文档,断言只对注册表里的块插入 `sourceId=... blockIndex=...`;移除这些标记后,正文与当前 `strings.TrimSpace(d.PlainText())` 的实际提供前缀逐字节相同。`material_test.go` 断言同一个短事实只出现一次、每个可引用标记紧邻其实际块、超长提示仍出现。
@@ -51,8 +51,20 @@
}
}
```
- [ ] **Step 2: 运行 RED。** `cd modules/backend && go test ./internal/runmgr -run 'TestMaterialSourceInlineAnnotations|TestBuildMaterialTaskInlineBudget' -count=1`;期望新增的“一次呈现/标记权限”断言失败,而旧来源 CAS 测试仍可运行。
- [ ] **Step 3: 实现最小改动。** 在 `materialSources` 记录已提供块的 byte 起止;按 `Start` 排序,在原 `provided` 字符串里只插入来源标记,保持所有非标记字节、顺序和截断位置不变;缺 Origin 不赋 ID。`buildMaterialTask` 只构造一次注册表,不再调用末尾的 `prompt()`;`materialRevision` 的 `material-recipe.v7` 更新为 `v8`,旧完成结果不被新输入布局复用。
在 live-tag 夹具新增 `TestMechanismSourceExtractionAfterSourceOnce`:给它 `sourceId=src_... blockIndex=0\n上线六月。验收条件需要补齐`,断言读取到真实 ID、索引和连续原句。当前夹具只接受尾部“引用定位片段:”行,故此测试须先 RED;它不发真实模型请求。
```go
func TestMechanismSourceExtractionAfterSourceOnce(t *testing.T) {
id := "src_" + strings.Repeat("a", 24)
got := mechanismCheckpointSources("sourceId=" + id + " blockIndex=0\n上线六月。验收条件需要补齐")
if len(got) != 1 || got[0][1] != id || got[0][2] != "0" || !strings.Contains(got[0][3], "上线六月") {
t.Fatalf("inline source unavailable to mechanism fixture: %v", got)
}
}
```
- [ ] **Step 2: 运行 RED。** 在 Backend 分别运行 `go test ./internal/runmgr -run 'TestMaterialSourceInlineAnnotations|TestBuildMaterialTaskInlineBudget' -count=1` 和 `go test -tags live ./internal/server -run '^TestMechanismSourceExtractionAfterSourceOnce$' -count=1`;期望新增的“一次呈现/标记权限”和夹具内联读取断言各自失败,而旧来源 CAS 测试仍可运行。
- [ ] **Step 3: 实现最小改动。** 在 `materialSources` 记录已提供块的 byte 起止;按 `Start` 排序,在原 `provided` 字符串里只插入来源标记,保持所有非标记字节、顺序和截断位置不变;缺 Origin 不赋 ID。`buildMaterialTask` 只构造一次注册表,不再调用末尾的 `prompt()`;`materialRevision` 的 `material-recipe.v7` 更新为 `v8`,旧完成结果不被新输入布局复用。同步更新 `evalMechanismStream` 的测试专用 source 提取器,使它读取新内联标记后面的已提供原句;它仍只提交来自可信 ID 和字面引用的假 provider 检查点,不替代真实模型验收。
```go
sources := materialSources(docs, perDoc)
@@ -62,7 +74,7 @@
provided := string([]rune(text)[:take])
b.WriteString(annotateProvidedMaterial(d, provided, sources))
```
- [ ] **Step 4: 验证 GREEN 与权限。** 重跑 Step 2,加 `go test ./internal/runmgr -run 'TestMaterialSourceQuoteRequiresActualProvidedBlock|TestMaterialSourceDuplicateTextDoesNotAuthorizeUnprovidedBlock|TestMaterialInputRevisionIncludesProcessingVersion' -count=1`。用旧 A01 材料在离线诊断中记录新旧输入字符数、sourceId 集合与 hash;只声明实际测得的长度,不推断新模型 token 使用量。
- [ ] **Step 4: 验证 GREEN 与权限。** 重跑 Step 2,加 `go test ./internal/runmgr -run 'TestMaterialSourceQuoteRequiresActualProvidedBlock|TestMaterialSourceDuplicateTextDoesNotAuthorizeUnprovidedBlock|TestMaterialInputRevisionIncludesProcessingVersion' -count=1`,以及 `go test -tags live ./internal/server -run '^TestMechanismSourceExtractionAfterSourceOnce$' -count=1`。用旧 A01 材料在离线诊断中记录新旧输入字符数、sourceId 集合与 hash;只声明实际测得的长度,不推断新模型 token 使用量。
- [ ] **Step 5: 自审并提交 Backend 独立提交。** 检查 `git diff --check`、新增 ID 与注册表一一对应、没有未提供文本或权限放宽;按本仓 `Why/Evidence/Impact/Refs` 提交。此项可被独立退回而不影响 Task 2 的审批防误判实现。
### Task 2:检查点审批断言守卫(Backend)