devlyn-cli 2.9.3 → 2.10.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 (28) hide show
  1. package/AGENTS.md +3 -3
  2. package/CLAUDE.md +4 -4
  3. package/README.md +4 -4
  4. package/benchmark/auto-resolve/fixtures/SCHEMA.md +1 -1
  5. package/benchmark/auto-resolve/scripts/pair_evidence_contract.py +1 -0
  6. package/bin/devlyn.js +55 -7
  7. package/config/skills/_shared/adapters/README.md +2 -2
  8. package/config/skills/_shared/adapters/grok.md +77 -0
  9. package/config/skills/_shared/archive_run.py +35 -1
  10. package/config/skills/_shared/collect-codex-findings.py +15 -10
  11. package/config/skills/_shared/engine-doctor.sh +6 -3
  12. package/config/skills/_shared/engine-preflight.md +12 -5
  13. package/config/skills/_shared/resolve-bootstrap.py +630 -0
  14. package/config/skills/_shared/resolve-stop-hook.py +325 -0
  15. package/config/skills/_shared/state-phase-write.py +2264 -13
  16. package/config/skills/_shared/terminal-claim-check.py +537 -0
  17. package/config/skills/_shared/verify-merge-findings.py +363 -16
  18. package/config/skills/devlyn:engines/SKILL.md +1 -1
  19. package/config/skills/devlyn:queue/SKILL.md +12 -0
  20. package/config/skills/devlyn:resolve/SKILL.md +54 -73
  21. package/config/skills/devlyn:resolve/references/phases/surface-close.md +34 -0
  22. package/config/skills/devlyn:resolve/references/phases/verify.md +65 -96
  23. package/config/skills/devlyn:resolve/references/state-schema.md +25 -18
  24. package/optional-skills/devlyn:reap/SKILL.md +1 -1
  25. package/optional-skills/devlyn:reap/scripts/reap.sh +25 -13
  26. package/optional-skills/devlyn:reap/scripts/scan.sh +15 -1
  27. package/package.json +1 -1
  28. package/scripts/lint-skills.sh +131 -67
@@ -60,17 +60,22 @@ _shared/spec-verify-check.py
60
60
  _shared/collect-codex-findings.py
61
61
  _shared/verify-merge-findings.py
62
62
  _shared/state-phase-write.py
63
+ _shared/terminal-claim-check.py
64
+ _shared/resolve-stop-hook.py
65
+ _shared/resolve-bootstrap.py
63
66
  devlyn:ideate/SKILL.md
64
67
  devlyn:ideate/references/spec-template.md
65
68
  devlyn:ideate/references/elicitation.md
66
69
  devlyn:ideate/references/project-mode.md
67
70
  devlyn:ideate/references/from-spec-mode.md
68
71
  devlyn:resolve/SKILL.md
72
+ devlyn:queue/SKILL.md
69
73
  devlyn:resolve/references/state-schema.md
70
74
  devlyn:resolve/references/free-form-mode.md
71
75
  devlyn:resolve/references/phases/plan.md
72
76
  devlyn:resolve/references/phases/probe-derive.md
73
77
  devlyn:resolve/references/phases/implement.md
78
+ devlyn:resolve/references/phases/surface-close.md
74
79
  devlyn:resolve/references/phases/build-gate.md
75
80
  devlyn:resolve/references/phases/cleanup.md
76
81
  devlyn:resolve/references/phases/verify.md
@@ -78,6 +83,7 @@ _shared/expected.schema.json
78
83
  _shared/adapters/README.md
79
84
  _shared/adapters/claude.md
80
85
  _shared/adapters/codex.md
86
+ _shared/adapters/grok.md
81
87
  _shared/adapters/omp.md
82
88
  _shared/codex-config.md
83
89
  _shared/codex-monitored.sh
@@ -198,16 +204,19 @@ else
198
204
  fi
199
205
 
200
206
  # ---------------------------------------------------------------------------
201
- # 4. No model-pinned Claude references, any generation. Engine-scope docs say
202
- # "Claude"; exact model ids belong in run metadata only.
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.
203
209
  # ---------------------------------------------------------------------------
