sillyspec 3.32.5 → 3.32.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sillyspec",
3
- "version": "3.32.5",
3
+ "version": "3.32.6",
4
4
  "description": "SillySpec CLI — 流程状态机,让 AI 严格按步骤来",
5
5
  "icon": "logo.jpg",
6
6
  "homepage": "https://sillyspec.ppdmq.top/",
@@ -27,6 +27,15 @@ const PROMISE_RE = /at[- ]least[- ]once|exactly[- ]once|不丢失|不重复|不
27
27
  /** adopted(头脑风暴预段)design 无槽时的机制词全文扫描(窄表防误报)。 */
28
28
  const MECHANISM_RE = /乱序|并发写|竞态|死锁|事务隔离|AbortSignal|多实例串|游标推进/
29
29
 
30
+ /** 盲维四问「自述不适用」整声明变体(2026-10-12-review-na-variant):两仓实测 12/228 实质
31
+ * 作答误升级——整体不适用声明写成「四问全 n/a:」「均不适用」「边界并发四问:不适用:」等
32
+ * 前缀而非「不适用」开头,被 /^不适用/ 机械判成实质作答(误伤样例:纯 CSS 变更 hover-polish
33
+ * 起子代理评审)。窄口径只认整声明开头:可选前缀 + 可选冒号 + 可选限定词 + 不适用|n/a;
34
+ * 逐问编号形态(「1. 乱序:n/a。…」)不聚合——该形态常含逐维实质推理,升级是设计内行为。
35
+ * 前缀声明语义与旧 /^不适用/ 同型(「不适用,但…」旧版本就按开头豁免),加宽词表不加新
36
+ * 语义维度;漏报兜底:豁免面 1/4 抽查采样 + 承诺词/diff 原语/edit_ratio 三路独立信号。 */
37
+ const NA_ANSWER_RE = /^(?:盲维四问|边界并发四问|四问)?\s*[::]?\s*(?:全部|均|皆|都|全)?\s*(?:不适用|n\/a\b)/i
38
+
30
39
  /** design 作答面否定语境消解(2026-10-05-review-promise-negation):盲维第 4 问作答讨论
31
40
  * 作用域风险时,「无串台面」「不会串台」「杜绝串台」等否定短语按字面命中 PROMISE_RE 一票
32
41
  * 升级(实测:两行 console.log 的变更被定档高危起子代理评审)。「串台」是名词性风险词——
@@ -151,13 +160,13 @@ export function classifyReviewNeed({ changeDir, input = '', patchText = null, ed
151
160
  if (/<!--\s*AGENT:槽3/.test(dText)) {
152
161
  const answer = readSlotAnswer(dText, /^<!--\s*AGENT:槽3/)
153
162
  if (!answer) exemptEvidence.push('盲维四问未作答(将由槽位门拦收)')
154
- else if (/^不适用/.test(answer)) exemptEvidence.push('盲维四问自述不适用')
163
+ else if (NA_ANSWER_RE.test(answer)) exemptEvidence.push('盲维四问自述不适用')
155
164
  else reasons.push('盲维四问有实质作答(存在时序/并发/切换/作用域风险面)')
156
165
  } else if (/^##\s*边界与并发/m.test(dText)) {
157
166
  // v2 纯 markdown(2026-10-04-thin-docs-v2):边界节正文作答判定(同 v1 三态语义)
158
167
  const answer = readV2SectionAnswer(dText, DESIGN_QUESTIONS_FALLBACK.sections[2].heading, DESIGN_QUESTIONS_FALLBACK)
159
168
  if (!answer) exemptEvidence.push('盲维四问未作答(将由 v2 工件校验拦收)')
160
- else if (/^不适用/.test(answer)) exemptEvidence.push('盲维四问自述不适用')
169
+ else if (NA_ANSWER_RE.test(answer)) exemptEvidence.push('盲维四问自述不适用')
161
170
  else reasons.push('盲维四问有实质作答(存在时序/并发/切换/作用域风险面)')
162
171
  } else if (MECHANISM_RE.test(dText)) {
163
172
  reasons.push('头脑风暴设计含并发/时序类机制词(adopted 扫描)')
package/src/flow.js CHANGED
@@ -759,14 +759,19 @@ export async function cmdFlowStart({ change, input, title: titleFlag = null, thi
759
759
  `【协议调用 1/2(本次)】change 已建 + 基线锚定(baseline_commit=${baseline ? baseline.slice(0, 10) : '(无 git 历史)'})${withTasks ? ' + 任务卡模式(--with-tasks:中间自愿用 task done,收尾仍 flow done)' : ''}`,
760
760
  ``,
761
761
  `【你要做的】直接干活:改代码、写测试。治理工件不用你写——flow done 机器做(协议记账单位=change 级)。`,
762
+ // 收口拒收红线前置(2026-10-11-flow-start-redline-frontload):钉死/空槽/绑定三面都是文档
763
+ // 先行校验,实证第一次最容易踩(四问文本被改写、区间 task-NN 写法零证据被拒)——横幅
764
+ // 头部先行告知,收口才暴露的规则前置到动笔前。
765
+ `🚫 收口拒收红线(文档先行校验,动笔前先读——第一次最容易踩的就是这三条):`,
766
+ ` ① design 四问文本与 FR 标题锚逐字钉死勿改写——问题原文保持原样、答案写在问题下方,改写/删除即收口拒收(文档↔锚逐字对比);`,
767
+ ` ② design.md 四节(做法/接口契约/边界并发四问/风险)每节至少一行——空节拒收(写「不适用:<理由>」也算答);`,
768
+ ` ③ requirements 每条 FR 须有带强度词的行为句(必须/禁止/SHOULD)+ 测试绑定行——缺任一即拒收。`,
762
769
  `书写面(纯 markdown 起草):requirements FR 正文/design 四节作答/测试绑定行都直接写正文——`,
763
- ` 文档内零指纹标记、零槽注释、零书写指导(规则以本横幅与命令卡为唯一源);`,
764
- ` 标题锚(FR 标题、四问文本)勿改写,收口做文档↔锚对比(锚失踪/空答拒收,成功标准漂移出 advisory)。`,
765
- `⚠️ design.md 四节(做法/接口契约/边界并发四问/风险)动码前后顺手作答——答案写在问题下方,`,
766
- ` 每节至少一行,写「不适用:<理由>」也算答;flow done 空节拒收(承诺锚点,评审与 FR 对账都对着它);`,
767
- ` 列改动文件用独立「## 文件变更清单」节+表格(| 操作 | 路径 | 说明 |)——勿写在「接口契约」节内(收口按节名解析声明面)。`,
768
- `📜 requirements 每条 FR = 标题锚 + 一句带强度词的行为规定(必须/禁止/SHOULD/可以)+ 按需场景块`,
769
- ` (#### 场景:名 + Given/When/Then);测试绑定节每条 FR 一行 \`FR-NN: test/路径「用例」\`。`,
770
+ ` 文档内零指纹标记、零槽注释、零书写指导(规则以本横幅与命令卡为唯一源);成功标准漂移只出 advisory 不拒收。`,
771
+ `⚠️ design.md 四节动码前后顺手作答;列改动文件用独立「## 文件变更清单」节+表格(| 操作 | 路径 | 说明 |)`,
772
+ ` ——勿写在「接口契约」节内(收口按节名解析声明面)。`,
773
+ `📜 requirements 每条 FR = 标题锚 + 行为句 + 按需场景块(#### 场景:名 + Given/When/Then);`,
774
+ ` 测试绑定节每条 FR 一行 \`FR-NN: test/路径「用例」\`(无测试面写「不适用:理由」)。`,
770
775
  `📦 冻结面在 flow done 时点采集(baseline..HEAD 提交面):未提交交付文件——会话专属 worktree 自动并入;`,
771
776
  ` 共享主仓可带 --freeze-dirty 显式声明并入;git 中间提交归档后可 reset --soft 压扁为单提交`,
772
777
  ` (审计真相在 change.patch 冻结件 sha256 锚定,不依赖 git 历史形态)。`,
@@ -781,7 +786,7 @@ export async function cmdFlowStart({ change, input, title: titleFlag = null, thi
781
786
  ` 执行循环:对每个未勾行 Working on task N/M → 做一件 → 测试绿后当场勾这一格 → 下一行——CLI 以 checkbox 为进度状态机`,
782
787
  ` (sillyspec task tick --change ${change} --task task-NN 即时回显进度 N/M 与下一任务指针,flow status 同源;或直接 Edit 翻格 \`- [ ]\`→\`- [x]\`),watcher 实时上平台。`,
783
788
  ` ⚠️ harness 的 TodoWrite 类工具是会话内便利面,不替代 tasks.md——平台进度/收口证据只读它(0/12 事故实证:todo 全 completed 而 tasks.md 0 勾);`,
784
- ` 勾选是收口证据面:每格勾选要有对应提交(消息带 task-NN)或 review.json,全勾但零证据会被拒收;勿攒一把勾(收口硬门拒单拍多格);`,
789
+ ` 勾选是收口证据面:每格勾选要有对应提交(消息带 task-NN——逐个列出或 /、,连写如 task-01/02/03,「task-01..task-05」区间写法不认)或 review.json,全勾但零证据会被拒收;勿攒一把勾(收口硬门拒单拍多格);`,
785
790
  ` flow status --change ${change} 为自愿查看/恢复面(恢复时给下一任务指针与进度)。`,
786
791
  ``,
787
792
  `🛑 三断点纪律(可控性要求——用户没说「全跑完」就必须在每个断点向用户汇报并等确认):`,
@@ -840,6 +845,9 @@ function printRecoveryBriefing({ cwd, specBase, change, changeDir, runtimeRoot,
840
845
  ...(title ? [`- 标题:${title}`] : []),
841
846
  `- 做到哪:任务勾选 ${checked}/${total};基线以来提交 ${commits} 个;变更/dirty 文件 ${dirty} 个;P2 质量扫描记录 ${hasLedger ? '在场' : '无'}。`,
842
847
  `- 六子步标记:${done.length ? `已完成 ${done.join('/')}` : '(无)'}${left.length ? `;待办 ${left.join('/')}` : ';全部完成'}`,
848
+ // 红线重申(2026-10-11-flow-start-redline-frontload):重入不出首进横幅——钉死规则与
849
+ // task-NN token 形态随简报补位,断点续跑生命周期内规则不丢。
850
+ `- 红线重申:design 四问文本/FR 标题锚逐字钉死勿改写(改写即拒收);勾选证据提交消息逐个带 task-NN 或 /、,连写(「task-01..task-05」区间写法不认)。`,
843
851
  `- 剩什么:${left.length === 0 && dirty === 0 ? '活已干完' : dirty > 0 ? '活未干完(继续改代码)' : '收尾待裁决'}`,
844
852
  `- 下一步:${left.length === 0 ? `sillyspec flow done --change ${change}` : `继续干活;干完跑 flow done(断点续)`}`,
845
853
  ...(digestLines.length > 0 ? ['', ...digestLines] : []),
@@ -1034,8 +1042,10 @@ export async function cmdFlowDone({ change, cwd, specBase, runtimeRootOpt = null
1034
1042
  // 机器稿基线做镜像豁免(route-hindsight 基线快照仍供改写比指标,与哨兵解耦)。
1035
1043
  const sent = detectFakeCheckCompletion({ changeDir, tasksMd: readFileSync(tasksPath, 'utf8'), commits: commitMessages })
1036
1044
  if (sent.status === 'fake') {
1037
- console.error(`🚫 哨兵断言拒收:tasks.md 全勾(${sent.checked}/${sent.claimTotal})但 ${sent.missing.length} 个任务零完成证据(区间提交标题与正文均无 token、无 review.json):${sent.missing.join('、')}`)
1038
- console.error(' 补证据(提交标题或正文带 task-NN,或产 review.json)或取消勾选后重跑——假完成主张不许过门')
1045
+ console.error(`🚫 哨兵断言拒收:tasks.md 全勾(${sent.checked}/${sent.claimTotal})但 ${sent.missing.length} 个任务零完成证据(baseline..HEAD 提交标题与正文均无 token、无 review.json):${sent.missing.join('、')}`)
1046
+ // token 合法形态写明(2026-10-11-flow-start-redline-frontload):实证「task-01..task-05」
1047
+ // 区间写法被判零证据时才知道格式约束——拒收文案自释,减少一轮试错。
1048
+ console.error(' 补证据(提交标题或正文带 task-NN——逐个列出或 /、,连写(如 task-01/02/03),「task-01..task-05」区间写法不认;或产 review.json)或取消勾选后重跑——假完成主张不许过门')
1039
1049
  appendTelemetry({ sentinel: 'fake', missing: sent.missing.length })
1040
1050
  reportMidFail('ledger')
1041
1051
  process.exit(1)
@@ -469,8 +469,10 @@ export async function runGate(stage, changeName, { cwd, specBase, runtimeRoot, s
469
469
  });
470
470
  }
471
471
  }
472
- // e2. stage review 在场探测(verify/execute --done 的 Stage Review Gate)
473
- try {
472
+ // e2. stage review 在场探测(execute --done 的 Stage Review Gate——verify 不在其列,
473
+ // 坑 stage-review-verify-enum-gap 2026-10-11:gate 实际只拦 brainstorm/plan/execute,
474
+ // register 枚举亦无 verify,verify 阶段不产 stage review 期望;verify 的真实门面是 e1 对账)
475
+ if (stage === 'execute') try {
474
476
  const { getLatestStageReviewRunId } = await import('./stage-review.js');
475
477
  const rrRoot = runtimeRoot || join(specRoot, '.runtime');
476
478
  const runId = getLatestStageReviewRunId(rrRoot, stage, changeName);
@@ -479,7 +481,7 @@ export async function runGate(stage, changeName, { cwd, specBase, runtimeRoot, s
479
481
  code: checkCode('full-stage-review') || 'full_stage_review_missing',
480
482
  ok: !!runId,
481
483
  errors: !runId
482
- ? [`缺 ${stage} 阶段的 stage review.json(tier=independent 要求独立审查产出)——--done 将被 Stage Review Gate 拦;可先 sillyspec register-stage-review --change ${changeName} --stage ${stage} 生成骨架再填(降级条款照 review.json reviewerNotes 首行留痕)`]
484
+ ? [`缺 ${stage} 阶段的 stage review.json(tier=independent 要求独立审查产出)——execute --done 将被 Stage Review Gate 拦;可先 sillyspec register-stage-review --change ${changeName} --stage ${stage} 生成骨架再填(降级条款照 review.json reviewerNotes 首行留痕)`]
483
485
  : [],
484
486
  data: { runId: runId || null },
485
487
  });
@@ -500,7 +502,10 @@ export async function runGate(stage, changeName, { cwd, specBase, runtimeRoot, s
500
502
  // (同一 getLatestStageReviewRunId 只读 marker 存在性,秒级):缺 review → warning 带
501
503
  // register 指引;在场 → 静默 ok。独立 check id 不与 --full 的 full-stage-review 碰撞,
502
504
  // error 语义(--done 拦)仍归 --full 档与 --done 本体。
503
- if (!full && (stage === 'verify' || stage === 'execute')) {
505
+ // stage 期望面对齐(坑 stage-review-verify-enum-gap,2026-10-11 实证):Stage Review Gate
506
+ // 实际只拦 brainstorm/plan/execute(gates.js),register-stage-review 枚举亦无 verify——
507
+ // verify 阶段不产 stage review 提示(提示命令不可执行 + 指称的门禁不存在,双重误导)。
508
+ if (!full && stage === 'execute') {
504
509
  try {
505
510
  const { getLatestStageReviewRunId } = await import('./stage-review.js');
506
511
  const rrRoot = runtimeRoot || join(specRoot, '.runtime');
@@ -511,7 +516,7 @@ export async function runGate(stage, changeName, { cwd, specBase, runtimeRoot, s
511
516
  ok: true,
512
517
  informational: true,
513
518
  warnings: runId ? [] : [
514
- `缺 ${stage} 阶段的 stage review.json——verify/execute --done 的 Stage Review Gate 会拦(本提示不改变 gate 结论)。先产出评审再注册:sillyspec register-stage-review --change ${changeName} --stage ${stage}(骨架生成后填,或 --from review.json 过继独立评审产出)`,
519
+ `缺 ${stage} 阶段的 stage review.json——execute --done 的 Stage Review Gate 会拦(本提示不改变 gate 结论)。先产出评审再注册:sillyspec register-stage-review --change ${changeName} --stage ${stage}(骨架生成后填,或 --from review.json 过继独立评审产出)`,
515
520
  ],
516
521
  data: { runId: runId || null },
517
522
  });