@ccoalm/ccl-skills 0.14.0 → 0.15.1

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 (59) hide show
  1. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/ccl-skills.ts +80 -4
  2. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-install-skills.md +16 -4
  3. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.sh +13 -2
  4. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/test.sh +53 -0
  5. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/SKILL.md +19 -24
  6. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/client-routing.md +32 -32
  7. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/manual-invocation-and-prompts.md +16 -14
  8. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md +24 -26
  9. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/AGENTS.md +11 -0
  10. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/claude_review.sh +60 -209
  11. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/init_policy_matrix.py +114 -367
  12. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_probe_result.py +52 -672
  13. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +17 -3
  14. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/runtime-surface-verification-design.md +4 -2
  15. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_claude_review_probe.sh +77 -444
  16. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_init_policy_matrix.sh +33 -98
  17. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_probe_result.sh +57 -173
  18. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +65 -0
  19. package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/SKILL.md +1 -1
  20. package/dist/assets/marketplace/plugins/ccl-skills/skills/grill-me/SKILL.md +1 -1
  21. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/SKILL.md +1 -1
  22. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/SKILL.md +5 -5
  23. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/alerting-and-on-call.md +8 -0
  24. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/SKILL.md +1 -1
  25. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/SKILL.md +14 -14
  26. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/dual-sidecar-and-traffic-config-center.md +1 -1
  27. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/grpc-authority-workaround.md +40 -83
  28. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/mesh-architecture.md +2 -2
  29. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/retry-timeout-circuit-breaker.md +44 -37
  30. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-recipe.md +1 -1
  31. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +2 -2
  32. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/delivery-lifecycle.md +1 -1
  33. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/rd-standards-doc-family-checklist.md +2 -2
  34. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-baseline/SKILL.md +1 -1
  35. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/SKILL.md +1 -1
  36. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/SKILL.md +9 -6
  37. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/eval-routing.md +6 -0
  38. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/external-practice-controls.md +4 -4
  39. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +52 -0
  40. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-golden-trace.rb +31 -7
  41. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing-bank.rb +62 -3
  42. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +188 -13
  43. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/review_ledger_binding.py +36 -13
  44. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/skill-behavior-eval.py +103 -21
  45. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_impact_chain_refscripts.sh +261 -14
  46. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +2 -0
  47. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_resolution.sh +253 -0
  48. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_runtime.py +428 -0
  49. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_verdict_differential.sh +49 -25
  50. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_review_ledger_binding.sh +63 -5
  51. package/dist/assets/release.json +76 -56
  52. package/dist/claude-adapter.js +14 -7
  53. package/dist/codex-host.d.ts +1 -3
  54. package/dist/codex-host.js +6 -9
  55. package/dist/host-probe.d.ts +11 -0
  56. package/dist/host-probe.js +27 -0
  57. package/dist/opencode-adapter.js +24 -19
  58. package/dist/unified.js +11 -9
  59. package/package.json +1 -1
@@ -146,8 +146,8 @@ register_mutation() {
146
146
  # SPECIFIC rejection reason in its stderr.
147
147
  self_check_stderr="$tmp_dir/guard_self_check.err"
148
148
  if mutate_and_expect_mismatch guard-self-check-broken-mutant \
149
- 'def is_bare_host_identifier(identifier: str) -> bool:' \
150
- 'def is_bare_host_identifier(identifier: str) -> bool # deliberately broken' \
149
+ 'def is_authority_name(name: str) -> bool:' \
150
+ 'def is_authority_name(name: str) -> bool # deliberately broken' \
151
151
  >/dev/null 2>"$self_check_stderr"
152
152
  then
153
153
  printf 'the walk accepted a BROKEN mutant as sensitivity; its own guard does not work, so every result below is meaningless\n' >&2
@@ -178,104 +178,39 @@ register_mutation drop-field-name-sanitizer \
178
178
  ' text = name if isinstance(name, str) else repr(name)' \
179
179
  ' return name if isinstance(name, str) else repr(name)'
180
180
 
181
- # The two directions of the host-vocabulary class. Both must be detectable, and
182
- # they fail for opposite reasons: widening it launders a proven customization
183
- # into the cascadable class, while removing it restores the total-outage
184
- # behaviour this class exists to prevent.
185
- register_mutation widen-host-vocabulary-to-any-entry \
186
- ' return bool(BARE_HOST_IDENTIFIER.fullmatch(identifier))' \
187
- ' return True'
181
+ # The MCP list is the one customization surface still required to be empty;
182
+ # dropping that requirement must flip every declared-mcp row.
183
+ register_mutation drop-mcp-empty-requirement \
184
+ 'REQUIRED_EMPTY_INIT_FIELDS = (
185
+ "mcp_servers",
186
+ )' \
187
+ 'REQUIRED_EMPTY_INIT_FIELDS = ()'
188
188
 
