@ccoalm/ccl-skills 0.3.0 → 0.5.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.
Files changed (79) hide show
  1. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/classify_envelope.py +34 -3
  2. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_abort_leak_state_helpers.sh +148 -0
  3. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_classify_envelope.sh +28 -0
  4. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_review_json.sh +7 -0
  5. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +13 -0
  6. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate_abort_leak.sh +271 -34
  7. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/public-data-acquisition.md +3 -1
  8. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/public-disclosure-channels.md +2 -0
  9. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +12 -12
  10. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/dual-track-review-gate.md +8 -0
  11. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/eval-routing.md +7 -8
  12. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/external-practice-controls.md +12 -0
  13. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-quickstart.md +3 -2
  14. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/firing-point-placement.md +8 -0
  15. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/harness-patterns-and-eval.md +7 -6
  16. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/recurring-anti-patterns-checklist.md +18 -0
  17. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +47 -2
  18. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-to-skill-extraction.md +28 -29
  19. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-ccl-skills.sh +165 -1
  20. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-health.rb +23 -10
  21. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +303 -1
  22. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_impact_chain_refscripts.sh +222 -91
  23. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +12 -0
  24. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_ci_checkout_ref_binding.sh +85 -0
  25. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_entrypoint_domain_scan_terms.sh +123 -0
  26. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_dateless_host.sh +6 -1
  27. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_verdict_differential.sh +1 -1
  28. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_round_attribution.sh +12 -12
  29. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_self_adjudication.sh +455 -0
  30. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_source_refuted.sh +20 -20
  31. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_liveness_predicate_gate.sh +288 -0
  32. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/SKILL.md +4 -4
  33. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/deliverable-doc-genre-skeletons.md +133 -0
  34. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/doc-charter-first.md +2 -0
  35. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/figure-and-table-craft.md +318 -0
  36. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/AGENTS.md +46 -0
  37. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/doc-lint.py +246 -0
  38. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/figure-lint.py +1092 -0
  39. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/mutation_probe.sh +100 -0
  40. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/test_figure_and_doc_lint.sh +375 -0
  41. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/control.md +10 -0
  42. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/empty-header.md +6 -0
  43. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/fake-header.md +13 -0
  44. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/fenced-noise.md +14 -0
  45. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/fig-dangling.md +5 -0
  46. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/fig-orphan-captioned.md +11 -0
  47. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/fig-orphan.md +9 -0
  48. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/fig.png +0 -0
  49. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/imbalance.md +41 -0
  50. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/no-unit.md +8 -0
  51. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/should-be-chart.md +11 -0
  52. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/tables-only-clean.md +35 -0
  53. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/unfilled.md +7 -0
  54. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/doc/wide-table.md +5 -0
  55. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/bad-viewbox.svg +9 -0
  56. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/blackmarker.svg +9 -0
  57. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/control.svg +12 -0
  58. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/crossings.svg +12 -0
  59. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/cvd-confusable.svg +9 -0
  60. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/decorative-line.svg +10 -0
  61. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/edge-no-arrow.svg +11 -0
  62. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/edge-vague.svg +12 -0
  63. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/figure-contract.json +21 -0
  64. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/figure-is-a-list.svg +12 -0
  65. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/flow-mixed.svg +13 -0
  66. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/low-contrast.svg +12 -0
  67. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/malformed.svg +1 -0
  68. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/no-aria.svg +9 -0
  69. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/no-group.svg +10 -0
  70. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/no-legend.svg +9 -0
  71. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/no-title.svg +12 -0
  72. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/no-viewbox.svg +9 -0
  73. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/offcontract-shape.svg +13 -0
  74. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/overflow.svg +13 -0
  75. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/transformed.svg +9 -0
  76. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/ungrouped-card.svg +12 -0
  77. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unlabeled-edge.svg +13 -0
  78. package/dist/assets/release.json +276 -31
  79. package/package.json +1 -1
