devlyn-cli 2.10.0 → 3.0.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 (82) hide show
  1. package/AGENTS.md +4 -9
  2. package/CLAUDE.md +11 -15
  3. package/README.md +31 -7
  4. package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.json +25 -0
  5. package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.md +10 -0
  6. package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.json +18 -0
  7. package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.md +9 -0
  8. package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.json +18 -0
  9. package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.md +9 -0
  10. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-cli-quote-tax-rules/l2_risk_probes/result.json +28 -0
  11. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F23-cli-fulfillment-wave/l2_risk_probes/result.json +28 -0
  12. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F25-cli-cart-promotion-rules/l2_risk_probes/result.json +30 -0
  13. package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.json +28 -0
  14. package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.md +15 -0
  15. package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.json +28 -0
  16. package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.md +15 -0
  17. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/F21-cli-scheduler-priority/l2_risk_probes/result.json +32 -0
  18. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.json +44 -0
  19. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.md +16 -0
  20. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.json +18 -0
  21. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.md +9 -0
  22. package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.json +28 -0
  23. package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.md +15 -0
  24. package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.json +28 -0
  25. package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.md +15 -0
  26. package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.json +28 -0
  27. package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.md +15 -0
  28. package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.json +28 -0
  29. package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.md +15 -0
  30. package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.json +28 -0
  31. package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.md +15 -0
  32. package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.json +28 -0
  33. package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.md +15 -0
  34. package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.json +28 -0
  35. package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.md +15 -0
  36. package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.json +28 -0
  37. package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.md +15 -0
  38. package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.json +28 -0
  39. package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.md +15 -0
  40. package/benchmark/auto-resolve/scripts/run-fixture.sh +11 -1
  41. package/benchmark/auto-resolve/scripts/test-benchmark-arg-parsing.sh +83 -1
  42. package/bin/devlyn.js +59 -9
  43. package/config/skills/_shared/.ruff.toml +2 -0
  44. package/config/skills/_shared/adapters/claude.md +9 -1
  45. package/config/skills/_shared/adapters/codex.md +5 -0
  46. package/config/skills/_shared/adapters/grok.md +37 -13
  47. package/config/skills/_shared/archive_run.py +738 -56
  48. package/config/skills/_shared/codex-config.md +19 -4
  49. package/config/skills/_shared/codex-monitored.sh +81 -12
  50. package/config/skills/_shared/collect-codex-findings.py +419 -60
  51. package/config/skills/_shared/engine-preflight.md +8 -7
  52. package/config/skills/_shared/expected.schema.json +68 -0
  53. package/config/skills/_shared/finish-gate.py +12 -11
  54. package/config/skills/_shared/grok-anchor-guard.py +78 -0
  55. package/config/skills/_shared/invocation-receipt.py +1041 -0
  56. package/config/skills/_shared/judge-output-parser.py +200 -0
  57. package/config/skills/_shared/judge-role-evidence.py +273 -0
  58. package/config/skills/_shared/phase-prompt-render.py +181 -0
  59. package/config/skills/_shared/process-evidence.py +909 -0
  60. package/config/skills/_shared/resolve-bootstrap.py +776 -84
  61. package/config/skills/_shared/resolve-stop-hook.py +33 -1
  62. package/config/skills/_shared/role-config.py +552 -0
  63. package/config/skills/_shared/run-bounded.py +1 -1
  64. package/config/skills/_shared/spec-verify-check.py +1037 -192
  65. package/config/skills/_shared/state-phase-write.py +2551 -83
  66. package/config/skills/_shared/terminal-claim-check.py +15 -0
  67. package/config/skills/_shared/verify-merge-findings.py +1127 -50
  68. package/config/skills/devlyn:engines/SKILL.md +8 -16
  69. package/config/skills/devlyn:ideate/SKILL.md +1 -1
  70. package/config/skills/devlyn:ideate/references/spec-template.md +1 -0
  71. package/config/skills/devlyn:queue/SKILL.md +7 -4
  72. package/config/skills/devlyn:resolve/SKILL.md +94 -35
  73. package/config/skills/devlyn:resolve/references/outer-loop.md +15 -0
  74. package/config/skills/devlyn:resolve/references/phases/build-gate.md +33 -4
  75. package/config/skills/devlyn:resolve/references/phases/implement.md +4 -3
  76. package/config/skills/devlyn:resolve/references/phases/plan.md +1 -5
  77. package/config/skills/devlyn:resolve/references/phases/probe-derive.md +4 -2
  78. package/config/skills/devlyn:resolve/references/phases/verify.md +120 -80
  79. package/config/skills/devlyn:resolve/references/state-schema.md +23 -9
  80. package/package.json +5 -1
  81. package/scripts/lint-fixtures.sh +4 -1
  82. package/scripts/lint-skills.sh +447 -290
@@ -56,9 +56,16 @@ fi
56
56
  # plus the `_shared/` kernel. Keep this list single-source so all installed
57
57
  # mirror parity checks cover the same files.