189
- register_mutation terminalize-host-vocabulary \
190
- ' return bool(BARE_HOST_IDENTIFIER.fullmatch(identifier))' \
191
- ' return False'
192
-
193
- # Dynamic host command vocabulary is useful only if both halves are enforced:
194
- # the baseline must affect the allow decision, and its CLI version must bind the
195
- # formal init. Baseline skills are deliberately not authority because a leaked
196
- # user skill would otherwise become callable in the formal run.
197
- register_mutation drop-host-baseline-vocabulary \
198
- ' if customization_entry_allowed(
199
- field,
200
- entry,
201
- expected_native_skills,
202
- baseline_commands,
203
- baseline_skills,
204
- ):' \
205
- ' if customization_entry_allowed(
206
- field,
207
- entry,
208
- expected_native_skills,
209
- set(),
210
- set(),
211
- ):'
212
-
213
- register_mutation authorize-host-baseline-skill \
214
- ' identifier in KNOWN_SAFE_BUILTIN_SKILLS
215
- or identifier in selected_names' \
216
- ' identifier in KNOWN_SAFE_BUILTIN_SKILLS
217
- or identifier in baseline_skills
218
- or identifier in selected_names'
219
-
220
- register_mutation drop-host-baseline-required-empty-check \
221
- ' if field not in HOST_VOCABULARY_FIELDS and init_event.get(field) != []:' \
222
- ' if field not in HOST_VOCABULARY_FIELDS and False:'
223
-
224
- register_mutation widen-host-baseline-to-namespaced-entries \
225
- ' or any(
226
- identifier not in known_host_identifiers
227
- and not is_bare_host_identifier(identifier)
228
- for identifier in identifiers
229
- )' \
230
- ' or any(identifier == "<unidentified>" for identifier in identifiers)'
231
-
232
- register_mutation drop-host-baseline-version-binding \
233
- ' if baseline_version is not None and ev.get("claude_code_version") != baseline_version:
234
- # The two invocations no longer prove one same-version host
235
- # vocabulary snapshot. Refuse this lane, but treat the mismatch as
236
- # capability drift rather than a proven tool/authority breach so a
237
- # different reviewer may continue.
238
- unknown_fields.add("claude_code_version:host-baseline-mismatch")' \
239
- ' if False:
240
- unknown_fields.add("claude_code_version:host-baseline-mismatch")'
189
+ # Vocabulary must stay data. Reading a populated skill/command/plugin list as a
190
+ # breach is exactly the outage class policy G removed -- a new host built-in or
191
+ # an installed plugin took the reviewer lane down while proving nothing -- so
192
+ # the oracle must see the class come back.
193
+ register_mutation judge-vocabulary-as-capability \
194
+ ' elif field in KNOWN_VOCABULARY_INIT_FIELDS:
195
+ # Vocabulary, not capability: any value, any shape. Whatever a
196
+ # CLI release or an installed plugin lists here cannot be
197
+ # invoked past the pinned `tools` set.
198
+ continue' \
199
+ ' elif field in KNOWN_VOCABULARY_INIT_FIELDS:
200
+ if isinstance(value, (list, dict)) and value:
201
+ nonempty.add(field)'
241
202
 
242
- # The shape gate. Dropping it lets a structured entry be judged on its `name`
243
- # alone, which reaches TOLERATED when that name is an allowed built-in -- the
244
- # most severe class in this file, so it needs its own mutant rather than riding
245
- # on the bare-identifier one.
246
- register_mutation drop-whole-value-gate \
247
- ' if field in HOST_VOCABULARY_FIELDS and (
248
- not host_entry_is_whole(entry, identifier)
249
- ):' \
250
- ' if False:'
251
-
252
- # ...and the weaker version of the same gate: checking only the SHAPE (a plain
253
- # string) while still judging a truncated token. This is what the gate looked
254
- # like before the third finding, so it must be detectable on its own.
255
- register_mutation weaken-whole-value-gate-to-shape-only \
256
- ' normalized = entry.lower()
257
- if normalized.startswith("/"):
258
- normalized = normalized[1:]
259
- return normalized == identifier' \
260
- ' return True'
261
-
262
- # The regression a round-9 review found in the gate itself: stripping before the
263
- # comparison re-introduces the lossiness the gate exists to reject, and wrapping
264
- # an ALLOWLISTED name in whitespace then reaches TOLERATED.
265
- register_mutation strip-before-the-whole-value-comparison \
266
- ' normalized = entry.lower()' \
267
- ' normalized = entry.strip().lower()'
268
-
269
- register_mutation drop-host-vocabulary-breach-guard \
270
- ' if unclassifiable_vocabulary and not surface_breached:' \
271
- ' if unclassifiable_vocabulary:'
272
-
273
- # The two parse paths implement the class separately, so each needs its own
274
- # mutant: dropping it from the main-invocation predicate leaves the probe path
275
- # correct, which is exactly the shape of divergence this oracle exists to catch.
276
- register_mutation drop-host-vocabulary-from-main-path \
277
- 'runtime_drift_only = bool(unknown or unverifiable or vocabulary) and not (' \
278
- 'runtime_drift_only = bool(unknown or unverifiable) and not ('
203
+ # ...and the softer misreading: vocabulary as schema drift. Same outage, one
204
+ # client switch cheaper, still wrong.
205
+ register_mutation drift-on-vocabulary \
206
+ ' elif field in KNOWN_VOCABULARY_INIT_FIELDS:
207
+ # Vocabulary, not capability: any value, any shape. Whatever a
208
+ # CLI release or an installed plugin lists here cannot be
209
+ # invoked past the pinned `tools` set.
210
+ continue' \
211
+ ' elif field in KNOWN_VOCABULARY_INIT_FIELDS:
212
+ if isinstance(value, (list, dict)) and value:
213
+ unknown_fields.add(field)'
279
214
 
280
215
  # Dispatch the registered walk with bounded concurrency. The mutants are
281
216
  # independent by construction: each writes its own `mutant_<name>.py` copy under
@@ -111,37 +111,9 @@ run_ok_runtime_surface() {
111
111
  --require-empty-init --expected-tools "$expected_tools" --allow-expected-tool-use --runtime-surface-only >/dev/null
112
112
  }
113
113
 