@@ -0,0 +1,455 @@
1
+ #!/usr/bin/env bash
2
+ # 045:给「被裁决方自审」的义务装机械触发器的验收用例
3
+ # (specs/045-self-adjudicated-obligation-trigger/plan.md 的 Acceptance matrix)。
4
+ #
5
+ # 044 轮撤回过度声称时,把若干义务降成了咨询项,连续五轮 challenge 返回同一类:
6
+ # 义务的入口条件由被约束方自己陈述,且**跳过时不产生可检测的缺席**。本套件钉的是
7
+ # 那个缺席现在可被机械检出。
8
+ #
9
+ # 两个触发器都键在 diff 的客观事实上,不是散文语义:
10
+ # A 改了 routing 面(SKILL.md 的 frontmatter description,或 eval/routing-tasks.jsonl)
11
+ # ⇒ 该 owner 的台账行必须带 bank-evidence locator,或带留痕的 downscoped token。
12
+ # B 带 behavioral-evidence 的新增台账行 ⇒ 必须带合法 result-class。
13
+ #
14
+ # 期望红的用例都必须点名 WHICH refusal:rc 单独是弱 oracle,为无关原因(fixture 缺陷、
15
+ # 锚点断掉)红同样是 rc=1,会把「形态已关闭」读成绿。
16
+ set -u
17
+ ROOT="$(cd "$(dirname "$0")/../../.." && pwd -P)"
18
+ GATE="$ROOT/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb"
19
+ LEDGER_REL="skills/skill-extraction-workflow/references/source-register.md"
20
+ BANK_REL="eval/routing-tasks.jsonl"
21
+ PLAN_REL="specs/045-self-adjudicated-obligation-trigger/plan.md"
22
+ TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT INT TERM
23
+
24
+ REPO="$TMP/repo"
25
+ git clone -q "$ROOT" "$REPO"
26
+ git -C "$REPO" config user.email test@example.invalid
27
+ git -C "$REPO" config user.name "Test User"
28
+ # A base WITHOUT the declaration, built by REMOVING it rather than by hoping the
29
+ # clone happens not to have it. Once this round is committed, `git clone "$ROOT"`
30
+ # carries the declaration, so a fixture that read the clone's HEAD as "before the
31
+ # grammar" passed from an uncommitted worktree and failed in CI — green meaning
32
+ # "not yet committed", which is the class of false green this suite exists for.
33
+ ORIG_HEAD="$(git -C "$REPO" rev-parse HEAD)"
34
+ git -C "$REPO" switch -q -C nogrammar-base "$ORIG_HEAD"
35
+ python3 - "$REPO/$LEDGER_REL" <<'STRIP'
36
+ import io, sys
37
+ p = sys.argv[1]
38
+ s = io.open(p, encoding="utf-8").read()
39
+ io.open(p, "w", encoding="utf-8").write(
40
+ "".join(l for l in s.splitlines(keepends=True)
41
+ if "result-class: failure|stable-success|insufficient-evidence" not in l))
42
+ STRIP
43
+ git -C "$REPO" add -A >/dev/null
44
+ git -C "$REPO" commit -qm "fixture base predating the 045 declaration"
45
+ PRE_GRAMMAR="$(git -C "$REPO" rev-parse HEAD)"
46
+ git -C "$REPO" switch -q -C fixture-seed "$ORIG_HEAD"
47
+ # Both triggers only fire for a round whose HEAD ledger declares the grammar, so
48
+ # the fixture base must carry that declaration. Seeded explicitly rather than
49
+ # inherited from the clone: `git clone` copies commits, so relying on the working
50
+ # tree would make the suite pass or fail depending on whether the author had
51
+ # committed yet — a green that means "not yet judged".
52
+ # A dedicated package for the rename case, so A18 does not have to rename a REAL
53
+ # owner and drag the whole rename machinery (and its own refusals) into the leg.
54
+ mkdir -p "$REPO/skills/fixture-rename-src"
55
+ printf -- '---\nname: fixture-rename-src\ndescription: A fixture routing surface that a later case renames and rewords at once.\n---\n\n# Fixture\n\n- Baseline rule present before any case.\n' > "$REPO/skills/fixture-rename-src/SKILL.md"
56
+ printf '\n%s\n' 'Fixture grammar declaration: result-class: failure|stable-success|insufficient-evidence' \
57
+ >> "$REPO/$LEDGER_REL"
58
+ git -C "$REPO" add -A >/dev/null
59
+ git -C "$REPO" commit -qm "seed grammar declaration for the 045 triggers"
60
+ git -C "$REPO" branch -f fixture-base HEAD >/dev/null
61
+
62
+ OWNER="product-rd-workflow"
63
+
64
+ new_case() { git -C "$REPO" switch -q -C "$1" fixture-base; }
65
+ commit_case() { git -C "$REPO" add -A >/dev/null; git -C "$REPO" commit -qm "$1"; }
66
+
67
+ anchor() { printf 'SELF-ADJUDICATION-FIXTURE-%s' "$1"; }
68
+
69
+ # A normative list rule the firing path can anchor on. Same shape the attribution
70
+ # suite uses: the anchor must land on a CHANGED list line carrying a normative verb.
71
+ add_owner_rule() { # <marker>
72
+ printf -- '- Rule %s must be recorded before the round lands.\n' "$(anchor "$1")" \
73
+ >> "$REPO/skills/$OWNER/SKILL.md"
74
+ }
75
+
76
+ # Edit the frontmatter `description` — the routing surface trigger A keys on.
77
+ # Appending to the body is NOT this; case A6 pins that distinction.
78
+ # The marker written here is deliberately DISTINCT from the rule anchor: the
79
+ # firing-path locator requires its anchor to occur exactly once in the file, and
80
+ # reusing one token made every A case red on a fixture defect rather than on the
81
+ # behaviour under test — a rc=1 that looked like the gate working. A SUFFIX is not
82
+ # enough either: the locator counts substring hits, so `…-A1-DESC` still contains
83
+ # `…-A1`. The distinguishing part has to come before the shared stem.
84
+ edit_owner_description() { # <marker>
85
+ python3 - "$REPO/skills/$OWNER/SKILL.md" "$(anchor "DESC-$1")" <<'PY'
86
+ import io, re, sys
87
+ path, marker = sys.argv[1], sys.argv[2]
88
+ s = io.open(path, encoding="utf-8").read()
89
+ m = re.match(r"\A---\s*\n(.*?)\n---\s*\n", s, re.S)
90
+ front = m.group(1)
91
+ new_front = re.sub(r"(?m)^(description:.*)$", r"\1 " + marker, front, count=1)
92
+ io.open(path, "w", encoding="utf-8").write(s[:m.start(1)] + new_front + s[m.end(1):])
93
+ PY
94
+ }
95
+
96
+ touch_bank() { printf '{"utterance":"fixture %s","expected_owner":"%s"}\n' "$1" "$OWNER" >> "$REPO/$BANK_REL"; }
97
+
98
+ write_plan() { # <downscope-token or empty>
99
+ mkdir -p "$REPO/$(dirname "$PLAN_REL")"
100
+ {
101
+ printf '# 045 fixture plan\n\n'
102
+ printf -- '- Bank evidence anchor %s must be reachable from the ledger row.\n' "$(anchor BANKEV)"
103
+ # An `[ -n ... ] && printf` tail returns 1 when the token is absent, and the
104
+ # group's status is the script's under errexit — that silently truncated the
105
+ # whole suite after its first leg. Spelled as an if so a no-token call is a
106
+ # normal success, not a run that ends without saying it ended.
107
+ if [ -n "${1:-}" ]; then
108
+ printf -- '- Downscope downscoped:%s is recorded here, so skipping the bank run still leaves an artifact.\n' "$1"
109
+ fi
110
+ } > "$REPO/$PLAN_REL"
111
+ return 0
112
+ }
113
+
114
+ # A row that satisfies every PRE-EXISTING requirement, so each case varies only
115
+ # the field under test. Extra evidence fragments are appended verbatim.
116
+ append_row() { # <marker> <lesson> <extra-behavior-fragments>
117
+ printf '| %s | `downstream-executor` | behavioral-evidence: RED-baseline; observed-failure: yes; firing-path: file:skills/%s/SKILL.md#%s%s | `updated` | `%s/SKILL.md` fixture change |\n' \
118
+ "$2" "$OWNER" "$(anchor "$1")" "$3" "$OWNER" >> "$REPO/$LEDGER_REL"
119
+ }
120
+
121
+ run_gate() {
122
+ set +e
123
+ out="$(env -u ALIAS_AUDIT_CMD CCL_SKILL_BASE_REF=fixture-base ruby "$GATE" "$REPO" 2>&1)"
124
+ rc=$?
125
+ set -e
126
+ }
127
+
128
+ legs_failed=0
129
+ report_leg() { # <leg-name> <expected-rc> <form-summary> [expected-token]
130
+ local name="$1" want="$2" summary="$3" token="${4:-}"
131
+ if [ "$rc" != "$want" ]; then
132
+ echo " $name: RED (rc=$rc, want $want) — $summary"
133
+ printf '%s\n' "$out" | sed 's/^/ | /'
134
+ legs_failed=$((legs_failed + 1))
135
+ return
136
+ fi
137
+ if [ -n "$token" ] && ! printf '%s' "$out" | grep -qF "$token"; then
138
+ echo " $name: RED (rc matched but refusal is not '$token') — $summary"
139
+ printf '%s\n' "$out" | sed 's/^/ | /'
140
+ legs_failed=$((legs_failed + 1))
141
+ return
142
+ fi
143
+ echo " ok $name — $summary"
144
+ }
145
+
146
+ RC_MISSING="impact_chain_bank_evidence_missing"
147
+ RC_CLASS="impact_chain_result_class_missing"
148
+
149
+ # ---- B:result 分类不可省略 ------------------------------------------------
150
+ # B1 带合法 result-class -> 通过
151
+ new_case case-b1; add_owner_rule B1; write_plan
152
+ append_row B1 'A fixture lesson whose row declares its result class' '; result-class: failure'
153
+ commit_case "B1"; run_gate
154
+ report_leg B1 0 "带合法 result-class 的行通过"
155
+
156
+ # B2 缺 result-class -> 红,且必须是这条拒绝
157
+ new_case case-b2; add_owner_rule B2; write_plan
158
+ append_row B2 'A fixture lesson whose row omits its result class' ''
159
+ commit_case "B2"; run_gate
160
+ report_leg B2 1 "缺 result-class 被拒(关闭「整格省略」这条绕过)" "$RC_CLASS"
161
+
162
+ # B3 result-class 值不在枚举 -> 红
163
+ new_case case-b3; add_owner_rule B3; write_plan
164
+ append_row B3 'A fixture lesson whose row invents a result class' '; result-class: probably-fine'
165
+ commit_case "B3"; run_gate
166
+ report_leg B3 1 "非枚举 result-class 被拒" "$RC_CLASS"
167
+
168
+ # B4 不带 behavioral-evidence 的行 + 无 owner 改动 -> 不触发
169
+ new_case case-b4; write_plan
170
+ printf '| A fixture row that declares nothing | `downstream-executor` | note only | `not-applicable` | supporting note |\n' \
171
+ >> "$REPO/$LEDGER_REL"
172
+ commit_case "B4"; run_gate
173
+ report_leg B4 0 "非本闸的行不被拖进 result-class 义务(保持既有 bifurcation)"
174
+
175
+ # ---- A:routing 面改动必须带 bank 证据 -------------------------------------
176
+ # A1 改 description + 带可解析 bank-evidence -> 通过
177
+ new_case case-a1; add_owner_rule A1; edit_owner_description A1; write_plan
178
+ append_row A1 'A fixture lesson whose routing-surface change carries bank evidence' \
179
+ "; result-class: failure; bank-evidence: file:$PLAN_REL#$(anchor BANKEV)"
180
+ commit_case "A1"; run_gate
181
+ report_leg A1 0 "改 description 且带 bank-evidence 通过"
182
+
183
+ # A2 改 description 但无 bank-evidence -> 红
184
+ new_case case-a2; add_owner_rule A2; edit_owner_description A2; write_plan
185
+ append_row A2 'A fixture lesson whose routing-surface change carries no bank evidence' '; result-class: failure'
186
+ commit_case "A2"; run_gate
187
+ report_leg A2 1 "改 description 却无 bank-evidence 被拒(关闭「不跑就没工件」)" "$RC_MISSING"
188
+
189
+ # A3 改 task-bank 但无 bank-evidence -> 红
190
+ new_case case-a3; add_owner_rule A3; touch_bank A3; write_plan
191
+ append_row A3 'A fixture lesson that edits the task bank without bank evidence' '; result-class: failure'
192
+ commit_case "A3"; run_gate
193
+ report_leg A3 1 "改 task-bank 却无 bank-evidence 被拒" "$RC_MISSING"
194
+
195
+ # A4 显式降范围且 token 留痕在 plan -> 通过
196
+ new_case case-a4; add_owner_rule A4; edit_owner_description A4; write_plan "DOWNSCOPE-A4"
197
+ append_row A4 'A fixture lesson that downscopes the bank run on the record' \
198
+ '; result-class: failure; bank-evidence: downscoped:DOWNSCOPE-A4'
199
+ commit_case "A4"; run_gate
200
+ report_leg A4 0 "降范围带留痕 token 通过(降范围仍产生工件)"
201
+
202
+ # A5 降范围但 token 不在任何 plan -> 红
203
+ new_case case-a5; add_owner_rule A5; edit_owner_description A5; write_plan
204
+ append_row A5 'A fixture lesson that downscopes with no recorded reason' \
205
+ '; result-class: failure; bank-evidence: downscoped:DOWNSCOPE-A5'
206
+ commit_case "A5"; run_gate
207
+ report_leg A5 1 "降范围 token 无留痕被拒(否则 downscoped: 就是新的自审出口)" "$RC_MISSING"
208
+
209
+ # A6 只改 SKILL.md 正文、未动 description -> 不触发
210
+ new_case case-a6; add_owner_rule A6; write_plan
211
+ append_row A6 'A fixture lesson that edits only the body' '; result-class: failure'
212
+ commit_case "A6"; run_gate
213
+ report_leg A6 0 "只改正文不触发 bank 义务(避免把正文编辑拖进来)"
214
+
215
+ # A7 bank-evidence 指回 owner 自己的包 -> 红
216
+ # 「工件存在」不等于「工件是证据」:description-only 的改动若能拿刚写下的那行当自己的
217
+ # bank 证据,闸就只是在核对一个自指的存在性。这条是本轮唯一一次收紧谓词,也正是本轮
218
+ # 要消灭的形态本身。
219
+ new_case case-a7; add_owner_rule A7; edit_owner_description A7; write_plan
220
+ append_row A7 'A fixture lesson citing its own package as bank evidence' \
221
+ "; result-class: failure; bank-evidence: file:skills/$OWNER/SKILL.md#$(anchor A7)"
222
+ commit_case "A7"; run_gate
223
+ report_leg A7 1 "自指 bank-evidence 被拒(改动本身不是关于它的证据)" "$RC_MISSING"
224
+
225
+ # G1 该轮 head 的台账未声明该语法 -> 不被追溯约束
226
+ # 这是非追溯性的承重件:没有它,新增一个必填字段会在任何回放里追溯拒掉全部历史轮
227
+ # (实测 64 个集成点里 34 个),而 verdict-differential 套件会正确地把那报成回归。
228
+ # 判据不是日期也不是 commit id(那些是会漂的代理),是「该轮 head 自己有没有声明」。
229
+ git -C "$REPO" switch -q -C case-g1 "$PRE_GRAMMAR"
230
+ add_owner_rule G1; write_plan
231
+ append_row G1 'A fixture lesson landing before the grammar was declared' ''
232
+ commit_case "G1"
233
+ set +e
234
+ out="$(env -u ALIAS_AUDIT_CMD CCL_SKILL_BASE_REF="$PRE_GRAMMAR" ruby "$GATE" "$REPO" 2>&1)"; rc=$?
235
+ set -e
236
+ report_leg G1 0 "head 未声明该语法的轮不被追溯约束(否则加字段=判死全部历史轮)"
237
+
238
+ # A8 只改 task-bank、不动任何 owner -> 仍必须红
239
+ # 第一版按 owner 迭代,bank-only 的改动根本进不了循环:路由 bank 可以随便动而无任何证据。
240
+ # A3 之所以没抓到,是因为它顺手也改了 owner——洞就藏在那条绿用例后面。
241
+ new_case case-a8; write_plan; touch_bank A8
242
+ printf '| A fixture lesson that moves the routing bank alone | `downstream-executor` | behavioral-evidence: RED-baseline; observed-failure: yes; result-class: failure | `updated` | supporting note only |\n' \
243
+ >> "$REPO/$LEDGER_REL"
244
+ commit_case "A8"; run_gate
245
+ report_leg A8 1 "只改 task-bank 也必须带 bank 证据(洞曾藏在 A3 的绿后面)" "$RC_MISSING"
246
+
247
+ # G2 声明过又被删掉 -> 红(不是「早于规则」,是关掉规则)
248
+ new_case case-g2; add_owner_rule G2; write_plan
249
+ python3 - "$REPO/$LEDGER_REL" <<'STRIP2'
250
+ import io, sys
251
+ p = sys.argv[1]
252
+ s = io.open(p, encoding="utf-8").read()
253
+ io.open(p, "w", encoding="utf-8").write(
254
+ "".join(l for l in s.splitlines(keepends=True)
255
+ if "result-class: failure|stable-success|insufficient-evidence" not in l))
256
+ STRIP2
257
+ append_row G2 'A fixture lesson that quietly removes the declaration' '; result-class: failure'
258
+ commit_case "G2"; run_gate
259
+ report_leg G2 1 "把声明删掉不等于早于规则,是静默关闭" "impact_chain_grammar_withdrawn"
260
+
261
+ # A9 只改 task-bank 且**一行台账都不加** -> 仍必须红
262
+ # A8 仍然加了行,于是 rows 非空、scope 存在;真正无人守的是「既不动 owner、也不动台账」
263
+ # 那条路径——外层进入条件和按行分组的循环都会放它过去。绿用例第二次挡住了它要覆盖的洞。
264
+ new_case case-a9; touch_bank A9
265
+ commit_case "A9"; run_gate
266
+ report_leg A9 1 "只动 bank、零台账行也必须红(外层进入条件曾漏掉这条路径)" "$RC_MISSING"
267
+
268
+ # A10 两个 owner 各改 description,只有一个带证据 -> 必须红,且点名欠证据的那个
269
+ # 义务由每个移动了自己路由面的 owner 各自承担;按轮求值会让一个 owner 的合法 locator
270
+ # 把整轮标成已满足,另一个就可以完全省略。
271
+ OWNER2="testing-strategy"
272
+ new_case case-a10; add_owner_rule A10; edit_owner_description A10; write_plan
273
+ printf -- '- Rule %s must be recorded before the round lands.\n' "$(anchor A10B)" >> "$REPO/skills/$OWNER2/SKILL.md"
274
+ python3 - "$REPO/skills/$OWNER2/SKILL.md" "$(anchor DESC-A10B)" <<'PY2'
275
+ import io, re, sys
276
+ path, marker = sys.argv[1], sys.argv[2]
277
+ s = io.open(path, encoding="utf-8").read()
278
+ m = re.match(r"\A---\s*\n(.*?)\n---\s*\n", s, re.S)
279
+ front = m.group(1)
280
+ new_front = re.sub(r"(?m)^(description:.*)$", r"\1 " + marker, front, count=1)
281
+ io.open(path, "w", encoding="utf-8").write(s[:m.start(1)] + new_front + s[m.end(1):])
282
+ PY2
283
+ append_row A10 'A fixture lesson whose first owner carries the evidence' \
284
+ "; result-class: failure; bank-evidence: file:$PLAN_REL#$(anchor BANKEV)"
285
+ printf '| A fixture lesson whose second owner carries none | `downstream-executor` | behavioral-evidence: RED-baseline; observed-failure: yes; result-class: failure; firing-path: file:skills/%s/SKILL.md#%s | `updated` | `%s/SKILL.md` fixture change |\n' \
286
+ "$OWNER2" "$(anchor A10B)" "$OWNER2" >> "$REPO/$LEDGER_REL"
287
+ commit_case "A10"; run_gate
288
+ report_leg A10 1 "多 owner 轮里每个 owner 各自欠证据(一个的 locator 不能替另一个还)" "$OWNER2"
289
+
290
+ # A11 自指的 command: 形态 -> 也必须红
291
+ # 第一版禁令只匹配 `file:skills/<owner>/`。同轮里顺手改了自己包内的一个脚本,就能写成
292
+ # `command:skills/<owner>/scripts/x.sh` 让改动给自己作证。两种 locator 都是在指一条路径,
293
+ # 禁的是那条路径,不是那个前缀拼法。
294
+ new_case case-a11; add_owner_rule A11; edit_owner_description A11; write_plan
295
+ printf '#!/usr/bin/env bash\necho fixture\n' > "$REPO/skills/$OWNER/scripts/fixture_a11.sh"
296
+ chmod +x "$REPO/skills/$OWNER/scripts/fixture_a11.sh"
297
+ append_row A11 'A fixture lesson citing its own package executable as bank evidence' \
298
+ "; result-class: failure; bank-evidence: command:skills/$OWNER/scripts/fixture_a11.sh"
299
+ commit_case "A11"; run_gate
300
+ report_leg A11 1 "自指的 command: 形态同样被拒(禁的是路径不是前缀拼法)" "$RC_MISSING"
301
+
302
+ # A12 跨轮不得串扰:轮1 只动 bank 且带证据,轮2 只动某 owner 的正文 -> 整体必须绿
303
+ # 曾经 routing_surface_touched 在 bank 变更时对**任何** owner 返回 true,于是轮1 会去要求
304
+ # 轮2 那个 owner 的行——把一个不相关的后续提交加进范围,就能改变对前一轮的判定。
305
+ # bank 是它自己的 subject,不是所有人的。
306
+ new_case case-a12; write_plan
307
+ touch_bank A12
308
+ printf '| A fixture round that moves the bank with evidence | `downstream-executor` | behavioral-evidence: RED-baseline; observed-failure: yes; result-class: failure; bank-evidence: file:%s#%s | `updated` | supporting note only |\n' \
309
+ "$PLAN_REL" "$(anchor BANKEV)" >> "$REPO/$LEDGER_REL"
310
+ commit_case "A12 round 1: bank only, evidenced"
311
+ add_owner_rule A12
312
+ append_row A12 'A later unrelated round that edits only owner body text' '; result-class: failure'
313
+ commit_case "A12 round 2: unrelated owner body"
314
+ run_gate
315
+ report_leg A12 0 "跨轮不串扰(bank 是自己的 subject,不是所有 owner 的)"
316
+
317
+ # A13 退化的 downscope token -> 必须红
318
+ # `\S+` 曾接受 `-`,而 include? 会在任意 bullet 行的连字符上命中:`downscoped:-` 就能
319
+ # 拿一条什么都没说的记录清偿义务。降范围是要被人查到的决定,偶然出现在散文里的字符不是。
320
+ new_case case-a13; add_owner_rule A13; edit_owner_description A13; write_plan
321
+ append_row A13 'A fixture lesson downscoping with a degenerate token' \
322
+ '; result-class: failure; bank-evidence: downscoped:-'
323
+ commit_case "A13"; run_gate
324
+ report_leg A13 1 "退化 token 不算留痕(`-` 会命中任意 bullet 的连字符)" "$RC_MISSING"
325
+
326
+ # B5 只动 bank 的轮里,声明行同样欠 result-class -> 必须红
327
+ # B 曾按变更 owner 收敛,而 bank-only 的轮没有变更 owner:那行声明行压根不被检查,
328
+ # 带着合法 bank-evidence 就整轮放行。非追溯性由 grammar 闸独立承担,B 不该再兼这份差事。
329
+ new_case case-b5; write_plan; touch_bank B5
330
+ printf '| A fixture bank-only round whose declaring row omits its class | `downstream-executor` | behavioral-evidence: RED-baseline; observed-failure: yes; bank-evidence: file:%s#%s | `updated` | supporting note only |\n' \
331
+ "$PLAN_REL" "$(anchor BANKEV)" >> "$REPO/$LEDGER_REL"
332
+ commit_case "B5"; run_gate
333
+ report_leg B5 1 "bank-only 轮的声明行同样欠 result-class(owner 收敛曾把它整个跳过)" "$RC_CLASS"
334
+
335
+ # A14 自指的等价路径拼法 -> 也必须红
336
+ # 禁令若拿裸 start_with? 比一种拼法,`./skills/<owner>/…` 与 `a/../` 绕路指的是同一个文件
337
+ # 却躲过检查。禁的是位置,就得在位置的规范形上判。
338
+ new_case case-a14; add_owner_rule A14; edit_owner_description A14; write_plan
339
+ append_row A14 'A fixture lesson citing its own package by an equivalent spelling' \
340
+ "; result-class: failure; bank-evidence: file:./skills/$OWNER/SKILL.md#$(anchor A14)"
341
+ commit_case "A14"; run_gate
342
+ report_leg A14 1 "等价路径拼法的自指同样被拒(在规范形上判位置)" "$RC_MISSING"
343
+
344
+ # A15 token 只是碰巧出现在别的行里 -> 必须红
345
+ # 只搜裸 token 时,一个常见英文词就能被无关行命中(`downscoped:evidence` 撞上
346
+ # 「Bank evidence anchor …」)。留痕要留的是那句声明本身,不是那个词。
347
+ new_case case-a15; add_owner_rule A15; edit_owner_description A15; write_plan
348
+ append_row A15 'A fixture lesson downscoping with an incidentally-occurring word' \
349
+ '; result-class: failure; bank-evidence: downscoped:evidence'
350
+ commit_case "A15"; run_gate
351
+ report_leg A15 1 "token 碰巧出现不算留痕(必须逐字记录 downscoped:<token>)" "$RC_MISSING"
352
+
353
+ # A16 新技能的第一版 description -> 必须红(创建也是路由面变更)
354
+ # 「两侧都要存在」曾把创建一并排除,理由写作「保守」。评审点破:一个新技能的第一版
355
+ # description 恰恰决定了哪些请求会到它那里,是最大的一次路由面变更,不是可豁免项。
356
+ new_case case-a16; write_plan
357
+ mkdir -p "$REPO/skills/fixture-new-owner"
358
+ printf -- '---\nname: fixture-new-owner\ndescription: A brand new routing surface that decides which requests reach this skill.\n---\n\n# Fixture\n\n- Rule %s must be recorded before the round lands.\n' "$(anchor A16)" \
359
+ > "$REPO/skills/fixture-new-owner/SKILL.md"
360
+ printf '| A fixture lesson introducing a new routing surface | `downstream-executor` | behavioral-evidence: RED-baseline; observed-failure: yes; result-class: failure; firing-path: file:skills/fixture-new-owner/SKILL.md#%s | `updated` | `fixture-new-owner/SKILL.md` fixture change |\n' \
361
+ "$(anchor A16)" >> "$REPO/$LEDGER_REL"
362
+ commit_case "A16"; run_gate
363
+ report_leg A16 1 "新技能的第一版 description 也欠 bank 证据(创建不是豁免)" "$RC_MISSING"
364
+
365
+ # A17 降范围 token 的前缀碰撞 -> 必须红
366
+ # `include?` 让 spec 里的 `downscoped:TOKENLONGER` 满足行里的 `downscoped:TOKEN`——
367
+ # 别人的 token 顺手替这一行还了债。声明必须在 token 边界处结束。
368
+ new_case case-a17; add_owner_rule A17; edit_owner_description A17; write_plan "DOWNSCOPE-A17-LONGER"
369
+ append_row A17 'A fixture lesson whose token is a strict prefix of the recorded one' \
370
+ '; result-class: failure; bank-evidence: downscoped:DOWNSCOPE-A17'
371
+ commit_case "A17"; run_gate
372
+ report_leg A17 1 "前缀碰撞不算留痕(声明须在 token 边界结束)" "$RC_MISSING"
373
+
374
+ # G3 删掉声明段、却把 marker 塞进一行台账 -> 仍必须按撤回处理
375
+ # 在整份 blob 上 include? 时,这样两边都读作「已声明」,撤回检测哑掉,之后每一轮
376
+ # 都继续被一个权威已不再陈述的语法判定。G2 抓不到它——它把所有含 marker 的行都删了。
377
+ new_case case-g3; add_owner_rule G3; write_plan
378
+ python3 - "$REPO/$LEDGER_REL" <<'STRIP3'
379
+ import io, sys
380
+ p = sys.argv[1]
381
+ s = io.open(p, encoding="utf-8").read()
382
+ kept = [l for l in s.splitlines(keepends=True)
383
+ if "result-class: failure|stable-success|insufficient-evidence" not in l]
384
+ kept.append("| A row that merely quotes result-class: failure|stable-success|insufficient-evidence | `x` | note | `not-applicable` | quote only |\n")
385
+ io.open(p, "w", encoding="utf-8").write("".join(kept))
386
+ STRIP3
387
+ append_row G3 'A fixture lesson hiding the marker inside a table row' '; result-class: failure'
388
+ commit_case "G3"; run_gate
389
+ report_leg G3 1 "marker 藏进台账行不算声明(行会引用,不会立法)" "impact_chain_grammar_withdrawn"
390
+
391
+ # A18 同一提交里改名 + 改 description -> 必须红
392
+ # 目标路径以「只是改名」被豁免、源路径以「没有 head 条目」被豁免,这次编辑就从两者之间
393
+ # 溜过去了。豁免给的是「description 没变」,不是「路径动过」。
394
+ new_case case-a18; write_plan
395
+ git -C "$REPO" mv skills/fixture-rename-src skills/fixture-rename-dst
396
+ python3 - "$REPO/skills/fixture-rename-dst/SKILL.md" "$(anchor A18)" <<'PY3'
397
+ import io, re, sys
398
+ path, marker = sys.argv[1], sys.argv[2]
399
+ s = io.open(path, encoding="utf-8").read()
400
+ m = re.match(r"\A---\s*\n(.*?)\n---\s*\n", s, re.S)
401
+ front = m.group(1)
402
+ new_front = re.sub(r"(?m)^(description:.*)$", r"\1 " + marker, front, count=1)
403
+ io.open(path, "w", encoding="utf-8").write(s[:m.start(1)] + new_front + s[m.end(1):])
404
+ PY3
405
+ printf -- '- Rule %s must be recorded before the round lands.\n' "$(anchor A18B)" >> "$REPO/skills/fixture-rename-dst/SKILL.md"
406
+ printf '| A fixture lesson renaming an owner and rewording its description at once | `downstream-executor` | behavioral-evidence: RED-baseline; observed-failure: yes; result-class: failure; firing-path: file:skills/fixture-rename-dst/SKILL.md#%s | `updated` | `fixture-rename-dst/SKILL.md` fixture change |\n' \
407
+ "$(anchor A18B)" >> "$REPO/$LEDGER_REL"
408
+ commit_case "A18"; run_gate
409
+ report_leg A18 1 "改名同时改 description 不得从两侧豁免之间溜过去" "$RC_MISSING"
410
+
411
+ # G4 撤回的诊断只能点名本闸真正实现的补救
412
+ # 上一版写着「或由具名风险 owner 承担」,而代码里没有任何解析风险 owner 的路径,exit 1
413
+ # 是无条件的——一条落不了地的补救承诺,等于把合法的有意撤回堵死却假装有出路。
414
+ # 这条钉的是**诊断与实现一致**:不许再出现只存在于措辞里的出口。
415
+ new_case case-g4; add_owner_rule G4; write_plan
416
+ python3 - "$REPO/$LEDGER_REL" <<'STRIP4'
417
+ import io, sys
418
+ p = sys.argv[1]
419
+ s = io.open(p, encoding="utf-8").read()
420
+ io.open(p, "w", encoding="utf-8").write(
421
+ "".join(l for l in s.splitlines(keepends=True)
422
+ if "result-class: failure|stable-success|insufficient-evidence" not in l))
423
+ STRIP4
424
+ append_row G4 'A fixture lesson withdrawing the declaration on purpose' '; result-class: failure'
425
+ commit_case "G4"; run_gate
426
+ if printf '%s' "$out" | grep -qi "named risk owner"; then
427
+ echo " G4: RED — 诊断仍在承诺一条本闸未实现的补救(named risk owner)"
428
+ legs_failed=$((legs_failed + 1))
429
+ else
430
+ report_leg G4 1 "撤回被拒,且诊断只点名真正实现的补救" "no data-side waiver"
431
+ fi
432
+
433
+ # A19 就地删掉 description 条目(文件保留)-> 必须红
434
+ # 「head 没有条目」曾被一律当作删除/改名走。可文件还在、只是不再声明路由面——那和改写它
435
+ # 一样是一次路由面变更,而且是让技能整个从路由里消失的那一种。
436
+ new_case case-a19; add_owner_rule A19; write_plan
437
+ python3 - "$REPO/skills/$OWNER/SKILL.md" <<'PY4'
438
+ import io, re, sys
439
+ path = sys.argv[1]
440
+ s = io.open(path, encoding="utf-8").read()
441
+ m = re.match(r"\A---\s*\n(.*?)\n---\s*\n", s, re.S)
442
+ front = m.group(1)
443
+ kept = [l for l in front.splitlines(keepends=True) if not l.startswith("description:")]
444
+ io.open(path, "w", encoding="utf-8").write(s[:m.start(1)] + "".join(kept).rstrip("\n") + s[m.end(1):])
445
+ PY4
446
+ append_row A19 'A fixture lesson deleting the description entry in place' '; result-class: failure'
447
+ commit_case "A19"; run_gate
448
+ report_leg A19 1 "就地删掉 description 也是路由面变更(文件还在,不是删除)" "$RC_MISSING"
449
+
450
+ echo "impact_chain_self_adjudication: legs_failed=$legs_failed"
451
+ if [ "$legs_failed" -ne 0 ]; then
452
+ echo "impact_chain_self_adjudication_failed=$legs_failed" >&2
453
+ exit 1
454
+ fi
455
+ echo "impact_chain_self_adjudication_ok"
@@ -53,7 +53,7 @@ FIRING_F="firing-path: file:skills/product-rd-workflow/SKILL.md#must record a RE
53
53
 