204
210
  section "Check 4: No model-pinned Claude references"
205
- offenders=$(grep -RIlnE 'Claude (Opus|Sonnet|Haiku|Fable)|claude-(opus|sonnet|haiku|fable)-[0-9]' \
211
+ offenders=$(grep -RInE 'Claude (Opus|Sonnet|Haiku|Fable)|claude-(opus|sonnet|haiku|fable)-[0-9]' \
206
212
  config/skills 2>/dev/null \
207
213
  | grep -v 'config/skills/roadmap-archival-workspace/' \
208
214
  | grep -v 'config/skills/devlyn:auto-resolve-workspace/' \
209
215
  | grep -v 'config/skills/devlyn:ideate-workspace/' \
210
216
  | 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\.' \
218
+ | cut -d: -f1 \
219
+ | sort -u \
211
220
  || true)
212
221
  if [ -z "$offenders" ]; then
213
222
  ok "no model-pinned Claude references"
@@ -332,23 +341,23 @@ if ! grep -Fq 'def pair_trigger_skip_contract_violation' config/skills/_shared/v
332
341
  || ! grep -Fq 'verify-pair-trigger-skipped-reason-unsupported' config/skills/_shared/verify-merge-findings.py \
333
342
  || ! grep -Fq 'verify-pair-trigger-mechanical-blocker-unsupported' config/skills/_shared/verify-merge-findings.py \
334
343
  || ! grep -Fq 'verify-pair-trigger-primary-judge-blocker-unsupported' config/skills/_shared/verify-merge-findings.py \
335
- || ! grep -Fq 'eligible:false` with no supported skip reason' config/skills/devlyn:resolve/references/state-schema.md \
336
- || ! grep -Fq 'Canonical eligible reasons are `mode.verify-only`' config/skills/devlyn:resolve/references/state-schema.md \
344
+ || ! grep -Fq 'Missing, contradictory, incomplete, or unknown trigger state BLOCKs VERIFY' config/skills/devlyn:resolve/references/state-schema.md \
345
+ || ! grep -Fq 'Canonical reasons are `pair.default`, `mode.verify-only`' config/skills/devlyn:resolve/references/state-schema.md \
337
346
  || ! grep -Fq '`mode.pair-verify`' config/skills/devlyn:resolve/references/state-schema.md \
338
- || ! grep -Fq 'Eligible triggers must contain only canonical' config/skills/devlyn:resolve/references/phases/verify.md \
339
- || ! grep -Fq 'include every applicable canonical reason' config/skills/devlyn:resolve/references/phases/verify.md \
347
+ || ! grep -Fq 'Eligible schema-v3 state must contain `pair.default` and every other applicable canonical' config/skills/devlyn:resolve/references/phases/verify.md \
348
+ || ! grep -Fq 'with `pair.default` plus every applicable outcome-independent canonical reason' config/skills/devlyn:resolve/references/phases/verify.md \
340
349
  || ! grep -Fq '`mode.pair-verify`' config/skills/devlyn:resolve/references/phases/verify.md \
341
350
  || ! grep -Fq '"pair_verify": false' config/skills/devlyn:resolve/references/state-schema.md \
342
- || ! grep -Fq 'requires a non-empty reasons list containing every applicable canonical eligible reason' config/skills/devlyn:resolve/references/state-schema.md \
343
- || ! grep -Fq 'containing every applicable canonical eligible reason' config/skills/devlyn:resolve/references/state-schema.md \
344
- || ! grep -Fq 'state.pair_verify == true' config/skills/devlyn:resolve/references/state-schema.md \
351
+ || ! grep -Fq 'Schema v3.0 eligible state requires `pair.default` plus every applicable telemetry reason' config/skills/devlyn:resolve/references/state-schema.md \
352
+ || ! grep -Fq 'Ineligible new-run state has empty reasons and only' config/skills/devlyn:resolve/references/state-schema.md \
353
+ || ! grep -Fq 'True only for `--pair-verify`' config/skills/devlyn:resolve/references/state-schema.md \
345
354
  || ! grep -Fq 'pair_verify: true` only when `--pair-verify` was passed' config/skills/devlyn:resolve/SKILL.md \
346
- || ! grep -Fq 'include every applicable canonical reason' config/skills/devlyn:resolve/SKILL.md \
355
+ || ! grep -Fq 'persist `pair_trigger` before spawn with `pair.default` plus every applicable outcome-independent reason' config/skills/devlyn:resolve/SKILL.md \
347
356
  || ! grep -Fq '`--pair-verify` and `--no-pair` are mutually exclusive' config/skills/devlyn:resolve/SKILL.md \
348
357
  || ! grep -Fq 'mutually exclusive with `risk_profile.pair_default_enabled == false`' config/skills/devlyn:resolve/references/state-schema.md \
349
358
  || ! grep -Fq 'if both are present, stop with `BLOCKED:invalid-flags`' config/skills/devlyn:resolve/references/phases/verify.md \
350
- || ! grep -Fq 'Contradictory, incomplete, or unknown trigger state is a VERIFY contract violation' config/skills/devlyn:resolve/SKILL.md \
351
- || ! grep -Fq 'user_no_pair` is valid only when `risk_profile.pair_default_enabled == false`' config/skills/devlyn:resolve/references/state-schema.md \
359
+ || ! grep -Fq 'Malformed risk or trigger state BLOCKs VERIFY' config/skills/devlyn:resolve/SKILL.md \
360
+ || ! grep -Fq 'pair_default_enabled` is false only for explicit `--no-pair`' config/skills/devlyn:resolve/references/state-schema.md \
352
361
  || ! grep -Fq 'def reject_json_constant' config/skills/_shared/verify-merge-findings.py \
353
362
  || ! grep -Fq 'loads_strict_json(raw)' config/skills/_shared/verify-merge-findings.py \
354
363
  || ! grep -Fq 'invalid JSON numeric constant: NaN' config/skills/_shared/verify-merge-findings.py; then
@@ -396,10 +405,56 @@ if ! grep -Fq 'SAFE_RUN_ID_RE' config/skills/_shared/archive_run.py \
396
405
  || ! grep -Fq 'invalid JSON numeric constant: NaN' config/skills/_shared/archive_run.py \
397
406
  || ! grep -Fq '"verify.pair.findings.jsonl"' config/skills/_shared/archive_run.py \
398
407
  || ! grep -Fq '"verify-merge.summary.json"' config/skills/_shared/archive_run.py \
408
+ || ! grep -Fq '"surface-close.output.json"' config/skills/_shared/archive_run.py \
399
409
  || ! grep -Fq '"*-judge.*"' config/skills/_shared/archive_run.py; then
400
410
  bad "archive_run.py must safely archive pair/risk-probe evidence and reject unsafe run ids"
401
411
  fi
402
412
 
413
+ section "Check 6c2: SURFACE_CLOSE v6 dispatch is complete and mirrored"
414
+ surface_close_missing=0
415
+ if python3 config/skills/_shared/state-phase-write.py --self-test >/dev/null 2>&1; then
416
+ ok "SURFACE_CLOSE state/envelope/adjudication/audit/rollback self-test passed"
417
+ else
418
+ bad "state-phase-write.py SURFACE_CLOSE self-test failed"
419
+ fi
420
+ if ! grep -Fq 'rollback_surface_delta' config/skills/_shared/state-phase-write.py \
421
+ || ! grep -Fq 'validate_surface_adjudication' config/skills/_shared/state-phase-write.py \
422
+ || ! grep -Fq 'validate_surface_execution' config/skills/_shared/state-phase-write.py \
423
+ || ! 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 \
425
+ || ! grep -Fq 'BLOCKED:surface-close-input-mismatch' config/skills/_shared/state-phase-write.py \
426
+ || ! grep -Fq 'surface-check' config/skills/_shared/state-phase-write.py \
427
+ || ! grep -Fq 'surface-rollback' config/skills/_shared/state-phase-write.py; then
428
+ bad "state-phase-write.py must mechanically adjudicate, audit, guard, and roll back SURFACE_CLOSE"
429
+ fi
430
+ for tree in config/skills .claude/skills .agents/skills; do
431
+ skill="$tree/devlyn:resolve/SKILL.md"
432
+ phase="$tree/devlyn:resolve/references/phases/surface-close.md"
433
+ if ! grep -Fq '## PHASE 2.5: SURFACE_CLOSE' "$skill" \
434
+ || ! grep -Fq '`state.source.type == "generated"` and complexity is trivial/medium' "$skill" \
435
+ || ! grep -Fq 'Engine is Claude always' "$skill" \
436
+ || ! grep -Fq 'executor flag/pin' "$skill" \
437
+ || ! grep -Fq 'auto_surface_close_claude_unavailable' "$skill" \
438
+ || ! grep -Fq 'canonical body VERBATIM' "$skill" \
439
+ || ! 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" \
441
+ || ! grep -Fq '.devlyn/surface-close.output.json' "$skill" \
442
+ || ! grep -Fq '**Common post-fix checkpoint (BUILD_GATE and VERIFY):**' "$skill" \
443
+ || ! grep -Fq 'durability-enforce --round <n> --origin-phase <build_gate|verify>' "$skill" \
444
+ || ! grep -Fq '`surface-rollback`' "$skill" \
445
+ || grep -Fq 'Supplied digests' "$phase" \
446
+ || grep -Fq 'Hash both artifacts first' "$phase" \
447
+ || ! grep -Fq 'Never modify inputs or read state, PLAN, or IMPLEMENT transcript/reasoning.' "$phase" \
448
+ || ! grep -Fq 'optionally followed by ` — <one-line evidence>`' "$phase" \
449
+ || ! grep -Fq 'N/A <authorized-file>[:<line>] — <one-line evidence-based relationship judgment>' "$phase"; then
450
+ bad "$tree — SURFACE_CLOSE v6 dispatch/timeout/adjudication/rollback contract missing"
451
+ surface_close_missing=1
452
+ fi
453
+ done
454
+ if [ $surface_close_missing -eq 0 ]; then
455
+ ok "SURFACE_CLOSE v6 dispatch/timeout/adjudication/rollback contract is mirrored"
456
+ fi
457
+
403
458
  section "Check 6d: Spec verification executes hidden-blind risk probes"
404
459
  if python3 config/skills/_shared/spec-verify-check.py --self-test >/dev/null 2>&1; then
405
460
  ok "spec-verify-check.py risk-probe and expected-contract self-test passed"
@@ -1078,38 +1133,39 @@ if ! grep -Fq 'If the spec includes a solo-headroom hypothesis, one of the two t
1078
1133
  else
1079
1134
  ok "resolve pair-JUDGE prompts prioritize solo-headroom hypothesis"
1080
1135
  fi
1081
- if ! grep -Fq 'names the primary judge; if pair-mode triggers, the first available OTHER' config/skills/devlyn:resolve/references/phases/verify.md \
1082
- || ! grep -Fq 'names the primary judge; if pair-mode triggers, the first available OTHER' .claude/skills/devlyn:resolve/references/phases/verify.md \
1083
- || ! grep -Fq 'names the primary judge; if pair-mode triggers, the first available OTHER' .agents/skills/devlyn:resolve/references/phases/verify.md \
1084
- || ! grep -Fq 'do not run the OTHER engine as the' config/skills/devlyn:resolve/SKILL.md \
1085
- || ! grep -Fq 'do not run the OTHER engine as the' .claude/skills/devlyn:resolve/SKILL.md \
1086
- || ! grep -Fq 'do not run the OTHER engine as the' .agents/skills/devlyn:resolve/SKILL.md \
1087
- || ! grep -Fq '_shared/adapters/claude.md` `## Invocation' config/skills/devlyn:resolve/references/phases/verify.md \
1088
- || ! grep -Fq '_shared/adapters/claude.md` `## Invocation' config/skills/devlyn:resolve/SKILL.md \
1136
+ 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
+ || ! grep -Fq 'The `--engine` flag does not disable default pairing' .agents/skills/devlyn:resolve/references/phases/verify.md \
1139
+ || ! 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
+ || ! grep -Fq 'the second judge uses the OTHER engine by default when available' .agents/skills/devlyn:resolve/SKILL.md \
1142
+ || ! grep -Fq '_shared/adapters/<name>.md' config/skills/devlyn:resolve/references/phases/verify.md \
1143
+ || ! grep -Fq '`## Invocation`' config/skills/devlyn:resolve/references/phases/verify.md \
1144
+ || ! grep -Fq '_shared/adapters/<name>.md` `## Invocation' config/skills/devlyn:resolve/SKILL.md \
1089
1145
  || ! grep -Fq '## Invocation' config/skills/_shared/adapters/claude.md \
1090
1146
  || ! grep -Fq '.devlyn/claude-judge.stdout' config/skills/_shared/adapters/claude.md; then
1091
1147
  bad "engine-neutral pair-judge dual declaration (iter-0060) out of sync"
1092
1148
  else
1093
1149
  ok "engine-neutral pair-judge dual declaration (iter-0060) in sync"
1094
1150
  fi
1095
- if ! grep -Fq 'current free-form `state.complexity` is `"large"`' config/skills/devlyn:resolve/SKILL.md \
1096
- || ! grep -Fq 'current free-form `state.complexity` is `"large"`' .claude/skills/devlyn:resolve/SKILL.md \
1097
- || ! grep -Fq 'current free-form `state.complexity` is `"large"`' .agents/skills/devlyn:resolve/SKILL.md \
1098
- || ! grep -Fq 'legacy/external spec `complexity: large` is accepted for compatibility' config/skills/devlyn:resolve/SKILL.md \
1099
- || ! grep -Fq 'legacy/external spec `complexity: large` is accepted for compatibility' .claude/skills/devlyn:resolve/SKILL.md \
1100
- || ! grep -Fq 'legacy/external spec `complexity: large` is accepted for compatibility' .agents/skills/devlyn:resolve/SKILL.md \
1101
- || ! grep -Fq 'current free-form `state.complexity` of `"large"`' config/skills/devlyn:resolve/references/state-schema.md \
1102
- || ! grep -Fq 'current free-form `state.complexity` of `"large"`' .claude/skills/devlyn:resolve/references/state-schema.md \
1103
- || ! grep -Fq 'current free-form `state.complexity` of `"large"`' .agents/skills/devlyn:resolve/references/state-schema.md \
1104
- || ! grep -Fq 'Legacy/external spec `complexity: large` remains accepted for compatibility' config/skills/devlyn:resolve/references/state-schema.md \
1105
- || ! grep -Fq 'Legacy/external spec `complexity: large` remains accepted for compatibility' .claude/skills/devlyn:resolve/references/state-schema.md \
1106
- || ! grep -Fq 'Legacy/external spec `complexity: large` remains accepted for compatibility' .agents/skills/devlyn:resolve/references/state-schema.md \
1107
- || ! grep -Fq 'Current free-form `state.complexity` is `"large"`' config/skills/devlyn:resolve/references/phases/verify.md \
1108
- || ! grep -Fq 'Current free-form `state.complexity` is `"large"`' .claude/skills/devlyn:resolve/references/phases/verify.md \
1109
- || ! grep -Fq 'Current free-form `state.complexity` is `"large"`' .agents/skills/devlyn:resolve/references/phases/verify.md \
1110
- || ! grep -Fq 'legacy/external spec' config/skills/devlyn:resolve/references/phases/verify.md \
1111
- || ! grep -Fq 'legacy/external spec' .claude/skills/devlyn:resolve/references/phases/verify.md \
1112
- || ! grep -Fq 'legacy/external spec' .agents/skills/devlyn:resolve/references/phases/verify.md; then
1151
+ 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
+ || ! grep -Fq '`complexity.high`, `complexity.large`' .agents/skills/devlyn:resolve/SKILL.md \
1154
+ || ! 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
+ || ! grep -Fq '`spec.complexity.high`, `spec.complexity.large`' .agents/skills/devlyn:resolve/SKILL.md \
1157
+ || ! 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
+ || ! grep -Fq 'Legacy complexity values remain accepted only for archived compatibility' .agents/skills/devlyn:resolve/references/state-schema.md \
1160
+ || ! 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
+ || ! grep -Fq '`complexity.high`, `complexity.large`, `spec.complexity.high`, `spec.complexity.large`' .agents/skills/devlyn:resolve/references/state-schema.md \
1163
+ || ! 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
+ || ! grep -Fq '`complexity.large`, `spec.complexity.high`, `spec.complexity.large`,' .agents/skills/devlyn:resolve/references/phases/verify.md \
1166
+ || ! 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
+ || ! grep -Fq '`spec.solo_headroom_hypothesis`, `risk.high`, `risk_probes.enabled`,' .agents/skills/devlyn:resolve/references/phases/verify.md; then
1113
1169
  bad "resolve VERIFY docs must distinguish current large complexity, legacy high state, and legacy large spec compatibility"
1114
1170
  else
1115
1171
  ok "resolve VERIFY docs distinguish current large complexity, legacy high state, and legacy large spec compatibility"
@@ -1165,15 +1221,15 @@ if ! grep -Fq 'def spec_has_solo_headroom_hypothesis' config/skills/_shared/veri
1165
1221
  || ! grep -Fq 'spec_has_solo_headroom_hypothesis(' .agents/skills/_shared/verify-merge-findings.py \
1166
1222
  || ! grep -Fq ') is False' .agents/skills/_shared/verify-merge-findings.py \
1167
1223
  || ! grep -Fq ') is True' .agents/skills/_shared/verify-merge-findings.py \
1168
- || ! grep -Fq 'The spec includes an actionable solo-headroom hypothesis.' \
1224
+ || ! grep -Fq '`spec.solo_headroom_hypothesis`' \
1169
1225
  config/skills/devlyn:resolve/references/phases/verify.md \
1170
- || ! grep -Fq 'The spec includes an actionable solo-headroom hypothesis.' \
1226
+ || ! grep -Fq '`spec.solo_headroom_hypothesis`' \
1171
1227
  .claude/skills/devlyn:resolve/references/phases/verify.md \
1172
- || ! grep -Fq 'The spec includes an actionable solo-headroom hypothesis.' \
1228
+ || ! grep -Fq '`spec.solo_headroom_hypothesis`' \
1173
1229
  .agents/skills/devlyn:resolve/references/phases/verify.md \
1174
- || ! grep -Fq 'actionable solo-headroom hypotheses' config/skills/devlyn:resolve/references/state-schema.md \
1175
- || ! grep -Fq 'actionable solo-headroom hypotheses' .claude/skills/devlyn:resolve/references/state-schema.md \
1176
- || ! grep -Fq 'actionable solo-headroom hypotheses' .agents/skills/devlyn:resolve/references/state-schema.md \
1230
+ || ! 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
+ || ! grep -Fq '`spec.solo_headroom_hypothesis`' .agents/skills/devlyn:resolve/references/state-schema.md \
1177
1233
  || ! grep -Fq 'same actionable solo-headroom hypothesis is a VERIFY pair-trigger reason' config/skills/devlyn:resolve/SKILL.md \
1178
1234
  || ! grep -Fq 'same actionable solo-headroom hypothesis is a VERIFY pair-trigger reason' .claude/skills/devlyn:resolve/SKILL.md \
1179
1235
  || ! grep -Fq 'same actionable solo-headroom hypothesis is a VERIFY pair-trigger reason' .agents/skills/devlyn:resolve/SKILL.md; then
@@ -1199,9 +1255,9 @@ if ! grep -Fq 'pair_evidence_intent' config/skills/devlyn:resolve/references/fre
1199
1255
  || ! grep -Fq 'state.source.criteria_sha256` for generated free-form mode' config/skills/devlyn:resolve/references/phases/verify.md \
1200
1256
  || ! grep -Fq 'state.source.criteria_sha256` for generated free-form mode' .claude/skills/devlyn:resolve/references/phases/verify.md \
1201
1257
  || ! grep -Fq 'state.source.criteria_sha256` for generated free-form mode' .agents/skills/devlyn:resolve/references/phases/verify.md \
1202
- || ! grep -Fq 'Free-form mode sets `type: "generated"`' config/skills/devlyn:resolve/references/state-schema.md \
1203
- || ! grep -Fq 'Free-form mode sets `type: "generated"`' .claude/skills/devlyn:resolve/references/state-schema.md \
1204
- || ! grep -Fq 'Free-form mode sets `type: "generated"`' .agents/skills/devlyn:resolve/references/state-schema.md \
1258
+ || ! 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
+ || ! grep -Fq 'Free-form sets `type: "generated"`' .agents/skills/devlyn:resolve/references/state-schema.md \
1205
1261
  || ! grep -Fq 'backticked observable command line that itself contains `miss`' config/skills/devlyn:resolve/references/free-form-mode.md \
1206
1262
  || ! grep -Fq 'backticked observable command line that itself contains `miss`' .claude/skills/devlyn:resolve/references/free-form-mode.md \
1207
1263
  || ! grep -Fq 'backticked observable command line that itself contains `miss`' .agents/skills/devlyn:resolve/references/free-form-mode.md \
@@ -1311,19 +1367,21 @@ if [ $verify_mech_missing -eq 0 ]; then
1311
1367
  ok "spec-verify VERIFY output routes into verify-merge-findings.py"
1312
1368
  fi
1313
1369
 
1314
- section "Check 6j: VERIFY pair trigger runs after primary JUDGE"
1370
+ section "Check 6j: VERIFY default pair dispatches concurrently"
1315
1371
  pair_trigger_order_missing=0
1316
1372
  for file in \
1317
1373
  config/skills/devlyn:resolve/SKILL.md \
1318
1374
  .claude/skills/devlyn:resolve/SKILL.md \
1319
1375
  .agents/skills/devlyn:resolve/SKILL.md
1320
1376
  do
1321
- if ! grep -Fq 'Pair-mode (cross-model JUDGE) is eligible only after MECHANICAL and the primary JUDGE have no verdict-binding findings' "$file" \
1322
- || ! grep -Fq 'After MECHANICAL and the primary JUDGE finish, compute `pair_trigger' "$file" \
1323
- || ! grep -Fq '`risk_profile` is strict typed state' "$file" \
1324
- || ! grep -Fq 'malformed `risk_profile` is also a VERIFY contract violation' "$file" \
1325
- || ! grep -Fq 'If MECHANICAL or the primary JUDGE has a verdict-binding finding' "$file"; then
1326
- bad "$file — VERIFY pair trigger order must be after primary JUDGE"
1377
+ if ! grep -Fq 'Verify dual-judge is default-when-available' "$file" \
1378
+ || ! grep -Fq 'persist `pair_trigger` before spawn with `pair.default`' "$file" \
1379
+ || ! grep -Fq 'dispatch both judges concurrently against the same frozen diff' "$file" \
1380
+ || ! grep -Fq 'A primary blocker never cancels the pair judge' "$file" \
1381
+ || ! grep -Fq 'run the same two required judges sequentially' "$file" \
1382
+ || ! grep -Fq 'Eligible schema-v3 state must include `pair.default`' "$file" \
1383
+ || ! grep -Fq '`primary_judge_blocker` is parser-recognized only for archived v2.0 replay; new runs never write it' "$file"; then
1384
+ bad "$file — VERIFY default pair rule missing."
1327
1385
  pair_trigger_order_missing=1
1328
1386
  fi
1329
1387
  done
@@ -1332,11 +1390,14 @@ for file in \
1332
1390
  .claude/skills/devlyn:resolve/references/phases/verify.md \
1333
1391
  .agents/skills/devlyn:resolve/references/phases/verify.md
1334
1392
  do
1335
- if ! grep -Fq 'Pair-mode is eligible only after MECHANICAL and the primary JUDGE have no' "$file" \
1336
- || ! grep -Fq 'After MECHANICAL and the primary JUDGE finish, compute and persist this before' "$file" \
1337
- || ! grep -Fq 'Malformed `state.risk_profile` is a VERIFY contract violation' "$file" \
1338
- || ! grep -Fq 'primary_judge_blocker' "$file"; then
1339
- bad "$file — VERIFY phase body must compute pair_trigger after primary JUDGE"
1393
+ if ! grep -Fq 'Pair-mode (default when OTHER engine is available)' "$file" \
1394
+ || ! grep -Fq 'with `pair.default` plus every applicable' "$file" \
1395
+ || ! grep -Fq 'dispatch the primary and pair JUDGEs concurrently against the same frozen' "$file" \
1396
+ || ! grep -Fq 'A primary blocker does not cancel the pair-JUDGE' "$file" \
1397
+ || ! grep -Fq 'runs the same two required judges' "$file" \
1398
+ || ! grep -Fq 'Eligible schema-v3 state must contain `pair.default`' "$file" \
1399
+ || ! grep -Fq 'New runs never' "$file"; then
1400
+ bad "$file — VERIFY default pair dispatch missing"
1340
1401
  pair_trigger_order_missing=1
1341
1402
  fi
1342
1403
  done
@@ -1345,16 +1406,19 @@ for file in \
1345
1406
  .claude/skills/devlyn:resolve/references/state-schema.md \
1346
1407
  .agents/skills/devlyn:resolve/references/state-schema.md
1347
1408
  do
1348
- if ! grep -Fq 'MECHANICAL and the primary JUDGE have no verdict-binding blockers' "$file" \
1349
- || ! grep -Fq 'may set only `user_no_pair`, `mechanical_blocker`, `primary_judge_blocker`, `auto_pair_other_engine_unavailable`, or null' "$file" \
1350
- || ! grep -Fq '`risk_profile` must remain an object with boolean' "$file" \
1351
- || ! grep -Fq 'state implies a pair decision is required but `pair_trigger` is missing' "$file"; then
1352
- bad "$file — state schema must document pair_trigger blocker and missing-trigger enforcement"
1409
+ if ! grep -Fq '"version": "3.0"' "$file" \
1410
+ || ! grep -Fq 'pair.default` dispatches both judges concurrently' "$file" \
1411
+ || ! grep -Fq 'runs the same two required judges sequentially' "$file" \
1412
+ || ! grep -Fq 'a primary blocker never skips the pair' "$file" \
1413
+ || ! grep -Fq 'Schema v3.0 eligible state requires `pair.default`' "$file" \
1414
+ || ! grep -Fq 'archived v2.0 replay' "$file" \
1415
+ || ! grep -Fq 'Missing, contradictory, incomplete, or unknown trigger state BLOCKs VERIFY' "$file"; then
1416
+ bad "$file — schema-v3 default pair contract missing"
1353
1417
  pair_trigger_order_missing=1
1354
1418
  fi
1355
1419
  done
1356
1420
  if [ $pair_trigger_order_missing -eq 0 ]; then
1357
- ok "VERIFY pair trigger order waits for primary JUDGE evidence"
1421
+ ok "VERIFY default pair dispatches concurrently"
1358
1422
  fi
1359
1423
 
1360
1424
  section "Check 6h: No undocumented spec.expected.json.browser_flows field"
@@ -3694,7 +3758,7 @@ if ! grep -Fq 'high-risk fixture must include a resolve risk-trigger term' scrip
3694
3758
  || ! grep -Fq 'expected.json must be an object' scripts/lint-fixtures.sh \
3695
3759
  || ! grep -Fq 'schema_ok=0' scripts/lint-fixtures.sh \
3696
3760
  || ! grep -Fq 'DEVLYN_LINT_FIXTURES_NO_JSONSCHEMA' scripts/lint-fixtures.sh \
3697
- || ! grep -Fq 'conditional pair/risk-probe triggers' benchmark/auto-resolve/fixtures/SCHEMA.md; then
3761
+ || ! grep -Fq 'conditional risk-probe triggers' benchmark/auto-resolve/fixtures/SCHEMA.md; then
3698
3762
  offenders="${offenders}"$'\n'"fixture lint must require high-risk fixtures to include resolve pair/risk trigger terms"
3699
3763
  fi
3700
3764
  unsafe_json_parser_refs=$(python3 - <<'PY'