114
- run_ok_expected_native_skills() {
115
- local expected_native_skills="$1" required_native_skills="$2" rc="$3" stdout="$4"
116
- local stderr="${5:-}"
117
- printf '%s' "$stdout" > "$tmp_dir/stdout"
118
- printf '%s' "$stderr" > "$tmp_dir/stderr"
119
- python3 "$parser" "$rc" "$tmp_dir/stdout" "$tmp_dir/stderr" \
120
- --require-empty-init \
121
- --expected-native-skills "$expected_native_skills" \
122
- --required-native-skills "$required_native_skills" >/dev/null
123
- }
124
-
125
- run_reason_expected_native_skills() {
126
- local expected_native_skills="$1" required_native_skills="$2" rc="$3" stdout="$4"
127
- local expected="$5" stderr="${6:-}" out
128
- printf '%s' "$stdout" > "$tmp_dir/stdout"
129
- printf '%s' "$stderr" > "$tmp_dir/stderr"
130
- if out="$(python3 "$parser" "$rc" "$tmp_dir/stdout" "$tmp_dir/stderr" \
131
- --require-empty-init \
132
- --expected-native-skills "$expected_native_skills" \
133
- --required-native-skills "$required_native_skills")"; then
134
- printf 'expected native-skill probe parser failure\n' >&2
135
- return 1
136
- fi
137
- printf '%s' "$out" | grep -F "$expected" >/dev/null
138
- }
139
-
140
- # Runtime-surface variants used to pin the main-invocation drift guard. The
141
- # first omits --allow-expected-tool-use (the wrapper always passes it, so this
142
- # is the guard's defence-in-depth leg); the second exercises the owner-aware
143
- # path, where a permitted-looking customization list can still carry an
144
- # unexpected identifier.
114
+ # Runtime-surface variant used to pin the main-invocation drift guard: it
115
+ # omits --allow-expected-tool-use (the wrapper always passes it, so this is the
116
+ # guard's defence-in-depth leg).
145
117
  run_reason_runtime_surface_no_tool_use_allowance() {
146
118
  local expected_tools="$1" rc="$2" stdout="$3" expected="$4" stderr="${5:-}" out
147
119
  printf '%s' "$stdout" > "$tmp_dir/stdout"
@@ -158,24 +130,6 @@ run_reason_runtime_surface_no_tool_use_allowance() {
158
130
  printf '%s' "$out" | grep -F "$expected" >/dev/null
159
131
  }
160
132
 
161
- run_reason_runtime_surface_native() {
162
- local expected_native_skills="$1" rc="$2" stdout="$3" expected="$4" stderr="${5:-}" out
163
- printf '%s' "$stdout" > "$tmp_dir/stdout"
164
- printf '%s' "$stderr" > "$tmp_dir/stderr"
165
- if out="$(python3 "$parser" "$rc" "$tmp_dir/stdout" "$tmp_dir/stderr" \
166
- --require-empty-init --expected-tools "" --allow-expected-tool-use --runtime-surface-only \
167
- --expected-native-skills "$expected_native_skills" \
168
- --required-native-skills "$expected_native_skills")"; then
169
- printf 'expected owner-aware runtime-surface parser failure\n' >&2
170
- return 1
171
- fi
172
- if printf '%s' "$out" | grep -F 'unrecognized surface-shaped init field' >/dev/null; then
173
- printf 'drift reason must not launder an unexpected identifier: %s\n' "$out" >&2
174
- return 1
175
- fi
176
- printf '%s' "$out" | grep -F "$expected" >/dev/null
177
- }
178
-
179
133
  run_reason_runtime_surface_implicit_strict() {
180
134
  local stdout="$1" expected="$2" out
181
135
  printf '%s' "$stdout" > "$tmp_dir/stdout"
@@ -292,34 +246,25 @@ run_ok_strict 0 "$empty_init"$'\n{"type":"result","subtype":"success","is_error"
292
246
  read_init='{"type":"system","subtype":"init","permissionMode":"default","tools":["Read","Grep","Glob"],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[]}'
293
247
  run_ok_expected_tools 'Read,Grep,Glob' 0 "$read_init"$'\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
294
248
  run_ok_expected_tool_use 'Read,Grep,Glob' 0 "$read_init"$'\n{"type":"assistant","message":{"content":[{"type":"tool_use","name":"Read","input":{}}]}}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
295
- # Claude Code 2.1.218 exposes these exact host built-ins whenever an explicit
296
- # plugin enables the command registry. They are not plugin-owned commands or
297
- # model tools, so a selected native skill remains valid.
298
- run_ok_expected_native_skills 'testing-strategy' 'testing-strategy' 0 \
299
- $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy","workflow-launch-exec","ultrareview"],"skills":["testing-strategy"],"plugins":["ccl-skills"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
300
- # The same owner-aware path remains value-exact: an arbitrary command cannot
301
- # hide beside the two registered host built-ins.
302
- run_reason_expected_native_skills 'testing-strategy' 'testing-strategy' 0 \
303
- $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy","workflow-launch-exec","ultrareview","unrelated:danger"],"skills":["testing-strategy"],"plugins":["ccl-skills"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' \
304
- 'runtime capability surface is not empty'
305
- # A dict-shaped entry is never whole, however allowed its `name` reads. The
306
- # entry hides a sibling key the identifier helper discards, so clearing it on
307
- # the truncated name would accept a customization whose proof was in the part
308
- # that was thrown away. host_entry_is_whole must reject the shape BEFORE the
309
- # allowlist reads it; flipping its non-string branch to True makes this case
310
- # pass, which is exactly the regression this asserts.
311
- run_reason_expected_native_skills 'testing-strategy' 'testing-strategy' 0 \
312
- $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy","workflow-launch-exec",{"name":"ultrareview","path":"hidden-sibling-value"}],"skills":["testing-strategy"],"plugins":["ccl-skills"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' \
313
- 'runtime capability surface is not empty'
314
-
315
- # A matching name in either executable surface is still terminal. Built-in UI
316
- # registration never authorizes a tool declaration or invocation.
317
- run_reason_expected_native_skills 'testing-strategy' 'testing-strategy' 0 \
249
+ # Claude Code 2.1.261 lists its own built-in commands and skills, plus every
250
+ # installed plugin entry, whenever an explicit plugin enables the command
251
+ # registry. They are vocabulary, not model tools: any entry is tolerated on
252
+ # both parse paths, including names the host adds tomorrow, namespaced or
253
+ # structured entries, and the selected owner's own namespaced command.
254
+ vocab_init='{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy","workflow-launch-exec","ultrareview","workflow-authoring","unrelated:danger",{"name":"ultrareview","path":"hidden-sibling-value"}],"terminal_slash_commands":["doctor"],"skills":["testing-strategy","workflow-authoring","brand-new-skill"],"plugins":["ccl-skills",{"name":"other","path":"/p"}]}'
255
+ run_ok_strict 0 "$vocab_init"$'\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
256
+ run_ok_runtime_surface '' 0 "$vocab_init"$'\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
257
+ # A matching name in either executable surface is still terminal. Vocabulary
258
+ # never authorizes a tool declaration, a tool invocation, or an MCP server.
259
+ run_reason_strict 0 \
318
260
  $'{"type":"system","subtype":"init","permissionMode":"default","tools":["workflow-launch-exec"],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy","workflow-launch-exec","ultrareview"],"skills":["testing-strategy"],"plugins":["ccl-skills"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' \
319
261
  'runtime capability surface is not empty'
320
- run_reason_expected_native_skills 'testing-strategy' 'testing-strategy' 0 \
262
+ run_reason_strict 0 \
321
263
  $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy","workflow-launch-exec","ultrareview"],"skills":["testing-strategy"],"plugins":["ccl-skills"]}\n{"type":"assistant","message":{"content":[{"type":"tool_use","name":"workflow-launch-exec","input":{}}]}}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' \
322
264
  'runtime capability surface is not empty'
265
+ run_reason_strict 0 \
266
+ $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":["inherited"],"slash_commands":["ccl-skills:testing-strategy","workflow-launch-exec","ultrareview"],"skills":["testing-strategy"],"plugins":["ccl-skills"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' \
267
+ 'runtime capability surface is not empty'
323
268
  run_reason_expected_tools_implicit_strict 'Read,Grep,Glob' 0 'ok' \
324
269
  'missing the required stream-json init evidence'
325
270
  run_reason_runtime_surface '' 0 "$empty_init"$'\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'auth-path false negative' 'Not logged in · Please run /login'
@@ -422,42 +367,31 @@ run_reason_strict 0 $'{"type":"system","subtype":"init","permissionMode":"defaul
422
367
  run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":["Bash"],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[],"capabilities":["interrupt_cancel_queued_v1"],"fast_mode_disabled_reason":"sdk_opt_in_required"}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'the no-tool sandbox is not enforced'
423
368
  run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":["Write"],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[],"capabilities":["interrupt_cancel_queued_v1"],"fast_mode_disabled_reason":"sdk_opt_in_required"}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
424
369
  run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[],"fast_mode_disabled_reason":"sdk_opt_in_required"}\n{"type":"assistant","message":{"content":[{"type":"tool_use","name":"Write","input":{}}]}}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