54
54
  # ---- A:合规撤回 —— 有类时必须绿,无类时必须红 ----
55
55
  new_case case-a; withdraw_fixture
56
- add_row "| A fixture claim is refuted by its primary source and is withdrawn wholesale | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
56
+ add_row "| A fixture claim is refuted by its primary source and is withdrawn wholesale | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
57
57
  commit_case "case A: compliant source-refuted withdrawal"; run_gate
58
58
  # A 的期望值在裁决后由绿改红:该类不再顶起 RED 底线(见 frozen-acceptance.md 的裁决记录)。
59
59
  # 合规撤回现在仍然被拦——它要么配一条 RED 行,要么由具名风险 owner 人工放行。
@@ -62,32 +62,32 @@ commit_case "case A: compliant source-refuted withdrawal"; run_gate
62
62
  # ---- B:真行为变更披该标签 —— 任何时候都必须红 ----
63
63
  new_case case-b
64
64
  printf '\n- Every fixture change must obtain approval before it lands.\n' >> "$REPO/$OWNER_REF"
65
- add_row "| A newly added normative rule wearing the withdrawal label | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
65
+ add_row "| A newly added normative rule wearing the withdrawal label | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
66
66
  commit_case "case B: real behaviour change wearing the label"; run_gate
67
67
  [ "$RC" != "0" ] && ok "B 真行为变更披标签 -> 仍红" || fail "B 不得通过(净增却用撤回类)"
