|
| 1 | +--- |
| 2 | +{ |
| 3 | + "schema": "shadow-dev/v1", |
| 4 | + "name": "20261009-fix-distribution-gate-regex", |
| 5 | + "type": "fix", |
| 6 | + "scope": "scripts", |
| 7 | + "status": "published", |
| 8 | + "baseBranch": "main", |
| 9 | + "branch": "fix/20261009-fix-distribution-gate-regex", |
| 10 | + "files": [ |
| 11 | + "knowledge/distribution-capability-contract.md", |
| 12 | + "package.json", |
| 13 | + "scripts/check-requires.mjs" |
| 14 | + ], |
| 15 | + "github": { |
| 16 | + "repository": "stack-wuh/shadow-dev-workflow", |
| 17 | + "issue": null, |
| 18 | + "issueUrl": null, |
| 19 | + "pullRequest": 37, |
| 20 | + "pullRequestUrl": "https://github.com/stack-wuh/shadow-dev-workflow/pull/37" |
| 21 | + }, |
| 22 | + "review": { |
| 23 | + "conclusion": "passed", |
| 24 | + "verifiedCommit": "c5319bb789131cf33377f93e593c080a2e7266d9", |
| 25 | + "verifiedAt": "2026-10-09T15:02:51.214Z" |
| 26 | + }, |
| 27 | + "workflow": { |
| 28 | + "operation": null, |
| 29 | + "checkpoint": "pr:37", |
| 30 | + "planHash": "8a160fc3ce8c2fe18c2368cb4d61fedf1f6fb3971a4c46aed99c9e15b94c9fdf", |
| 31 | + "updatedAt": null, |
| 32 | + "lastError": null, |
| 33 | + "release": { |
| 34 | + "files": [ |
| 35 | + "package.json", |
| 36 | + "scripts/check-requires.mjs", |
| 37 | + "shadow-docs/changes/20261009-build-artifact-capability-gate/brief.md", |
| 38 | + "shadow-docs/changes/20261009-fix-distribution-gate-regex/" |
| 39 | + ], |
| 40 | + "message": "fix(scripts): 一致性门禁止跨行吞引用(负例必判红)+ 复原 npm test 两文件", |
| 41 | + "title": "[fix] 一致性门假绿修复:引用扫描禁止跨行 + npm test 复原", |
| 42 | + "body": "" |
| 43 | + } |
| 44 | + }, |
| 45 | + "knowledge": { |
| 46 | + "action": "更新", |
| 47 | + "target": "knowledge/distribution-capability-contract.md", |
| 48 | + "reason": "卡片验证方式补入「门负例必跑 + 引用扫描禁止跨行」这条踩出来的稳定教训" |
| 49 | + } |
| 50 | +} |
| 51 | +--- |
| 52 | + |
| 53 | +# 一致性门不再跨行吞引用:负例必判红 + npm test 覆盖两个测试文件 |
| 54 | + |
| 55 | +## 动机 |
| 56 | +`check-requires.mjs` 的引用正则用了可跨行的 `\s+`,把下一条 `shadow-dev` 的 `shadow-` 前缀一起吃掉(实测 `repo inspect\nshadow-dev` 成为一组),导致 `worktree inspect` 等引用**从未被统计**——门会假绿,而假绿的门比没有门更危险(它给「pin 与声明已互校」的错误信心)。同一批改动还把 `scripts.test` 写成 `node --test test/`,在本机 node 22 下测试发现失败(`# tests 1 # fail 1`),main 上现在是红的。 |
| 57 | + |
| 58 | +## 复杂度评级 |
| 59 | +- **评级:** S |
| 60 | +- **理由:** ①契约变更:无(门的判定逻辑修正与 npm script 复原,不改任何命令行为);②触及面:单个脚本 + 一行 manifest;③可发现性:门正/负例与测试脚本立刻可判红。 |
| 61 | +- **期望验证深度:** code-read + 三条必判红/判绿冒烟(按 2026-10-09 裁决不写 TDD) |
| 62 | + |
| 63 | +## 引用规范 |
| 64 | +- `knowledge/distribution-capability-contract.md` |
| 65 | + - 当前结论: 声明与消费两级包含、差集非空即判红;改 pin 后必须跑门。 |
| 66 | + - 适用 scope: scripts/check-requires.mjs, package.json |
| 67 | +- `norms/tdd-verification.md`:S 级不创建测试文件;既有测试必须保持绿。 |
| 68 | + |
| 69 | +## 决策 |
| 70 | +- **选型:** 正则改为禁止跨行(`[^\S\n]+`),并把两条判红路径都实跑验证;`scripts.test` 回到显式两文件。 |
| 71 | +- **对比方案:** 加测试文件钉住正则——未选(裁决:不写 TDD),改以「门负例必判红」冒烟作为交付证据,并写进卡片的验证方式。 |
| 72 | +- **理由:** 门是唯一保证 pin/声明不互相冒充的机制,它的假绿路径必须被当作 bug 当场证伪。 |
| 73 | + |
| 74 | +## 任务 |
| 75 | +### Phase 1 |
| 76 | +- [x] 修正引用正则 — `scripts/check-requires.mjs` — 禁止跨行匹配;重跑正例,引用数应上升且 `undeclared=[] missing-in-cli=[]` |
| 77 | +- [x] 两条判红冒烟 — `scripts/check-requires.mjs` — (a) 从声明删一键 → 必 exit 1 且点名 `undeclared`;(b) 声明一个不存在键 → 必 exit 1 且点名 `missing-in-cli`(这就是 pin/CLI 过旧的判红路径) |
| 78 | +- [x] 复原测试入口 — `package.json` — `scripts.test` = `node --test test/install-cli.test.mjs test/pack.test.mjs`,跑绿 |
| 79 | + |
| 80 | +## 非目标 |
| 81 | +- 不动 hooks/pin/两轨形态;不加 CI workflow(独立 change) |
| 82 | + |
| 83 | +## 结果 |
| 84 | +- 实际耗时: ≈5 分钟 |
| 85 | +- 验证(S 级=走查 + 三条冒烟):门正例(引用数上升、两级差集为空);负例 a 删一键 → exit 1 且 undeclared 点名;负例 b 声明不存在键 → exit 1 且 missing-in-cli 点名;`npm test` 两文件恢复全绿。 |
| 86 | +- 影响面自查:上一批(PR #36)把两条假绿带进了 main——门从未真正判过红、`npm test` 在 main 上是红的。本 change 是它自己的第一个真 bug。 |
| 87 | + |
| 88 | +## 知识评估 |
| 89 | +- **预期影响:** 更新 |
| 90 | +- **候选卡片:** `knowledge/distribution-capability-contract.md` |
| 91 | +- **理由:** 卡片「验证方式」需补一条硬要求:**一致性门交付前必须跑负例证明它会判红**——这是本次踩出来的稳定教训,属原位更新不另立新卡。 |
0 commit comments