425
- # Drift + a real breach in the same init must report as the BREACH. Review round
426
- # 4 suspected `unexpected_customization_identifiers` was missing from the
427
- # main-path `runtime_drift_only` guard; it stays out because every identifier it
428
- # reports lands in a set that IS in the guard, and these fixtures pin that so the
429
- # soft drift reason can never launder a combined case. Note which set: an
430
- # identifier that is provably a customization marks its field non-empty, while a
431
- # bare host-vocabulary name lands in the unclassifiable set instead — so the
432
- # fixtures below use a NAMESPACED foreign identifier, which is the one that is
433
- # still a proven breach.
434
- run_reason_runtime_surface '' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":["some-skill"],"plugins":[],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","structured_output":{"mode":"challenge","findings":[]}}' 'runtime isolation surface is invalid'
435
- run_reason_runtime_surface '' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":["some-skill"],"plugins":[],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","structured_output":{"mode":"challenge","findings":[]}}' 'unexpected_customizations=skills'
436
- # ...and the main-path guard must match the probe path's breach set exactly.
437
- # A tool_use with no allowance, and an unexpected identifier under an owner-aware
438
- # run, are the two legs where the two guards could silently diverge again.
370
+ # Drift + a real breach in the same init must report as the BREACH, and these
371
+ # fixtures pin that so the soft drift reason can never launder a combined case.
372
+ # The breach here is an inherited MCP server -- the one customization list that
373
+ # is still a capability surface.
374
+ run_reason_runtime_surface '' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":["some-server"],"slash_commands":[],"skills":[],"plugins":[],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","structured_output":{"mode":"challenge","findings":[]}}' 'runtime isolation surface is invalid'
375
+ run_reason_runtime_surface '' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":["some-server"],"slash_commands":[],"skills":[],"plugins":[],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","structured_output":{"mode":"challenge","findings":[]}}' 'unexpected_customizations=mcp_servers'
376
+ # ...and the main-path guard must match the probe path's breach set exactly:
377
+ # a tool_use with no allowance is the leg where the two guards could silently
378
+ # diverge again.
439
379
  run_reason_runtime_surface_no_tool_use_allowance 'Write' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":["Write"],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[],"future_surface":["x"]}\n{"type":"assistant","message":{"content":[{"type":"tool_use","name":"Write","input":{}}]}}\n{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","structured_output":{"mode":"challenge","findings":[]}}' 'runtime isolation surface is invalid'