68
68
 
69
69
  # ---- C:缺一手源 URL —— 必须红 ----
70
70
  new_case case-c; withdraw_fixture
71
- add_row "| A withdrawal whose row cites no refuting source | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; \`product-rd-workflow/SKILL.md\` |"
71
+ add_row "| A withdrawal whose row cites no refuting source | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; \`product-rd-workflow/SKILL.md\` |"
72
72
  commit_case "case C: missing refuting source"; run_gate
73
73
  [ "$RC" != "0" ] && ok "C 缺一手源 -> 仍红" || fail "C 不得通过(无源即无据)"
74
74
 
75
75
  # ---- D:缺零损失指针 —— 必须红 ----
76
76
  new_case case-d; withdraw_fixture
77
- add_row "| A withdrawal whose row carries no zero-loss map | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
77
+ add_row "| A withdrawal whose row carries no zero-loss map | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
78
78
  commit_case "case D: missing zero-loss pointer"; run_gate
79
79
  [ "$RC" != "0" ] && ok "D 缺零损失指针 -> 仍红" || fail "D 不得通过(义务保全无对照)"
80
80
 
81
- # ---- E:observed-failure: yes —— 必须红 ----
81
+ # ---- E:observed-failure: yes; result-class: failure —— 必须红 ----
82
82
  new_case case-e; withdraw_fixture