58
58
  critical_path_files=$(cat <<'EOF'
59
+ _shared/.ruff.toml
60
+ _shared/process-evidence.py
61
+ _shared/invocation-receipt.py
62
+ _shared/role-config.py
63
+ _shared/judge-role-evidence.py
59
64
  _shared/spec-verify-check.py
65
+ _shared/judge-output-parser.py
60
66
  _shared/collect-codex-findings.py
61
67
  _shared/verify-merge-findings.py
68
+ _shared/archive_run.py
62
69
  _shared/state-phase-write.py
63
70
  _shared/terminal-claim-check.py
64
71
  _shared/resolve-stop-hook.py
@@ -70,6 +77,7 @@ devlyn:ideate/references/project-mode.md
70
77
  devlyn:ideate/references/from-spec-mode.md
71
78
  devlyn:resolve/SKILL.md
72
79
  devlyn:queue/SKILL.md
80
+ devlyn:engines/SKILL.md
73
81
  devlyn:resolve/references/state-schema.md
74
82
  devlyn:resolve/references/free-form-mode.md
75
83
  devlyn:resolve/references/phases/plan.md
@@ -152,6 +160,7 @@ offenders=$(git grep -Il -- 'mcp__codex-cli__' -- \
152
160
  ':!config/skills/preflight-workspace/**' \
153
161
  ':!benchmark/auto-resolve/external/**' \
154
162
  ':!benchmark/auto-resolve/results/**' \
163
+ ':!benchmark/ceiling/results/**' \
155
164
  ':!benchmark/auto-resolve/PILOT-RESULTS*' \
156
165
  2>/dev/null || true)
157
166
  if [ -z "$offenders" ]; then
@@ -176,6 +185,7 @@ offenders=$(git grep -Il -- 'Requires Codex MCP\|Codex MCP server\|Codex MCP ava
176
185
  ':!config/skills/preflight-workspace/**' \
177
186
  ':!benchmark/auto-resolve/external/**' \
178
187
  ':!benchmark/auto-resolve/results/**' \
188
+ ':!benchmark/ceiling/results/**' \
179
189
  ':!benchmark/auto-resolve/PILOT-RESULTS*' \
180
190
  2>/dev/null || true)
181
191
  if [ -z "$offenders" ]; then
@@ -204,8 +214,8 @@ else
204
214
  fi
205
215
 
206
216
  # ---------------------------------------------------------------------------
207
- # 4. No model-pinned Claude references, any generation, except the adjudicated
208
- # SURFACE_CLOSE envelope whose requested id must equal CLI arg and modelUsage.
217
+ # 4. No model-pinned Claude references, any generation, except the
218
+ # validated explicit-effort capability declaration.
209
219
  # ---------------------------------------------------------------------------
210
220
  section "Check 4: No model-pinned Claude references"
211
221
  offenders=$(grep -RInE 'Claude (Opus|Sonnet|Haiku|Fable)|claude-(opus|sonnet|haiku|fable)-[0-9]' \
@@ -214,7 +224,7 @@ offenders=$(grep -RInE 'Claude (Opus|Sonnet|Haiku|Fable)|claude-(opus|sonnet|hai
214
224
  | grep -v 'config/skills/devlyn:auto-resolve-workspace/' \
215
225
  | grep -v 'config/skills/devlyn:ideate-workspace/' \
216
226
  | grep -v 'config/skills/preflight-workspace/' \
217
- | grep -vE '^config/skills/devlyn:resolve/SKILL\.md:[0-9]+:Freeze .*--tools "Read,Grep,Glob,Edit,Write" --dangerously-skip-permissions --model claude-sonnet-5 --output-format json --strict-mcp-config --mcp-config '\''\{"mcpServers":\{\}\}'\''.*, recording the same model at SPW spawn\.' \
227
+ | grep -vE '^config/skills/_shared/adapters/claude\.md:[0-9]+:<!-- devlyn-effort 2\.1\.263 claude-fable-5-1 low,medium,high,xhigh,max -->$' \
218
228
  | cut -d: -f1 \
219
229
  | sort -u \
220
230
  || true)
@@ -266,6 +276,105 @@ else
266
276
  bad "devlyn:design-ui must not be listed in OPTIONAL_ADDONS"
267
277
  fi
268
278
 
279
+ # ---------------------------------------------------------------------------
280
+ # 5b. Every completed managed-skills install writes its own version marker.
281
+ # ---------------------------------------------------------------------------
282
+ section "Check 5b: Installed skill roots carry exact version markers"
283
+ if make_temp_dir tmp_install_marker /tmp/devlyn-install-marker.XXXXXX; then
284
+ marker_home="$tmp_install_marker/home"
285
+ marker_project="$tmp_install_marker/project"
286
+ timeout_low="$tmp_install_marker/timeout-low"
287
+ timeout_high="$tmp_install_marker/timeout-high"
288
+ installer="$PWD/bin/devlyn.js"
289
+ mkdir -p "$marker_home" "$marker_project" "$timeout_low/.claude" "$timeout_high/.claude"
290
+ printf '{"env":{"BASH_MAX_TIMEOUT_MS":"600000"}}\n' > "$timeout_low/.claude/settings.json"
291
+ printf '{"env":{"BASH_MAX_TIMEOUT_MS":"7200000"}}\n' > "$timeout_high/.claude/settings.json"
292
+
293
+ if (cd "$marker_project" \
294
+ && HOME="$marker_home" node "$installer" -y >"$tmp_install_marker/claude.log" 2>&1 \
295
+ && HOME="$marker_home" node "$installer" agents all >"$tmp_install_marker/agents.log" 2>&1) \
296
+ && (cd "$timeout_low" && HOME="$marker_home" node "$installer" -y >"$tmp_install_marker/timeout-low.log" 2>&1) \
297
+ && cp "$timeout_low/.claude/settings.json" "$tmp_install_marker/timeout-low-first.json" \
298
+ && (cd "$timeout_low" && HOME="$marker_home" node "$installer" -y >"$tmp_install_marker/timeout-low-second.log" 2>&1) \
299
+ && cmp -s "$timeout_low/.claude/settings.json" "$tmp_install_marker/timeout-low-first.json" \
300
+ && (cd "$timeout_high" && HOME="$marker_home" node "$installer" -y >"$tmp_install_marker/timeout-high.log" 2>&1); then
301
+ if python3 - "$installer" "$marker_home" "$marker_project" "$timeout_low" "$timeout_high" <<'PY'
302
+ import json
303
+ import pathlib
304
+ import stat
305
+ import sys
306
+
307
+ installer = pathlib.Path(sys.argv[1])
308
+ home = pathlib.Path(sys.argv[2])
309
+ project = pathlib.Path(sys.argv[3])
310
+ timeout_low = pathlib.Path(sys.argv[4])
311
+ timeout_high = pathlib.Path(sys.argv[5])
312
+ package = json.loads((installer.parent.parent / "package.json").read_text())
313
+ expected = {"schemaVersion": 1, "package": package["name"], "version": package["version"]}
314
+ roots = [
315
+ project / ".claude" / "skills",
316
+ home / ".codex" / "skills",
317
+ home / ".agents" / "skills",
318
+ home / ".grok" / "skills",
319
+ ]
320
+ for root in roots:
321
+ marker = root / ".devlyn-install.json"
322
+ actual = json.loads(marker.read_text())
323
+ if actual != expected:
324
+ raise SystemExit(f"{marker}: expected {expected}, got {actual}")
325
+ if stat.S_IMODE(marker.stat().st_mode) != 0o600:
326
+ raise SystemExit(f"{marker}: expected mode 0600")
327
+ if list(root.glob(".devlyn-install.json.*.tmp")):
328
+ raise SystemExit(f"{root}: stale marker temp file")
329
+ for target, expected_timeout in (
330
+ (project, "3600000"),
331
+ (timeout_low, "3600000"),
332
+ (timeout_high, "7200000"),
333
+ ):
334
+ env = json.loads((target / ".claude" / "settings.json").read_text())["env"]
335
+ if env.get("BASH_MAX_TIMEOUT_MS") != expected_timeout:
336
+ raise SystemExit(f"{target}: expected BASH_MAX_TIMEOUT_MS={expected_timeout}")
337
+ if "BASH_DEFAULT_TIMEOUT_MS" in env:
338
+ raise SystemExit(f"{target}: BASH_DEFAULT_TIMEOUT_MS must not be installed")
339
+ PY
340
+ then
341
+ if grep -Fxq '.claude/skills/.devlyn-install.json' "$marker_project/.gitignore"; then
342
+ ok "managed roots have exact 0600 markers; Bash max is installed, raised, preserved, and idempotent"
343
+ else
344
+ bad "Claude project install must ignore its local marker"
345
+ fi
346
+ else
347
+ bad "completed installs must write the exact per-root marker"
348
+ fi
349
+ else
350
+ bad "isolated managed-skills install failed"
351
+ fi
352
+
353
+ incomplete="$tmp_install_marker/incomplete"
354
+ mkdir -p "$incomplete/package" "$incomplete/home/.codex/skills" "$incomplete/claude/.claude/skills" "$incomplete/codex"
355
+ cp -R bin config package.json "$incomplete/package/"
356
+ rm -rf "$incomplete/package/config/skills/devlyn:queue"
357
+ printf '{"version":"stale"}\n' > "$incomplete/home/.codex/skills/.devlyn-install.json"
358
+ printf '{"version":"stale"}\n' > "$incomplete/claude/.claude/skills/.devlyn-install.json"
359
+ if ! (cd "$incomplete/claude" \
360
+ && HOME="$incomplete/home" node "$incomplete/package/bin/devlyn.js" -y >"$incomplete/claude.log" 2>&1) \
361
+ && ! (cd "$incomplete/codex" \
362
+ && HOME="$incomplete/home" node "$incomplete/package/bin/devlyn.js" agents codex >"$incomplete/codex.log" 2>&1) \
363
+ && grep -Fq 'Incomplete devlyn skill install; missing: devlyn:queue' "$incomplete/claude.log" \
364
+ && grep -Fq 'Incomplete devlyn skill install; missing: devlyn:queue' "$incomplete/codex.log" \
365
+ && [ -d "$incomplete/claude/.claude/skills/devlyn:resolve" ] \
366
+ && [ -d "$incomplete/home/.codex/skills/devlyn:resolve" ] \
367
+ && [ ! -e "$incomplete/claude/.claude/skills/.devlyn-install.json" ] \
368
+ && [ ! -e "$incomplete/home/.codex/skills/.devlyn-install.json" ]; then
369
+ ok "incomplete Claude and Codex copies fail visibly without stale or replacement markers"
370
+ else
371
+ bad "incomplete Claude and Codex copies must fail visibly without an install marker"
372
+ fi
373
+ rm -rf "$tmp_install_marker"
374
+ else
375
+ bad "could not allocate install-marker smoke directory"
376
+ fi
377
+
269
378
  # ---------------------------------------------------------------------------
270
379
  # 6. Source ↔ installed mirror parity on critical path.
271
380
  # Only runs if .claude/skills exists (i.e. installer has been run).
@@ -292,6 +401,14 @@ check_skill_mirror_parity \
292
401
 
293
402
  # ---------------------------------------------------------------------------
294
403
  # 6b. VERIFY merge verdict binding self-test.
404
+ for helper in role-config judge-role-evidence; do
405
+ if python3 "config/skills/_shared/$helper.py" --self-test >/dev/null 2>&1; then
406
+ ok "$helper.py self-test passed"
407
+ else
408
+ bad "$helper.py self-test failed"
409
+ fi
410
+ done
411
+
295
412
  # F23 full-pipeline prompt-fix rerun exposed a real failure where Codex
296
413
  # pair-JUDGE emitted HIGH findings but state kept pair_judge as
297
414
  # PASS_WITH_ISSUES. Routing severity must be deterministic, not prose.
@@ -302,6 +419,7 @@ if python3 config/skills/_shared/verify-merge-findings.py --self-test >/dev/null
302
419
  else
303
420
  bad "verify-merge-findings.py self-test failed"
304
421
  fi
422
+
305
423
  if ! grep -Fq 'def pair_trigger_skip_contract_violation' config/skills/_shared/verify-merge-findings.py \
306
424
  || ! grep -Fq 'def pair_trigger_missing_contract_violation' config/skills/_shared/verify-merge-findings.py \
307
425
  || ! grep -Fq 'def pair_trigger_reason_completeness_violation' config/skills/_shared/verify-merge-findings.py \
@@ -366,7 +484,6 @@ fi
366
484
  verify_merge_risk_profile_guard_missing=0
367
485
  for file in \
368
486
  config/skills/_shared/verify-merge-findings.py \
369
- .claude/skills/_shared/verify-merge-findings.py \
370
487
  .agents/skills/_shared/verify-merge-findings.py; do
371
488
  if ! grep -Fq 'def risk_profile_contract_violation' "$file" \
372
489
  || ! grep -Fq 'verify-risk-profile-malformed' "$file" \
@@ -380,15 +497,52 @@ if [ $verify_merge_risk_profile_guard_missing -eq 0 ]; then
380
497
  ok "verify-merge-findings.py risk_profile shape guard is mirrored"
381
498
  fi
382
499
 
500
+ section "Check 6b1: Process evidence runner is sealed"
501
+ if python3 config/skills/_shared/process-evidence.py --self-test >/dev/null 2>&1; then
502
+ ok "process-evidence.py self-test passed"
503
+ else
504
+ bad "process-evidence.py self-test failed"
505
+ fi
506
+ if ! grep -Fq 'PHASES = {"implement", "build_gate", "verify"}' config/skills/_shared/process-evidence.py \
507
+ || ! grep -Fq 'classification' config/skills/_shared/process-evidence.py \
508
+ || ! grep -Fq 'validate_bound_carrier' config/skills/_shared/process-evidence.py \
509
+ || ! grep -Fq 'validate_summary_commands' config/skills/_shared/process-evidence.py; then
510
+ bad "process-evidence.py must preserve phase identity, capability classification, and bound-byte validation"
511
+ fi
512
+
513
+ section "Check 6b2: Codex invocation receipts are phase-owned"
514
+ if python3 config/skills/_shared/invocation-receipt.py --self-test >/dev/null 2>&1; then
515
+ ok "invocation-receipt.py self-test passed"
516
+ else
517
+ bad "invocation-receipt.py self-test failed"
518
+ fi
519
+ if ! grep -Fq 'sandbox must remain workspace-write' config/skills/_shared/invocation-receipt.py \
520
+ || ! grep -Fq 'SCHEMA_VERSION = "2.0"' config/skills/_shared/invocation-receipt.py \
521
+ || ! grep -Fq 'sandbox_workspace_write.network_access' config/skills/_shared/invocation-receipt.py \
522
+ || ! grep -Fq 'forbidden Codex bypass flag' config/skills/_shared/invocation-receipt.py \
523
+ || ! grep -Fq 'forbidden Codex sandbox: danger-full-access' config/skills/_shared/codex-monitored.sh \
524
+ || ! grep -Fq 'DEVLYN_INVOCATION_RECEIPT' config/skills/_shared/codex-monitored.sh; then
525
+ bad "Codex invocation receipts must bind phase identity and reject authority widening"
526
+ fi
527
+
383
528
  section "Check 6c: Codex stdout collection writes canonical pair findings"
384
529
  if python3 config/skills/_shared/collect-codex-findings.py --self-test >/dev/null 2>&1; then
385
530
  ok "collect-codex-findings.py self-test passed"
386
531
  else
387
532
  bad "collect-codex-findings.py self-test failed"
388
533
  fi
534
+ # iter-0082: the frozen collector contract — every negative through every ingress
535
+ # path, plus real judge captures replayed against hand-verified expectations.
536
+ # The self-test above is unit-shaped; this is the integration bar against real bytes.
537
+ if python3 benchmark/ceiling/probes/r-weld-0082/test-collector-contract.py >/dev/null 2>&1; then
538
+ ok "collector contract (iter-0082 negatives + real-capture corpus) passed"
539
+ else
540
+ bad "collector contract failed — run benchmark/ceiling/probes/r-weld-0082/test-collector-contract.py"
541
+ fi
389
542
  if ! grep -Fq 'def reject_json_constant' config/skills/_shared/collect-codex-findings.py \
390
- || ! grep -Fq 'loads_strict_json(raw)' config/skills/_shared/collect-codex-findings.py \
391
- || ! grep -Fq 'NaN Codex stdout finding must not normalize' config/skills/_shared/collect-codex-findings.py; then
543
+ || ! grep -Fq 'PARSER["collect_stdout"]' config/skills/_shared/collect-codex-findings.py \
544
+ || ! grep -Fq 'parse_constant=reject_json_constant' config/skills/_shared/judge-output-parser.py \
545
+ || ! grep -Fq 'NaN pair-JUDGE stdout finding' config/skills/_shared/collect-codex-findings.py; then
392
546
  bad "collect-codex-findings.py must reject non-standard JSON constants in pair-JUDGE stdout"
393
547
  fi
394
548
 
@@ -405,6 +559,7 @@ if ! grep -Fq 'SAFE_RUN_ID_RE' config/skills/_shared/archive_run.py \
405
559
  || ! grep -Fq 'invalid JSON numeric constant: NaN' config/skills/_shared/archive_run.py \
406
560
  || ! grep -Fq '"verify.pair.findings.jsonl"' config/skills/_shared/archive_run.py \
407
561
  || ! grep -Fq '"verify-merge.summary.json"' config/skills/_shared/archive_run.py \
562
+ || ! grep -Fq '"verify.primary.timeout.json"' config/skills/_shared/archive_run.py \
408
563
  || ! grep -Fq '"surface-close.output.json"' config/skills/_shared/archive_run.py \
409
564
  || ! grep -Fq '"*-judge.*"' config/skills/_shared/archive_run.py; then
410
565
  bad "archive_run.py must safely archive pair/risk-probe evidence and reject unsafe run ids"
@@ -417,17 +572,50 @@ if python3 config/skills/_shared/state-phase-write.py --self-test >/dev/null 2>&
417
572
  else
418
573
  bad "state-phase-write.py SURFACE_CLOSE self-test failed"
419
574
  fi
575
+ if python3 - <<'PY'
576
+ import ast
577
+ import runpy
578
+
579
+ entries = ["src/{a,b}/**"]
580
+ paths = ("src/a/example.py", "src/b/example.py", "src/c/example.py")
581
+ expected = (True, True, False)
582
+ sources = {"path_matches_surface": [], "validate_surface_brace_glob": []}
583
+ for name in ("state-phase-write.py", "spec-verify-check.py"):
584
+ path = f"config/skills/_shared/{name}"
585
+ module = runpy.run_path(path)
586
+ actual = tuple(module["path_matches_surface"](path, entries) for path in paths)
587
+ assert actual == expected, (name, actual)
588
+ tree = ast.parse(open(path, encoding="utf-8").read())
589
+ text = open(path, encoding="utf-8").read()
590
+ for function_name in sources:
591
+ function = next(node for node in tree.body if isinstance(node, ast.FunctionDef) and node.name == function_name)
592
+ sources[function_name].append(ast.get_source_segment(text, function))
593
+ for invalid in ("src/{a,b", "src/{a,}/**", "src/{a,{b,c}}", "src/{a,**}"):
594
+ try:
595
+ module["path_matches_surface"]("src/a/example.py", [invalid])
596
+ except ValueError as exc:
597
+ assert invalid in str(exc) and "supported form" in str(exc)
598
+ else:
599
+ raise AssertionError((name, invalid))
600
+ for function_name, bodies in sources.items():
601
+ assert bodies[0] == bodies[1], f"{function_name} bodies differ"
602
+ PY
603
+ then
604
+ ok "brace-glob surface matching and errors are byte-parity checked in both consumers"
605
+ else
606
+ bad "brace-glob surface matching or errors drifted between state and spec checks"
607
+ fi
420
608
  if ! grep -Fq 'rollback_surface_delta' config/skills/_shared/state-phase-write.py \
421
609
  || ! grep -Fq 'validate_surface_adjudication' config/skills/_shared/state-phase-write.py \
422
610
  || ! grep -Fq 'validate_surface_execution' config/skills/_shared/state-phase-write.py \
423
611
  || ! grep -Fq 'phases.surface_close spawn requires --engine claude' config/skills/_shared/state-phase-write.py \
424
- || ! grep -Fq 'phases.surface_close spawn requires --model' config/skills/_shared/state-phase-write.py \
612
+ || ! grep -Fq 'SURFACE_CLOSE requires canonical native JSON' config/skills/_shared/state-phase-write.py \
425
613
  || ! grep -Fq 'BLOCKED:surface-close-input-mismatch' config/skills/_shared/state-phase-write.py \
426
614
  || ! grep -Fq 'surface-check' config/skills/_shared/state-phase-write.py \
427
615
  || ! grep -Fq 'surface-rollback' config/skills/_shared/state-phase-write.py; then
428
616
  bad "state-phase-write.py must mechanically adjudicate, audit, guard, and roll back SURFACE_CLOSE"
429
617
  fi
430
- for tree in config/skills .claude/skills .agents/skills; do
618
+ for tree in config/skills .agents/skills; do
431
619
  skill="$tree/devlyn:resolve/SKILL.md"
432
620
  phase="$tree/devlyn:resolve/references/phases/surface-close.md"
433
621
  if ! grep -Fq '## PHASE 2.5: SURFACE_CLOSE' "$skill" \
@@ -437,7 +625,7 @@ for tree in config/skills .claude/skills .agents/skills; do
437
625
  || ! grep -Fq 'auto_surface_close_claude_unavailable' "$skill" \
438
626
  || ! grep -Fq 'canonical body VERBATIM' "$skill" \
439
627
  || ! grep -Fq 'run-bounded.py 600 -- claude -p' "$skill" \
440
- || ! grep -Fq -- '--tools "Read,Grep,Glob,Edit,Write" --dangerously-skip-permissions --model claude-sonnet-5 --output-format json --strict-mcp-config --mcp-config '\''{"mcpServers":{}}'\''' "$skill" \
628
+ || ! grep -Fq -- '--tools "Read,Grep,Glob,Edit,Write" --dangerously-skip-permissions --output-format json --strict-mcp-config --mcp-config '\''{"mcpServers":{}}'\''' "$skill" \
441
629
  || ! grep -Fq '.devlyn/surface-close.output.json' "$skill" \
442
630
  || ! grep -Fq '**Common post-fix checkpoint (BUILD_GATE and VERIFY):**' "$skill" \
443
631
  || ! grep -Fq 'durability-enforce --round <n> --origin-phase <build_gate|verify>' "$skill" \
@@ -481,16 +669,6 @@ if ! grep -Fq 'generated criteria carrier was not staged into .devlyn/spec-verif
481
669
  || ! grep -Fq 'def source_integrity_error' config/skills/_shared/spec-verify-check.py \
482
670
  || ! grep -Fq 'source.criteria_sha256 mismatch' config/skills/_shared/spec-verify-check.py \
483
671
  || ! grep -Fq 'Generated criteria were written without one' config/skills/_shared/spec-verify-check.py \
484
- || ! grep -Fq 'generated criteria carrier was not staged into .devlyn/spec-verify.json' .claude/skills/_shared/spec-verify-check.py \
485
- || ! grep -Fq 'spec source with mismatched source.spec_sha256 was accepted' .claude/skills/_shared/spec-verify-check.py \
486
- || ! grep -Fq 'spec source with matching source.spec_sha256 was not staged' .claude/skills/_shared/spec-verify-check.py \
487
- || ! grep -Fq 'source.spec_sha256 mismatch' .claude/skills/_shared/spec-verify-check.py \
488
- || ! grep -Fq 'generated criteria without a JSON carrier was accepted' .claude/skills/_shared/spec-verify-check.py \
489
- || ! grep -Fq 'generated criteria without source.criteria_sha256 was accepted' .claude/skills/_shared/spec-verify-check.py \
490
- || ! grep -Fq 'generated criteria with mismatched source.criteria_sha256 was accepted' .claude/skills/_shared/spec-verify-check.py \
491
- || ! grep -Fq 'def source_integrity_error' .claude/skills/_shared/spec-verify-check.py \
492
- || ! grep -Fq 'source.criteria_sha256 mismatch' .claude/skills/_shared/spec-verify-check.py \
493
- || ! grep -Fq 'Generated criteria were written without one' .claude/skills/_shared/spec-verify-check.py \
494
672
  || ! grep -Fq 'generated criteria carrier was not staged into .devlyn/spec-verify.json' .agents/skills/_shared/spec-verify-check.py \
495
673
  || ! grep -Fq 'spec source with mismatched source.spec_sha256 was accepted' .agents/skills/_shared/spec-verify-check.py \
496
674
  || ! grep -Fq 'spec source with matching source.spec_sha256 was not staged' .agents/skills/_shared/spec-verify-check.py \
@@ -527,27 +705,6 @@ if ! grep -Fq 'def validate_present_solo_headroom_hypothesis' config/skills/_sha
527
705
  || ! grep -Fq 'weak sibling solo-headroom hypothesis was accepted by --check-expected' config/skills/_shared/spec-verify-check.py \
528
706
  || ! grep -Fq 'docs-style solo-headroom hypothesis was rejected by --check' config/skills/_shared/spec-verify-check.py \
529
707
  || ! grep -Fq 'docs-style sibling solo-headroom command was rejected by --check-expected' config/skills/_shared/spec-verify-check.py \
530
- || ! grep -Fq 'def validate_present_solo_headroom_hypothesis' .claude/skills/_shared/spec-verify-check.py \
531
- || ! grep -Fq 'def state_requires_risk_probes' .claude/skills/_shared/spec-verify-check.py \
532
- || ! grep -Fq 'def risk_probes_state_error' .claude/skills/_shared/spec-verify-check.py \
533
- || ! grep -Fq -- '--include-risk-probes accepted missing required risk-probes.jsonl' .claude/skills/_shared/spec-verify-check.py \
534
- || ! grep -Fq -- '--include-risk-probes accepted non-boolean risk_probes_enabled' .claude/skills/_shared/spec-verify-check.py \
535
- || ! grep -Fq -- '--include-risk-probes accepted non-object risk_profile' .claude/skills/_shared/spec-verify-check.py \
536
- || ! grep -Fq 'def validate_risk_probes_cover_solo_headroom_hypothesis' .claude/skills/_shared/spec-verify-check.py \
537
- || ! grep -Fq 'def has_backticked_observable_miss_command' .claude/skills/_shared/spec-verify-check.py \
538
- || ! grep -Fq 'backticked command/observable line that exposes the miss' .claude/skills/_shared/spec-verify-check.py \
539
- || ! grep -Fq 'weak solo-headroom hypothesis was accepted by --check' .claude/skills/_shared/spec-verify-check.py \
540
- || ! grep -Fq 'descriptive backtick solo-headroom hypothesis was accepted by --check' .claude/skills/_shared/spec-verify-check.py \
541
- || ! grep -Fq 'risk probe missing solo-headroom command coverage was accepted' .claude/skills/_shared/spec-verify-check.py \
542
- || ! grep -Fq 'risk probe with unrelated solo-headroom derived_from was accepted' .claude/skills/_shared/spec-verify-check.py \
543
- || ! grep -Fq 'risk-probes[0].derived_from must reference the solo-headroom hypothesis bullet' .claude/skills/_shared/spec-verify-check.py \
544
- || ! grep -Fq 'solo-headroom command in a later risk probe was accepted' .claude/skills/_shared/spec-verify-check.py \
545
- || ! grep -Fq 'solo-headroom command prefix match was accepted' .claude/skills/_shared/spec-verify-check.py \
546
- || ! grep -Fq '(?<![A-Za-z0-9_.:/=-])' .claude/skills/_shared/spec-verify-check.py \
547
- || ! grep -Fq 'risk-probes[0].cmd must contain a solo-headroom hypothesis observable command' .claude/skills/_shared/spec-verify-check.py \
548
- || ! grep -Fq 'weak sibling solo-headroom hypothesis was accepted by --check-expected' .claude/skills/_shared/spec-verify-check.py \
549
- || ! grep -Fq 'docs-style solo-headroom hypothesis was rejected by --check' .claude/skills/_shared/spec-verify-check.py \
550
- || ! grep -Fq 'docs-style sibling solo-headroom command was rejected by --check-expected' .claude/skills/_shared/spec-verify-check.py \
551
708
  || ! grep -Fq 'def validate_present_solo_headroom_hypothesis' .agents/skills/_shared/spec-verify-check.py \
552
709
  || ! grep -Fq 'def state_requires_risk_probes' .agents/skills/_shared/spec-verify-check.py \
553
710
  || ! grep -Fq 'def risk_probes_state_error' .agents/skills/_shared/spec-verify-check.py \
@@ -574,29 +731,22 @@ else
574
731
  ok "spec-verify-check.py rejects weak solo-headroom hypotheses"
575
732
  fi
576
733
  if ! grep -Fq 'requires `.devlyn/risk-probes.jsonl`' config/skills/devlyn:resolve/SKILL.md \
577
- || ! grep -Fq 'requires `.devlyn/risk-probes.jsonl`' .claude/skills/devlyn:resolve/SKILL.md \
578
734
  || ! grep -Fq 'requires `.devlyn/risk-probes.jsonl`' .agents/skills/devlyn:resolve/SKILL.md \
579
735
  || ! grep -Fq 'missing `.devlyn/risk-probes.jsonl` is a CRITICAL mechanical blocker' config/skills/devlyn:resolve/SKILL.md \
580
- || ! grep -Fq 'missing `.devlyn/risk-probes.jsonl` is a CRITICAL mechanical blocker' .claude/skills/devlyn:resolve/SKILL.md \
581
736
  || ! grep -Fq 'missing `.devlyn/risk-probes.jsonl` is a CRITICAL mechanical blocker' .agents/skills/devlyn:resolve/SKILL.md \
582
737
  || ! grep -Fq 'requires that file when `state.risk_profile.risk_probes_enabled == true`' config/skills/devlyn:resolve/references/phases/build-gate.md \
583
- || ! grep -Fq 'requires that file when `state.risk_profile.risk_probes_enabled == true`' .claude/skills/devlyn:resolve/references/phases/build-gate.md \
584
738
  || ! grep -Fq 'requires that file when `state.risk_profile.risk_probes_enabled == true`' .agents/skills/devlyn:resolve/references/phases/build-gate.md \
585
739
  || ! grep -Fq 'Malformed `state.risk_profile` is also CRITICAL because it can hide enabled risk probes' config/skills/devlyn:resolve/references/phases/build-gate.md \
586
- || ! grep -Fq 'Malformed `state.risk_profile` is also CRITICAL because it can hide enabled risk probes' .claude/skills/devlyn:resolve/references/phases/build-gate.md \
587
740
  || ! grep -Fq 'Malformed `state.risk_profile` is also CRITICAL because it can hide enabled risk probes' .agents/skills/devlyn:resolve/references/phases/build-gate.md \
588
741
  || ! grep -Fq 'When `state.risk_profile.risk_probes_enabled == true`, missing `.devlyn/risk-probes.jsonl` is also CRITICAL' config/skills/devlyn:resolve/references/phases/verify.md \
589
- || ! grep -Fq 'When `state.risk_profile.risk_probes_enabled == true`, missing `.devlyn/risk-probes.jsonl` is also CRITICAL' .claude/skills/devlyn:resolve/references/phases/verify.md \
590
742
  || ! grep -Fq 'When `state.risk_profile.risk_probes_enabled == true`, missing `.devlyn/risk-probes.jsonl` is also CRITICAL' .agents/skills/devlyn:resolve/references/phases/verify.md; then
591
743
  bad "BUILD_GATE and VERIFY must fail closed when enabled risk probes are missing"
592
744
  else
593
745
  ok "BUILD_GATE and VERIFY require enabled risk probes"
594
746
  fi
595
747
  if grep -Fq 'or any(char.isspace() for char in stripped)' config/skills/_shared/spec-verify-check.py \
596
- || grep -Fq 'or any(char.isspace() for char in stripped)' .claude/skills/_shared/spec-verify-check.py \
597
748
  || grep -Fq 'or any(char.isspace() for char in stripped)' .agents/skills/_shared/spec-verify-check.py \
598
749
  || grep -Fq 'or any(char.isspace() for char in stripped)' config/skills/_shared/verify-merge-findings.py \
599
- || grep -Fq 'or any(char.isspace() for char in stripped)' .claude/skills/_shared/verify-merge-findings.py \
600
750
  || grep -Fq 'or any(char.isspace() for char in stripped)' .agents/skills/_shared/verify-merge-findings.py \
601
751
  || grep -Fq 'or any(char.isspace() for char in stripped)' benchmark/auto-resolve/scripts/pair_evidence_contract.py; then
602
752
  bad "solo-headroom command detection must not treat descriptive whitespace as a command"
@@ -604,10 +754,8 @@ else
604
754
  ok "solo-headroom command detection rejects descriptive whitespace"
605
755
  fi
606
756
  if ! grep -Fq '"printf",' config/skills/_shared/spec-verify-check.py \
607
- || ! grep -Fq '"printf",' .claude/skills/_shared/spec-verify-check.py \
608
757
  || ! grep -Fq '"printf",' .agents/skills/_shared/spec-verify-check.py \
609
758
  || ! grep -Fq '"printf",' config/skills/_shared/verify-merge-findings.py \
610
- || ! grep -Fq '"printf",' .claude/skills/_shared/verify-merge-findings.py \
611
759
  || ! grep -Fq '"printf",' .agents/skills/_shared/verify-merge-findings.py \
612
760
  || ! grep -Fq '"printf",' benchmark/auto-resolve/scripts/pair_evidence_contract.py; then
613
761
  bad "solo-headroom command detection must keep explicit printf command support"
@@ -622,10 +770,8 @@ import sys
622
770
  files = [
623
771
  pathlib.Path("benchmark/auto-resolve/scripts/pair_evidence_contract.py"),
624
772
  pathlib.Path("config/skills/_shared/spec-verify-check.py"),
625
- pathlib.Path(".claude/skills/_shared/spec-verify-check.py"),
626
773
  pathlib.Path(".agents/skills/_shared/spec-verify-check.py"),
627
774
  pathlib.Path("config/skills/_shared/verify-merge-findings.py"),
628
- pathlib.Path(".claude/skills/_shared/verify-merge-findings.py"),
629
775
  pathlib.Path(".agents/skills/_shared/verify-merge-findings.py"),
630
776
  ]
631
777
  names = [
@@ -702,13 +848,16 @@ fi
702
848
  if ! grep -Fq '"uses_visible_input_key_names"' config/skills/_shared/spec-verify-check.py \
703
849
  || ! grep -Fq '"asserts_visible_output_key_names"' config/skills/_shared/spec-verify-check.py \
704
850
  || ! grep -Fq '"asserts_no_unexpected_output_keys"' config/skills/_shared/spec-verify-check.py \
705
- || ! grep -Fq 'shape_contract co-occurring with error_contract without' config/skills/_shared/spec-verify-check.py \
851
+ || ! grep -Fq 'shape_contract claiming visible exact error object without' config/skills/_shared/spec-verify-check.py \
852
+ || ! grep -Fq 'visible_text_names_exact_json_error_object' config/skills/_shared/spec-verify-check.py \
706
853
  || ! grep -Fq 'JSON error object shape_contract with exact object evidence was rejected' config/skills/_shared/spec-verify-check.py \
707
854
  || ! grep -Fq 'shape_contract without any evidence was accepted' config/skills/_shared/spec-verify-check.py \
708
855
  || ! grep -Fq 'shape_contract with exact key evidence was rejected' config/skills/_shared/spec-verify-check.py \
709
856
  || ! grep -Fq '`shape_contract` when the visible text names exact keys' config/skills/devlyn:resolve/references/phases/probe-derive.md \
710
- || ! grep -Fq '`shape_contract` must' config/skills/devlyn:resolve/SKILL.md; then
711
- bad "risk-probe shape contracts must require exact visible input/output key evidence unconditionally, and asserts_exact_error_object when co-occurring with error_contract/http_error_contract"
857
+ || ! grep -Fq 'visible_text_names_exact_json_error_object' config/skills/devlyn:resolve/references/phases/probe-derive.md \
858
+ || ! grep -Fq '`shape_contract` must' config/skills/devlyn:resolve/SKILL.md \
859
+ || ! grep -Fq 'visible_text_names_exact_json_error_object' config/skills/devlyn:resolve/SKILL.md; then
860
+ bad "risk-probe shape contracts must require exact visible input/output key evidence unconditionally, and asserts_exact_error_object when the probe claims the visible text names an exact JSON error object"
712
861
  fi
713
862
  if ! grep -Fq '"auth_signature_contract"' config/skills/_shared/spec-verify-check.py \
714
863
  || ! grep -Fq '"idempotency_replay"' config/skills/_shared/spec-verify-check.py \
@@ -751,40 +900,28 @@ if [ $expected_check_missing -eq 0 ]; then
751
900
  ok "ideate docs require --check-expected for sibling expected contracts"
752
901
  fi
753
902
  if ! grep -Fq 'any present actionable solo-headroom hypothesis' config/skills/devlyn:ideate/SKILL.md \
754
- || ! grep -Fq 'any present actionable solo-headroom hypothesis' .claude/skills/devlyn:ideate/SKILL.md \
755
903
  || ! grep -Fq 'any present actionable solo-headroom hypothesis' .agents/skills/devlyn:ideate/SKILL.md \
756
904
  || ! grep -Fq 'any present actionable solo-headroom hypothesis' config/skills/devlyn:ideate/references/elicitation.md \
757
- || ! grep -Fq 'any present actionable solo-headroom hypothesis' .claude/skills/devlyn:ideate/references/elicitation.md \
758
905
  || ! grep -Fq 'any present actionable solo-headroom hypothesis' .agents/skills/devlyn:ideate/references/elicitation.md \
759
906
  || ! grep -Fq 'any present actionable solo-headroom hypothesis' config/skills/devlyn:ideate/references/project-mode.md \
760
- || ! grep -Fq 'any present actionable solo-headroom hypothesis' .claude/skills/devlyn:ideate/references/project-mode.md \
761
907
  || ! grep -Fq 'any present actionable solo-headroom hypothesis' .agents/skills/devlyn:ideate/references/project-mode.md \
762
908
  || ! grep -Fq 'any present actionable solo-headroom hypothesis' config/skills/devlyn:resolve/SKILL.md \
763
- || ! grep -Fq 'any present actionable solo-headroom hypothesis' .claude/skills/devlyn:resolve/SKILL.md \
764
909
  || ! grep -Fq 'any present actionable solo-headroom hypothesis' .agents/skills/devlyn:resolve/SKILL.md \
765
910
  || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" config/skills/devlyn:ideate/SKILL.md \
766
- || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" .claude/skills/devlyn:ideate/SKILL.md \
767
911
  || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" .agents/skills/devlyn:ideate/SKILL.md \
768
912
  || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" config/skills/devlyn:ideate/references/elicitation.md \
769
- || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" .claude/skills/devlyn:ideate/references/elicitation.md \
770
913
  || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" .agents/skills/devlyn:ideate/references/elicitation.md \
771
914
  || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" config/skills/devlyn:ideate/references/from-spec-mode.md \
772
- || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" .claude/skills/devlyn:ideate/references/from-spec-mode.md \
773
915
  || ! grep -Fq "legacy inline \`## Verification\` JSON carrier" .agents/skills/devlyn:ideate/references/from-spec-mode.md \
774
916
  || ! grep -Fq "inline \`## Verification\` JSON carrier" config/skills/devlyn:resolve/SKILL.md \
775
- || ! grep -Fq "inline \`## Verification\` JSON carrier" .claude/skills/devlyn:resolve/SKILL.md \
776
917
  || ! grep -Fq "inline \`## Verification\` JSON carrier" .agents/skills/devlyn:resolve/SKILL.md \
777
918
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' config/skills/devlyn:ideate/SKILL.md \
778
- || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .claude/skills/devlyn:ideate/SKILL.md \
779
919
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .agents/skills/devlyn:ideate/SKILL.md \
780
920
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' config/skills/devlyn:ideate/references/elicitation.md \
781
- || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .claude/skills/devlyn:ideate/references/elicitation.md \
782
921
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .agents/skills/devlyn:ideate/references/elicitation.md \
783
922
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' config/skills/devlyn:ideate/references/project-mode.md \
784
- || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .claude/skills/devlyn:ideate/references/project-mode.md \
785
923
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .agents/skills/devlyn:ideate/references/project-mode.md \
786
924
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' config/skills/devlyn:resolve/SKILL.md \
787
- || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .claude/skills/devlyn:resolve/SKILL.md \
788
925
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .agents/skills/devlyn:resolve/SKILL.md; then
789
926
  bad "ideate/resolve docs must describe mechanical solo-headroom validation"
790
927
  else
@@ -805,18 +942,6 @@ if ! grep -Fq 'def validate_expected_against_sibling_spec' config/skills/_shared
805
942
  || ! grep -Fq 'actionable solo ceiling avoidance was rejected by --check' config/skills/_shared/spec-verify-check.py \
806
943
  || ! grep -Fq 'weak sibling solo ceiling avoidance was accepted by --check-expected' config/skills/_shared/spec-verify-check.py \
807
944
  || ! grep -Fq 'actionable sibling solo ceiling avoidance was rejected by --check-expected' config/skills/_shared/spec-verify-check.py \
808
- || ! grep -Fq 'backticked_observable_miss_commands(spec_text)' .claude/skills/_shared/spec-verify-check.py \
809
- || ! grep -Fq 'observable command must match spec.expected.json' .claude/skills/_shared/spec-verify-check.py \
810
- || ! grep -Fq 'observable command must match `## Verification` JSON carrier' .claude/skills/_shared/spec-verify-check.py \
811
- || ! grep -Fq 'mismatched inline solo-headroom command was accepted by --check' .claude/skills/_shared/spec-verify-check.py \
812
- || ! grep -Fq 'matched inline solo-headroom command was rejected by --check' .claude/skills/_shared/spec-verify-check.py \
813
- || ! grep -Fq 'mismatched sibling solo-headroom command was accepted by --check-expected' .claude/skills/_shared/spec-verify-check.py \
814
- || ! grep -Fq 'matched sibling solo-headroom command was rejected by --check-expected' .claude/skills/_shared/spec-verify-check.py \
815
- || ! grep -Fq 'def validate_present_solo_ceiling_avoidance' .claude/skills/_shared/spec-verify-check.py \
816
- || ! grep -Fq 'weak solo ceiling avoidance was accepted by --check' .claude/skills/_shared/spec-verify-check.py \
817
- || ! grep -Fq 'actionable solo ceiling avoidance was rejected by --check' .claude/skills/_shared/spec-verify-check.py \
818
- || ! grep -Fq 'weak sibling solo ceiling avoidance was accepted by --check-expected' .claude/skills/_shared/spec-verify-check.py \
819
- || ! grep -Fq 'actionable sibling solo ceiling avoidance was rejected by --check-expected' .claude/skills/_shared/spec-verify-check.py \
820
945
  || ! grep -Fq 'backticked_observable_miss_commands(spec_text)' .agents/skills/_shared/spec-verify-check.py \
821
946
  || ! grep -Fq 'observable command must match spec.expected.json' .agents/skills/_shared/spec-verify-check.py \
822
947
  || ! grep -Fq 'observable command must match `## Verification` JSON carrier' .agents/skills/_shared/spec-verify-check.py \
@@ -833,147 +958,106 @@ if ! grep -Fq 'def validate_expected_against_sibling_spec' config/skills/_shared
833
958
  fi
834
959
  if ! grep -Fq 'Verification includes at least one compound scenario that exercises the interaction end-to-end' \
835
960
  config/skills/devlyn:ideate/references/spec-template.md \
836
- || ! grep -Fq 'Verification includes at least one compound scenario that exercises the interaction end-to-end' \
837
- .claude/skills/devlyn:ideate/references/spec-template.md \
838
- || ! grep -Fq 'Verification includes at least one compound scenario that exercises the interaction end-to-end' \
839
- .agents/skills/devlyn:ideate/references/spec-template.md; then
961
+ || ! grep -Fq 'Verification includes at least one compound scenario that exercises the interaction end-to-end' .agents/skills/devlyn:ideate/references/spec-template.md; then
840
962
  bad "ideate spec template must require compound interaction verification for pair-relevant high-risk specs"
841
963
  else
842
964
  ok "ideate spec template requires compound interaction verification for pair-relevant specs"
843
965
  fi
844
966
  if ! grep -Fq 'ask for one concrete compound' config/skills/devlyn:ideate/references/elicitation.md \
845
- || ! grep -Fq 'ask for one concrete compound' .claude/skills/devlyn:ideate/references/elicitation.md \
846
967
  || ! grep -Fq 'ask for one concrete compound' .agents/skills/devlyn:ideate/references/elicitation.md; then
847
968
  bad "ideate elicitation must ask for compound interaction scenarios when pair-relevant risks appear"
848
969
  else
849
970
  ok "ideate elicitation asks for compound interaction scenarios when pair-relevant risks appear"
850
971
  fi
851
972
  if ! grep -Fq 'solo-headroom hypothesis inside `## Verification`' config/skills/devlyn:ideate/references/spec-template.md \
852
- || ! grep -Fq 'solo-headroom hypothesis inside `## Verification`' .claude/skills/devlyn:ideate/references/spec-template.md \
853
973
  || ! grep -Fq 'solo-headroom hypothesis inside `## Verification`' .agents/skills/devlyn:ideate/references/spec-template.md \
854
974
  || ! grep -Fq 'ask for one solo-headroom hypothesis' config/skills/devlyn:ideate/references/elicitation.md \
855
- || ! grep -Fq 'ask for one solo-headroom hypothesis' .claude/skills/devlyn:ideate/references/elicitation.md \
856
975
  || ! grep -Fq 'ask for one solo-headroom hypothesis' .agents/skills/devlyn:ideate/references/elicitation.md; then
857
976
  bad "ideate must require a visible solo-headroom hypothesis for benchmark and pair-evidence specs"
858
977
  else
859
978
  ok "ideate requires solo-headroom hypothesis for benchmark and pair-evidence specs"
860
979
  fi
861
980
  if ! grep -Fq 'must literally contain `solo-headroom hypothesis`' config/skills/devlyn:ideate/references/spec-template.md \
862
- || ! grep -Fq 'must literally contain `solo-headroom hypothesis`' .claude/skills/devlyn:ideate/references/spec-template.md \
863
981
  || ! grep -Fq 'must literally contain `solo-headroom hypothesis`' .agents/skills/devlyn:ideate/references/spec-template.md \
864
982
  || ! grep -Fq 'backticked line itself must contain `miss`' config/skills/devlyn:ideate/references/spec-template.md \
865
- || ! grep -Fq 'backticked line itself must contain `miss`' .claude/skills/devlyn:ideate/references/spec-template.md \
866
983
  || ! grep -Fq 'backticked line itself must contain `miss`' .agents/skills/devlyn:ideate/references/spec-template.md \
867
984
  || ! grep -Fq '`solo_claude`, `miss`, and a backticked observable command' config/skills/devlyn:ideate/references/spec-template.md \
868
- || ! grep -Fq '`solo_claude`, `miss`, and a backticked observable command' .claude/skills/devlyn:ideate/references/spec-template.md \
869
985
  || ! grep -Fq '`solo_claude`, `miss`, and a backticked observable command' .agents/skills/devlyn:ideate/references/spec-template.md \
870
986
  || ! grep -Fq 'command/observable' config/skills/devlyn:ideate/references/spec-template.md \
871
- || ! grep -Fq 'command/observable' .claude/skills/devlyn:ideate/references/spec-template.md \
872
987
  || ! grep -Fq 'command/observable' .agents/skills/devlyn:ideate/references/spec-template.md \
873
988
  || ! grep -Fq 'must literally contain `solo-headroom hypothesis`' config/skills/devlyn:ideate/references/elicitation.md \
874
- || ! grep -Fq 'must literally contain `solo-headroom hypothesis`' .claude/skills/devlyn:ideate/references/elicitation.md \
875
989
  || ! grep -Fq 'must literally contain `solo-headroom hypothesis`' .agents/skills/devlyn:ideate/references/elicitation.md \
876
990
  || ! grep -Fq 'line itself must contain `miss`' config/skills/devlyn:ideate/references/elicitation.md \
877
- || ! grep -Fq 'line itself must contain `miss`' .claude/skills/devlyn:ideate/references/elicitation.md \
878
991
  || ! grep -Fq 'line itself must contain `miss`' .agents/skills/devlyn:ideate/references/elicitation.md \
879
992
  || ! grep -Fq 'Do not write a benchmark/risk-probe/pair-evidence spec until this' config/skills/devlyn:ideate/references/elicitation.md \
880
- || ! grep -Fq 'Do not write a benchmark/risk-probe/pair-evidence spec until this' .claude/skills/devlyn:ideate/references/elicitation.md \
881
993
  || ! grep -Fq 'Do not write a benchmark/risk-probe/pair-evidence spec until this' .agents/skills/devlyn:ideate/references/elicitation.md \
882
994
  || ! grep -Fq 'spec not ready — solo-headroom hypothesis required' config/skills/devlyn:ideate/references/elicitation.md \
883
- || ! grep -Fq 'spec not ready — solo-headroom hypothesis required' .claude/skills/devlyn:ideate/references/elicitation.md \
884
995
  || ! grep -Fq 'spec not ready — solo-headroom hypothesis required' .agents/skills/devlyn:ideate/references/elicitation.md \
885
996
  || ! grep -Fq '`solo_claude`, `miss`, and a backticked observable command' config/skills/devlyn:ideate/references/elicitation.md \
886
- || ! grep -Fq '`solo_claude`, `miss`, and a backticked observable command' .claude/skills/devlyn:ideate/references/elicitation.md \
887
997
  || ! grep -Fq '`solo_claude`, `miss`, and a backticked observable command' .agents/skills/devlyn:ideate/references/elicitation.md \
888
998
  || ! grep -Fq 'command/observable' config/skills/devlyn:ideate/references/elicitation.md \
889
- || ! grep -Fq 'command/observable' .claude/skills/devlyn:ideate/references/elicitation.md \
890
999
  || ! grep -Fq 'command/observable' .agents/skills/devlyn:ideate/references/elicitation.md \
891
1000
  || ! grep -Fq 'Verification literally contains `solo-headroom hypothesis`, `solo_claude`' config/skills/devlyn:ideate/references/from-spec-mode.md \
892
- || ! grep -Fq 'Verification literally contains `solo-headroom hypothesis`, `solo_claude`' .claude/skills/devlyn:ideate/references/from-spec-mode.md \
893
1001
  || ! grep -Fq 'Verification literally contains `solo-headroom hypothesis`, `solo_claude`' .agents/skills/devlyn:ideate/references/from-spec-mode.md \
894
1002
  || ! grep -Fq 'backticked line itself must contain `miss`' config/skills/devlyn:ideate/references/from-spec-mode.md \
895
- || ! grep -Fq 'backticked line itself must contain `miss`' .claude/skills/devlyn:ideate/references/from-spec-mode.md \
896
1003
  || ! grep -Fq 'backticked line itself must contain `miss`' .agents/skills/devlyn:ideate/references/from-spec-mode.md \
897
1004
  || ! grep -Fq 'command/observable' config/skills/devlyn:ideate/references/from-spec-mode.md \
898
- || ! grep -Fq 'command/observable' .claude/skills/devlyn:ideate/references/from-spec-mode.md \
899
1005
  || ! grep -Fq 'command/observable' .agents/skills/devlyn:ideate/references/from-spec-mode.md \
900
1006
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' config/skills/devlyn:ideate/references/from-spec-mode.md \
901
- || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .claude/skills/devlyn:ideate/references/from-spec-mode.md \
902
1007
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .agents/skills/devlyn:ideate/references/from-spec-mode.md \
903
1008
  || ! grep -Fq "source for VERIFY's canonical \`spec.solo_headroom_hypothesis\` trigger reason" config/skills/devlyn:ideate/references/spec-template.md \
904
- || ! grep -Fq "source for VERIFY's canonical \`spec.solo_headroom_hypothesis\` trigger reason" .claude/skills/devlyn:ideate/references/spec-template.md \
905
1009
  || ! grep -Fq "source for VERIFY's canonical \`spec.solo_headroom_hypothesis\` trigger reason" .agents/skills/devlyn:ideate/references/spec-template.md \
906
1010
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' config/skills/devlyn:ideate/references/spec-template.md \
907
- || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .claude/skills/devlyn:ideate/references/spec-template.md \
908
1011
  || ! grep -Fq 'spec.expected.json.verification_commands[].cmd' .agents/skills/devlyn:ideate/references/spec-template.md; then
909
1012
  bad "ideate solo-headroom hypothesis prompt must match the actionable checker contract"
910
1013
  else
911
1014
  ok "ideate solo-headroom hypothesis prompt matches checker contract"
912
1015
  fi
913
1016
  if ! grep -Fq 'quick mode must not infer a solo-headroom hypothesis' config/skills/devlyn:ideate/references/elicitation.md \
914
- || ! grep -Fq 'quick mode must not infer a solo-headroom hypothesis' .claude/skills/devlyn:ideate/references/elicitation.md \
915
1017
  || ! grep -Fq 'quick mode must not infer a solo-headroom hypothesis' .agents/skills/devlyn:ideate/references/elicitation.md \
916
1018
  || ! grep -Fq 'do not infer a solo-headroom hypothesis' config/skills/devlyn:ideate/SKILL.md \
917
- || ! grep -Fq 'do not infer a solo-headroom hypothesis' .claude/skills/devlyn:ideate/SKILL.md \
918
1019
  || ! grep -Fq 'do not infer a solo-headroom hypothesis' .agents/skills/devlyn:ideate/SKILL.md; then
919
1020
  bad "ideate quick mode must not invent solo-headroom hypotheses"
920
1021
  else
921
1022
  ok "ideate quick mode does not invent solo-headroom hypotheses"
922
1023
  fi
923
1024
  if ! grep -Fq 'solo ceiling avoidance' config/skills/devlyn:ideate/references/spec-template.md \
924
- || ! grep -Fq 'solo ceiling avoidance' .claude/skills/devlyn:ideate/references/spec-template.md \
925
1025
  || ! grep -Fq 'solo ceiling avoidance' .agents/skills/devlyn:ideate/references/spec-template.md \
926
1026
  || ! grep -Fq 'rejected or solo-saturated controls such as `S2`-`S6`' config/skills/devlyn:ideate/references/spec-template.md \
927
- || ! grep -Fq 'rejected or solo-saturated controls such as `S2`-`S6`' .claude/skills/devlyn:ideate/references/spec-template.md \
928
1027
  || ! grep -Fq 'rejected or solo-saturated controls such as `S2`-`S6`' .agents/skills/devlyn:ideate/references/spec-template.md \
929
1028
  || ! grep -Fq 'Solo ceiling avoidance' config/skills/devlyn:ideate/references/elicitation.md \
930
- || ! grep -Fq 'Solo ceiling avoidance' .claude/skills/devlyn:ideate/references/elicitation.md \
931
1029
  || ! grep -Fq 'Solo ceiling avoidance' .agents/skills/devlyn:ideate/references/elicitation.md \
932
1030
  || ! grep -Fq 'spec not ready — solo ceiling avoidance required' config/skills/devlyn:ideate/references/elicitation.md \
933
- || ! grep -Fq 'spec not ready — solo ceiling avoidance required' .claude/skills/devlyn:ideate/references/elicitation.md \
934
1031
  || ! grep -Fq 'spec not ready — solo ceiling avoidance required' .agents/skills/devlyn:ideate/references/elicitation.md \
935
1032
  || ! grep -Fq 'pair-evidence not ready — Pair-candidate headroom is unproven until the spec states solo ceiling avoidance' config/skills/devlyn:ideate/references/from-spec-mode.md \
936
- || ! grep -Fq 'pair-evidence not ready — Pair-candidate headroom is unproven until the spec states solo ceiling avoidance' .claude/skills/devlyn:ideate/references/from-spec-mode.md \
937
1033
  || ! grep -Fq 'pair-evidence not ready — Pair-candidate headroom is unproven until the spec states solo ceiling avoidance' .agents/skills/devlyn:ideate/references/from-spec-mode.md \
938
1034
  || ! grep -Fq 'also do not infer solo ceiling avoidance' config/skills/devlyn:ideate/SKILL.md \
939
- || ! grep -Fq 'also do not infer solo ceiling avoidance' .claude/skills/devlyn:ideate/SKILL.md \
940
1035
  || ! grep -Fq 'also do not infer solo ceiling avoidance' .agents/skills/devlyn:ideate/SKILL.md \
941
1036
  || ! grep -Fq 'per-feature Verification must also include a solo ceiling avoidance note' config/skills/devlyn:ideate/references/project-mode.md \
942
- || ! grep -Fq 'per-feature Verification must also include a solo ceiling avoidance note' .claude/skills/devlyn:ideate/references/project-mode.md \
943
1037
  || ! grep -Fq 'per-feature Verification must also include a solo ceiling avoidance note' .agents/skills/devlyn:ideate/references/project-mode.md; then
944
1038
  bad "ideate must require solo ceiling avoidance for new unmeasured pair candidates"
945
1039
  else
946
1040
  ok "ideate requires solo ceiling avoidance for new unmeasured pair candidates"
947
1041
  fi
948
1042
  if ! grep -Fq 'complexity: medium' config/skills/devlyn:ideate/references/spec-template.md \
949
- || ! grep -Fq 'complexity: medium' .claude/skills/devlyn:ideate/references/spec-template.md \
950
1043
  || ! grep -Fq 'complexity: medium' .agents/skills/devlyn:ideate/references/spec-template.md \
951
1044
  || ! grep -Fq 'Complexity signal' config/skills/devlyn:ideate/references/elicitation.md \
952
- || ! grep -Fq 'Complexity signal' .claude/skills/devlyn:ideate/references/elicitation.md \
953
1045
  || ! grep -Fq 'Complexity signal' .agents/skills/devlyn:ideate/references/elicitation.md \
954
1046
  || ! grep -Fq 'downstream VERIFY pair-trigger signal' config/skills/devlyn:ideate/references/elicitation.md \
955
- || ! grep -Fq 'downstream VERIFY pair-trigger signal' .claude/skills/devlyn:ideate/references/elicitation.md \
956
1047
  || ! grep -Fq 'downstream VERIFY pair-trigger signal' .agents/skills/devlyn:ideate/references/elicitation.md \
957
1048
  || ! grep -Fq 'complexity=medium default' config/skills/devlyn:ideate/references/from-spec-mode.md \
958
- || ! grep -Fq 'complexity=medium default' .claude/skills/devlyn:ideate/references/from-spec-mode.md \
959
1049
  || ! grep -Fq 'complexity=medium default' .agents/skills/devlyn:ideate/references/from-spec-mode.md \
960
1050
  || ! grep -Fq 'supported `complexity` frontmatter' config/skills/devlyn:ideate/SKILL.md \
961
- || ! grep -Fq 'supported `complexity` frontmatter' .claude/skills/devlyn:ideate/SKILL.md \
962
1051
  || ! grep -Fq 'supported `complexity` frontmatter' .agents/skills/devlyn:ideate/SKILL.md \
963
1052
  || ! grep -Fq 'supported `complexity` frontmatter' config/skills/devlyn:ideate/references/elicitation.md \
964
- || ! grep -Fq 'supported `complexity` frontmatter' .claude/skills/devlyn:ideate/references/elicitation.md \
965
1053
  || ! grep -Fq 'supported `complexity` frontmatter' .agents/skills/devlyn:ideate/references/elicitation.md \
966
1054
  || ! grep -Fq 'supported `complexity` frontmatter' config/skills/devlyn:resolve/SKILL.md \
967
- || ! grep -Fq 'supported `complexity` frontmatter' .claude/skills/devlyn:resolve/SKILL.md \
968
1055
  || ! grep -Fq 'supported `complexity` frontmatter' .agents/skills/devlyn:resolve/SKILL.md \
969
1056
  || ! grep -Fq 'sibling spec `complexity` frontmatter' config/skills/devlyn:ideate/SKILL.md \
970
- || ! grep -Fq 'sibling spec `complexity` frontmatter' .claude/skills/devlyn:ideate/SKILL.md \
971
1057
  || ! grep -Fq 'sibling spec `complexity` frontmatter' .agents/skills/devlyn:ideate/SKILL.md \
972
1058
  || ! grep -Fq 'sibling spec `complexity` frontmatter' config/skills/devlyn:resolve/SKILL.md \
973
- || ! grep -Fq 'sibling spec `complexity` frontmatter' .claude/skills/devlyn:resolve/SKILL.md \
974
1059
  || ! grep -Fq 'sibling spec `complexity` frontmatter' .agents/skills/devlyn:resolve/SKILL.md \
975
1060
  || ! grep -Fq 'Frontmatter has `id`, `title`, `kind`, `status: planned`, `complexity`' config/skills/devlyn:ideate/SKILL.md \
976
- || ! grep -Fq 'Frontmatter has `id`, `title`, `kind`, `status: planned`, `complexity`' .claude/skills/devlyn:ideate/SKILL.md \
977
1061
  || ! grep -Fq 'Frontmatter has `id`, `title`, `kind`, `status: planned`, `complexity`' .agents/skills/devlyn:ideate/SKILL.md; then
978
1062
  bad "ideate specs must emit complexity frontmatter for resolve pair triggers"
979
1063
  else
@@ -981,163 +1065,97 @@ else
981
1065
  fi
982
1066
  if ! grep -Fq 'warning: Verification may need one compound end-to-end scenario before pair-relevant risks are measurable' \
983
1067
  config/skills/devlyn:ideate/references/from-spec-mode.md \
984
- || ! grep -Fq 'warning: Verification may need one compound end-to-end scenario before pair-relevant risks are measurable' \
985
- .claude/skills/devlyn:ideate/references/from-spec-mode.md \
986
- || ! grep -Fq 'warning: Verification may need one compound end-to-end scenario before pair-relevant risks are measurable' \
987
- .agents/skills/devlyn:ideate/references/from-spec-mode.md; then
1068
+ || ! grep -Fq 'warning: Verification may need one compound end-to-end scenario before pair-relevant risks are measurable' .agents/skills/devlyn:ideate/references/from-spec-mode.md; then
988
1069
  bad "ideate from-spec mode must warn when preserved high-risk specs lack compound verification"
989
1070
  else
990
1071
  ok "ideate from-spec mode warns on pair-relevant specs with weak verification"
991
1072
  fi
992
1073
  if ! grep -Fq 'pair-evidence not ready — Pair-candidate headroom is unproven until the spec states a solo-headroom hypothesis' \
993
1074
  config/skills/devlyn:ideate/references/from-spec-mode.md \
994
- || ! grep -Fq 'pair-evidence not ready — Pair-candidate headroom is unproven until the spec states a solo-headroom hypothesis' \
995
- .claude/skills/devlyn:ideate/references/from-spec-mode.md \
996
- || ! grep -Fq 'pair-evidence not ready — Pair-candidate headroom is unproven until the spec states a solo-headroom hypothesis' \
997
- .agents/skills/devlyn:ideate/references/from-spec-mode.md \
1075
+ || ! grep -Fq 'pair-evidence not ready — Pair-candidate headroom is unproven until the spec states a solo-headroom hypothesis' .agents/skills/devlyn:ideate/references/from-spec-mode.md \
998
1076
  || ! grep -Fq 'Do not call' config/skills/devlyn:ideate/references/from-spec-mode.md \
999
- || ! grep -Fq 'Do not call' .claude/skills/devlyn:ideate/references/from-spec-mode.md \
1000
1077
  || ! grep -Fq 'Do not call' .agents/skills/devlyn:ideate/references/from-spec-mode.md \
1001
1078
  || ! grep -Fq 'announcement must say `pair-evidence not ready`' config/skills/devlyn:ideate/SKILL.md \
1002
- || ! grep -Fq 'announcement must say `pair-evidence not ready`' .claude/skills/devlyn:ideate/SKILL.md \
1003
1079
  || ! grep -Fq 'announcement must say `pair-evidence not ready`' .agents/skills/devlyn:ideate/SKILL.md; then
1004
1080
  bad "ideate from-spec mode must warn when pair-candidate specs lack solo-headroom hypothesis"
1005
1081
  else
1006
1082
  ok "ideate from-spec mode warns on missing solo-headroom hypothesis"
1007
1083
  fi
1008
1084
  if ! grep -Fq 'per-feature Verification must' config/skills/devlyn:ideate/references/project-mode.md \
1009
- || ! grep -Fq 'per-feature Verification must' .claude/skills/devlyn:ideate/references/project-mode.md \
1010
1085
  || ! grep -Fq 'per-feature Verification must' .agents/skills/devlyn:ideate/references/project-mode.md; then
1011
1086
  bad "ideate project mode must require compound verification inside each pair-relevant feature spec"
1012
1087
  else
1013
1088
  ok "ideate project mode keeps compound verification inside pair-relevant feature specs"
1014
1089
  fi
1015
1090
  if ! grep -Fq 'per-feature Verification must include a solo-headroom' config/skills/devlyn:ideate/references/project-mode.md \
1016
- || ! grep -Fq 'per-feature Verification must include a solo-headroom' .claude/skills/devlyn:ideate/references/project-mode.md \
1017
1091
  || ! grep -Fq 'per-feature Verification must include a solo-headroom' .agents/skills/devlyn:ideate/references/project-mode.md \
1018
- || rg -q 'Context or Verification' config/skills/devlyn:ideate/references .claude/skills/devlyn:ideate/references .agents/skills/devlyn:ideate/references; then
1092
+ || grep -rq 'Context or Verification' config/skills/devlyn:ideate/references .agents/skills/devlyn:ideate/references; then
1019
1093
  bad "ideate project mode must keep solo-headroom hypothesis inside each pair-candidate feature spec"
1020
1094
  else
1021
1095
  ok "ideate project mode keeps solo-headroom hypothesis inside each pair-candidate feature spec"
1022
1096
  fi
1023
- if ! grep -Fq 'feature spec must literally contain' \
1024
- config/skills/devlyn:ideate/references/project-mode.md \
1025
- || ! grep -Fq 'feature spec must literally contain' \
1026
- .claude/skills/devlyn:ideate/references/project-mode.md \
1027
- || ! grep -Fq 'feature spec must literally contain' \
1028
- .agents/skills/devlyn:ideate/references/project-mode.md \
1029
- || ! grep -Fq '`solo-headroom hypothesis`, `solo_claude`, `miss`, and a backticked' \
1030
- config/skills/devlyn:ideate/references/project-mode.md \
1031
- || ! grep -Fq '`solo-headroom hypothesis`, `solo_claude`, `miss`, and a backticked' \
1032
- .claude/skills/devlyn:ideate/references/project-mode.md \
1033
- || ! grep -Fq '`solo-headroom hypothesis`, `solo_claude`, `miss`, and a backticked' \
1034
- .agents/skills/devlyn:ideate/references/project-mode.md \
1097
+ if ! grep -Fq 'feature spec must literally contain' config/skills/devlyn:ideate/references/project-mode.md \
1098
+ || ! grep -Fq 'feature spec must literally contain' .agents/skills/devlyn:ideate/references/project-mode.md \
1099
+ || ! grep -Fq '`solo-headroom hypothesis`, `solo_claude`, `miss`, and a backticked' config/skills/devlyn:ideate/references/project-mode.md \
1100
+ || ! grep -Fq '`solo-headroom hypothesis`, `solo_claude`, `miss`, and a backticked' .agents/skills/devlyn:ideate/references/project-mode.md \
1035
1101
  || ! grep -Fq 'behavior a capable' config/skills/devlyn:ideate/references/project-mode.md \
1036
- || ! grep -Fq 'behavior a capable' .claude/skills/devlyn:ideate/references/project-mode.md \
1037
1102
  || ! grep -Fq 'behavior a capable' .agents/skills/devlyn:ideate/references/project-mode.md \
1038
1103
  || ! grep -Fq 'backticked line itself must' config/skills/devlyn:ideate/references/project-mode.md \
1039
- || ! grep -Fq 'backticked line itself must' .claude/skills/devlyn:ideate/references/project-mode.md \
1040
1104
  || ! grep -Fq 'backticked line itself must' .agents/skills/devlyn:ideate/references/project-mode.md \
1041
- || ! grep -Fq 'command/observable' \
1042
- config/skills/devlyn:ideate/references/project-mode.md \
1043
- || ! grep -Fq 'command/observable' \
1044
- .claude/skills/devlyn:ideate/references/project-mode.md \
1045
- || ! grep -Fq 'command/observable' \
1046
- .agents/skills/devlyn:ideate/references/project-mode.md; then
1105
+ || ! grep -Fq 'command/observable' config/skills/devlyn:ideate/references/project-mode.md \
1106
+ || ! grep -Fq 'command/observable' .agents/skills/devlyn:ideate/references/project-mode.md; then
1047
1107
  bad "ideate project mode solo-headroom prompt must keep the actionable checker contract"
1048
1108
  else
1049
1109
  ok "ideate project mode solo-headroom prompt keeps checker contract"
1050
1110
  fi
1051
1111
 
1052
- if ! grep -Fq 'If the visible spec includes a solo-headroom hypothesis, the first probe must' \
1053
- config/skills/devlyn:resolve/references/phases/probe-derive.md \
1054
- || ! grep -Fq 'If the visible spec includes a solo-headroom hypothesis, the first probe must' \
1055
- .claude/skills/devlyn:resolve/references/phases/probe-derive.md \
1056
- || ! grep -Fq 'If the visible spec includes a solo-headroom hypothesis, the first probe must' \
1057
- .agents/skills/devlyn:resolve/references/phases/probe-derive.md \
1058
- || ! grep -Fq 'When the visible spec includes a solo-headroom hypothesis, the first probe must' \
1059
- config/skills/devlyn:resolve/SKILL.md \
1060
- || ! grep -Fq 'When the visible spec includes a solo-headroom hypothesis, the first probe must' \
1061
- .claude/skills/devlyn:resolve/SKILL.md \
1062
- || ! grep -Fq 'When the visible spec includes a solo-headroom hypothesis, the first probe must' \
1063
- .agents/skills/devlyn:resolve/SKILL.md \
1064
- || ! grep -Fq 'its `cmd` must contain the hypothesis'\''s backticked' \
1065
- config/skills/devlyn:resolve/SKILL.md \
1066
- || ! grep -Fq 'its `cmd` must contain the hypothesis'\''s backticked' \
1067
- .claude/skills/devlyn:resolve/SKILL.md \
1068
- || ! grep -Fq 'its `cmd` must contain the hypothesis'\''s backticked' \
1069
- .agents/skills/devlyn:resolve/SKILL.md \
1070
- || ! grep -Fq 'its `derived_from` must reference the hypothesis bullet' \
1071
- config/skills/devlyn:resolve/SKILL.md \
1072
- || ! grep -Fq 'its `derived_from` must reference the hypothesis bullet' \
1073
- .claude/skills/devlyn:resolve/SKILL.md \
1074
- || ! grep -Fq 'its `derived_from` must reference the hypothesis bullet' \
1075
- .agents/skills/devlyn:resolve/SKILL.md; then
1112
+ if ! grep -Fq 'If the visible spec includes a solo-headroom hypothesis, the first probe must' config/skills/devlyn:resolve/references/phases/probe-derive.md \
1113
+ || ! grep -Fq 'If the visible spec includes a solo-headroom hypothesis, the first probe must' .agents/skills/devlyn:resolve/references/phases/probe-derive.md \
1114
+ || ! grep -Fq 'When the visible spec includes a solo-headroom hypothesis, the first probe must' config/skills/devlyn:resolve/SKILL.md \
1115
+ || ! grep -Fq 'When the visible spec includes a solo-headroom hypothesis, the first probe must' .agents/skills/devlyn:resolve/SKILL.md \
1116
+ || ! grep -Fq 'its `cmd` must contain the hypothesis'\''s backticked' config/skills/devlyn:resolve/SKILL.md \
1117
+ || ! grep -Fq 'its `cmd` must contain the hypothesis'\''s backticked' .agents/skills/devlyn:resolve/SKILL.md \
1118
+ || ! grep -Fq 'its `derived_from` must reference the hypothesis bullet' config/skills/devlyn:resolve/SKILL.md \
1119
+ || ! grep -Fq 'its `derived_from` must reference the hypothesis bullet' .agents/skills/devlyn:resolve/SKILL.md; then
1076
1120
  bad "resolve risk-probe prompts must consume solo-headroom hypothesis before pair-evidence work"
1077
1121
  else
1078
1122
  ok "resolve risk-probe prompts consume solo-headroom hypothesis"
1079
1123
  fi
1080
- if ! grep -Fq 'the behavior the spec says `solo_claude` is expected to miss' \
1081
- config/skills/devlyn:resolve/references/phases/probe-derive.md \
1082
- || ! grep -Fq 'the behavior the spec says `solo_claude` is expected to miss' \
1083
- .claude/skills/devlyn:resolve/references/phases/probe-derive.md \
1084
- || ! grep -Fq 'the behavior the spec says `solo_claude` is expected to miss' \
1085
- .agents/skills/devlyn:resolve/references/phases/probe-derive.md \
1086
- || ! grep -Fq 'exercise the stated `solo_claude` miss' \
1087
- config/skills/devlyn:resolve/references/phases/probe-derive.md \
1088
- || ! grep -Fq 'exercise the stated `solo_claude` miss' \
1089
- .claude/skills/devlyn:resolve/references/phases/probe-derive.md \
1090
- || ! grep -Fq 'exercise the stated `solo_claude` miss' \
1091
- .agents/skills/devlyn:resolve/references/phases/probe-derive.md \
1092
- || ! grep -Fq 'with a `cmd` containing the hypothesis'\''s' \
1093
- config/skills/devlyn:resolve/references/phases/probe-derive.md \
1094
- || ! grep -Fq 'with a `cmd` containing the hypothesis'\''s' \
1095
- .claude/skills/devlyn:resolve/references/phases/probe-derive.md \
1096
- || ! grep -Fq 'with a `cmd` containing the hypothesis'\''s' \
1097
- .agents/skills/devlyn:resolve/references/phases/probe-derive.md \
1098
- || ! grep -Fq '`derived_from` pointing at the hypothesis' \
1099
- config/skills/devlyn:resolve/references/phases/probe-derive.md \
1100
- || ! grep -Fq '`derived_from` pointing at the hypothesis' \
1101
- .claude/skills/devlyn:resolve/references/phases/probe-derive.md \
1102
- || ! grep -Fq '`derived_from` pointing at the hypothesis' \
1103
- .agents/skills/devlyn:resolve/references/phases/probe-derive.md; then
1124
+ if ! grep -Fq 'the behavior the spec says `solo_claude` is expected to miss' config/skills/devlyn:resolve/references/phases/probe-derive.md \
1125
+ || ! grep -Fq 'the behavior the spec says `solo_claude` is expected to miss' .agents/skills/devlyn:resolve/references/phases/probe-derive.md \
1126
+ || ! grep -Fq 'exercise the stated `solo_claude` miss' config/skills/devlyn:resolve/references/phases/probe-derive.md \
1127
+ || ! grep -Fq 'exercise the stated `solo_claude` miss' .agents/skills/devlyn:resolve/references/phases/probe-derive.md \
1128
+ || ! grep -Fq 'with a `cmd` containing the hypothesis'\''s' config/skills/devlyn:resolve/references/phases/probe-derive.md \
1129
+ || ! grep -Fq 'with a `cmd` containing the hypothesis'\''s' .agents/skills/devlyn:resolve/references/phases/probe-derive.md \
1130
+ || ! grep -Fq '`derived_from` pointing at the hypothesis' config/skills/devlyn:resolve/references/phases/probe-derive.md \
1131
+ || ! grep -Fq '`derived_from` pointing at the hypothesis' .agents/skills/devlyn:resolve/references/phases/probe-derive.md; then
1104
1132
  bad "resolve risk-probe solo-headroom prompt must target the stated solo_claude miss"
1105
1133
  else
1106
1134
  ok "resolve risk-probe solo-headroom prompt targets the stated solo_claude miss"
1107
1135
  fi
1108
- if ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one of the two targeted' \
1136
+ if ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one targeted review must use' \
1109
1137
  config/skills/devlyn:resolve/references/phases/verify.md \
1110
- || ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one of the two targeted' \
1111
- .claude/skills/devlyn:resolve/references/phases/verify.md \
1112
- || ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one of the two targeted' \
1138
+ || ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one targeted review must use' \
1113
1139
  .agents/skills/devlyn:resolve/references/phases/verify.md \
1114
- || ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one of those targeted probes must' \
1140
+ || ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one targeted review must use' \
1115
1141
  config/skills/devlyn:resolve/SKILL.md \
1116
- || ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one of those targeted probes must' \
1117
- .claude/skills/devlyn:resolve/SKILL.md \
1118
- || ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one of those targeted probes must' \
1142
+ || ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one targeted review must use' \
1119
1143
  .agents/skills/devlyn:resolve/SKILL.md \
1120
- || ! grep -Fq 'using the hypothesis'\''s backticked observable command as its command anchor' \
1144
+ || ! grep -Fq 'hypothesis'\''s backticked observable command as the exact anchor' \
1121
1145
  config/skills/devlyn:resolve/SKILL.md \
1122
- || ! grep -Fq 'using the hypothesis'\''s backticked observable command as its command anchor' \
1123
- .claude/skills/devlyn:resolve/SKILL.md \
1124
- || ! grep -Fq 'using the hypothesis'\''s backticked observable command as its command anchor' \
1146
+ || ! grep -Fq 'hypothesis'\''s backticked observable command as the exact anchor' \
1125
1147
  .agents/skills/devlyn:resolve/SKILL.md \
1126
- || ! grep -Fq 'hypothesis'\''s backticked observable command as its command anchor' \
1148
+ || ! grep -Fq 'hypothesis'\''s backticked observable command as its exact anchor' \
1127
1149
  config/skills/devlyn:resolve/references/phases/verify.md \
1128
- || ! grep -Fq 'hypothesis'\''s backticked observable command as its command anchor' \
1129
- .claude/skills/devlyn:resolve/references/phases/verify.md \
1130
- || ! grep -Fq 'hypothesis'\''s backticked observable command as its command anchor' \
1150
+ || ! grep -Fq 'hypothesis'\''s backticked observable command as its exact anchor' \
1131
1151
  .agents/skills/devlyn:resolve/references/phases/verify.md; then
1132
1152
  bad "resolve pair-JUDGE prompts must prioritize solo-headroom hypothesis"
1133
1153
  else
1134
1154
  ok "resolve pair-JUDGE prompts prioritize solo-headroom hypothesis"
1135
1155
  fi
1136
1156
  if ! grep -Fq 'The `--engine` flag does not disable default pairing' config/skills/devlyn:resolve/references/phases/verify.md \
1137
- || ! grep -Fq 'The `--engine` flag does not disable default pairing' .claude/skills/devlyn:resolve/references/phases/verify.md \
1138
1157
  || ! grep -Fq 'The `--engine` flag does not disable default pairing' .agents/skills/devlyn:resolve/references/phases/verify.md \
1139
1158
  || ! grep -Fq 'the second judge uses the OTHER engine by default when available' config/skills/devlyn:resolve/SKILL.md \
1140
- || ! grep -Fq 'the second judge uses the OTHER engine by default when available' .claude/skills/devlyn:resolve/SKILL.md \
1141
1159
  || ! grep -Fq 'the second judge uses the OTHER engine by default when available' .agents/skills/devlyn:resolve/SKILL.md \
1142
1160
  || ! grep -Fq '_shared/adapters/<name>.md' config/skills/devlyn:resolve/references/phases/verify.md \
1143
1161
  || ! grep -Fq '`## Invocation`' config/skills/devlyn:resolve/references/phases/verify.md \
@@ -1149,22 +1167,16 @@ else
1149
1167
  ok "engine-neutral pair-judge dual declaration (iter-0060) in sync"
1150
1168
  fi
1151
1169
  if ! grep -Fq '`complexity.high`, `complexity.large`' config/skills/devlyn:resolve/SKILL.md \
1152
- || ! grep -Fq '`complexity.high`, `complexity.large`' .claude/skills/devlyn:resolve/SKILL.md \
1153
1170
  || ! grep -Fq '`complexity.high`, `complexity.large`' .agents/skills/devlyn:resolve/SKILL.md \
1154
1171
  || ! grep -Fq '`spec.complexity.high`, `spec.complexity.large`' config/skills/devlyn:resolve/SKILL.md \
1155
- || ! grep -Fq '`spec.complexity.high`, `spec.complexity.large`' .claude/skills/devlyn:resolve/SKILL.md \
1156
1172
  || ! grep -Fq '`spec.complexity.high`, `spec.complexity.large`' .agents/skills/devlyn:resolve/SKILL.md \
1157
1173
  || ! grep -Fq 'Legacy complexity values remain accepted only for archived compatibility' config/skills/devlyn:resolve/references/state-schema.md \
1158
- || ! grep -Fq 'Legacy complexity values remain accepted only for archived compatibility' .claude/skills/devlyn:resolve/references/state-schema.md \
1159
1174
  || ! grep -Fq 'Legacy complexity values remain accepted only for archived compatibility' .agents/skills/devlyn:resolve/references/state-schema.md \
1160
1175
  || ! grep -Fq '`complexity.high`, `complexity.large`, `spec.complexity.high`, `spec.complexity.large`' config/skills/devlyn:resolve/references/state-schema.md \
1161
- || ! grep -Fq '`complexity.high`, `complexity.large`, `spec.complexity.high`, `spec.complexity.large`' .claude/skills/devlyn:resolve/references/state-schema.md \
1162
1176
  || ! grep -Fq '`complexity.high`, `complexity.large`, `spec.complexity.high`, `spec.complexity.large`' .agents/skills/devlyn:resolve/references/state-schema.md \
1163
1177
  || ! grep -Fq '`complexity.large`, `spec.complexity.high`, `spec.complexity.large`,' config/skills/devlyn:resolve/references/phases/verify.md \
1164
- || ! grep -Fq '`complexity.large`, `spec.complexity.high`, `spec.complexity.large`,' .claude/skills/devlyn:resolve/references/phases/verify.md \
1165
1178
  || ! grep -Fq '`complexity.large`, `spec.complexity.high`, `spec.complexity.large`,' .agents/skills/devlyn:resolve/references/phases/verify.md \
1166
1179
  || ! grep -Fq '`spec.solo_headroom_hypothesis`, `risk.high`, `risk_probes.enabled`,' config/skills/devlyn:resolve/references/phases/verify.md \
1167
- || ! grep -Fq '`spec.solo_headroom_hypothesis`, `risk.high`, `risk_probes.enabled`,' .claude/skills/devlyn:resolve/references/phases/verify.md \
1168
1180
  || ! grep -Fq '`spec.solo_headroom_hypothesis`, `risk.high`, `risk_probes.enabled`,' .agents/skills/devlyn:resolve/references/phases/verify.md; then
1169
1181
  bad "resolve VERIFY docs must distinguish current large complexity, legacy high state, and legacy large spec compatibility"
1170
1182
  else
@@ -1187,23 +1199,6 @@ if ! grep -Fq 'def spec_has_solo_headroom_hypothesis' config/skills/_shared/veri
1187
1199
  || ! grep -Fq 'spec_has_solo_headroom_hypothesis(' config/skills/_shared/verify-merge-findings.py \
1188
1200
  || ! grep -Fq ') is False' config/skills/_shared/verify-merge-findings.py \
1189
1201
  || ! grep -Fq ') is True' config/skills/_shared/verify-merge-findings.py \
1190
- || ! grep -Fq 'def spec_has_solo_headroom_hypothesis' .claude/skills/_shared/verify-merge-findings.py \
1191
- || ! grep -Fq 'spec.solo_headroom_hypothesis' .claude/skills/_shared/verify-merge-findings.py \
1192
- || ! grep -Fq 'and "solo_claude" in lower' .claude/skills/_shared/verify-merge-findings.py \
1193
- || ! grep -Fq 'and "miss" in lower' .claude/skills/_shared/verify-merge-findings.py \
1194
- || ! grep -Fq 'OBSERVABLE_COMMAND_MARKERS = ("command", "observable", "expose")' .claude/skills/_shared/verify-merge-findings.py \
1195
- || ! grep -Fq 'def is_command_like_backtick' .claude/skills/_shared/verify-merge-findings.py \
1196
- || ! grep -Fq 'for key in ("spec_path", "criteria_path")' .claude/skills/_shared/verify-merge-findings.py \
1197
- || ! grep -Fq 'has_backticked_observable_command(text)' .claude/skills/_shared/verify-merge-findings.py \
1198
- || ! grep -Fq 'Observable command: `node check.js` exposes behavior' .claude/skills/_shared/verify-merge-findings.py \
1199
- || ! grep -Fq 'observable `SOLO_CLAUDE` exposes the miss' .claude/skills/_shared/verify-merge-findings.py \
1200
- || ! grep -Fq 'observable `priority rollback` exposes the miss' .claude/skills/_shared/verify-merge-findings.py \
1201
- || ! grep -Fq 'implementation token `rollback`' .claude/skills/_shared/verify-merge-findings.py \
1202
- || ! grep -Fq '`SOLO_CLAUDE` should miss' .claude/skills/_shared/verify-merge-findings.py \
1203
- || ! grep -Fq '{"source": {"criteria_path": str(criteria_path)}}' .claude/skills/_shared/verify-merge-findings.py \
1204
- || ! grep -Fq 'spec_has_solo_headroom_hypothesis(' .claude/skills/_shared/verify-merge-findings.py \
1205
- || ! grep -Fq ') is False' .claude/skills/_shared/verify-merge-findings.py \
1206
- || ! grep -Fq ') is True' .claude/skills/_shared/verify-merge-findings.py \
1207
1202
  || ! grep -Fq 'def spec_has_solo_headroom_hypothesis' .agents/skills/_shared/verify-merge-findings.py \
1208
1203
  || ! grep -Fq 'spec.solo_headroom_hypothesis' .agents/skills/_shared/verify-merge-findings.py \
1209
1204
  || ! grep -Fq 'and "solo_claude" in lower' .agents/skills/_shared/verify-merge-findings.py \
@@ -1221,63 +1216,43 @@ if ! grep -Fq 'def spec_has_solo_headroom_hypothesis' config/skills/_shared/veri
1221
1216
  || ! grep -Fq 'spec_has_solo_headroom_hypothesis(' .agents/skills/_shared/verify-merge-findings.py \
1222
1217
  || ! grep -Fq ') is False' .agents/skills/_shared/verify-merge-findings.py \
1223
1218
  || ! grep -Fq ') is True' .agents/skills/_shared/verify-merge-findings.py \
1224
- || ! grep -Fq '`spec.solo_headroom_hypothesis`' \
1225
- config/skills/devlyn:resolve/references/phases/verify.md \
1226
- || ! grep -Fq '`spec.solo_headroom_hypothesis`' \
1227
- .claude/skills/devlyn:resolve/references/phases/verify.md \
1228
- || ! grep -Fq '`spec.solo_headroom_hypothesis`' \
1229
- .agents/skills/devlyn:resolve/references/phases/verify.md \
1219
+ || ! grep -Fq '`spec.solo_headroom_hypothesis`' config/skills/devlyn:resolve/references/phases/verify.md \
1220
+ || ! grep -Fq '`spec.solo_headroom_hypothesis`' .agents/skills/devlyn:resolve/references/phases/verify.md \
1230
1221
  || ! grep -Fq '`spec.solo_headroom_hypothesis`' config/skills/devlyn:resolve/references/state-schema.md \
1231
- || ! grep -Fq '`spec.solo_headroom_hypothesis`' .claude/skills/devlyn:resolve/references/state-schema.md \
1232
1222
  || ! grep -Fq '`spec.solo_headroom_hypothesis`' .agents/skills/devlyn:resolve/references/state-schema.md \
1233
1223
  || ! grep -Fq 'same actionable solo-headroom hypothesis is a VERIFY pair-trigger reason' config/skills/devlyn:resolve/SKILL.md \
1234
- || ! grep -Fq 'same actionable solo-headroom hypothesis is a VERIFY pair-trigger reason' .claude/skills/devlyn:resolve/SKILL.md \
1235
1224
  || ! grep -Fq 'same actionable solo-headroom hypothesis is a VERIFY pair-trigger reason' .agents/skills/devlyn:resolve/SKILL.md; then
1236
1225
  bad "resolve VERIFY pair trigger must include actionable solo-headroom hypothesis specs"
1237
1226
  else
1238
1227
  ok "resolve VERIFY pair trigger includes actionable solo-headroom hypothesis specs"
1239
1228
  fi
1240
1229
  if ! grep -Fq 'pair_evidence_intent' config/skills/devlyn:resolve/references/free-form-mode.md \
1241
- || ! grep -Fq 'pair_evidence_intent' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1242
1230
  || ! grep -Fq 'pair_evidence_intent' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1243
1231
  || ! grep -Fq 'has_actionable_solo_headroom' config/skills/devlyn:resolve/references/free-form-mode.md \
1244
- || ! grep -Fq 'has_actionable_solo_headroom' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1245
1232
  || ! grep -Fq 'has_actionable_solo_headroom' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1246
1233
  || ! grep -Fq 'state.source.type = "generated"' config/skills/devlyn:resolve/SKILL.md \
1247
- || ! grep -Fq 'state.source.type = "generated"' .claude/skills/devlyn:resolve/SKILL.md \
1248
1234
  || ! grep -Fq 'state.source.type = "generated"' .agents/skills/devlyn:resolve/SKILL.md \
1249
1235
  || ! grep -Fq 'state.source.criteria_path = ".devlyn/criteria.generated.md"' config/skills/devlyn:resolve/references/free-form-mode.md \
1250
- || ! grep -Fq 'state.source.criteria_path = ".devlyn/criteria.generated.md"' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1251
1236
  || ! grep -Fq 'state.source.criteria_path = ".devlyn/criteria.generated.md"' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1252
1237
  || ! grep -Fq 'state.source.criteria_sha256' config/skills/devlyn:resolve/references/free-form-mode.md \
1253
- || ! grep -Fq 'state.source.criteria_sha256' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1254
1238
  || ! grep -Fq 'state.source.criteria_sha256' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1255
1239
  || ! grep -Fq 'state.source.criteria_sha256` for generated free-form mode' config/skills/devlyn:resolve/references/phases/verify.md \
1256
- || ! grep -Fq 'state.source.criteria_sha256` for generated free-form mode' .claude/skills/devlyn:resolve/references/phases/verify.md \
1257
1240
  || ! grep -Fq 'state.source.criteria_sha256` for generated free-form mode' .agents/skills/devlyn:resolve/references/phases/verify.md \
1258
1241
  || ! grep -Fq 'Free-form sets `type: "generated"`' config/skills/devlyn:resolve/references/state-schema.md \
1259
- || ! grep -Fq 'Free-form sets `type: "generated"`' .claude/skills/devlyn:resolve/references/state-schema.md \
1260
1242
  || ! grep -Fq 'Free-form sets `type: "generated"`' .agents/skills/devlyn:resolve/references/state-schema.md \
1261
1243
  || ! grep -Fq 'backticked observable command line that itself contains `miss`' config/skills/devlyn:resolve/references/free-form-mode.md \
1262
- || ! grep -Fq 'backticked observable command line that itself contains `miss`' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1263
1244
  || ! grep -Fq 'backticked observable command line that itself contains `miss`' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1264
1245
  || ! grep -Fq 'BLOCKED:solo-headroom-hypothesis-required' config/skills/devlyn:resolve/references/free-form-mode.md \
1265
- || ! grep -Fq 'BLOCKED:solo-headroom-hypothesis-required' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1266
1246
  || ! grep -Fq 'BLOCKED:solo-headroom-hypothesis-required' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1267
1247
  || ! grep -Fq 'pair-evidence intent without an actionable solo-headroom hypothesis must halt' config/skills/devlyn:resolve/SKILL.md \
1268
- || ! grep -Fq 'pair-evidence intent without an actionable solo-headroom hypothesis must halt' .claude/skills/devlyn:resolve/SKILL.md \
1269
1248
  || ! grep -Fq 'pair-evidence intent without an actionable solo-headroom hypothesis must halt' .agents/skills/devlyn:resolve/SKILL.md \
1270
1249
  || ! grep -Fq 'preserve that literal hypothesis in `.devlyn/criteria.generated.md`' config/skills/devlyn:resolve/references/free-form-mode.md \
1271
- || ! grep -Fq 'preserve that literal hypothesis in `.devlyn/criteria.generated.md`' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1272
1250
  || ! grep -Fq 'preserve that literal hypothesis in `.devlyn/criteria.generated.md`' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1273
1251
  || ! grep -Fq 'emit the canonical `spec.solo_headroom_hypothesis` pair trigger reason' config/skills/devlyn:resolve/references/free-form-mode.md \
1274
- || ! grep -Fq 'emit the canonical `spec.solo_headroom_hypothesis` pair trigger reason' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1275
1252
  || ! grep -Fq 'emit the canonical `spec.solo_headroom_hypothesis` pair trigger reason' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1276
1253
  || ! grep -Fq '/devlyn:ideate` guidance for `BLOCKED:solo-headroom-hypothesis-required`' config/skills/devlyn:resolve/references/state-schema.md \
1277
- || ! grep -Fq '/devlyn:ideate` guidance for `BLOCKED:solo-headroom-hypothesis-required`' .claude/skills/devlyn:resolve/references/state-schema.md \
1278
1254
  || ! grep -Fq '/devlyn:ideate` guidance for `BLOCKED:solo-headroom-hypothesis-required`' .agents/skills/devlyn:resolve/references/state-schema.md \
1279
1255
  || ! grep -Fq '/devlyn:ideate` guidance after `BLOCKED:solo-headroom-hypothesis-required`' config/skills/devlyn:resolve/SKILL.md \
1280
- || ! grep -Fq '/devlyn:ideate` guidance after `BLOCKED:solo-headroom-hypothesis-required`' .claude/skills/devlyn:resolve/SKILL.md \
1281
1256
  || ! grep -Fq '/devlyn:ideate` guidance after `BLOCKED:solo-headroom-hypothesis-required`' .agents/skills/devlyn:resolve/SKILL.md \
1282
1257
  || ! grep -Fq 'Free-form goals that ask for benchmark evidence, pair-evidence, risk-probe' README.md \
1283
1258
  || ! grep -Fq '`/devlyn:resolve` stops with `BLOCKED:solo-headroom-hypothesis-required`' README.md \
@@ -1287,22 +1262,16 @@ else
1287
1262
  ok "resolve free-form mode blocks pair-evidence goals without actionable solo-headroom hypothesis"
1288
1263
  fi
1289
1264
  if ! grep -Fq 'unmeasured_pair_candidate_intent' config/skills/devlyn:resolve/references/free-form-mode.md \
1290
- || ! grep -Fq 'unmeasured_pair_candidate_intent' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1291
1265
  || ! grep -Fq 'unmeasured_pair_candidate_intent' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1292
1266
  || ! grep -Fq 'has_solo_ceiling_avoidance' config/skills/devlyn:resolve/references/free-form-mode.md \
1293
- || ! grep -Fq 'has_solo_ceiling_avoidance' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1294
1267
  || ! grep -Fq 'has_solo_ceiling_avoidance' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1295
1268
  || ! grep -Fq 'BLOCKED:solo-ceiling-avoidance-required' config/skills/devlyn:resolve/references/free-form-mode.md \
1296
- || ! grep -Fq 'BLOCKED:solo-ceiling-avoidance-required' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1297
1269
  || ! grep -Fq 'BLOCKED:solo-ceiling-avoidance-required' .agents/skills/devlyn:resolve/references/free-form-mode.md \
1298
1270
  || ! grep -Fq 'unmeasured pair-candidate intent without solo ceiling avoidance must halt' config/skills/devlyn:resolve/SKILL.md \
1299
- || ! grep -Fq 'unmeasured pair-candidate intent without solo ceiling avoidance must halt' .claude/skills/devlyn:resolve/SKILL.md \
1300
1271
  || ! grep -Fq 'unmeasured pair-candidate intent without solo ceiling avoidance must halt' .agents/skills/devlyn:resolve/SKILL.md \
1301
1272
  || ! grep -Fq '/devlyn:ideate` guidance after `BLOCKED:solo-ceiling-avoidance-required`' config/skills/devlyn:resolve/SKILL.md \
1302
- || ! grep -Fq '/devlyn:ideate` guidance after `BLOCKED:solo-ceiling-avoidance-required`' .claude/skills/devlyn:resolve/SKILL.md \
1303
1273
  || ! grep -Fq '/devlyn:ideate` guidance after `BLOCKED:solo-ceiling-avoidance-required`' .agents/skills/devlyn:resolve/SKILL.md \
1304
1274
  || ! grep -Fq '/devlyn:ideate` guidance for `BLOCKED:solo-ceiling-avoidance-required`' config/skills/devlyn:resolve/references/state-schema.md \
1305
- || ! grep -Fq '/devlyn:ideate` guidance for `BLOCKED:solo-ceiling-avoidance-required`' .claude/skills/devlyn:resolve/references/state-schema.md \
1306
1275
  || ! grep -Fq '/devlyn:ideate` guidance for `BLOCKED:solo-ceiling-avoidance-required`' .agents/skills/devlyn:resolve/references/state-schema.md \
1307
1276
  || ! grep -Fq '`/devlyn:resolve` stops with `BLOCKED:solo-ceiling-avoidance-required`' README.md; then
1308
1277
  bad "resolve free-form mode must block new unmeasured pair candidates without solo ceiling avoidance"
@@ -1367,11 +1336,61 @@ if [ $verify_mech_missing -eq 0 ]; then
1367
1336
  ok "spec-verify VERIFY output routes into verify-merge-findings.py"
1368
1337
  fi
1369
1338
 
1339
+ section "Check 6i1: Verification provenance contract is wired"
1340
+ verification_provenance_missing=0
1341
+ for file in \
1342
+ config/skills/devlyn:resolve/SKILL.md \
1343
+ .agents/skills/devlyn:resolve/SKILL.md
1344
+ do
1345
+ if ! grep -Fq 'resolved BUILD_GATE engine through the fresh-worker route' "$file" \
1346
+ || ! grep -Fq 'BLOCKED:build-env-underprovisioned' "$file" \
1347
+ || ! grep -Fq '.devlyn/<primary-engine>-judge.stdout' "$file" \
1348
+ || ! grep -Fq '.devlyn/<other-engine>-judge.stdout' "$file" \
1349
+ || ! grep -Fq 'state-bound process-evidence manifest/raw stream' "$file"; then
1350
+ bad "$file — orchestrator provenance/capability/archive contract missing"
1351
+ verification_provenance_missing=1
1352
+ fi
1353
+ done
1354
+ for file in \
1355
+ config/skills/devlyn:resolve/references/phases/verify.md \
1356
+ .agents/skills/devlyn:resolve/references/phases/verify.md
1357
+ do
1358
+ if ! grep -Fq 'executable verification belongs exclusively to MECHANICAL' "$file" \
1359
+ || ! grep -Fq 'native read/search tools or non-mutating shell commands' "$file" \
1360
+ || ! grep -Fq 'JUDGE does not execute literal verification, lint, test, build, risk-probe, or' "$file" \
1361
+ || ! grep -Fq 'newly invented interaction commands.' "$file" \
1362
+ || ! grep -Fq '.devlyn/<primary-engine>-judge.stdout' "$file" \
1363
+ || ! grep -Fq '.devlyn/<other-engine>-judge.stdout' "$file" \
1364
+ || ! grep -Fq 'process-evidence manifest and raw stdout/stderr streams' "$file"; then
1365
+ bad "$file — JUDGE sealed-evidence contract missing"
1366
+ verification_provenance_missing=1
1367
+ fi
1368
+ if grep -Fq 'execute at least one combined adversarial check' "$file" \
1369
+ || grep -Fq 'Execute at most two targeted probes' "$file" \
1370
+ || grep -Fq "repo's CLI/API/test runner" "$file"; then
1371
+ bad "$file — stale JUDGE command-execution instruction remains"
1372
+ verification_provenance_missing=1
1373
+ fi
1374
+ done
1375
+ for file in \
1376
+ config/skills/devlyn:resolve/SKILL.md \
1377
+ .agents/skills/devlyn:resolve/SKILL.md \
1378
+ config/skills/devlyn:resolve/references/phases/verify.md \
1379
+ .agents/skills/devlyn:resolve/references/phases/verify.md
1380
+ do
1381
+ if grep -Eiq 'executes? no commands|no code-mutation or command-execution tools|do not receive command-execution tools' "$file"; then
1382
+ bad "$file — blanket JUDGE inspection prohibition remains"
1383
+ verification_provenance_missing=1
1384
+ fi
1385
+ done
1386
+ if [ $verification_provenance_missing -eq 0 ]; then
1387
+ ok "BUILD_GATE, sealed JUDGE inputs, canonical captures, and archive flow are wired"
1388
+ fi
1389
+
1370
1390
  section "Check 6j: VERIFY default pair dispatches concurrently"
1371
1391
  pair_trigger_order_missing=0
1372
1392
  for file in \
1373
1393
  config/skills/devlyn:resolve/SKILL.md \
1374
- .claude/skills/devlyn:resolve/SKILL.md \
1375
1394
  .agents/skills/devlyn:resolve/SKILL.md
1376
1395
  do
1377
1396
  if ! grep -Fq 'Verify dual-judge is default-when-available' "$file" \
@@ -1387,7 +1406,6 @@ do
1387
1406
  done
1388
1407
  for file in \
1389
1408
  config/skills/devlyn:resolve/references/phases/verify.md \
1390
- .claude/skills/devlyn:resolve/references/phases/verify.md \
1391
1409
  .agents/skills/devlyn:resolve/references/phases/verify.md
1392
1410
  do
1393
1411
  if ! grep -Fq 'Pair-mode (default when OTHER engine is available)' "$file" \
@@ -1403,7 +1421,6 @@ do
1403
1421
  done
1404
1422
  for file in \
1405
1423
  config/skills/devlyn:resolve/references/state-schema.md \
1406
- .claude/skills/devlyn:resolve/references/state-schema.md \
1407
1424
  .agents/skills/devlyn:resolve/references/state-schema.md
1408
1425
  do
1409
1426
  if ! grep -Fq '"version": "3.0"' "$file" \
@@ -1421,6 +1438,37 @@ if [ $pair_trigger_order_missing -eq 0 ]; then
1421
1438
  ok "VERIFY default pair dispatches concurrently"
1422
1439
  fi
1423
1440
 
1441
+ section "Check 6k: PLAN route is orchestrator-fixed"
1442
+ plan_route_ok=1
1443
+ for plan_route_file in "config/skills/devlyn:resolve/SKILL.md" CLAUDE.md AGENTS.md \
1444
+ "config/skills/devlyn:engines/SKILL.md" ".agents/skills/devlyn:resolve/SKILL.md" \
1445
+ ".agents/skills/devlyn:engines/SKILL.md"; do
1446
+ [ -f "$plan_route_file" ] || plan_route_ok=0
1447
+ done
1448
+ sed -n '/^<engine_routing>$/,/^<\/engine_routing>$/p' "config/skills/devlyn:resolve/SKILL.md" \
1449
+ | grep -Fq 'PLAN is orchestrator-fixed and never inherits `--engine`, an executor pin, or `state.engine`' || plan_route_ok=0
1450
+ sed -n '/^## PHASE 1: PLAN$/,/^## PHASE 1.5/p' "config/skills/devlyn:resolve/SKILL.md" \
1451
+ | grep -Fq 'PLAN is orchestrator-fixed and never inherits `--engine`, an executor pin, or `state.engine`' || plan_route_ok=0
1452
+ grep -Fq 'PLAN is orchestrator-fixed and never inherits `--engine` or an executor pin' CLAUDE.md || plan_route_ok=0
1453
+ grep -Fq 'PLAN is orchestrator-fixed and never inherits `--engine` or the executor pin' AGENTS.md || plan_route_ok=0
1454
+ grep -Fq 'PLAN is orchestrator-fixed and never follows the pin' config/skills/devlyn:engines/SKILL.md || plan_route_ok=0
1455
+ if grep -En '([Ee]xecutor|Default engine: Claude for)[^[:cntrl:]]{0,80}PLAN[[:space:]]*/[[:space:]]*IMPLEMENT([[:space:]]*/[[:space:]]*BUILD_GATE)?[[:space:]]*/[[:space:]]*CLEANUP' \
1456
+ config/skills/devlyn:resolve/SKILL.md \
1457
+ CLAUDE.md \
1458
+ AGENTS.md \
1459
+ README.md \
1460
+ config/skills/devlyn:engines/SKILL.md \
1461
+ .agents/skills/devlyn:resolve/SKILL.md \
1462
+ .agents/skills/devlyn:engines/SKILL.md \
1463
+ >/dev/null 2>&1; then
1464
+ plan_route_ok=0
1465
+ fi
1466
+ if [ $plan_route_ok -eq 1 ]; then
1467
+ ok "PLAN is orchestrator-fixed: exact declarations locked on all surfaces, no executor-role enumeration"
1468
+ else
1469
+ bad "PLAN route contract violated: a locked orchestrator-fixed declaration is missing or an executor-role enumeration re-teaches PLAN"
1470
+ fi
1471
+
1424
1472
  section "Check 6h: No undocumented spec.expected.json.browser_flows field"
1425
1473
  browser_flow_refs=$(grep -RInF 'spec.expected.json.browser_flows' \
1426
1474
  config/skills README.md bin/ package.json 2>/dev/null || true)
@@ -1511,6 +1559,72 @@ fi
1511
1559
  # The wrapper owns the flag expansion; skill docs own requiring
1512
1560
  # CODEX_MONITORED_ISOLATED=1 for probe-derive and pair-JUDGE.
1513
1561
  # ---------------------------------------------------------------------------
1562
+ section "Check 10a0: Codex primary VERIFY budget is bounded and mirrored"
1563
+ primary_verify_missing=0
1564
+ primary_verify_route='CODEX_MONITORED_ISOLATED=1 CODEX_MONITORED_TIMEOUT_SEC=600 bash "$CODEX_MONITORED_PATH" -C "$PWD" -s read-only -c model_reasoning_effort=high "<primary prompt>" >.devlyn/codex-judge.stdout 2>.devlyn/codex-judge.stderr'
1565
+ for file in \
1566
+ config/skills/devlyn:resolve/SKILL.md \
1567
+ .agents/skills/devlyn:resolve/SKILL.md \
1568
+ config/skills/devlyn:resolve/references/phases/verify.md \
1569
+ .agents/skills/devlyn:resolve/references/phases/verify.md
1570
+ do
1571
+ if { ! grep -Fxq "$primary_verify_route" "$file" \
1572
+ && ! grep -Fq "\`$primary_verify_route\`" "$file"; } \
1573
+ || ! grep -Fq '.devlyn/verify.primary.timeout.json' "$file" \
1574
+ || ! grep -Fq 'pair-style `TIMEOUT`' "$file"; then
1575
+ bad "$file — Codex primary-JUDGE route/timeout authority missing"
1576
+ primary_verify_missing=1
1577
+ fi
1578
+ done
1579
+ for file in \
1580
+ config/skills/devlyn:resolve/references/phases/verify.md \
1581
+ .agents/skills/devlyn:resolve/references/phases/verify.md
1582
+ do
1583
+ for needle in \
1584
+ 'one broad pass over the' \
1585
+ 'It then makes one' \
1586
+ 'targeted interaction pass over the clauses the broad pass left unresolved.' \
1587
+ 'Before any third pass' \
1588
+ 'verdict-binding BLOCKED coverage finding'
1589
+ do
1590
+ if ! grep -Fq "$needle" "$file"; then
1591
+ bad "$file — bounded primary review instruction missing: $needle"
1592
+ primary_verify_missing=1
1593
+ fi
1594
+ done
1595
+ done
1596
+ for file in \
1597
+ config/skills/_shared/adapters/codex.md \
1598
+ .agents/skills/_shared/adapters/codex.md
1599
+ do
1600
+ for needle in \
1601
+ 'batch related reads' \
1602
+ 'sealed parity proves' \
1603
+ 'Open self-test bodies or MECHANICAL raw streams only for a'
1604
+ do
1605
+ if ! grep -Fq "$needle" "$file"; then
1606
+ bad "$file — Codex bounded retrieval tactic missing: $needle"
1607
+ primary_verify_missing=1
1608
+ fi
1609
+ done
1610
+ done
1611
+ for file in \
1612
+ config/skills/_shared/verify-merge-findings.py \
1613
+ .agents/skills/_shared/verify-merge-findings.py \
1614
+ config/skills/_shared/archive_run.py \
1615
+ .agents/skills/_shared/archive_run.py \
1616
+ config/skills/_shared/resolve-bootstrap.py \
1617
+ .agents/skills/_shared/resolve-bootstrap.py
1618
+ do
1619
+ if ! grep -Fq 'verify.primary.timeout.json' "$file"; then
1620
+ bad "$file — primary timeout deterministic/archive contract missing"
1621
+ primary_verify_missing=1
1622
+ fi
1623
+ done
1624
+ if [ $primary_verify_missing -eq 0 ]; then
1625
+ ok "Codex primary VERIFY is bounded, fail-closed, archived, and mirrored"
1626
+ fi
1627
+
1514
1628
  section "Check 10a: Bounded Codex calls use isolated wrapper mode"
1515
1629
  isolation_missing=0
1516
1630
  for needle in \
@@ -1572,12 +1686,18 @@ cat > "$tmp_iso/codex" <<'EOF'
1572
1686
  printf '%s\n' "$@" > "$CODEX_FAKE_ARGS_OUT"
1573
1687
  EOF
1574
1688
  chmod +x "$tmp_iso/codex"
1575
- CODEX_FAKE_ARGS_OUT="$tmp_iso/args.txt" \
1576
- CODEX_MONITORED_ISOLATED=1 \
1577
- CODEX_MONITORED_HEARTBEAT=999 \
1578
- CODEX_BIN="$tmp_iso/codex" \
1579
- bash config/skills/_shared/codex-monitored.sh -s read-only prompt \
1580
- >"$tmp_iso/stdout.txt" 2>"$tmp_iso/stderr.txt"
1689
+ (
1690
+ unset DEVLYN_INVOCATION_RUN_ID DEVLYN_INVOCATION_PHASE \
1691
+ DEVLYN_INVOCATION_ROUND DEVLYN_INVOCATION_WORKDIR \
1692
+ DEVLYN_INVOCATION_PROMPT_FILE DEVLYN_INVOCATION_SESSION_FILE \
1693
+ DEVLYN_INVOCATION_RECEIPT
1694
+ CODEX_FAKE_ARGS_OUT="$tmp_iso/args.txt" \
1695
+ CODEX_MONITORED_ISOLATED=1 \
1696
+ CODEX_MONITORED_HEARTBEAT=999 \
1697
+ CODEX_BIN="$tmp_iso/codex" \
1698
+ bash config/skills/_shared/codex-monitored.sh -s read-only prompt \
1699
+ >"$tmp_iso/stdout.txt" 2>"$tmp_iso/stderr.txt"
1700
+ )
1581
1701
  iso_exit=$?
1582
1702
  if [ $iso_exit -ne 0 ]; then
1583
1703
  bad "codex-monitored.sh isolated fake invocation exited $iso_exit"
@@ -1615,6 +1735,34 @@ else
1615
1735
  while IFS= read -r f; do bad "$f"; done <<< "$shared_path_offenders"
1616
1736
  fi
1617
1737
 
1738
+ section "Check 10a2: Bounded non-interactive calls discard inherited input"
1739
+ if python3 - <<'PY'
1740
+ import json, subprocess, sys
1741
+
1742
+ prompt = "sealed argv prompt\n두 번째 줄"
1743
+ poison = b"OPERATOR_HEREDOC_SHOULD_NOT_BECOME_USER_INPUT\n"
1744
+ child = (
1745
+ "import json,sys,time; "
1746
+ "print(json.dumps({'argv':sys.argv[1:],'stdin_hex':sys.stdin.buffer.read().hex()},ensure_ascii=False),flush=True); "
1747
+ "print('stderr preserved',file=sys.stderr,flush=True); "
1748
+ "time.sleep(float(sys.argv[2])); raise SystemExit(int(sys.argv[3]))"
1749
+ )
1750
+ for label, delay, code, expected_exit in (("normal", 0, 0, 0), ("nonzero", 0, 17, 17), ("timeout", 30, 0, 124)):
1751
+ args = [prompt, str(delay), str(code)]
1752
+ result = subprocess.run(
1753
+ [sys.executable, "config/skills/_shared/run-bounded.py", "1", "--", sys.executable, "-c", child, *args],
1754
+ input=poison, capture_output=True, timeout=9,
1755
+ )
1756
+ assert result.returncode == expected_exit, (label, result.returncode)
1757
+ assert json.loads(result.stdout) == {"argv": args, "stdin_hex": ""}, (label, result.stdout)
1758
+ assert result.stderr == b"stderr preserved\n", (label, result.stderr)
1759
+ PY
1760
+ then
1761
+ ok "run-bounded.py closes child stdin and preserves argv, streams, exits and timeout"
1762
+ else
1763
+ bad "run-bounded.py inherited-input/exit/timeout regression failed"
1764
+ fi
1765
+
1618
1766
  # ---------------------------------------------------------------------------
1619
1767
  # 10b. Shared routing docs must describe the current 2-skill surface.
1620
1768
  # A stale auto-resolve/preflight/ideate-CHALLENGE reference can misroute
@@ -2640,7 +2788,7 @@ if ! grep -Fq 'solo_claude beats bare' benchmark/auto-resolve/scripts/build-pair
2640
2788
  || ! grep -Fq 'wrong mapping' benchmark/auto-resolve/scripts/test-build-pair-eligible-manifest.sh; then
2641
2789
  offenders="${offenders}"$'\n'"build-pair-eligible-manifest.py must use arm-mapped clean scores for F9 and L1<=L0 promotion"
2642
2790
  fi
2643
- if [ -d benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-cli-quote-tax-rules ] \
2791
+ if [ -f benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-cli-quote-tax-rules/judge.json ] \
2644
2792
  && ! python3 benchmark/auto-resolve/scripts/full-pipeline-pair-gate.py \
2645
2793
  --run-id 20260510-f16-f23-f25-combined-proof \
2646
2794
  --pair-arm l2_risk_probes \
@@ -2651,7 +2799,7 @@ if [ -d benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-c
2651
2799
  --out-md /tmp/devlyn-lint-f16-f23-f25-pair-gate.md >/dev/null 2>&1; then
2652
2800
  offenders="${offenders}"$'\n'"current local artifacts for 20260510-f16-f23-f25-combined-proof must re-gate as PASS"
2653
2801
  fi
2654
- if [ -d benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/F21-cli-scheduler-priority ] \
2802
+ if [ -f benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/F21-cli-scheduler-priority/judge.json ] \
2655
2803
  && ! python3 benchmark/auto-resolve/scripts/full-pipeline-pair-gate.py \
2656
2804
  --run-id 20260511-f21-current-riskprobes-v1 \
2657
2805
  --pair-arm l2_risk_probes \
@@ -3399,7 +3547,7 @@ if ! grep -Fq '"max_observed_pair_solo_wall_ratio": 2.2506234413965087' benchmar
3399
3547
  fi
3400
3548
  if make_temp_dir package_results /tmp/devlyn-lint-package-results.XXXXXX \
3401
3549
  && make_temp_dir package_audit /tmp/devlyn-lint-package-audit.XXXXXX \
3402
- && make_temp_file package_audit_stdout /tmp/devlyn-lint-package-audit.XXXXXX.out; then
3550
+ && make_temp_file package_audit_stdout /tmp/devlyn-lint-package-audit.out.XXXXXX; then
3403
3551
  cp -R benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof "$package_results/"
3404
3552
  cp -R benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1 "$package_results/"
3405
3553
  for rejected_run in \
@@ -3507,9 +3655,10 @@ PY
3507
3655
  else
3508
3656
  offenders="${offenders}"$'\n'"packaged pair evidence subset could not allocate temporary audit workspace"
3509
3657
  fi
3510
- if make_temp_file pack_json /tmp/devlyn-lint-pack.XXXXXX.json \
3511
- && npm pack --dry-run --json > "$pack_json" 2>/dev/null; then
3512
- if ! node - "$pack_json" <<'NODE'
3658
+ if make_temp_file pack_json /tmp/devlyn-lint-pack.json.XXXXXX \
3659
+ && make_temp_dir pack_cache /tmp/devlyn-lint-pack-cache.XXXXXX; then
3660
+ if npm_config_cache="$pack_cache" npm pack --dry-run --json > "$pack_json" 2>/dev/null; then
3661
+ if ! node - "$pack_json" <<'NODE'
3513
3662
  const fs = require("fs");
3514
3663
  const path = require("path");
3515
3664
  const packPath = process.argv[2];
@@ -3534,10 +3683,14 @@ const required = [
3534
3683
  "benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/headroom-gate.json",
3535
3684
  "benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/full-pipeline-pair-gate.md",
3536
3685
  "benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/full-pipeline-pair-gate.json",
3686
+ "benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-cli-quote-tax-rules/l2_risk_probes/result.json",
3687
+ "benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F23-cli-fulfillment-wave/l2_risk_probes/result.json",
3688
+ "benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F25-cli-cart-promotion-rules/l2_risk_probes/result.json",
3537
3689
  "benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.md",
3538
3690
  "benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.json",
3539
3691
  "benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.md",
3540
3692
  "benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.json",
3693
+ "benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/F21-cli-scheduler-priority/l2_risk_probes/result.json",
3541
3694
  "benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.json",
3542
3695
  "benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.json",
3543
3696
  "benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.json",
@@ -3595,13 +3748,17 @@ if (forbidden.length > 0) {
3595
3748
  process.exit(2);
3596
3749
  }
3597
3750
  NODE
3598
- then
3599
- offenders="${offenders}"$'\n'"npm pack dry-run must include benchmark runner/gate regression tests, all shadow fixture files, retired fixture replay docs, and exclude pycache artifacts"
3751
+ then
3752
+ offenders="${offenders}"$'\n'"npm pack dry-run must include benchmark runner/gate regression tests, all shadow fixture files, retired fixture replay docs, and exclude pycache artifacts"
3753
+ fi
3754
+ else
3755
+ offenders="${offenders}"$'\n'"npm pack dry-run failed while checking benchmark runner/gate regression tests"
3600
3756
  fi
3601
3757
  else
3602
- offenders="${offenders}"$'\n'"npm pack dry-run failed while checking benchmark runner/gate regression tests"
3758
+ offenders="${offenders}"$'\n'"npm pack dry-run could not allocate temporary package workspace"
3603
3759
  fi
3604
3760
  [ -n "${pack_json:-}" ] && rm -f "$pack_json"
3761
+ [ -n "${pack_cache:-}" ] && rm -rf "$pack_cache"
3605
3762
  non_executable_shell_scripts=$(find benchmark/auto-resolve/scripts -maxdepth 1 -name '*.sh' -type f ! -perm -111 -print | sort)
3606
3763
  if [ -n "$non_executable_shell_scripts" ]; then
3607
3764
  while IFS= read -r f; do
@@ -3957,7 +4114,7 @@ else
3957
4114
  else
3958
4115
  bad "idgen temp files unavailable; cannot verify determinism"
3959
4116
  fi
3960
- if make_temp_dir tmp_bad && make_temp_file idgen_nan_out /tmp/pair-plan-idgen-nan.XXXXXX.out; then
4117
+ if make_temp_dir tmp_bad && make_temp_file idgen_nan_out /tmp/pair-plan-idgen-nan.out.XXXXXX; then
3961
4118
  cp -R "$fixture/." "$tmp_bad/"
3962
4119
  printf '{"verification_commands": NaN}\n' > "$tmp_bad/expected.json"
3963
4120
  if python3 "$idgen" --fixture "$tmp_bad" --generated-at 2026-04-29T18:30:00Z >"$idgen_nan_out" 2>&1; then
@@ -3968,7 +4125,7 @@ else
3968
4125
  rm -rf "$tmp_bad" "$idgen_nan_out"
3969
4126
  fi
3970
4127
 
3971
- if make_temp_file bad_plan && make_temp_file plan_lint_nan_out /tmp/pair-plan-lint-nan.XXXXXX.out; then
4128
+ if make_temp_file bad_plan && make_temp_file plan_lint_nan_out /tmp/pair-plan-lint-nan.out.XXXXXX; then
3972
4129
  printf '{"schema_version": NaN}\n' > "$bad_plan"
3973
4130
  if python3 benchmark/auto-resolve/scripts/pair-plan-lint.py --plan "$bad_plan" --quiet >"$plan_lint_nan_out" 2>&1; then
3974
4131
  bad "pair-plan-lint.py accepted NaN in pair-plan.json"