440
- run_reason_runtime_surface_native 'testing-strategy' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy"],"skills":["testing-strategy","other-plugin:unrelated-skill"],"plugins":["ccl-skills"],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","structured_output":{"mode":"challenge","findings":[]}}' 'unexpected_customization_identifiers=skills:other-plugin:unrelated-skill'
441
- # The same fixture with a BARE unknown skill is deliberately the other verdict:
442
- # it reports the soft class, because a bare name outside the built-in snapshot is
443
- # not proof of a customization. Pinned explicitly so the split above is asserted
444
- # rather than merely allowed by the fixture's choice of identifier. `future_surface`
445
- # is dropped here on purpose — with schema drift also present the reason is the
446
- # broader drift phrase, which this helper forbids by design; that combined case is
447
- # pinned in the policy matrix instead.
448
- run_reason_runtime_surface_native 'testing-strategy' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy"],"skills":["testing-strategy","unrelated-skill"],"plugins":["ccl-skills"]}\n{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","structured_output":{"mode":"challenge","findings":[]}}' 'unclassifiable_host_vocabulary=skills:unrelated-skill'
380
+ # Vocabulary beside schema drift is still only drift: the populated lists add
381
+ # nothing to the verdict, so the reason stays the fallback-eligible drift phrase.
382
+ run_reason_runtime_surface '' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["ccl-skills:testing-strategy","brand-new-builtin"],"skills":["testing-strategy","other-plugin:unrelated-skill"],"plugins":["ccl-skills"],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","structured_output":{"mode":"challenge","findings":[]}}' 'unrecognized surface-shaped init field'
449
383
  # Same rule on the probe path: drift alongside a declared surface, an unexpected
450
384
  # tool, or a tool_use must report the BREACH. The drift phrase routes to
451
385
  # fallback, so reaching it first would launder a real breach.
452
- combo_drift_breach=$'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":["some-skill"],"plugins":[],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
386
+ combo_drift_breach=$'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":["some-server"],"slash_commands":[],"skills":[],"plugins":[],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
453
387
  run_reason 0 "$combo_drift_breach" 'runtime capability surface is not empty'
454
388
  run_reason_excludes 0 "$combo_drift_breach" 'unrecognized surface-shaped init field'
455
389
  combo_drift_tool=$'{"type":"system","subtype":"init","permissionMode":"default","tools":["Write"],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[],"future_surface":["x"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
456
390
  run_reason_excludes 0 "$combo_drift_tool" 'unrecognized surface-shaped init field'
457
391
  combo_drift_use=$'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[],"future_surface":["x"]}\n{"type":"assistant","message":{"content":[{"type":"tool_use","name":"Write","input":{}}]}}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
458
392
  run_reason_excludes 0 "$combo_drift_use" 'unrecognized surface-shaped init field'
459
- # A declared CCL skill/plugin surface is still rejected under drift tolerance.
460
- run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":["some-skill"],"plugins":[],"fast_mode_disabled_reason":"sdk_opt_in_required"}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
393
+ # An inherited MCP server is still rejected under drift tolerance.
394
+ run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":["some-server"],"slash_commands":[],"skills":[],"plugins":[],"fast_mode_disabled_reason":"sdk_opt_in_required"}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
461
395
  # THE flakiness fix: model hallucinates TOOL_ENABLED but every runtime surface is empty -> pass.
462
396
  run_ok 0 "$empty_init"$'\n{"type":"result","subtype":"success","is_error":false,"num_turns":1,"permission_denials":[],"result":"TOOL_ENABLED"}'
463
397
  # clean ok via stream -> pass.
@@ -470,9 +404,10 @@ run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","too
470
404
  # declared set; unknown/non-string elements make init ground truth invalid.
471
405
  run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[{"name":"Bash"}],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'missing required isolation fields'
472
406
  run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[{"name":"x"}],"slash_commands":[],"skills":[],"plugins":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
473
- run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["review"],"skills":[],"plugins":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
474
- run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":["review"],"plugins":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
475
- run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":["x"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
407
+ # Skill, command and plugin lists are vocabulary: populated is not a breach.
408
+ run_ok 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["review"],"skills":[],"plugins":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
409
+ run_ok 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":["review"],"plugins":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
410
+ run_ok 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":["x"]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
476
411
  # closes the latent false-negative: Bash DECLARED in init.tools, reply says ok -> fail.
477
412
  run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":["Bash","Read"],"mcp_servers":[],"slash_commands":[],"skills":[],"plugins":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'Bash tool is available'
478
413
  # Bash actually INVOKED via tool_use block -> fail (sandbox not enforced).
@@ -509,76 +444,25 @@ run_reason 0 "$empty_init"$'\n{"type":"system","subtype":"init","permissionMode"
509
444
  # pretty-printed single envelope (bare-brace lines) must still pass via the text fallback.
510
445
  run_ok 0 $'{\n "type": "result",\n "subtype": "success",\n "is_error": false,\n "result": "ok"\n}'