83
- add_row "| A withdrawal self-declaring an observed failure | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: yes | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
83
+ add_row "| A withdrawal self-declaring an observed failure | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: yes; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
84
84
  commit_case "case E: observed-failure yes"; run_gate
85
- [ "$RC" != "0" ] && ok "E observed-failure: yes -> 仍红" || fail "E 不得通过(分类语义不得自选)"
85
+ [ "$RC" != "0" ] && ok "E observed-failure: yes; result-class: failure -> 仍红" || fail "E 不得通过(分类语义不得自选)"
86
86
 
87
87
  # ---- F:既有类不得回归 ----
88
88
  new_case case-f
89
89
  printf '\n- Every fixture delivery must record a RED-baseline row before it lands.\n' >> "$REPO/$OWNER_REF"
90
- add_row "| An ordinary behaviour-changing rule with a RED-baseline row | \`downstream-executor\` | behavioral-evidence: RED-baseline; observed-failure: yes; $FIRING_F | \`updated\` | \`product-rd-workflow/SKILL.md\` |"
90
+ add_row "| An ordinary behaviour-changing rule with a RED-baseline row | \`downstream-executor\` | behavioral-evidence: RED-baseline; observed-failure: yes; result-class: failure; $FIRING_F | \`updated\` | \`product-rd-workflow/SKILL.md\` |"
91
91
  commit_case "case F: existing RED-baseline path"; run_gate
