sillyspec 3.29.4 → 3.31.0
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-auto/SKILL.md +1 -1
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +2 -2
- package/.claude/skills/sillyspec-commit/SKILL.md +1 -1
- package/.claude/skills/sillyspec-flow/SKILL.md +57 -0
- package/.claude/skills/sillyspec-quick/SKILL.md +7 -105
- package/AGENTS.md +38 -20
- package/SKILL.md +9 -3
- package/assets/command-cards/flow.md +32 -0
- package/assets/command-cards/run-archive.md +26 -0
- package/assets/command-cards/run-brainstorm.md +33 -0
- package/assets/command-cards/run-execute.md +29 -0
- package/assets/command-cards/run-plan.md +27 -0
- package/assets/command-cards/run-quick.md +17 -0
- package/assets/command-cards/run-verify.md +29 -0
- package/assets/command-cards/status.md +27 -0
- package/package.json +2 -1
- package/packages/dashboard/server/executor.js +2 -1
- package/packages/dashboard/server/parser.js +7 -7
- package/r7-test-env/README-R7-TEST.md +93 -0
- package/r7-test-env/demo-project/lib/calc.js +6 -0
- package/r7-test-env/demo-project/package.json +1 -0
- package/r7-test-env/demo-project/test.js +10 -0
- package/r7-test-env/prompt-R7-SMOKE.md +41 -0
- package/r7-test-env/sillyspec-r7.cmd +3 -0
- package/round4/account.mjs +98 -0
- package/round4/b1-analyze-task08.mjs +40 -0
- package/round4/b1-b1-target-validation.md +32 -0
- package/round4/b3a-prompt-audit-result.md +66 -0
- package/round4/b3a-prompt-audit.mjs +89 -0
- package/round4/brief-autocompact.md +34 -0
- package/round4/brief-session-replay.md +50 -0
- package/round4/deep-read-synthesis.md +38 -0
- package/round4/extract-full.mjs +38 -0
- package/round4/extract-timeline.mjs +43 -0
- package/round4/find-sessions.mjs +13 -0
- package/round4/full-r4-l.md +4707 -0
- package/round4/full-r4-o-l.md +4300 -0
- package/round4/full-r4-os.md +1681 -0
- package/round4/full-r4-sf.md +4255 -0
- package/round4/full-r4-sq.md +1734 -0
- package/round4/gate-audit-relay-receipt.md +30 -0
- package/round4/gate-value-audit.md +52 -0
- package/round4/optimization-plan.md +165 -0
- package/round4/prereg.md +67 -0
- package/round4/prompt-R4-L.md +63 -0
- package/round4/prompt-R4-O-L.md +59 -0
- package/round4/prompt-R4-O-S.md +56 -0
- package/round4/prompt-R4-S-F.md +60 -0
- package/round4/prompt-R4-S-Q.md +66 -0
- package/round4/r4-final-report.html +347 -0
- package/round4/r4-os-timeline.txt +297 -0
- package/round4/r4-sf-timeline.txt +738 -0
- package/round4/r4-sq-timeline.txt +322 -0
- package/round4/r4l-timeline.txt +793 -0
- package/round4/r4ol-timeline.txt +729 -0
- package/round4/r4sf-timeline.txt +852 -0
- package/round4/r5-scenario-matrix.md +46 -0
- package/round4/result-S.md +171 -0
- package/round4/result-final.md +46 -0
- package/round4/result-quality.md +63 -0
- package/src/change-list.js +9 -0
- package/src/classify-change.js +6 -0
- package/src/command-cards.js +74 -0
- package/src/commit-guard.js +2 -0
- package/src/config-schema.js +64 -12
- package/src/contract-matrix.js +26 -5
- package/src/db.js +35 -4
- package/src/decision-distill.js +9 -3
- package/src/diagnostic-codes.js +2 -1
- package/src/docs-check.js +1 -1
- package/src/doctor-diagnostics.js +44 -2
- package/src/flow-draft.js +748 -0
- package/src/flow-parity.js +236 -0
- package/src/flow-review.js +184 -0
- package/src/flow.js +1492 -0
- package/src/foreign-declared.js +17 -1
- package/src/fr-index.js +396 -22
- package/src/fs-atomic.js +5 -1
- package/src/git-helper.js +2 -2
- package/src/greenfield-bootstrap.js +98 -0
- package/src/handoff.js +120 -7
- package/src/hunk-attribution.js +191 -0
- package/src/index.js +602 -21
- package/src/init.js +25 -8
- package/src/knowledge-classify.js +47 -1
- package/src/knowledge-digest.js +162 -0
- package/src/knowledge-quicklog.js +246 -0
- package/src/machine-draft.js +128 -0
- package/src/machine-interface.js +194 -7
- package/src/mcp-server.js +1 -0
- package/src/module-impact.js +51 -22
- package/src/module-resolve.js +3 -1
- package/src/preview-progress.js +160 -0
- package/src/progress/change-registry.js +11 -3
- package/src/progress/shared.js +3 -2
- package/src/progress.js +56 -13
- package/src/quicklog.js +44 -6
- package/src/redomain.js +147 -0
- package/src/review-material-pack.js +204 -1
- package/src/run/archive-distill.js +4 -2
- package/src/run/bg-sync.js +67 -0
- package/src/run/command.js +127 -10
- package/src/run/complete-handlers.js +363 -73
- package/src/run/complete.js +356 -74
- package/src/run/gate-snapshot-ledger.js +213 -0
- package/src/run/gate-snapshot.js +260 -38
- package/src/run/gates.js +482 -268
- package/src/run/green-cache.js +123 -0
- package/src/run/junction-rm.js +70 -0
- package/src/run/next.js +14 -0
- package/src/run/prompt.js +185 -55
- package/src/run/quick-audit.js +213 -14
- package/src/run/shared.js +123 -4
- package/src/run/stage.js +182 -216
- package/src/run/test-ledger.js +264 -0
- package/src/run/verify-quality-scan.js +84 -7
- package/src/scope-audit.js +6 -1
- package/src/sentinel-assertions.js +114 -0
- package/src/setup.js +3 -3
- package/src/spec-sync.js +41 -1
- package/src/stage-contract.js +26 -8
- package/src/stage-review-checklist.js +2 -0
- package/src/stage-review.js +7 -2
- package/src/stage-templates.js +157 -0
- package/src/stages/archive.js +2 -0
- package/src/stages/brainstorm.js +24 -106
- package/src/stages/execute.js +222 -85
- package/src/stages/knowledge.js +74 -1
- package/src/stages/plan-postcheck.js +385 -20
- package/src/stages/plan.js +23 -1
- package/src/stages/quick.js +10 -2
- package/src/stages/verify.js +4 -2
- package/src/sync.js +81 -23
- package/src/task-done.js +181 -0
- package/src/task-review.js +8 -55
- package/src/taskcard-frontmatter.js +57 -0
- package/src/test-bindings.js +549 -0
- package/src/timeline.js +218 -0
- package/src/ui-visual.js +175 -0
- package/src/verify-draft.js +214 -0
- package/src/verify-postcheck.js +919 -159
- package/src/verify-probes.js +103 -25
- package/src/watcher.js +1031 -0
- package/src/worktree-apply.js +44 -4
- package/src/worktree-deps.js +22 -8
- package/src/worktree-policy.js +42 -0
- package/src/worktree.js +102 -15
- package/templates/agents-instruction.md +37 -18
package/src/verify-probes.js
CHANGED
|
@@ -26,16 +26,18 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from 'fs'
|
|
28
28
|
import { join, dirname, basename, resolve, isAbsolute, relative } from 'path'
|
|
29
|
-
import jsYaml from 'js-yaml'
|
|
30
29
|
import { gitQuiet, unquoteGitPath } from './git-helper.js'
|
|
31
30
|
import { hasUnconfirmedPrefill } from './prefill.js'
|
|
31
|
+
import { runUiVisualProbe, renderUiVisualProbeLines, readUiVisualGate } from './ui-visual.js'
|
|
32
32
|
import {
|
|
33
33
|
FACTS_SCHEMA_VERSION, EVIDENCE_SLOT_HEADING, RECEIPT_SLOT_HEADING, parseEvidenceSlots,
|
|
34
34
|
} from './verify-facts-schema.js'
|
|
35
35
|
import { parseFileChangeListDetailed } from './change-list.js'
|
|
36
36
|
import { parseDecisions } from './decision-distill.js'
|
|
37
|
+
import { writeChangeTrace, orphanAccRef } from './test-bindings.js'
|
|
37
38
|
import { parseAllowedPaths, parseRepo, parseRepoRegistry } from './stages/plan-postcheck.js'
|
|
38
39
|
import { verifyApiParity, _readWorktreeMeta } from './contract-matrix.js'
|
|
40
|
+
import { parseTaskFrontmatter } from './taskcard-frontmatter.js'
|
|
39
41
|
import { RECEIPT_SOURCE_CROSS_LAYER_RE as RECEIPT_CROSS_LAYER_RE, RECEIPT_SOURCE_UNIT_RE as RECEIPT_UNIT_RE, CLI_SMOKE_SOURCE_MARK as SMOKE_RECEIPT_SOURCE_MARK } from './change-risk-profile.js'
|
|
40
42
|
import { splitOwnVsForeignDiffFiles } from './foreign-declared.js'
|
|
41
43
|
import { resolveSpecDir, resolveRuntimeRoot, detectWorktreeSpecDrift } from './run/shared.js'
|
|
@@ -1073,7 +1075,7 @@ function designHasSubmitEndpoint(text) {
|
|
|
1073
1075
|
// sectionHint(命中的接口段头列表,审计注记)。
|
|
1074
1076
|
// 落盘面(数据通道=落盘即消费,stage-contract 零 import 纪律):backfillFactsFromMdAndTests
|
|
1075
1077
|
// 主路径写 facts.apiFace / facts.consumerHints,task-05 validator 经 facts 消费不经函数调用。
|
|
1076
|
-
const API_FACE_SECTION_RE =
|
|
1078
|
+
const API_FACE_SECTION_RE = /接口|端点|\bapi\b|\brest\b/i // quick-B 词边界:OpenAPI 标题(api 前邻字母)不再误收进 sectionHint
|
|
1077
1079
|
const API_FACE_METHOD_RE = /(?:^|[^A-Za-z])(GET|POST|PUT|DELETE|PATCH)(?![A-Za-z])/
|
|
1078
1080
|
// 路径样式 token:/ 起始、前邻非字母数字(日期 2026/09/17 的 /09 前是数字段不认),
|
|
1079
1081
|
// 首字符字母数字/_/-/{,后续段字符含 {}/: 模板形态(/orders/{id}、/orders/:id 全串命中)
|
|
@@ -1713,26 +1715,34 @@ const PROBE7_NONTESTABLE_RE = /文档|部署|doc|deploy|manual|config/i
|
|
|
1713
1715
|
|
|
1714
1716
|
/**
|
|
1715
1717
|
* 解析 task-NN.md frontmatter 的 acceptance(string/array 双形态归一为数组)。
|
|
1716
|
-
*
|
|
1717
|
-
*
|
|
1718
|
+
* 解析归一 taskcard-frontmatter.js 单一源(2026-09-20-taskcard-yaml-hardgate:此前坏 YAML
|
|
1719
|
+
* catch 返回 [] 冒充「无 acceptance」,探针 7 渲染假防御文案)——status 三态让调用方区分
|
|
1720
|
+
* 「真无 acceptance」与「frontmatter 非法 YAML」。口径锚 src/stages/plan-postcheck.js
|
|
1721
|
+
* acceptance best-effort 段(string → 原文单条、array → 逐条)。
|
|
1718
1722
|
* @param {string} content task 卡全文
|
|
1719
|
-
* @returns {
|
|
1720
|
-
*
|
|
1723
|
+
* @returns {{ status: 'no-frontmatter'|'invalid-yaml'|'ok', acceptance: string[],
|
|
1724
|
+
* error: {message: string, line: number, column: number}|null }}
|
|
1725
|
+
* no-frontmatter = 无 frontmatter(调用方跳过该卡);invalid-yaml = frontmatter 非法 YAML
|
|
1726
|
+
* (acceptance 不可读,error 带文件 1 基行:列);ok = 合法解析,acceptance 归一数组
|
|
1727
|
+
* (frontmatter 在场但无 acceptance → [],此时防御行为真——plan-postcheck 已拦缺失)
|
|
1721
1728
|
*/
|
|
1722
1729
|
export function parseTaskAcceptance(content) {
|
|
1723
|
-
const
|
|
1724
|
-
if (!
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1730
|
+
const parsed = parseTaskFrontmatter(content)
|
|
1731
|
+
if (!parsed.hasFrontmatter) return { status: 'no-frontmatter', acceptance: [], error: null }
|
|
1732
|
+
if (!parsed.ok) return { status: 'invalid-yaml', acceptance: [], error: parsed.error }
|
|
1733
|
+
const fmObj = parsed.fm || {}
|
|
1734
|
+
if (typeof fmObj.acceptance === 'string') {
|
|
1735
|
+
const t = fmObj.acceptance.trim()
|
|
1736
|
+
return { status: 'ok', acceptance: t ? [t] : [], error: null }
|
|
1737
|
+
}
|
|
1738
|
+
if (Array.isArray(fmObj.acceptance)) {
|
|
1739
|
+
return {
|
|
1740
|
+
status: 'ok',
|
|
1741
|
+
acceptance: fmObj.acceptance.filter(x => typeof x === 'string' && x.trim() !== '').map(x => x.trim()),
|
|
1742
|
+
error: null,
|
|
1733
1743
|
}
|
|
1734
|
-
}
|
|
1735
|
-
return []
|
|
1744
|
+
}
|
|
1745
|
+
return { status: 'ok', acceptance: [], error: null }
|
|
1736
1746
|
}
|
|
1737
1747
|
|
|
1738
1748
|
/**
|
|
@@ -1939,6 +1949,12 @@ function renderProbe7Lines(p7) {
|
|
|
1939
1949
|
for (const t of (p7.tasks || [])) {
|
|
1940
1950
|
L.push('')
|
|
1941
1951
|
L.push(`**${t.task}**`)
|
|
1952
|
+
if (t.fmError) {
|
|
1953
|
+
// 坏 YAML 如实陈述(2026-09-20-taskcard-yaml-hardgate):非「无 acceptance」防御——
|
|
1954
|
+
// plan 门禁 0b 硬校验应已拦截;已过 plan 门仍见此行 = 门禁失效信号(可反馈工具缺陷)
|
|
1955
|
+
L.push(`- ⚠️ frontmatter 非法 YAML(${t.task}.md:${t.fmError.line}:${t.fmError.column} ${mdEscapeCell(t.fmError.message, 160)})——acceptance 不可读,本行非「无 acceptance」防御;plan 门禁 frontmatter 硬校验应已拦截,若已过 plan 门仍见此行即门禁失效信号`)
|
|
1956
|
+
continue
|
|
1957
|
+
}
|
|
1942
1958
|
if (!Array.isArray(t.acceptance) || t.acceptance.length === 0) {
|
|
1943
1959
|
L.push('- (卡无 acceptance——防御,plan-postcheck 已拦)')
|
|
1944
1960
|
continue
|
|
@@ -2138,10 +2154,17 @@ export function runVerifyProbes({ cwd, changeName, specDir = null }) {
|
|
|
2138
2154
|
try {
|
|
2139
2155
|
for (const f of readdirSync(tasksDir).filter(n => /^task-\d+\.md$/.test(n)).sort()) {
|
|
2140
2156
|
const raw = readFileSync(join(tasksDir, f), 'utf8')
|
|
2141
|
-
|
|
2142
|
-
|
|
2157
|
+
// 三态分流(2026-09-20-taskcard-yaml-hardgate):no-frontmatter 跳卡(原 null 语义);
|
|
2158
|
+
// invalid-yaml 挂 fmError 进条目——渲染层区分「坏 YAML」与「真无 acceptance」防御行
|
|
2159
|
+
const parsed = parseTaskAcceptance(raw)
|
|
2160
|
+
if (parsed.status === 'no-frontmatter') continue // 无 frontmatter → 跳过(plan-postcheck 已拦)
|
|
2143
2161
|
const fmId = (raw.match(/^id:\s*(\S+)/m) || [])[1]
|
|
2144
|
-
cards.push({
|
|
2162
|
+
cards.push({
|
|
2163
|
+
task: fmId || f.replace(/\.md$/, ''),
|
|
2164
|
+
acceptance: parsed.acceptance,
|
|
2165
|
+
fmError: parsed.status === 'invalid-yaml' ? parsed.error : null,
|
|
2166
|
+
raw,
|
|
2167
|
+
})
|
|
2145
2168
|
}
|
|
2146
2169
|
} catch { /* tasks 目录不可读 → applicable 维持 false */ }
|
|
2147
2170
|
probe7.applicable = cards.length > 0
|
|
@@ -2196,10 +2219,41 @@ export function runVerifyProbes({ cwd, changeName, specDir = null }) {
|
|
|
2196
2219
|
probe7.tasks.push({
|
|
2197
2220
|
task: card.task,
|
|
2198
2221
|
acceptance: card.acceptance,
|
|
2222
|
+
fmError: card.fmError || null,
|
|
2199
2223
|
testFiles,
|
|
2200
2224
|
hints: buildAcceptanceHints(card.acceptance, testFiles, cwd, wtRoot, probe7CrossRoots),
|
|
2201
2225
|
})
|
|
2202
2226
|
}
|
|
2227
|
+
// ── trace 落盘(2026-09-24-fr-test-bindings task-03,fr-test-binding 写侧):矩阵归属
|
|
2228
|
+
// 行→candidate(requirement_ids join→局部 FR 锚;无锚→orphan 指纹 row_id,D-005)。
|
|
2229
|
+
// 预填≠确认(discovery=machine/confirmed_by=null);fail-open:落盘异常不炸探针。──
|
|
2230
|
+
try {
|
|
2231
|
+
if (probe7.applicable && changeName) {
|
|
2232
|
+
const traceRows = []
|
|
2233
|
+
for (const t of probe7.tasks) {
|
|
2234
|
+
if (!Array.isArray(t.testFiles) || t.testFiles.length === 0) continue
|
|
2235
|
+
const card = cards.find(c => c.task === t.task)
|
|
2236
|
+
const reqIds = ((String(card && card.raw || '').match(/^requirement_ids:\s*\[([^\]]*)\]/m) || [])[1] || '')
|
|
2237
|
+
.split(',').map(x => x.trim().replace(/['"]/g, '')).filter(Boolean)
|
|
2238
|
+
;(t.acceptance || []).forEach((item, i) => {
|
|
2239
|
+
traceRows.push({
|
|
2240
|
+
anchor: reqIds[0] || null,
|
|
2241
|
+
row_id: changeName + ':' + t.task + ':' + orphanAccRef(i, String(item)),
|
|
2242
|
+
tests: t.testFiles,
|
|
2243
|
+
reason: 'spec',
|
|
2244
|
+
state: 'candidate',
|
|
2245
|
+
discovery: 'machine',
|
|
2246
|
+
confirmed_by: null,
|
|
2247
|
+
source_change: changeName,
|
|
2248
|
+
})
|
|
2249
|
+
})
|
|
2250
|
+
}
|
|
2251
|
+
if (traceRows.length > 0) {
|
|
2252
|
+
const w = writeChangeTrace(join(specBase, 'changes', changeName), changeName, traceRows)
|
|
2253
|
+
if (w.changed) console.log('🔗 探针 7 绑定候选落盘:' + traceRows.length + ' 行 → ' + w.path)
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
} catch { /* trace 落盘 fail-open(探针行为不变,下次构建重试) */ }
|
|
2203
2257
|
}
|
|
2204
2258
|
}
|
|
2205
2259
|
|
|
@@ -2243,6 +2297,16 @@ export function runVerifyProbes({ cwd, changeName, specDir = null }) {
|
|
|
2243
2297
|
probe11.warnings = [`探针 11 执行失败(fail-soft 跳过):${e && e.message ? e.message : e}`]
|
|
2244
2298
|
}
|
|
2245
2299
|
|
|
2300
|
+
// ── 探针 12:UI 视觉证据(分级门;2026-09-27-ui-visual-guidance——过程引导的收口对账面:
|
|
2301
|
+
// 只验证据在场不产新证据;缺证据默认 ⚠️,ui_visual_gate=error 升阻断;视觉降级无用户
|
|
2302
|
+
// 裁决留痕恒 error(堵 D-004 型静默降级)。fail-soft 同 8-11。──
|
|
2303
|
+
let probe12 = { applicable: false, uiTouched: false, level: 'ok', notes: [] }
|
|
2304
|
+
try {
|
|
2305
|
+
probe12 = runUiVisualProbe({ changeDir: join(specBase, 'changes', changeName), gate: readUiVisualGate(specBase) })
|
|
2306
|
+
} catch (e) {
|
|
2307
|
+
probe12.notes = [`探针 12 执行失败(fail-soft 跳过):${e && e.message ? e.message : e}`]
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2246
2310
|
// ── 接口面 + 消费端归类(task-04 / FR-05 / D-005~D-007):design.md 接口段 tolerant
|
|
2247
2311
|
// 解析 + 清单消费端归类——骨架「## 接口验证覆盖矩阵」段预填与 facts 落盘
|
|
2248
2312
|
// (backfillFactsFromMdAndTests)共用同一解析器(单一产物源,不各读各的)。fail-soft:
|
|
@@ -2256,7 +2320,7 @@ export function runVerifyProbes({ cwd, changeName, specDir = null }) {
|
|
|
2256
2320
|
}
|
|
2257
2321
|
} catch { /* design 读/解析异常 → 空面(fail-soft) */ }
|
|
2258
2322
|
|
|
2259
|
-
return { probe1, probe3, probe5, probe6, probe7, probe8, probe9, probe10, apiFace, consumerHints }
|
|
2323
|
+
return { probe1, probe3, probe5, probe6, probe7, probe8, probe9, probe10, probe12, apiFace, consumerHints }
|
|
2260
2324
|
}
|
|
2261
2325
|
|
|
2262
2326
|
/**
|
|
@@ -2368,6 +2432,8 @@ export function renderVerifyProbesReport(result) {
|
|
|
2368
2432
|
L.push(...(renderProbe10Lines(result.probe10 || { applicable: false, checkedFiles: 0, unclearedFiles: [], notes: [] })))
|
|
2369
2433
|
// 探针 11 紧随 10;旧 result 无 probe11 键 → 不适用兜底(8/9/10 同款零回归口径)。
|
|
2370
2434
|
L.push(...(renderProbe11Lines(result.probe11 || { applicable: false, entryCount: 0, findings: [], warnings: [] })))
|
|
2435
|
+
// 探针 12 紧随 11(UI 视觉证据分级门);旧 result 无 probe12 键 → 不适用兜底零回归。
|
|
2436
|
+
L.push(...(renderUiVisualProbeLines(result.probe12 || { applicable: false, notes: [] })))
|
|
2371
2437
|
return L.join('\n')
|
|
2372
2438
|
}
|
|
2373
2439
|
|
|
@@ -2565,10 +2631,15 @@ function renderApiCoverageMatrixLines(apiFace) {
|
|
|
2565
2631
|
const declared = face && typeof face.declared === 'number' ? face.declared : null
|
|
2566
2632
|
const L = [`${API_MATRIX_HEADING} [层:人工判断——CLI 预填复核]`]
|
|
2567
2633
|
L.push('<!-- 口径注记(与探针 7 互指,R-07):探针 7 = 验收项 × 测试承接面(每条 acceptance 由哪些测试承接);本矩阵 = 接口端点 × 验证用例面(design 接口段每个端点由哪些验证用例/冒烟步骤覆盖)——两者并排互补,双矩阵并行存在。端点集来自 design.md 接口段 tolerant 解析(parseDesignApiTable:段头宽收 + 方法/路径双条件),预填≠结论,agent 逐行复核。判定枚举(五选一):covered / covered-service / partial / uncovered / non-testable——covered-service 适用:端点行为由 service 层等非端点层测试锁定;证据须含测试文件锚点三形态之一(`.test.` / file:line / 反引号包裹的路径或测试名)。 -->')
|
|
2568
|
-
L.push('<!-- 预填说明:端点行由 CLI 机械预填,判定/用例依据 ID/结果/证据由 agent 逐格填写——用例依据 ID
|
|
2634
|
+
L.push('<!-- 预填说明:端点行由 CLI 机械预填,判定/用例依据 ID/结果/证据由 agent 逐格填写——用例依据 ID 锚点五形态(可复制样例):design接口表#POST /api/xx(# 后必须 METHOD /path,仅表名/行号/散文描述不计命中)、权限矩阵[admin×读]、契约表@任务卡字段清单、DDL@users.id、载荷@e2e_body.json(须真实命中对应表/段,防空指)。 -->')
|
|
2569
2635
|
L.push('<!-- 文法注释:子行 = 端点行下一行、两空格缩进、以「↳ <消费端>:」前缀书写(消费端细分承接面,不计矩阵行账);探索行 = 判定 uncovered 且证据列含 [探索] 标记(探索性验证不算覆盖)。 -->')
|
|
2570
2636
|
if (endpoints.length === 0 && declared === null) {
|
|
2571
|
-
|
|
2637
|
+
// 分诊(2026-09-23 执行会话实证:散文式接口定义(### 标题+prose)解析零端点,提示被埋没——
|
|
2638
|
+
// sectionHint 非空 = 接口段标题在场而行解析零,定向报「表格形态才进矩阵」,左移修复时机)
|
|
2639
|
+
const sectionHeads = face && Array.isArray(face.sectionHint) ? face.sectionHint : []
|
|
2640
|
+
L.push(sectionHeads.length > 0
|
|
2641
|
+
? `- 无接口面(检测到接口段标题「${sectionHeads[0]}」但表格解析零端点)——矩阵只解析表格形态(每端点一行 METHOD | path),散文式接口定义不进矩阵。修复:接口定义改为表格(每端点一行 METHOD /path)或加声明行「本变更接口面:N 端点」,再重跑 \`verify-probes --change <变更名> --init --force\` 重生成本段(⚠️ 全骨架重生成,手填结论会重置——先备份);判级 critical 的零面拦截归 validator`
|
|
2642
|
+
: `- 无接口面(design 接口段解析零端点且无「本变更接口面:N 端点」声明行)——本变更若实际触碰接口,先补 design 接口段表格或声明行,再重跑 \`verify-probes --change <变更名> --init --force\` 重生成本段(⚠️ 全骨架重生成,手填结论会重置——先备份);判级 critical 的零面拦截归 validator`)
|
|
2572
2643
|
return L
|
|
2573
2644
|
}
|
|
2574
2645
|
if (endpoints.length > 0 && declared !== null && declared !== endpoints.length) {
|
|
@@ -2582,7 +2653,7 @@ function renderApiCoverageMatrixLines(apiFace) {
|
|
|
2582
2653
|
}
|
|
2583
2654
|
} else {
|
|
2584
2655
|
L.push(`| 本变更接口面:${declared} 端点(agent 声明) | <待填:五选一> | <待填:用例 ID> | <待填> | <待填:锚点> |`)
|
|
2585
|
-
L.push('<!-- 解析零行降级(D-005):接口面以 agent 声明为准(对账分母=声明数);声明与实际不符时补 design 接口段表格后重跑 --init
|
|
2656
|
+
L.push('<!-- 解析零行降级(D-005):接口面以 agent 声明为准(对账分母=声明数);声明与实际不符时补 design 接口段表格后重跑 --init --force 重生成本段(quick-B:--force 才有刷新通道,手填内容会重置先备份) -->')
|
|
2586
2657
|
}
|
|
2587
2658
|
L.push('<!-- advisory 尾注(warning 计算归 validator,本段只留位):有消费端未填子行的端点将列于此(advisory——消费端归类=design 清单启发式,数据面 facts.consumerHints);写端点(POST/PUT/DELETE/PATCH)未在权限矩阵段声明的将列于此(advisory——补行或显式豁免「无权限约束」,数据面 facts.apiFace.writeEndpoints;表缺行会让派生框架继承你的洞) -->')
|
|
2588
2659
|
return L
|
|
@@ -2725,6 +2796,13 @@ export function writeVerifyFacts(changeDir, result, changeName, opts = {}) {
|
|
|
2725
2796
|
} catch { /* 首次落盘/v1/损坏 → 全新快照(v1 无固化段,直接升 v2) */ }
|
|
2726
2797
|
writeFileSync(factsPath, JSON.stringify(facts, null, 2) + '\n')
|
|
2727
2798
|
console.log(`📝 已刷新 verify-facts.json 机器底稿: ${factsPath}(v2 分段合并,固化段保留;CLI 全权写,勿手改)${opts.platformNote || ''}`)
|
|
2799
|
+
// 左移警告(2026-09-23 执行会话实证:散文式接口定义到 verify 期才被零面拦下,表格形态要求
|
|
2800
|
+
// 埋在骨架注记里没人看——--init 刷完 facts 就在控制台点名,修复时机从 verify 收口提前到此刻)
|
|
2801
|
+
const face = result && result.apiFace
|
|
2802
|
+
if (face && Array.isArray(face.sectionHint) && face.sectionHint.length > 0
|
|
2803
|
+
&& (!face.endpoints || face.endpoints.length === 0) && face.declared == null) {
|
|
2804
|
+
console.warn(`⚠️ design 检测到接口段标题「${face.sectionHint[0]}」但表格解析零端点——接口验证覆盖矩阵只解析表格形态(每端点一行 METHOD | path),散文式接口定义不进矩阵。修复:design.md 接口定义改表格或加声明行「本变更接口面:N 端点」后重跑 --init。`)
|
|
2805
|
+
}
|
|
2728
2806
|
return { facts, path: factsPath }
|
|
2729
2807
|
}
|
|
2730
2808
|
|