511
446
 
512
- # --- host vocabulary is unverifiable, not a proven breach -------------------
513
- # The review-skill invocation is the only shape whose customization lists are
514
- # populated by the host's own built-ins, so a name this repo's snapshot does not
515
- # know cannot be shown to be a user customization. It must refuse WITHOUT
516
- # terminating the lane; anything that IS provably a customization must not
517
- # inherit that softer class. `product-rd-workflow` is used as the selected skill
518
- # because a name that is also a built-in skill trips the ambiguous-owner guard
519
- # and would mask the verdict under test.
520
- native_vocab_result=$'\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
521
- native_vocab_init() {
522
- printf '{"type":"system","subtype":"init","permissionMode":"default","tools":%s,"mcp_servers":[],"slash_commands":%s,"skills":%s,"plugins":[{"name":"ccl-skills"}]}' \
523
- "${1:-[]}" "${2:-[\"init\",\"agents\"]}" "${3:-[\"ccl-skills:product-rd-workflow\",\"dataviz\"]}"
524
- }
525
- run_reason_native_excludes() {
526
- local stdout="$1" forbidden="$2" expected="$3" out
527
- printf '%s' "$stdout" > "$tmp_dir/stdout"
528
- : > "$tmp_dir/stderr"
529
- if out="$(python3 "$parser" 0 "$tmp_dir/stdout" "$tmp_dir/stderr" \
530
- --require-empty-init \
531
- --expected-native-skills product-rd-workflow \
532
- --required-native-skills product-rd-workflow)"; then
533
- printf 'expected native-skill parser failure for stdout: %s\n' "$stdout" >&2
534
- return 1
535
- fi
536
- if printf '%s' "$out" | grep -F "$forbidden" >/dev/null; then
537
- printf 'a proven customization must not report as %q: %s\n' "$forbidden" "$out" >&2
538
- return 1
539
- fi
540
- printf '%s' "$out" | grep -F "$expected" >/dev/null
541
- }
542
- # the base itself is accepted, or none of the rows below prove anything
543
- run_ok_expected_native_skills product-rd-workflow product-rd-workflow 0 \
544
- "$(native_vocab_init)$native_vocab_result"
545
- # a built-in the snapshot has not caught up with, in either host-vocabulary field
546
- run_reason_expected_native_skills product-rd-workflow product-rd-workflow 0 \
547
- "$(native_vocab_init '[]' '["init","agents","brand-new-builtin"]')$native_vocab_result" \
548
- 'unclassifiable host-vocabulary entry'
549
- run_reason_expected_native_skills product-rd-workflow product-rd-workflow 0 \
550
- "$(native_vocab_init '[]' '["init"]' '["ccl-skills:product-rd-workflow","brand-new-skill"]')$native_vocab_result" \
551
- 'unclassifiable host-vocabulary entry'
552
- # ...and the identifier is named, so the follow-up is a one-liner
553
- run_reason_expected_native_skills product-rd-workflow product-rd-workflow 0 \
554
- "$(native_vocab_init '[]' '["init","brand-new-builtin"]')$native_vocab_result" \
555
- 'slash_commands:brand-new-builtin'
556
- # A NAMESPACED entry proves a surface beyond the one expected plugin; a
557
- # path-shaped or unparseable identifier proves nothing about host origin; a
558
- # duplicate is a spoofing signal. All four stay terminal.
559
- run_reason_native_excludes \
560
- "$(native_vocab_init '[]' '["init","evil-plugin:pwn"]')$native_vocab_result" \
561
- 'unclassifiable host-vocabulary' 'runtime capability surface is not empty'
562
- run_reason_native_excludes \
563
- "$(native_vocab_init '[]' '["init","dir/cmd"]')$native_vocab_result" \
564
- 'unclassifiable host-vocabulary' 'runtime capability surface is not empty'
565
- run_reason_native_excludes \
566
- "$(native_vocab_init '[]' '["init","ev!l"]')$native_vocab_result" \
567
- 'unclassifiable host-vocabulary' 'runtime capability surface is not empty'
568
- run_reason_native_excludes \
569
- "$(native_vocab_init '[]' '["init","init"]')$native_vocab_result" \
570
- 'unclassifiable host-vocabulary' 'runtime capability surface is not empty'
571
- # The softer class must never absorb a real breach that happens alongside it.
572
- run_reason_native_excludes \
573
- "$(native_vocab_init '["Write"]' '["init","brand-new-builtin"]')$native_vocab_result" \
574
- 'unclassifiable host-vocabulary' 'runtime capability surface is not empty'
575
- # Same policy on the main-invocation path, with the identifier in the detail
576
- # fields so an operator can see which name drifted.
577
- run_reason_runtime_surface_native product-rd-workflow 0 \
578
- "$(native_vocab_init '[]' '["init","brand-new-builtin"]')$native_vocab_result" \
579
- 'unclassifiable host-vocabulary entry'
580
- run_reason_runtime_surface_native product-rd-workflow 0 \
581
- "$(native_vocab_init '[]' '["init","brand-new-builtin"]')$native_vocab_result" \
582
- 'unclassifiable_host_vocabulary=slash_commands:brand-new-builtin'
447
+ # --- vocabulary is data, not a verdict --------------------------------------
448
+ # Any value in slash_commands / terminal_slash_commands / skills / plugins is
449
+ # tolerated on both parse paths; only tools, tool_use, the MCP list and
450
+ # permissionMode decide. Pinned so the class can never be tightened back into a
451
+ # snapshot of the host's own names: that snapshot made every CLI release that
452
+ # shipped a new built-in a reviewer-lane outage while proving nothing.
453
+ vocab_any='{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["init","brand-new-builtin","evil-plugin:pwn","dir/cmd","ev!l","init"," import","brand-new runtime isolation"],"terminal_slash_commands":[{"name":"init"},"not-declared"],"skills":["brand-new-skill",{"name":"verify","command":"/x/y"},"evil-plugin:pwn"],"plugins":[{"name":"ccl-skills"},{"name":"other","path":"/p"},"x"]}'
454
+ run_ok_strict 0 "$vocab_any"$'\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
455
+ run_ok_runtime_surface '' 0 "$vocab_any"$'\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
456
+ # absent or oddly typed vocabulary fields are not "missing isolation fields"
457
+ run_ok_strict 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
458
+ run_ok_strict 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":{"a":1},"skills":"none","plugins":null,"terminal_slash_commands":"doctor"}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}'
459
+ # ...while the MCP list, the one customization list that is capability, must
460
+ # still be present and empty.
461
+ run_reason_strict 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"slash_commands":[],"skills":[],"plugins":[]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'missing required isolation fields'
462
+ # ...and every breach class keeps its strength beside vocabulary.
463
+ run_reason_runtime_surface '' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":["Write"],"mcp_servers":[],"slash_commands":["init","brand-new-builtin"],"skills":["brand-new-skill"],"plugins":[{"name":"ccl-skills"}]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime isolation surface is invalid'
464
+ run_reason_runtime_surface '' 0 $'{"type":"system","subtype":"init","permissionMode":"bypassPermissions","tools":[],"mcp_servers":[],"slash_commands":["init","brand-new-builtin"],"skills":["brand-new-skill"],"plugins":[{"name":"ccl-skills"}]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'unsafe_values=permissionMode'
465
+ run_reason_runtime_surface '' 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[{"name":"x"}],"slash_commands":["init","brand-new-builtin"],"skills":["brand-new-skill"],"plugins":[{"name":"ccl-skills"}]}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'unexpected_customizations=mcp_servers'
466
+ run_reason 0 $'{"type":"system","subtype":"init","permissionMode":"default","tools":[],"mcp_servers":[],"slash_commands":["init","brand-new-builtin"],"skills":["brand-new-skill"],"plugins":[{"name":"ccl-skills"}]}\n{"type":"assistant","message":{"content":[{"type":"tool_use","name":"Write","input":{}}]}}\n{"type":"result","subtype":"success","is_error":false,"result":"ok"}' 'runtime capability surface is not empty'
583
467
 