92
92
  if [ "$RC" = "0" ]; then ok "F 既有 RED-baseline 路径 -> 绿(无回归)"; else echo "--- F 完整输出 ---"; printf '%s\n' "$OUT"; fail "F 回归"; fi
93
93
 
@@ -95,8 +95,8 @@ if [ "$RC" = "0" ]; then ok "F 既有 RED-baseline 路径 -> 绿(无回归)"
95
95
  # 独立评审 REVIEW-1:any? 顶起底线时,真行为变更会搭便车。
96
96
  new_case case-g; withdraw_fixture
97
97
  printf '\n- Every unrelated fixture delivery must obtain approval before it lands. zzmixedrule\n' >> "$REPO/$OWNER_REF"
98
- add_row "| A compliant withdrawal alongside an unrelated change | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
99
- add_row "| An unrelated behaviour change riding along on a stable-control label | \`downstream-executor\` | behavioral-evidence: semantic-control; observed-failure: no; firing-path: file:skills/product-rd-workflow/SKILL.md#must obtain approval before it lands | \`updated\` | \`product-rd-workflow/SKILL.md\` |"
98
+ add_row "| A compliant withdrawal alongside an unrelated change | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
99
+ add_row "| An unrelated behaviour change riding along on a stable-control label | \`downstream-executor\` | behavioral-evidence: semantic-control; observed-failure: no; result-class: failure; firing-path: file:skills/product-rd-workflow/SKILL.md#must obtain approval before it lands | \`updated\` | \`product-rd-workflow/SKILL.md\` |"
100
100
  commit_case "case G: mixed rows"; run_gate
