sillyspec 3.28.11 → 3.28.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/sillyspec-execute/SKILL.md +222 -223
- package/.claude/skills/sillyspec-plan/SKILL.md +156 -156
- package/.claude/skills/sillyspec-quick/SKILL.md +8 -8
- package/.claude/skills/sillyspec-verify/SKILL.md +87 -91
- package/.husky/pre-commit +4 -0
- package/.husky/pre-push +3 -0
- package/AGENTS.md +1 -1
- package/package.json +1 -1
- package/src/change-risk-profile.js +29 -7
- package/src/commit-guard.js +119 -0
- package/src/config-schema.js +2 -0
- package/src/decision-distill.js +32 -25
- package/src/diagnostic-codes.js +95 -0
- package/src/doctor-diagnostics.js +170 -1
- package/src/fr-index.js +359 -0
- package/src/knowledge-stats.js +99 -2
- package/src/machine-interface.js +37 -0
- package/src/run/archive-distill.js +29 -0
- package/src/run/prompt.js +32 -1
- package/src/run/verify-quality-scan.js +151 -5
- package/src/stage-contract.js +496 -19
- package/src/stage-review-checklist.js +13 -1
- package/src/stages/brainstorm.js +6 -1
- package/src/stages/verify.js +6 -2
- package/src/verify-facts-schema.js +21 -5
- package/src/verify-postcheck.js +86 -2
- package/src/verify-probes.js +1293 -27
package/src/stages/brainstorm.js
CHANGED
|
@@ -531,6 +531,10 @@ created_at: <now-datetime>
|
|
|
531
531
|
- ...
|
|
532
532
|
\`\`\`
|
|
533
533
|
|
|
534
|
+
### 触达域现行 FR(FR 索引注入,2026-09-18-fr-index-l1)
|
|
535
|
+
{FR_INDEX_DIGEST}
|
|
536
|
+
写作纪律(防重复 FR——L1 索引实验的承接数据源):改写/取代上列已有行为 → 对应新 FR 块**必须加承接行**引用全局 id(如 \`承接: FR-core-engine-003\`,多个逗号分隔);全新行为 → 新 FR 块不加承接。承接行在归档时由 CLI 翻旧条目 superseded 并建取代链。
|
|
537
|
+
|
|
534
538
|
### requirements.md 格式要求
|
|
535
539
|
\`\`\`markdown
|
|
536
540
|
---
|
|
@@ -548,11 +552,12 @@ created_at: <now-datetime>
|
|
|
548
552
|
|
|
549
553
|
### FR-01: 需求名称
|
|
550
554
|
覆盖决策:D-001@v1, D-002@v1(如适用)
|
|
555
|
+
承接: FR-<域>-NNN(如适用——改写/取代上列注入清单中的已有行为时必填,全新行为省略本行)
|
|
551
556
|
Given 前提条件
|
|
552
557
|
When 触发动作
|
|
553
558
|
Then 期望结果
|
|
554
559
|
|
|
555
|
-
(每个边界条件独立 GWT
|
|
560
|
+
(每个边界条件独立 GWT 块;场景名行 \`#### 场景:X\` 会被归档索引用作摘要,建议保留)
|
|
556
561
|
|
|
557
562
|
## 非功能需求
|
|
558
563
|
- 兼容性:...
|
package/src/stages/verify.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { REVIEW_CHECKLISTS } from '../stage-review-checklist.js'
|
|
2
|
+
|
|
1
3
|
export const definition = {
|
|
2
4
|
name: 'verify',
|
|
3
5
|
title: '验证确认',
|
|
@@ -194,7 +196,7 @@ export const definition = {
|
|
|
194
196
|
- **误判时的诚实出路(豁免级)**:在 design.md 顶部 frontmatter 加一行 \`risk_level: <真实等级>\`(doc-only / unit-sufficient / contract-required / integration-critical / deployment-critical),CLI 会以声明为准覆盖关键词判级。声明后若是 unit-sufficient 等豁免级,PASS WITH NOTES 不再被强制拦;但结论为 PASS 仍需对应证据。
|
|
195
197
|
- **留痕要求(防逃逸)**:用了显式声明,必须在本报告「变更风险等级」section 写明「risk_level 由 design frontmatter 显式声明 = <等级>(覆盖关键词判级)」+ 一句话理由,让豁免可审计;若有命中被否定语境抑制,同样写明被抑制关键词与理由(抑制可审计,不许用来静默降级)。
|
|
196
198
|
你只需:在 verify-result.md 的「变更风险等级」section 如实记录变更性质;若变更涉及 daemon/backend 跨进程、session/lease/lifecycle 状态机、或部署启动路径,在「Runtime Evidence」section 提供真实集成证据(启动命令、daemon↔backend 调用与日志关键片段、终态断言)。
|
|
197
|
-
-
|
|
199
|
+
- **集成回执须真实执行——commands.smoke 配置后由 CLI 亲跑并机器落盘(source: cli-noai-smoke 标记,亲跑段谎报无效)**,其余形态仍须 agent 实跑后据实填写:CLI 对其余形态只校验**字面存在**(是否含关键词),**不会替你启动 daemon、打真实请求或跑迁移**——它是否名副其实取决于你是否实跑过,不得凭堆关键词通过门控。(测试套件对账另算:commands.test 由 CLI 真实执行,那块谎报无效。)
|
|
198
200
|
|
|
199
201
|
3. **生成 verify-result.md 骨架(勿从零手写)**:先跑 \`sillyspec verify-probes --change <change-name> --init\`——一条命令生成十章节骨架(已存在不覆盖),其中**探针结果章节已机械预填**(探针 1 的 TODO/FIXME 命中清单、探针 3 的测试覆盖、探针 5 的 API 契约对账表、探针 6 的删除对账三态判定),文件落 \`{SPEC_ROOT}/changes/<change-name>/verify-result.md\`(CLI 替换出的**主仓绝对路径**;若当前 cwd 在 worktree 内也绝不落 worktree 副本——CLI 校验读主仓,副本随 worktree 清理蒸发)。你只需把各 \`<!--TODO-->\` 占位替换为语义结论;半语义探针(2 关键词覆盖 / 4 决策追踪)与断言抽查、集成盲区标注由你补在对应 TODO 处
|
|
200
202
|
4. **预填探针段不可篡改或删除**:verify \`--done\` gate 会重跑探针对比 verify-result.md 正文,不符即拦(ERROR);对探针结果有异议只能在预填段旁追加说明,不得改写原文
|
|
@@ -202,12 +204,14 @@ export const definition = {
|
|
|
202
204
|
6. 给出结论:PASS / PASS WITH NOTES / FAIL(受风险门控约束)——**结论只认骨架「结论枚举:」槽行(行首锚定,把 <待填:三选一> 整体替换为枚举值);槽留待填会被 gate 判不过,正文其他位置的 PASS/FAIL 字样不参与判定**
|
|
203
205
|
- **结论想写 PASS 前自查四事实条件(PASS 封顶语义,--done 门禁按 verify-facts.json 实拦)**:①集成实测未跑 ②「## 移交项(结构化)」含 blocking 级行 ③db/**/*.sql 未声明执行(verify-result.md 无「已对目标库执行」声明、回执 command 亦不含该文件)④验收×测试覆盖矩阵含 partial/uncovered 行且移交项零有效行——任一成立即不得写 PASS:改写 PASS WITH NOTES 并在「## 移交项(结构化)」表格如实分行(类型枚举 env-blocked/manual-acceptance/db-script/other)。severity 口径:db-script/env-blocked 恒 blocking;manual-acceptance/other 默认 advisory、须显式标 blocking 才计入封顶;确需把 blocking 降为 advisory 必须附「(降级:<理由>,依据 <file:line 或 D-xxx>)」
|
|
204
206
|
7. **核对 module-impact.md**(若 \`{SPEC_ROOT}/changes/<change>/module-impact.md\` 存在):对照本次实际代码变更(git diff)与 module-impact.md 的模块影响矩阵,发现不一致(漏标受影响模块 / 影响类型错误 / 实际未触碰的模块被误标)则在 verify-result.md 标注。module-impact 由 plan 首版生成、execute 各 Wave 更新,verify 是最后一次核对机会(archive 仅终审不再生成)。这是 advisory 核对(不阻断 verify 完成),但 module-impact 与实际严重背离应记为风险。
|
|
207
|
+
8. **smoke 纪律(local.yaml 配置 commands.smoke 或本变更判级 integration/deployment-critical 时执行以下纪律;本步 prompt 为静态导出,命中条件以文本内嵌说明注入——未命中时本段不适用)**:
|
|
208
|
+
${REVIEW_CHECKLISTS.verify.map((item) => ' - ' + item).join('\n')}
|
|
205
209
|
|
|
206
210
|
### verify-result.md 章节结构(骨架已含,占位替换即可)
|
|
207
211
|
|
|
208
212
|
结论(PASS / PASS WITH NOTES / FAIL)→ 证据账(cannot_verify 任务,槽段)→ 集成验证回执(槽段)→ 任务完成度 → 设计一致性 → 探针结果(已预填)→ 测试结果 → 决策追踪矩阵(\`| 决策 ID | FR | Task | Evidence | 状态 |\`,存在 decisions.md 才留)→ 技术债务 → 变更风险等级 → Runtime Evidence → 代码审查。
|
|
209
213
|
|
|
210
|
-
**「## 集成验证回执」槽行结构**(integration/deployment-critical 变更必填;其余写「无」)双形态二选一(多行 YAML 形态推荐,字段序无关):\n- claim: <一句话>\n command: <命令>\n exit: <0 或非 0>\n log: <日志路径>\n亦认单行管道形态:\`- claim: <一句话> | command: <命令> | exit: <0 或非 0> | log: <日志路径>\`——CLI 一致性校验四条件:log 存在 × mtime 在 verify 窗口内 × 日志尾无失败签名(error/exception/traceback/fatal 行首,剔除「0 errors」类良性行)× exit 0;全绿才算在场证据,字面措辞不再参与判定(v2 起 literals 仅存量回退)。CLI
|
|
214
|
+
**「## 集成验证回执」槽行结构**(integration/deployment-critical 变更必填;其余写「无」)双形态二选一(多行 YAML 形态推荐,字段序无关):\n- claim: <一句话>\n command: <命令>\n exit: <0 或非 0>\n log: <日志路径>\n亦认单行管道形态:\`- claim: <一句话> | command: <命令> | exit: <0 或非 0> | log: <日志路径>\`——CLI 一致性校验四条件:log 存在 × mtime 在 verify 窗口内 × 日志尾无失败签名(error/exception/traceback/fatal 行首,剔除「0 errors」类良性行)× exit 0;全绿才算在场证据,字面措辞不再参与判定(v2 起 literals 仅存量回退)。commands.smoke 配置后由 CLI 亲跑并机器落盘(source: cli-noai-smoke 标记的机器段即其产物);其余形态仍须 agent 实跑后据实填写(CLI 不代跑其余集成进程——回执必须来自你真实执行过的命令)。
|
|
211
215
|
|
|
212
216
|
**Runtime Evidence 行结构**(integration/deployment-critical 必填;按实际触碰的运行时组件写,未涉及的行写「不涉及」勿堆关键词):长驻进程启动命令 / 触碰的服务端点 / 触发核心路径的请求(附关键响应)/ 进程日志关键片段(证明走了新路径)/ 生命周期终态断言(初始态→运行态→终态)/ 失败模式排除(逐条说明为何未触发)。
|
|
213
217
|
|
|
@@ -70,7 +70,10 @@ const RECEIPT_CONT_LINE_RE = /^[ \t]+([A-Za-z_][\w-]*):\s*(.*)$/
|
|
|
70
70
|
* 解析 verify-result.md 的两个受控槽段(D-001@v2 slot-backfill 录入界面)。
|
|
71
71
|
* 占位形态(<待填:三选一> / <待填:0 或非 0>)不含枚举词,行首锚定 + 枚举词双保险 fail-closed。
|
|
72
72
|
* @param {string} mdText verify-result.md 全文(LF 归一由调用方 readFileSync 层负责或此处容错)
|
|
73
|
-
* @returns {{ requiredEvidence: Array<{task,status,exempt:boolean,exemptionReason:string|null,verifiedFiles:string[]}>, runtimeEvidence: Array<{claim,command,exitCode,logPath}>, hasEvidenceSlot: boolean, hasReceiptSlot: boolean }}
|
|
73
|
+
* @returns {{ requiredEvidence: Array<{task,status,exempt:boolean,exemptionReason:string|null,verifiedFiles:string[]}>, runtimeEvidence: Array<{claim,command,exitCode,logPath,source?:string}>, hasEvidenceSlot: boolean, hasReceiptSlot: boolean }}
|
|
74
|
+
* runtimeEvidence[].source(2026-09-17-api-coverage-smoke task-02,additive):单行形态 |/|
|
|
75
|
+
* 尾注 `source: <token>` 或多行 YAML `source:` 字段回填(CLI 机器段标记 cli-noai-smoke 的
|
|
76
|
+
* 解析入口);无标记条目不落键,四字段 fail-closed 语义不动。
|
|
74
77
|
*/
|
|
75
78
|
export function parseEvidenceSlots(mdText) {
|
|
76
79
|
const text = String(mdText || '').replace(/\r\n/g, '\n')
|
|
@@ -128,11 +131,17 @@ export function parseEvidenceSlots(mdText) {
|
|
|
128
131
|
for (let i = 0; i < receiptBody.length; i++) {
|
|
129
132
|
const m = receiptBody[i].match(RECEIPT_LINE_RE)
|
|
130
133
|
if (m) {
|
|
134
|
+
// source 尾注提取(2026-09-17-api-coverage-smoke task-02,additive 第五字段):log 是
|
|
135
|
+
// rest-of-line,行内 |/| 尾注段中认 `source: <token>`(CLI 机器段行尾注形态
|
|
136
|
+
// 「| source: cli-noai-smoke」);首段 log 剥尾注口径零变化,四字段收取不动,无尾注
|
|
137
|
+
// 条目不落 source 键(存量回执零回归)。
|
|
138
|
+
const srcM = m[4].match(/[||]\s*source:\s*([^\s||]+)/)
|
|
131
139
|
runtimeEvidence.push({
|
|
132
140
|
claim: m[1].trim(),
|
|
133
141
|
command: m[2].trim(),
|
|
134
142
|
exitCode: Number(m[3]),
|
|
135
143
|
logPath: m[4].split(/[||]/)[0].trim().replace(/^`|`$/g, ''),
|
|
144
|
+
...(srcM ? { source: srcM[1] } : {}),
|
|
136
145
|
})
|
|
137
146
|
continue
|
|
138
147
|
}
|
|
@@ -155,7 +164,10 @@ export function parseEvidenceSlots(mdText) {
|
|
|
155
164
|
? fields.log.split(/[||]/)[0].trim().replace(/^`|`$/g, '')
|
|
156
165
|
: ''
|
|
157
166
|
if (!claim || !command || !/^\d+$/.test(exit) || !log) continue
|
|
158
|
-
|
|
167
|
+
// source 字段回填(多行 YAML 形态,task-02 additive):fields.source 聚合时已过
|
|
168
|
+
// stripPairedBackticks(同款口径),空值不落键——四字段 fail-closed 收取条件不动。
|
|
169
|
+
const src = typeof fields.source === 'string' ? fields.source.trim() : ''
|
|
170
|
+
runtimeEvidence.push({ claim, command, exitCode: Number(exit), logPath: log, ...(src ? { source: src } : {}) })
|
|
159
171
|
}
|
|
160
172
|
}
|
|
161
173
|
|
|
@@ -190,12 +202,16 @@ export function validateFactsV2(facts) {
|
|
|
190
202
|
errors.push(`requiredEvidence[${item.task}] satisfied 但 verifiedFiles 为空`)
|
|
191
203
|
}
|
|
192
204
|
}
|
|
193
|
-
// PASS
|
|
194
|
-
//
|
|
195
|
-
//
|
|
205
|
+
// PASS 封顶事实面 additive 登记(2026-09-17-pass-cap-semantics task-01 / D-011 故障面;
|
|
206
|
+
// smokeRan 增 2026-09-17-api-coverage-smoke task-03 / FR-02):字段不在场一律不报错
|
|
207
|
+
// (存量 facts 零迁移通过,producer=backfillFactsFromMdAndTests 首次 backfill 产出);
|
|
208
|
+
// 在场才校验类型/枚举。schemaVersion 保持 2。
|
|
196
209
|
if (facts.integrationRan != null && !['ran', 'not-ran'].includes(facts.integrationRan)) {
|
|
197
210
|
errors.push(`integrationRan 非法枚举值:${facts.integrationRan}`)
|
|
198
211
|
}
|
|
212
|
+
if (facts.smokeRan != null && !['ran', 'not-ran', 'not-configured'].includes(facts.smokeRan)) {
|
|
213
|
+
errors.push(`smokeRan 非法枚举值:${facts.smokeRan}`)
|
|
214
|
+
}
|
|
199
215
|
if (facts.dbScriptDeclarations != null
|
|
200
216
|
&& (!Array.isArray(facts.dbScriptDeclarations) || !facts.dbScriptDeclarations.every(x => typeof x === 'string'))) {
|
|
201
217
|
errors.push('dbScriptDeclarations 应为 string[]')
|
package/src/verify-postcheck.js
CHANGED
|
@@ -37,8 +37,10 @@ import { filterDeliverableFiles, classifyToolScaffold } from './worktree-apply.j
|
|
|
37
37
|
import { parseTargetFiles, parseRepo } from './stages/plan-postcheck.js'
|
|
38
38
|
// 探针重跑(P3b task-02 一致性抽查):依赖方向已核实无环——verify-probes 只依赖
|
|
39
39
|
// fs/path/git-helper/change-list/plan-postcheck/contract-matrix/foreign-declared/run-shared,
|
|
40
|
-
//
|
|
41
|
-
|
|
40
|
+
// 不反向依赖本模块,此处直连不引入循环。smoke 机器段一致性(2026-09-17-api-coverage-smoke
|
|
41
|
+
// task-02)复用同向 import:记录读取/态推导/标记扫描解析单点在 verify-probes
|
|
42
|
+
// (readSmokeResultRecord/deriveSmokeSectionState/scanSmokeReceiptSection,与 ensure 注入同源)。
|
|
43
|
+
import { runVerifyProbes, readSmokeResultRecord, deriveSmokeSectionState, scanSmokeReceiptSection } from './verify-probes.js'
|
|
42
44
|
import { parseEvidenceSlots, classifyVerifiedFile } from './verify-facts-schema.js'
|
|
43
45
|
|
|
44
46
|
// 测试命令最长执行时间;超时视为失败(防止 CLI 被挂起的测试卡死)
|
|
@@ -3060,6 +3062,69 @@ export function isStrictChange({ pm, cwd, changeName } = {}) {
|
|
|
3060
3062
|
return createdAt >= IR_STRICT_SINCE
|
|
3061
3063
|
}
|
|
3062
3064
|
|
|
3065
|
+
/**
|
|
3066
|
+
* smoke 回执槽机器段一致性对比(2026-09-17-api-coverage-smoke task-02 / FR-03 / Grill #6 /
|
|
3067
|
+
* R-06):机器段唯一事实源 = .runtime/verify-quality-scan-<change>.json 的 smokeResult 段
|
|
3068
|
+
* (verify-probes ensure 注入的同源记录),md 侧 agent 只可追加段、不可改写/删除机器段。
|
|
3069
|
+
* 时序保障:backfillFactsFromMdAndTests 的 ensure 注入(gates verify 收尾前置 + 二次回填)
|
|
3070
|
+
* 先于本对比(checkProbeConsistency 在 gates 后段),此刻仍不符 = 机器段被改写/删除/冒充。
|
|
3071
|
+
* 对比口径(全 ERROR——数值面防篡改,非环境敏感维度):
|
|
3072
|
+
* - 记录 passed:md 须有标记回执条目(无 = 被删除);每条 command/exit/log 与记录逐字段比对
|
|
3073
|
+
* (trim 后严格相等——ensure 注入原样、解析侧 trim,正常链路恒一致),任一不符 = 被改写;
|
|
3074
|
+
* - 记录 not-configured / not-ran:md 出现标记回执条目 = 冒充(未配置/未绿跑却有绿回执行);
|
|
3075
|
+
* 缺态注释行在场但态与记录不符 = 被改写;
|
|
3076
|
+
* - 无记录:md 出现任何 CLI 标记行(回执条目或缺态注释)= 冒充——标记行唯一合法来源是
|
|
3077
|
+
* ensure,而 ensure 只在有记录时注入。
|
|
3078
|
+
* export 说明(2026-09-17-api-coverage-smoke task-07):供 test/smoke-gate.test.mjs
|
|
3079
|
+
* 直接断言(task-02 偏离①挂账的接线正主——checkProbeConsistency 内部消费不变)。
|
|
3080
|
+
* @param {string} reportText verify-result.md 全文
|
|
3081
|
+
* @param {string} specBase .sillyspec 根
|
|
3082
|
+
* @param {string} changeName 变更名
|
|
3083
|
+
* @returns {{ state: string|null, absentState: string|null, machineCount: number, mismatches: Array<{probe:string,expected:*,actual:*,severity:'error',note:string}> }}
|
|
3084
|
+
*/
|
|
3085
|
+
export function auditSmokeReceiptConsistency(reportText, specBase, changeName) {
|
|
3086
|
+
const smoke = readSmokeResultRecord(specBase, changeName)
|
|
3087
|
+
const state = deriveSmokeSectionState(smoke)
|
|
3088
|
+
const scan = scanSmokeReceiptSection(reportText)
|
|
3089
|
+
const mismatches = []
|
|
3090
|
+
const push = (expected, actual, note) =>
|
|
3091
|
+
mismatches.push({ probe: 'smoke-receipt', expected, actual, severity: 'error', note })
|
|
3092
|
+
const fixHint = '机器段唯一事实源是 .runtime/verify-quality-scan 记录 json 的 smokeResult(R-06),禁止手改——记录已过期则重跑 verify 质量扫描步(sillyspec run verify),CLI 会重新 ensure 机器段'
|
|
3093
|
+
if (!state) {
|
|
3094
|
+
if (scan.machineEntries.length > 0) {
|
|
3095
|
+
push('无 smokeResult 记录(无 CLI 标记行)', `md 回执槽 ${scan.machineEntries.length} 条 source=cli-noai-smoke 标记条目`, `无 quality-scan smokeResult 记录而回执槽出现 CLI 机器段标记行——标记行唯一合法来源是 CLI ensure 注入(ensure 只在有记录时注入),疑似 agent 手写冒充。${fixHint}`)
|
|
3096
|
+
} else if (scan.absentState) {
|
|
3097
|
+
push('无 smokeResult 记录(无 CLI 标记行)', `缺态注释行 ${scan.absentState}`, `无 quality-scan smokeResult 记录而回执槽出现 CLI 缺态标注行——疑似 agent 手写冒充。${fixHint}`)
|
|
3098
|
+
}
|
|
3099
|
+
return { state, absentState: scan.absentState, machineCount: scan.machineEntries.length, mismatches }
|
|
3100
|
+
}
|
|
3101
|
+
if (state === 'passed') {
|
|
3102
|
+
if (scan.machineEntries.length === 0) {
|
|
3103
|
+
push('passed 机器段在场(command/exit/log 实录)', '回执槽无 source=cli-noai-smoke 标记条目', `quality-scan 记录 smokeResult.status='passed' 而回执槽机器段缺失/被删除(ensure 已在 backfill 时点先行注入,此刻仍缺 = 正文被改)。${fixHint}`)
|
|
3104
|
+
}
|
|
3105
|
+
for (const [i, e] of scan.machineEntries.entries()) {
|
|
3106
|
+
const cmdOk = String((smoke && smoke.command) || '').trim() === String(e.command || '').trim()
|
|
3107
|
+
const exitOk = (typeof (smoke && smoke.exitCode) === 'number' ? smoke.exitCode : null)
|
|
3108
|
+
=== (typeof e.exitCode === 'number' ? e.exitCode : null)
|
|
3109
|
+
const logOk = String((smoke && smoke.logPath) || '').trim() === String(e.logPath || '').trim()
|
|
3110
|
+
if (!cmdOk || !exitOk || !logOk) {
|
|
3111
|
+
push(
|
|
3112
|
+
`command=${smoke.command} / exit=${smoke.exitCode} / log=${smoke.logPath}`,
|
|
3113
|
+
`第 ${i + 1} 条标记条目 command=${e.command} / exit=${e.exitCode} / log=${e.logPath}`,
|
|
3114
|
+
`机器段数值与 quality-scan 记录 smokeResult 不符(command/exit/log 任一字段被改写即打回;多出的重复标记条目按同口径逐条比对)。${fixHint}`)
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
} else {
|
|
3118
|
+
if (scan.machineEntries.length > 0) {
|
|
3119
|
+
push(`缺态标注 ${state}(无绿跑机器段)`, `${scan.machineEntries.length} 条 source=cli-noai-smoke 标记回执条目`, `quality-scan 记录为 ${state}(未配置/未绿跑)而回执槽出现 CLI 机器段标记回执行——疑似 agent 手写冒充绿回执(ensure 已按记录态对齐,此刻仍在 = 正文被改)。${fixHint}`)
|
|
3120
|
+
}
|
|
3121
|
+
if (scan.absentState && scan.absentState !== state) {
|
|
3122
|
+
push(`缺态标注 ${state}`, `缺态注释行 ${scan.absentState}`, `缺态注释行态与 quality-scan 记录不符——疑似被改写。${fixHint}`)
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
return { state, absentState: scan.absentState, machineCount: scan.machineEntries.length, mismatches }
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3063
3128
|
export function checkProbeConsistency({ cwd, specBase = null, changeName = null, runtimeRoot = null, strictMode = false }) {
|
|
3064
3129
|
if (!changeName) {
|
|
3065
3130
|
return { status: 'skipped', severity: null, mismatches: [],
|
|
@@ -3190,6 +3255,15 @@ export function checkProbeConsistency({ cwd, specBase = null, changeName = null,
|
|
|
3190
3255
|
note: '守卫不一致实体组数与重跑不符(探针9 聚类/信号比对对 design 清单与 Java 文件形态环境敏感,WARNING 不阻断)——建议重跑 sillyspec verify-probes --change <变更名> --init 刷新预填段' })
|
|
3191
3256
|
}
|
|
3192
3257
|
|
|
3258
|
+
// —— smoke 回执槽机器段一致性(ERROR——2026-09-17-api-coverage-smoke task-02 / FR-03 /
|
|
3259
|
+
// Grill #6 / R-06):现 parseProbePrefillAnchors 只对比探针子节计数、不覆盖回执槽,
|
|
3260
|
+
// 本维度补回执槽机器段防篡改——md 标记条目(source=cli-noai-smoke)command/exit/log
|
|
3261
|
+
// 对 quality-scan 记录 json smokeResult 逐字段比对,agent 改写/删除/冒充 → ERROR 打回
|
|
3262
|
+
// (时序:backfill ensure 已先行注入/态对齐)。解析与记录读取单点在 verify-probes
|
|
3263
|
+
// (auditSmokeReceiptConsistency),与 ensure 注入同源不二算。——
|
|
3264
|
+
const smokeAudit = auditSmokeReceiptConsistency(reportText, sb, changeName)
|
|
3265
|
+
for (const sm of smokeAudit.mismatches) mismatches.push(sm)
|
|
3266
|
+
|
|
3193
3267
|
// —— facts 基线对比(2026-09-08-ir-verify-facts FR-05 / task-05):重跑指标 vs
|
|
3194
3268
|
// verify-facts.json probes 快照(init 时点)。md 锚点对账查「正文没被改」,本维度查
|
|
3195
3269
|
// 「md 被手改对齐新代码后 facts 底稿过期」(P3d 数据源保鲜)。分级沿用现实现口径:
|
|
@@ -3276,13 +3350,23 @@ export function checkProbeConsistency({ cwd, specBase = null, changeName = null,
|
|
|
3276
3350
|
} catch { /* 固化失败不阻断对账 */ }
|
|
3277
3351
|
}
|
|
3278
3352
|
|
|
3353
|
+
// smoke 机器段诊断(additive,factsConsistency 同款先例:状态/条目计数随结果透传,供
|
|
3354
|
+
// gates 侧 envelope 落盘与排查;不参与判定——判定由上方 mismatches 收集完成)
|
|
3355
|
+
const smokeConsistency = {
|
|
3356
|
+
state: smokeAudit.state, absentState: smokeAudit.absentState,
|
|
3357
|
+
machineCount: smokeAudit.machineCount,
|
|
3358
|
+
verdict: smokeAudit.mismatches.length === 0 ? 'match' : 'mismatch',
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3279
3361
|
if (mismatches.length === 0) {
|
|
3280
3362
|
const okResult = finish('ok', null, [], null)
|
|
3281
3363
|
okResult.factsConsistency = factsConsistency
|
|
3364
|
+
okResult.smokeConsistency = smokeConsistency
|
|
3282
3365
|
return okResult
|
|
3283
3366
|
}
|
|
3284
3367
|
const severity = mismatches.some(m => m.severity === 'error') ? 'error' : 'warning'
|
|
3285
3368
|
const mismatchResult = finish('mismatch', severity, mismatches, null)
|
|
3286
3369
|
mismatchResult.factsConsistency = factsConsistency
|
|
3370
|
+
mismatchResult.smokeConsistency = smokeConsistency
|
|
3287
3371
|
return mismatchResult
|
|
3288
3372
|
}
|