584
468
  printf 'parse_probe_result_tests_ok\n'
@@ -1233,6 +1233,71 @@ out="$(run_gate --review-plan-file "$WORK/owner-review-plan.json" --allow-fallba
1233
1233
  check "owner-aware success without a wrapper binding receipt fails closed" \
1234
1234
  '[ "$rc" = 2 ] && json_fields "$out" reason_code=binding_mismatch next_action=stop_reviewer_lane && [ "$(printf "%s" "$out" | python3 -c "import json,sys; print(len(json.load(sys.stdin).get(\"reviewed_skills\", [])))")" = 0 ]'
1235
1235
 
1236
+ # Owner count is independent of concern count: a cross-skill candidate can have
1237
+ # more owners than the eight known concerns without changing the review scope.
1238
+ python3 - "$WORK" <<'PY'
1239
+ import copy
1240
+ import json
1241
+ from pathlib import Path
1242
+ import sys
1243
+
1244
+ work = Path(sys.argv[1])
1245
+ owners = (
1246
+ "requirement-scope", "product-rd-workflow", "platform-service-connectivity",
1247
+ "platform-observability", "skill-extraction-workflow", "python-service-dev",
1248
+ "web-react-dev", "testing-strategy", "terminal-cli-dev",
1249
+ )
1250
+ plan = json.loads((work / "review-plan.json").read_text())
1251
+ patches = []
1252
+ for owner in owners:
1253
+ root = work / owner
1254
+ root.mkdir(exist_ok=True)
1255
+ entrypoint = root / "SKILL.md"
1256
+ if not entrypoint.exists():
1257
+ entrypoint.write_text(f"# Synthetic {owner} owner\n")
1258
+ plan["self_review"].append({
1259
+ "concern": "correctness", "skill": owner,
1260
+ "conclusion": f"The {owner} boundary preserves its stated acceptance behavior.",
1261
+ "evidence_refs": ["e1"],
1262
+ })
1263
+ path = f"skills/{owner}/SKILL.md"
1264
+ patches.append(f"diff --git a/{path} b/{path}\n--- a/{path}\n+++ b/{path}\n@@ -1 +1 @@\n-old\n+new\n")
1265
+ (work / "many-owner-diff.patch").write_text("".join(patches))
1266
+ plans = {"many-owner": plan}
1267
+ missing_owner = copy.deepcopy(plan)
1268
+ missing_owner["self_review"].pop()
1269
+ plans["many-owner-missing-owner"] = missing_owner
1270
+ missing_concern = copy.deepcopy(plan)
1271
+ missing_concern["self_review"] = [row for row in missing_concern["self_review"] if row["concern"] != "safety"]
1272
+ plans["many-owner-missing-concern"] = missing_concern
1273
+ duplicate = copy.deepcopy(plan)
1274
+ duplicate["self_review"].append(copy.deepcopy(duplicate["self_review"][-1]))
1275
+ plans["many-owner-duplicate"] = duplicate
1276
+ default_duplicate = copy.deepcopy(plan)
1277
+ default_duplicate["self_review"].append({**default_duplicate["self_review"][0], "skill": "code-review"})
1278
+ plans["many-owner-default-duplicate"] = default_duplicate
1279
+ for name, value in plans.items():
1280
+ (work / f"{name}-plan.json").write_text(json.dumps(value))
1281
+ PY
1282
+
1283
+ reset_case passed unavailable unavailable
1284
+ out="$(run_gate --diff-file "$WORK/many-owner-diff.patch" --review-plan-file "$WORK/many-owner-plan.json")"; rc=$?
1285
+ check "nine derived owners can assess shared concerns in one explicit plan" \
1286
+ '[ "$rc" = 0 ] && json_fields "$out" status=passed review_plan_source=implementer-supplied owner_selection_source=controller-derived+implementer-declared && [ "$(printf %s "$out" | python3 -c "import json,sys; p=json.load(sys.stdin); print(len(p[\"selected_skills\"]), len(p[\"reviewed_skills\"]))")" = "10 9" ]'
1287
+ printf '%s\n' "$out" >"$WORK/many-owner-review.json"
1288
+
1289
+ reset_case passed unavailable unavailable
1290
+ out="$(run_completion_gate --diff-file "$WORK/many-owner-diff.patch" --review-plan-file "$WORK/many-owner-plan.json" --completion-review-result-file "$WORK/many-owner-review.json")"; rc=$?
1291
+ check "nine-owner explicit self-review closes the exact-candidate completion checkpoint" \
1292
+ '[ "$rc" = 0 ] && [ ! -e "$WORK/state/client_sequence" ] && json_fields "$out" mode=complete status=passed completion_gated=false next_action=complete'
1293
+
1294
+ for invalid_plan in missing-owner missing-concern duplicate default-duplicate; do
1295
+ reset_case passed unavailable unavailable
1296
+ out="$(run_gate --diff-file "$WORK/many-owner-diff.patch" --review-plan-file "$WORK/many-owner-$invalid_plan-plan.json")"; rc=$?
1297
+ check "shared-concern owner plans reject $invalid_plan before provider execution" \
1298
+ '[ "$rc" = 2 ] && [ ! -e "$WORK/state/client_sequence" ] && json_fields "$out" reason_code=self_review_incomplete next_action=deep_self_review'
1299
+ done
1300
+
1236
1301
  printf 'diff --git a/skills/testing-strategy/SKILL.md b/skills/testing-strategy/SKILL.md\n--- a/skills/testing-strategy/SKILL.md\n+++ b/skills/testing-strategy/SKILL.md\n@@ -1 +1 @@\n-old\n+new\n' >"$WORK/diff.patch"