101
101
  [ "$RC" != "0" ] && ok "G 混合行 -> 仍红" || fail "G 不得通过(真行为变更搭撤回的便车)"
102
102
 
@@ -104,21 +104,21 @@ commit_case "case G: mixed rows"; run_gate
104
104
  # 独立挑战 CHALLENGE-1:删无关文字凑净负、加一条新规则、指针写不存在的锚。
105
105
  new_case case-h; withdraw_fixture
106
106
  printf '\n- Every smuggled fixture rule must be rejected by the withdrawal class. zzsmuggled\n' >> "$REPO/$OWNER_REF"
107
- add_row "| A smuggled rule hidden behind an offsetting deletion | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`README.md#no-such-anchor-exists-here\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
107
+ add_row "| A smuggled rule hidden behind an offsetting deletion | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`README.md#no-such-anchor-exists-here\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
108
108
  commit_case "case H: offset addition with bogus anchor"; run_gate
109
109
  [ "$RC" != "0" ] && ok "H 抵消式新增 + 假锚点 -> 仍红" || fail "H 不得通过(新增规范行 / 锚点不解析)"
110
110
 
111
111
  # ---- I:脚本改动、零删除 —— 必须红(旧代理谓词看不见脚本)----
112
112
  new_case case-i
113
113
  printf '\n# fixture: an added shell line that changes behaviour without matching any prose predicate\n' >> "$REPO/skills/product-rd-workflow/scripts/check-agent-contract-coverage.sh"
114
- add_row "| A script change wearing the withdrawal label with nothing deleted | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
114
+ add_row "| A script change wearing the withdrawal label with nothing deleted | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
115
115
  commit_case "case I: script change, no deletion"; run_gate
116
116
  [ "$RC" != "0" ] && ok "I 脚本改动零删除 -> 仍红" || fail "I 不得通过(非 .md、且无删除)"
117
117
 
118
118
  # ---- J:`Always` 规则、零删除 —— 必须红(旧谓词故意排除 always)----
119
119
  new_case case-j
120
120
  printf '\n- Always authenticate fixture requests before dispatch.\n' >> "$REPO/$OWNER_REF"
121
- add_row "| An Always-phrased rule wearing the withdrawal label with nothing deleted | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
121
+ add_row "| An Always-phrased rule wearing the withdrawal label with nothing deleted | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
122
122
  commit_case "case J: Always rule, no deletion"; run_gate
123
123
  [ "$RC" != "0" ] && ok "J Always 规则零删除 -> 仍红" || fail "J 不得通过(有新增行)"
124
124
 
@@ -126,33 +126,33 @@ commit_case "case J: Always rule, no deletion"; run_gate
126
126
  # 独立评审:chmod 在 --name-status 里显示为 M、在 --numstat 里记 0/0。
127
127
  new_case case-k; withdraw_fixture
128
128
  chmod 755 "$REPO/skills/product-rd-workflow/references/adr-convention.md"
129
- add_row "| A mode change riding along with a genuine deletion | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
129
+ add_row "| A mode change riding along with a genuine deletion | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
130
130
  commit_case "case K: chmod plus deletion"; run_gate
131
131
  [ "$RC" != "0" ] && ok "K 改权限 + 删除 -> 仍红" || fail "K 不得通过(mode 变更未被 numstat 反映)"
132
132
 
133
133
  # ---- L:指针路径穿越出仓 —— 必须红 ----
134
134
  new_case case-l; withdraw_fixture
135
- add_row "| A withdrawal whose zero-loss pointer escapes the repository | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`../../../etc/hosts#localhost\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
135
+ add_row "| A withdrawal whose zero-loss pointer escapes the repository | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`../../../etc/hosts#localhost\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
136
136
  commit_case "case L: traversal pointer"; run_gate
137
137
  [ "$RC" != "0" ] && ok "L 指针穿越出仓 -> 仍红" || fail "L 不得通过(路径逃出仓库)"
138
138
 
139
139
  # ---- M:锚点是存在但无意义的单字符子串 —— 必须红 ----
140
140
  new_case case-m; withdraw_fixture
141
- add_row "| A withdrawal whose anchor is a bare existing substring | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#a\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
141
+ add_row "| A withdrawal whose anchor is a bare existing substring | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#a\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
142
142
  commit_case "case M: one-character substring anchor"; run_gate
143
143
  [ "$RC" != "0" ] && ok "M 单字符子串锚 -> 仍红" || fail "M 不得通过(锚点未落在标题上)"
144
144
 
145
145
  # ---- N:锚点是存在但不相干的整词 —— 必须红 ----
146
146
  new_case case-n; withdraw_fixture
147
- add_row "| A withdrawal whose anchor is an unrelated existing word | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#survives-verbatim\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
147
+ add_row "| A withdrawal whose anchor is an unrelated existing word | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#survives-verbatim\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
148
148
  commit_case "case N: unrelated existing substring anchor"; run_gate
149
149
  [ "$RC" != "0" ] && ok "N 不相干整词锚 -> 仍红" || fail "N 不得通过(锚点未落在标题上)"
150
150
 
151
151
  # ---- O:既有 semantic-control 路径不得回归(配对 RED 行)----
152
152
  new_case case-o
153
153
  printf '\n- Every fixture control rule must be recorded before it lands. zzsemctl\n' >> "$REPO/$OWNER_REF"
154
- add_row "| An unchanged control alongside a RED-baseline row | \`downstream-executor\` | behavioral-evidence: semantic-control; observed-failure: no; firing-path: file:skills/product-rd-workflow/SKILL.md#must be recorded before it lands | \`updated\` | \`product-rd-workflow/SKILL.md\` |"
155
- add_row "| The behaviour change the control accompanies | \`downstream-executor\` | behavioral-evidence: RED-baseline; observed-failure: yes; firing-path: file:skills/product-rd-workflow/SKILL.md#must be recorded before it lands | \`updated\` | \`product-rd-workflow/SKILL.md\` |"
154
+ add_row "| An unchanged control alongside a RED-baseline row | \`downstream-executor\` | behavioral-evidence: semantic-control; observed-failure: no; result-class: failure; firing-path: file:skills/product-rd-workflow/SKILL.md#must be recorded before it lands | \`updated\` | \`product-rd-workflow/SKILL.md\` |"
155
+ add_row "| The behaviour change the control accompanies | \`downstream-executor\` | behavioral-evidence: RED-baseline; observed-failure: yes; result-class: failure; firing-path: file:skills/product-rd-workflow/SKILL.md#must be recorded before it lands | \`updated\` | \`product-rd-workflow/SKILL.md\` |"
156
156
  commit_case "case O: semantic-control beside RED-baseline"; run_gate
157
157
  [ "$RC" = "0" ] && ok "O semantic-control + RED-baseline -> 绿(无回归)" || { echo "--- O ---"; printf '%s\n' "$OUT" | tail -3; fail "O 既有路径回归"; }
158
158
 
@@ -163,7 +163,7 @@ import io,sys
163
163
  p=sys.argv[1]
164
164
  io.open(p,'w',encoding='utf-8').write("# 零损失义务对照\n\n| before 义务 | 去向 |\n| --- | --- |\n| 某条义务 | survives-verbatim: 别处 |\n")
165
165
  PYP
166
- add_row "| A withdrawal whose map does not quote what was removed | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
166
+ add_row "| A withdrawal whose map does not quote what was removed | \`downstream-executor\` | behavioral-evidence: source-refuted; observed-failure: no; result-class: failure | \`updated\` | zero-loss: \`$ZLOSS#零损失义务对照\`; refuting source: $SRC; \`product-rd-workflow/SKILL.md\` |"
167
167
  commit_case "case P: map does not account for deleted text"; run_gate
168
168
  [ "$RC" != "0" ] && ok "P 对照表未逐字交代被删内容 -> 仍红" || fail "P 不得通过(删了什么没抄出来)"
169
169