1237
1302
  reset_case passed unavailable unavailable
1238
1303
  out="$(run_gate --allow-fallback-egress)"; rc=$?
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: defect-diagnosis
3
- description: bug / 报错 / test 挂了 / 线上问题 / 复现 / 找根因 / debug → diagnose first-hand failure evidence, isolate cause, verify before fixing, add regression proof, and route prevention. Also use for AI-proposed causes or fixes.
3
+ description: bug / 报错 / test 挂了 / 线上问题 / 接口变慢·性能退化 / 复现 / 找根因 / debug → diagnose first-hand failure evidence, isolate cause, verify before fixing, add regression proof, and route prevention. Also use for AI-proposed causes or fixes.
4
4
  ---
5
5
 
6
6
  # Defect Diagnosis
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: grill-me
3
- description: grill-me / 访谈 / 拷问 / 压力测试方案 / stress-test a plan — lightweight one-question-at-a-time interview to challenge a plan, design, API shape, data model, or feature direction before implementation. Skip code-level YAGNI/delete/adversarial review of written code → `product-rd-workflow`'s independent-review gate; full delivery/spec/plan authoring → product-rd-workflow; tests → testing-strategy; implementation → stack/dev skill; process lesson extraction → skill-extraction-workflow.
3
+ description: grill-me / 访谈 / 一问一答拷问(一次问一个)/ 压力测试方案 / stress-test a plan — lightweight one-question-at-a-time interview to challenge a plan, design, API shape, data model, or feature direction before implementation. Skip 拷问用的问题池·推荐默认值等材料,以及拷问后的结论整理(不是逐问过程)→ requirement-intent;code-level YAGNI/delete/adversarial review of written code → `product-rd-workflow`'s independent-review gate; full delivery/spec/plan authoring → product-rd-workflow; tests → testing-strategy; implementation → stack/dev skill; process lesson extraction → skill-extraction-workflow.
4
4
  ---
5
5
 
6
6
  # grill-me — 轻量方案拷问
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: miniapp-product-dev
3
- description: "小程序 / Taro / 微信小程序 / 支付宝小程序 / 抖音小程序 / 小程序上线审核 → implement, debug, test, and ship mini-program client features: pages, state, API integration, auth, sharing, platform capabilities, review, and device verification. Triggers also include \"重构这个小程序页面/组件(局部)\", \"refactor a mini-program page/component\"."
3
+ description: "小程序 / Taro / 微信小程序 / 支付宝小程序 / 抖音小程序 / 小程序上线审核 / 微信开发者工具编译·构建·真机调试 → implement, debug, test, and ship mini-program client features: pages, state, API integration, auth, sharing, platform capabilities, review, and device verification. Triggers also include \"重构这个小程序页面/组件(局部)\", \"refactor a mini-program page/component\"."
4
4
  ---
5
5
 
6
6
  # Miniapp Product Dev