devlyn-cli 3.2.0 → 3.3.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 (424) hide show
  1. package/AGENTS.md +2 -2
  2. package/CLAUDE.md +2 -2
  3. package/README.md +22 -113
  4. package/bin/devlyn.js +13 -225
  5. package/bin/instruction-templates.json +752 -1
  6. package/bin/instructions.js +101 -17
  7. package/config/skills/_shared/adapters/grok.md +1 -2
  8. package/config/skills/_shared/archive_run.py +15 -3
  9. package/config/skills/_shared/judge-role-evidence.py +21 -1
  10. package/config/skills/_shared/runtime-principles.md +1 -1
  11. package/config/skills/_shared/spec-verify-check.py +0 -653
  12. package/config/skills/_shared/state-phase-write.py +371 -30
  13. package/config/skills/_shared/task-complete.py +635 -143
  14. package/config/skills/_shared/terminal-claim-check.py +229 -4
  15. package/config/skills/_shared/verify-merge-findings.py +93 -2
  16. package/config/skills/devlyn:ideate/SKILL.md +3 -4
  17. package/config/skills/devlyn:ideate/references/elicitation.md +2 -35
  18. package/config/skills/devlyn:ideate/references/from-spec-mode.md +3 -18
  19. package/config/skills/devlyn:ideate/references/project-mode.md +1 -16
  20. package/config/skills/devlyn:ideate/references/spec-template.md +0 -2
  21. package/config/skills/devlyn:queue/SKILL.md +6 -4
  22. package/config/skills/devlyn:resolve/SKILL.md +16 -25
  23. package/config/skills/devlyn:resolve/references/free-form-mode.md +0 -14
  24. package/config/skills/devlyn:resolve/references/outer-loop.md +1 -1
  25. package/config/skills/devlyn:resolve/references/phases/build-gate.md +1 -1
  26. package/config/skills/devlyn:resolve/references/phases/cleanup.md +3 -3
  27. package/config/skills/devlyn:resolve/references/phases/implement.md +1 -1
  28. package/config/skills/devlyn:resolve/references/phases/probe-derive.md +1 -16
  29. package/config/skills/devlyn:resolve/references/phases/verify.md +4 -9
  30. package/config/skills/devlyn:resolve/references/state-schema.md +9 -7
  31. package/config/skills/devlyn:resolve/references/task-completion.md +46 -37
  32. package/{config/skills → optional-skills}/code-health-standards/SKILL.md +4 -13
  33. package/{config/skills → optional-skills}/code-review-standards/SKILL.md +4 -12
  34. package/{config/skills → optional-skills}/root-cause-analysis/SKILL.md +4 -12
  35. package/{config/skills → optional-skills}/ui-implementation-standards/SKILL.md +4 -14
  36. package/package.json +1 -57
  37. package/benchmark/auto-resolve/BENCHMARK-DESIGN.md +0 -289
  38. package/benchmark/auto-resolve/BENCHMARK-RESULTS.md +0 -341
  39. package/benchmark/auto-resolve/README.md +0 -696
  40. package/benchmark/auto-resolve/RUBRIC.md +0 -177
  41. package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/NOTES.md +0 -34
  42. package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/expected.json +0 -68
  43. package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/metadata.json +0 -10
  44. package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/setup.sh +0 -4
  45. package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/spec.md +0 -44
  46. package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/task.ko.txt +0 -8
  47. package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/task.txt +0 -8
  48. package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/NOTES.md +0 -68
  49. package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/expected.json +0 -60
  50. package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/metadata.json +0 -10
  51. package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/setup.sh +0 -17
  52. package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/spec.md +0 -51
  53. package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/task.txt +0 -9
  54. package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/verifiers/invalid.js +0 -29
  55. package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/verifiers/parallel.js +0 -50
  56. package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/NOTES.md +0 -75
  57. package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/expected.json +0 -52
  58. package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/metadata.json +0 -10
  59. package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/setup.sh +0 -171
  60. package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/spec.md +0 -50
  61. package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/task.txt +0 -9
  62. package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/NOTES.md +0 -89
  63. package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/expected.json +0 -74
  64. package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/metadata.json +0 -10
  65. package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/setup.sh +0 -251
  66. package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/spec.md +0 -57
  67. package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/task.txt +0 -13
  68. package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/verifiers/replay-malformed-body.js +0 -64
  69. package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/NOTES.md +0 -104
  70. package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/expected.json +0 -46
  71. package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/metadata.json +0 -10
  72. package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/setup.sh +0 -336
  73. package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/spec.md +0 -51
  74. package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/task.txt +0 -9
  75. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/NOTES.md +0 -38
  76. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/expected.json +0 -64
  77. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/metadata.json +0 -10
  78. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/setup.sh +0 -32
  79. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/spec.md +0 -63
  80. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/task.txt +0 -7
  81. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/verifiers/exact-success.js +0 -54
  82. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/verifiers/no-hardcoded-pricing.js +0 -47
  83. package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/verifiers/stock-error.js +0 -45
  84. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/NOTES.md +0 -57
  85. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/expected-pair-plan-registry.json +0 -170
  86. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/expected.json +0 -84
  87. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/metadata.json +0 -21
  88. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/pair-plan.sample-fail.json +0 -214
  89. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/pair-plan.sample-pass.json +0 -223
  90. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/setup.sh +0 -5
  91. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/spec.md +0 -55
  92. package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/task.txt +0 -14
  93. package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/NOTES.md +0 -39
  94. package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/expected.json +0 -62
  95. package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/metadata.json +0 -10
  96. package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/setup.sh +0 -2
  97. package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/spec.md +0 -67
  98. package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/task.txt +0 -7
  99. package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/verifiers/error-order.js +0 -55
  100. package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/verifiers/priority-blocked.js +0 -48
  101. package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/NOTES.md +0 -35
  102. package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/expected.json +0 -56
  103. package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/metadata.json +0 -10
  104. package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/setup.sh +0 -2
  105. package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/spec.md +0 -64
  106. package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/task.txt +0 -7
  107. package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/verifiers/conflicting-duplicate.js +0 -34
  108. package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/verifiers/idempotent-close.js +0 -41
  109. package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/NOTES.md +0 -39
  110. package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/expected.json +0 -56
  111. package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/metadata.json +0 -10
  112. package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/setup.sh +0 -2
  113. package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/spec.md +0 -76
  114. package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/task.txt +0 -7
  115. package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/verifiers/priority-rollback.js +0 -64
  116. package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/verifiers/single-warehouse-fefo.js +0 -66
  117. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/NOTES.md +0 -40
  118. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/expected.json +0 -66
  119. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/metadata.json +0 -10
  120. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/setup.sh +0 -36
  121. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/spec.md +0 -71
  122. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/task.txt +0 -7
  123. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/verifiers/catalog-source.js +0 -57
  124. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/verifiers/exact-success.js +0 -63
  125. package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/verifiers/stock-error.js +0 -34
  126. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/NOTES.md +0 -31
  127. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/expected.json +0 -68
  128. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/metadata.json +0 -10
  129. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/setup.sh +0 -17
  130. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/spec.md +0 -68
  131. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/task.txt +0 -7
  132. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/verifiers/conflicting-duplicate.js +0 -29
  133. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/verifiers/exact-payout.js +0 -58
  134. package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/verifiers/rules-source.js +0 -56
  135. package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/NOTES.md +0 -35
  136. package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/expected-pair-plan-registry.json +0 -162
  137. package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/expected.json +0 -67
  138. package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/metadata.json +0 -19
  139. package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/setup.sh +0 -4
  140. package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/spec.md +0 -55
  141. package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/task.txt +0 -9
  142. package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/NOTES.md +0 -34
  143. package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/expected.json +0 -57
  144. package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/metadata.json +0 -10
  145. package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/setup.sh +0 -2
  146. package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/spec.md +0 -67
  147. package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/task.txt +0 -7
  148. package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/verifiers/duplicate-event-error.js +0 -35
  149. package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/verifiers/priority-transfer-rollback.js +0 -53
  150. package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/NOTES.md +0 -38
  151. package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/expected.json +0 -57
  152. package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/metadata.json +0 -10
  153. package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/setup.sh +0 -2
  154. package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/spec.md +0 -70
  155. package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/task.txt +0 -3
  156. package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/verifiers/duplicate-renewal-error.js +0 -42
  157. package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/verifiers/priority-credit-rollback.js +0 -70
  158. package/benchmark/auto-resolve/fixtures/F4-web-browser-design/NOTES.md +0 -47
  159. package/benchmark/auto-resolve/fixtures/F4-web-browser-design/expected.json +0 -57
  160. package/benchmark/auto-resolve/fixtures/F4-web-browser-design/metadata.json +0 -10
  161. package/benchmark/auto-resolve/fixtures/F4-web-browser-design/setup.sh +0 -6
  162. package/benchmark/auto-resolve/fixtures/F4-web-browser-design/spec.md +0 -48
  163. package/benchmark/auto-resolve/fixtures/F4-web-browser-design/task.txt +0 -9
  164. package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/NOTES.md +0 -45
  165. package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/expected.json +0 -65
  166. package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/metadata.json +0 -10
  167. package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/setup.sh +0 -55
  168. package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/spec.md +0 -48
  169. package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/task.txt +0 -7
  170. package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/NOTES.md +0 -43
  171. package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/expected.json +0 -77
  172. package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/metadata.json +0 -10
  173. package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/setup.sh +0 -4
  174. package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/spec.md +0 -48
  175. package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/task.txt +0 -10
  176. package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/NOTES.md +0 -57
  177. package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/expected.json +0 -76
  178. package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/metadata.json +0 -10
  179. package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/setup.sh +0 -36
  180. package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/spec.md +0 -45
  181. package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/task.txt +0 -7
  182. package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/NOTES.md +0 -53
  183. package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/expected.json +0 -63
  184. package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/metadata.json +0 -10
  185. package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/setup.sh +0 -4
  186. package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/spec.md +0 -48
  187. package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/task.txt +0 -1
  188. package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/NOTES.md +0 -105
  189. package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/expected.json +0 -74
  190. package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/metadata.json +0 -10
  191. package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/setup.sh +0 -28
  192. package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/spec.md +0 -59
  193. package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/task.txt +0 -5
  194. package/benchmark/auto-resolve/fixtures/SCHEMA.md +0 -188
  195. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/NOTES.md +0 -37
  196. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/RETIRED.md +0 -13
  197. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/expected.json +0 -56
  198. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/metadata.json +0 -10
  199. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/setup.sh +0 -18
  200. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/spec.md +0 -69
  201. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/task.txt +0 -7
  202. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/verifiers/exact-proration.js +0 -48
  203. package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/verifiers/rules-source-and-conflict.js +0 -79
  204. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/NOTES.md +0 -54
  205. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/RETIRED.md +0 -7
  206. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/expected.json +0 -67
  207. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/metadata.json +0 -10
  208. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/setup.sh +0 -2
  209. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/spec.md +0 -67
  210. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/task.txt +0 -5
  211. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/verifiers/policy-precedence.js +0 -72
  212. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/verifiers/validation-and-immutability.js +0 -43
  213. package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/verifiers/validation-boundary.js +0 -116
  214. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/NOTES.md +0 -35
  215. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/RETIRED.md +0 -12
  216. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/expected.json +0 -58
  217. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/metadata.json +0 -10
  218. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/setup.sh +0 -2
  219. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/spec.md +0 -73
  220. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/task.txt +0 -17
  221. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/verifiers/mixed-idempotent-settlement.js +0 -53
  222. package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/verifiers/rejection-boundaries.js +0 -74
  223. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/NOTES.md +0 -28
  224. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/RETIRED.md +0 -15
  225. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/expected.json +0 -57
  226. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/metadata.json +0 -10
  227. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/setup.sh +0 -50
  228. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/spec.md +0 -59
  229. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/task.txt +0 -9
  230. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/verifiers/ordered-settlement.js +0 -88
  231. package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/verifiers/reject-invalid.js +0 -45
  232. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/NOTES.md +0 -30
  233. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/RETIRED.md +0 -16
  234. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/expected.json +0 -64
  235. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/metadata.json +0 -10
  236. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/setup.sh +0 -21
  237. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/spec.md +0 -58
  238. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/task.txt +0 -9
  239. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/verifiers/dup-op.js +0 -54
  240. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/verifiers/priority-apply.js +0 -82
  241. package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/verifiers/rollback.js +0 -77
  242. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/NOTES.md +0 -99
  243. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/RETIRED.md +0 -18
  244. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/expected.json +0 -64
  245. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/metadata.json +0 -10
  246. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/setup.sh +0 -4
  247. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/spec.md +0 -61
  248. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/task.txt +0 -9
  249. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/verifiers/correctness-small.js +0 -135
  250. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/verifiers/scale.js +0 -100
  251. package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/verifiers/validation.js +0 -75
  252. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/NOTES.md +0 -93
  253. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/RETIRED.md +0 -16
  254. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/expected.json +0 -65
  255. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/metadata.json +0 -10
  256. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/setup.sh +0 -18
  257. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/spec.md +0 -66
  258. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/task.txt +0 -9
  259. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/verifiers/correctness-small.js +0 -84
  260. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/verifiers/scale.js +0 -184
  261. package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/verifiers/validation.js +0 -74
  262. package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/NOTES.md +0 -60
  263. package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/RETIRED.md +0 -29
  264. package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/expected.json +0 -73
  265. package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/metadata.json +0 -10
  266. package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/setup.sh +0 -28
  267. package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/spec.md +0 -58
  268. package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/task.txt +0 -5
  269. package/benchmark/auto-resolve/fixtures/test-repo/README.md +0 -12
  270. package/benchmark/auto-resolve/fixtures/test-repo/bin/cli.js +0 -63
  271. package/benchmark/auto-resolve/fixtures/test-repo/package-lock.json +0 -823
  272. package/benchmark/auto-resolve/fixtures/test-repo/package.json +0 -22
  273. package/benchmark/auto-resolve/fixtures/test-repo/playwright.config.js +0 -17
  274. package/benchmark/auto-resolve/fixtures/test-repo/server/index.js +0 -37
  275. package/benchmark/auto-resolve/fixtures/test-repo/tests/cli.test.js +0 -25
  276. package/benchmark/auto-resolve/fixtures/test-repo/tests/server.test.js +0 -58
  277. package/benchmark/auto-resolve/fixtures/test-repo/web/index.html +0 -37
  278. package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.json +0 -25
  279. package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.md +0 -10
  280. package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.json +0 -18
  281. package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.md +0 -9
  282. package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.json +0 -18
  283. package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.md +0 -9
  284. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-cli-quote-tax-rules/l2_risk_probes/result.json +0 -28
  285. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F23-cli-fulfillment-wave/l2_risk_probes/result.json +0 -28
  286. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F25-cli-cart-promotion-rules/l2_risk_probes/result.json +0 -30
  287. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/full-pipeline-pair-gate.json +0 -82
  288. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/full-pipeline-pair-gate.md +0 -18
  289. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/headroom-gate.json +0 -46
  290. package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/headroom-gate.md +0 -17
  291. package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.json +0 -28
  292. package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.md +0 -15
  293. package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.json +0 -28
  294. package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.md +0 -15
  295. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/F21-cli-scheduler-priority/l2_risk_probes/result.json +0 -32
  296. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.json +0 -44
  297. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.md +0 -16
  298. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.json +0 -18
  299. package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.md +0 -9
  300. package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.json +0 -28
  301. package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.md +0 -15
  302. package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.json +0 -28
  303. package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.md +0 -15
  304. package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.json +0 -28
  305. package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.md +0 -15
  306. package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.json +0 -28
  307. package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.md +0 -15
  308. package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.json +0 -28
  309. package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.md +0 -15
  310. package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.json +0 -28
  311. package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.md +0 -15
  312. package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.json +0 -28
  313. package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.md +0 -15
  314. package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.json +0 -28
  315. package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.md +0 -15
  316. package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.json +0 -28
  317. package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.md +0 -15
  318. package/benchmark/auto-resolve/run-real-benchmark.md +0 -303
  319. package/benchmark/auto-resolve/scripts/audit-headroom-rejections.py +0 -441
  320. package/benchmark/auto-resolve/scripts/audit-pair-evidence.py +0 -1256
  321. package/benchmark/auto-resolve/scripts/build-pair-eligible-manifest.py +0 -306
  322. package/benchmark/auto-resolve/scripts/check-f9-artifacts.py +0 -268
  323. package/benchmark/auto-resolve/scripts/collect-swebench-predictions.py +0 -108
  324. package/benchmark/auto-resolve/scripts/compile-report.py +0 -493
  325. package/benchmark/auto-resolve/scripts/fetch-swebench-instances.py +0 -129
  326. package/benchmark/auto-resolve/scripts/frozen-verify-gate.py +0 -434
  327. package/benchmark/auto-resolve/scripts/full-pipeline-pair-gate.py +0 -612
  328. package/benchmark/auto-resolve/scripts/headroom-gate.py +0 -378
  329. package/benchmark/auto-resolve/scripts/iter-0033c-compare.py +0 -683
  330. package/benchmark/auto-resolve/scripts/iter-0033c-l1-summary.py +0 -97
  331. package/benchmark/auto-resolve/scripts/judge-opus-pass.sh +0 -542
  332. package/benchmark/auto-resolve/scripts/judge.sh +0 -565
  333. package/benchmark/auto-resolve/scripts/oracle-scope-tier-a.py +0 -256
  334. package/benchmark/auto-resolve/scripts/oracle-scope-tier-b.py +0 -287
  335. package/benchmark/auto-resolve/scripts/oracle-test-fidelity.py +0 -328
  336. package/benchmark/auto-resolve/scripts/pair-candidate-frontier.py +0 -469
  337. package/benchmark/auto-resolve/scripts/pair-plan-idgen.py +0 -401
  338. package/benchmark/auto-resolve/scripts/pair-plan-lint.py +0 -475
  339. package/benchmark/auto-resolve/scripts/pair-rejected-fixtures.sh +0 -103
  340. package/benchmark/auto-resolve/scripts/pair_evidence_contract.py +0 -270
  341. package/benchmark/auto-resolve/scripts/prepare-swebench-frozen-case.py +0 -273
  342. package/benchmark/auto-resolve/scripts/prepare-swebench-frozen-corpus.py +0 -148
  343. package/benchmark/auto-resolve/scripts/prepare-swebench-solver-worktree.py +0 -210
  344. package/benchmark/auto-resolve/scripts/recent-benchmark-summary.py +0 -232
  345. package/benchmark/auto-resolve/scripts/run-fixture.sh +0 -1024
  346. package/benchmark/auto-resolve/scripts/run-frozen-verify-pair.sh +0 -683
  347. package/benchmark/auto-resolve/scripts/run-full-pipeline-pair-candidate.sh +0 -458
  348. package/benchmark/auto-resolve/scripts/run-headroom-candidate.sh +0 -336
  349. package/benchmark/auto-resolve/scripts/run-iter-0033c.sh +0 -208
  350. package/benchmark/auto-resolve/scripts/run-suite.sh +0 -251
  351. package/benchmark/auto-resolve/scripts/run-swebench-frozen-corpus.sh +0 -310
  352. package/benchmark/auto-resolve/scripts/run-swebench-solver-batch.sh +0 -257
  353. package/benchmark/auto-resolve/scripts/ship-gate.py +0 -391
  354. package/benchmark/auto-resolve/scripts/solo-ceiling-avoidance.py +0 -53
  355. package/benchmark/auto-resolve/scripts/solo-headroom-hypothesis.py +0 -77
  356. package/benchmark/auto-resolve/scripts/swebench-frozen-matrix.py +0 -478
  357. package/benchmark/auto-resolve/scripts/test-audit-headroom-rejections.sh +0 -288
  358. package/benchmark/auto-resolve/scripts/test-audit-pair-evidence.sh +0 -1672
  359. package/benchmark/auto-resolve/scripts/test-benchmark-arg-parsing.sh +0 -1015
  360. package/benchmark/auto-resolve/scripts/test-build-pair-eligible-manifest.sh +0 -491
  361. package/benchmark/auto-resolve/scripts/test-check-f9-artifacts.sh +0 -91
  362. package/benchmark/auto-resolve/scripts/test-frozen-verify-gate.sh +0 -517
  363. package/benchmark/auto-resolve/scripts/test-full-pipeline-pair-gate.sh +0 -610
  364. package/benchmark/auto-resolve/scripts/test-headroom-gate.sh +0 -401
  365. package/benchmark/auto-resolve/scripts/test-iter-0033c-compare.sh +0 -525
  366. package/benchmark/auto-resolve/scripts/test-iter-0033c-l1-summary.sh +0 -254
  367. package/benchmark/auto-resolve/scripts/test-lint-fixtures.sh +0 -580
  368. package/benchmark/auto-resolve/scripts/test-pair-candidate-frontier.sh +0 -591
  369. package/benchmark/auto-resolve/scripts/test-run-full-pipeline-pair-candidate.sh +0 -497
  370. package/benchmark/auto-resolve/scripts/test-run-headroom-candidate.sh +0 -401
  371. package/benchmark/auto-resolve/scripts/test-run-swebench-solver-batch.sh +0 -111
  372. package/benchmark/auto-resolve/scripts/test-ship-gate.sh +0 -1189
  373. package/benchmark/auto-resolve/scripts/test-swebench-frozen-case.sh +0 -1221
  374. package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/NOTES.md +0 -28
  375. package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/expected.json +0 -63
  376. package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/metadata.json +0 -10
  377. package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/setup.sh +0 -3
  378. package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/spec.md +0 -47
  379. package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/task.txt +0 -1
  380. package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/NOTES.md +0 -34
  381. package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/expected.json +0 -53
  382. package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/metadata.json +0 -10
  383. package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/setup.sh +0 -3
  384. package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/spec.md +0 -50
  385. package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/task.txt +0 -1
  386. package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/verifiers/duplicate-order-error.js +0 -27
  387. package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/verifiers/priority-stock-reservation.js +0 -44
  388. package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/NOTES.md +0 -34
  389. package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/expected.json +0 -55
  390. package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/metadata.json +0 -10
  391. package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/setup.sh +0 -3
  392. package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/spec.md +0 -52
  393. package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/task.txt +0 -1
  394. package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/verifiers/duplicate-ticket-error.js +0 -29
  395. package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/verifiers/priority-agent-assignment.js +0 -48
  396. package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/NOTES.md +0 -34
  397. package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/expected.json +0 -55
  398. package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/metadata.json +0 -10
  399. package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/setup.sh +0 -3
  400. package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/spec.md +0 -55
  401. package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/task.txt +0 -1
  402. package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/verifiers/duplicate-return-error.js +0 -43
  403. package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/verifiers/priority-return-routing.js +0 -70
  404. package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/NOTES.md +0 -37
  405. package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/expected.json +0 -54
  406. package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/metadata.json +0 -10
  407. package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/setup.sh +0 -3
  408. package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/spec.md +0 -59
  409. package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/task.txt +0 -1
  410. package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/verifiers/credit-ledger-priority.js +0 -98
  411. package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/verifiers/duplicate-charge-error.js +0 -38
  412. package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/NOTES.md +0 -36
  413. package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/expected.json +0 -56
  414. package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/metadata.json +0 -10
  415. package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/setup.sh +0 -3
  416. package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/spec.md +0 -59
  417. package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/task.txt +0 -1
  418. package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/verifiers/duplicate-refund-error.js +0 -41
  419. package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/verifiers/priority-refund-ledger.js +0 -65
  420. package/config/skills/_shared/pair-plan-schema.md +0 -298
  421. package/scripts/lint-fixtures.sh +0 -352
  422. package/scripts/lint-shadow-fixtures.sh +0 -58
  423. package/scripts/lint-skills.sh +0 -4265
  424. package/scripts/test-owner-phases.py +0 -193
@@ -1,683 +0,0 @@
1
- #!/usr/bin/env bash
2
- # run-frozen-verify-pair.sh — compare solo VERIFY vs pair VERIFY on one frozen diff.
3
- #
4
- # This isolates VERIFY/JUDGE from IMPLEMENT: the implementation diff is applied
5
- # before /devlyn:resolve starts, then both arms run verify-only against the same
6
- # committed code and `.devlyn/external-diff.patch`.
7
-
8
- set -euo pipefail
9
-
10
- usage() {
11
- cat >&2 <<EOF
12
- usage: $0 --fixture <FID> --diff <path> [--run-id ID] [--pair-mode forced|gated]
13
- [--fixtures-root <path>] [--base-repo <path>]
14
- [--timeout-seconds N] [--prepare-only] [--resume-completed-arms]
15
-
16
- Runs two verify-only arms:
17
- solo = /devlyn:resolve --verify-only ... --engine claude
18
- pair = forced: /devlyn:resolve --verify-only ... --engine claude --pair-verify
19
- gated: /devlyn:resolve --verify-only ... --engine claude
20
-
21
- By default fixtures come from benchmark/auto-resolve/fixtures and the base repo
22
- is fixtures/test-repo. External corpora such as SWE-bench can pass their own
23
- case root and checked-out base repo.
24
- EOF
25
- exit "${1:-1}"
26
- }
27
-
28
- require_value() {
29
- local flag="$1"
30
- local value="${2:-}"
31
- if [ -z "$value" ] || [[ "$value" == --* ]]; then
32
- echo "$flag requires a value" >&2
33
- exit 1
34
- fi
35
- }
36
-
37
- require_safe_id() {
38
- local label="$1"
39
- local value="$2"
40
- if [[ ! "$value" =~ ^[A-Za-z0-9_.-]+$ ]]; then
41
- echo "$label must match [A-Za-z0-9_.-]+: $value" >&2
42
- exit 1
43
- fi
44
- }
45
-
46
- FIXTURE=""
47
- DIFF_PATH=""
48
- RUN_ID=""
49
- PAIR_MODE="forced"
50
- FIXTURES_ROOT=""
51
- BASE_REPO=""
52
- PREPARE_ONLY=0
53
- TIMEOUT_OVERRIDE=""
54
- RESUME_COMPLETED_ARMS=0
55
- while [ $# -gt 0 ]; do
56
- case "$1" in
57
- --fixture) require_value "$1" "${2:-}"; FIXTURE="$2"; shift 2;;
58
- --diff) require_value "$1" "${2:-}"; DIFF_PATH="$2"; shift 2;;
59
- --run-id) require_value "$1" "${2:-}"; RUN_ID="$2"; shift 2;;
60
- --pair-mode) require_value "$1" "${2:-}"; PAIR_MODE="$2"; shift 2;;
61
- --fixtures-root) require_value "$1" "${2:-}"; FIXTURES_ROOT="$2"; shift 2;;
62
- --base-repo) require_value "$1" "${2:-}"; BASE_REPO="$2"; shift 2;;
63
- --timeout-seconds) require_value "$1" "${2:-}"; TIMEOUT_OVERRIDE="$2"; shift 2;;
64
- --prepare-only) PREPARE_ONLY=1; shift;;
65
- --resume-completed-arms) RESUME_COMPLETED_ARMS=1; shift;;
66
- -h|--help) usage 0;;
67
- *) echo "unknown arg: $1" >&2; usage 1;;
68
- esac
69
- done
70
-
71
- [ -n "$FIXTURE" ] && [ -n "$DIFF_PATH" ] || usage 1
72
- require_safe_id "--fixture" "$FIXTURE"
73
- [ -f "$DIFF_PATH" ] || { echo "diff not found: $DIFF_PATH" >&2; exit 1; }
74
- [ -s "$DIFF_PATH" ] || { echo "diff is empty: $DIFF_PATH" >&2; exit 1; }
75
- [ "$PAIR_MODE" = "forced" ] || [ "$PAIR_MODE" = "gated" ] || { echo "--pair-mode must be forced|gated (got '$PAIR_MODE')" >&2; exit 1; }
76
-
77
- BENCH_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
78
- REPO_ROOT="$(cd "$BENCH_ROOT/../.." && pwd)"
79
- [ -n "$FIXTURES_ROOT" ] || FIXTURES_ROOT="$BENCH_ROOT/fixtures"
80
- [ -n "$BASE_REPO" ] || BASE_REPO="$BENCH_ROOT/fixtures/test-repo"
81
- FIXTURES_ROOT="$(cd "$FIXTURES_ROOT" && pwd)"
82
- BASE_REPO="$(cd "$BASE_REPO" && pwd)"
83
- FIX_DIR="$FIXTURES_ROOT/$FIXTURE"
84
- [ -d "$FIX_DIR" ] || { echo "fixture not found: $FIXTURE" >&2; exit 1; }
85
- [ -d "$BASE_REPO" ] || { echo "base repo not found: $BASE_REPO" >&2; exit 1; }
86
-
87
- META="$FIX_DIR/metadata.json"
88
- EXPECTED="$FIX_DIR/expected.json"
89
- SPEC="$FIX_DIR/spec.md"
90
- TASK="$FIX_DIR/task.txt"
91
- SETUP="$FIX_DIR/setup.sh"
92
- for f in "$META" "$EXPECTED" "$SPEC" "$TASK" "$SETUP"; do
93
- [ -f "$f" ] || { echo "fixture missing required file: $f" >&2; exit 1; }
94
- done
95
-
96
- TIMEOUT=$(python3 - "$META" "$BENCH_ROOT/scripts" <<'PY'
97
- import pathlib
98
- import sys
99
-
100
- sys.path.insert(0, sys.argv[2])
101
- from pair_evidence_contract import loads_strict_json_object
102
-
103
- metadata = loads_strict_json_object(pathlib.Path(sys.argv[1]).read_text())
104
- timeout = metadata.get("timeout_seconds")
105
- if not isinstance(timeout, int) or isinstance(timeout, bool) or timeout <= 0:
106
- raise SystemExit("metadata timeout_seconds must be a positive integer")
107
- print(timeout)
108
- PY
109
- )
110
- if [ -n "$TIMEOUT_OVERRIDE" ]; then
111
- case "$TIMEOUT_OVERRIDE" in ''|*[!0-9]*) echo "--timeout-seconds must be an integer" >&2; exit 1;; esac
112
- [ "$TIMEOUT_OVERRIDE" -gt 0 ] || { echo "--timeout-seconds must be > 0" >&2; exit 1; }
113
- TIMEOUT="$TIMEOUT_OVERRIDE"
114
- fi
115
- if [ -z "$RUN_ID" ]; then
116
- TS=$(date -u +%Y%m%dT%H%M%SZ)
117
- SHA=$(git -C "$REPO_ROOT" rev-parse --short HEAD 2>/dev/null || echo nogit)
118
- RUN_ID="${TS}-${SHA}-frozen-verify"
119
- fi
120
- require_safe_id "--run-id" "$RUN_ID"
121
-
122
- RESULT_ROOT="$BENCH_ROOT/results/$RUN_ID"
123
- mkdir -p "$RESULT_ROOT"
124
-
125
- print_command() {
126
- local cmd=(bash "$0"
127
- --fixture "$FIXTURE"
128
- --fixtures-root "$FIXTURES_ROOT"
129
- --base-repo "$BASE_REPO"
130
- --diff "$DIFF_PATH"
131
- --run-id "$RUN_ID"
132
- --pair-mode "$PAIR_MODE"
133
- --timeout-seconds "$TIMEOUT"
134
- )
135
- [ "$PREPARE_ONLY" -eq 0 ] || cmd+=(--prepare-only)
136
- [ "$RESUME_COMPLETED_ARMS" -eq 0 ] || cmd+=(--resume-completed-arms)
137
- printf 'Command: '
138
- printf '%q ' "${cmd[@]}"
139
- printf '\n'
140
- }
141
-
142
- echo ""
143
- echo "═══ Frozen Verify Pair Run ═══"
144
- echo "Run-id: $RUN_ID"
145
- echo "Fixture: $FIXTURE"
146
- echo "Cases: $FIXTURES_ROOT"
147
- echo "Base: $BASE_REPO"
148
- echo "Diff: $DIFF_PATH"
149
- echo "Pair: $PAIR_MODE"
150
- echo "Timeout: ${TIMEOUT}s per arm"
151
- [ "$PREPARE_ONLY" -eq 0 ] || echo "Mode: prepare-only"
152
- print_command
153
- echo ""
154
-
155
- mirror_skills() {
156
- local src_skills="$REPO_ROOT/config/skills"
157
- local dst_skills="$REPO_ROOT/.claude/skills"
158
- mkdir -p "$dst_skills"
159
- local mirrored=0
160
- for src_dir in "$src_skills"/*/; do
161
- [ -d "$src_dir" ] || continue
162
- local name
163
- name=$(basename "$src_dir")
164
- case "$name" in
165
- devlyn:auto-resolve-workspace|devlyn:ideate-workspace|preflight-workspace|roadmap-archival-workspace)
166
- continue ;;
167
- esac
168
- local staging="$dst_skills/.${name}.staging"
169
- rm -rf "$staging"
170
- cp -R "$src_dir" "$staging"
171
- rm -rf "$dst_skills/$name"
172
- mv "$staging" "$dst_skills/$name"
173
- mirrored=$((mirrored + 1))
174
- done
175
- echo "[frozen-verify] mirrored $mirrored committed skill(s): config/skills/ -> .claude/skills/"
176
- }
177
-
178
- stage_codex_env() {
179
- local work_dir="$1"
180
- local arm="$2"
181
- mkdir -p "$work_dir/.claude"
182
- cp -R "$REPO_ROOT/.claude/skills" "$work_dir/.claude/skills"
183
- [ -f "$REPO_ROOT/CLAUDE.md" ] && cp "$REPO_ROOT/CLAUDE.md" "$work_dir/CLAUDE.md"
184
-
185
- if ! command -v codex >/dev/null 2>&1; then
186
- echo "warning: codex not on PATH — pair arm cannot exercise Codex pair-JUDGE" >&2
187
- return
188
- fi
189
- local real_bin shim_src monitored_src monitored_path snapshot_path injected_path blocked
190
- real_bin="$(command -v codex)"
191
- shim_src="$REPO_ROOT/scripts/codex-shim/codex"
192
- monitored_src="$REPO_ROOT/config/skills/_shared/codex-monitored.sh"
193
- [ -x "$shim_src" ] || { echo "missing codex shim: $shim_src" >&2; exit 1; }
194
- [ -r "$monitored_src" ] || { echo "missing codex wrapper: $monitored_src" >&2; exit 1; }
195
- mkdir -p "$work_dir/.devlyn-bin"
196
- cp "$shim_src" "$work_dir/.devlyn-bin/codex"
197
- chmod +x "$work_dir/.devlyn-bin/codex"
198
- monitored_path="$work_dir/.claude/skills/_shared/codex-monitored.sh"
199
- snapshot_path=$(grep -m1 '^export PATH=' "$HOME/.claude/shell-snapshots/snapshot-zsh-"*.sh 2>/dev/null | head -1 | sed 's/^[^=]*=//' | tr -d '"' || true)
200
- [ -n "$snapshot_path" ] || snapshot_path="$PATH"
201
- injected_path="$work_dir/.devlyn-bin:$snapshot_path"
202
- blocked=0
203
- [ "$arm" = "solo" ] && blocked=1
204
- python3 - "$work_dir/.claude/settings.json" "$injected_path" "$real_bin" "$monitored_path" "$blocked" <<'PY'
205
- import json, sys
206
- out_path, path_val, real_bin, monitored, blocked = sys.argv[1:6]
207
- env = {"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1", "PATH": path_val}
208
- if blocked == "1":
209
- env["CODEX_BLOCKED"] = "1"
210
- else:
211
- env["CODEX_REAL_BIN"] = real_bin
212
- env["CODEX_MONITORED_PATH"] = monitored
213
- with open(out_path, "w") as f:
214
- json.dump({"env": env}, f, indent=2)
215
- f.write("\n")
216
- PY
217
- }
218
-
219
- cleanup_workdir_processes() {
220
- local work_dir="$1"
221
- local signal="$2"
222
- local physical_work_dir current_pgid
223
- physical_work_dir="$(cd "$work_dir" 2>/dev/null && pwd -P || printf '%s' "$work_dir")"
224
- current_pgid="$(ps -o pgid= -p "$$" | tr -d ' ')"
225
- ps -axo pid=,pgid=,command= \
226
- | awk -v p1="$work_dir" -v p2="$physical_work_dir" -v self="$$" -v current_pgid="$current_pgid" '
227
- $1 != self && $2 != current_pgid && (index($0, p1) || index($0, p2)) { print $2 }
228
- ' \
229
- | sort -u \
230
- | while IFS= read -r pgid; do
231
- [ -n "$pgid" ] || continue
232
- kill "-$signal" -- "-$pgid" 2>/dev/null || true
233
- done
234
- }
235
-
236
- archive_ready() {
237
- local work_dir="$1"
238
- python3 - "$work_dir" <<'PY'
239
- import pathlib, sys
240
- root = pathlib.Path(sys.argv[1]) / ".devlyn" / "runs"
241
- raise SystemExit(0 if root.is_dir() and any(root.glob("*/pipeline.state.json")) else 1)
242
- PY
243
- }
244
-
245
- summarize_arm() {
246
- local result_dir="$1"
247
- local elapsed="$2"
248
- local invoke_exit="$3"
249
- python3 - "$result_dir" "$elapsed" "$invoke_exit" "$BENCH_ROOT/scripts" <<'PY'
250
- import json, pathlib, sys
251
- sys.path.insert(0, sys.argv[4])
252
- from pair_evidence_contract import loads_strict_json_object, reject_json_constant
253
-
254
- result_dir = pathlib.Path(sys.argv[1])
255
- elapsed = int(sys.argv[2])
256
- invoke_exit = int(sys.argv[3])
257
- archive = result_dir / "run-archive"
258
- state_path = archive / "pipeline.state.json"
259
- def as_dict(value):
260
- return value if isinstance(value, dict) else {}
261
-
262
- def strict_nonnegative_int(value):
263
- return isinstance(value, int) and not isinstance(value, bool) and value >= 0
264
-
265
- state = as_dict(loads_strict_json_object(state_path.read_text())) if state_path.is_file() else {}
266
- phases = as_dict(state.get("phases"))
267
- verify = as_dict(phases.get("verify"))
268
- legacy_verify = as_dict(state.get("verify"))
269
- sub_verdicts = verify.get("sub_verdicts")
270
- pair_trigger = verify.get("pair_trigger") or legacy_verify.get("pair_trigger")
271
- PAIR_VERDICTS = {"PASS", "PASS_WITH_ISSUES", "NEEDS_WORK", "BLOCKED", "FAIL"}
272
-
273
- def has_pair_judge_verdict(sub_verdicts):
274
- return isinstance(sub_verdicts, dict) and (
275
- sub_verdicts.get("judge_codex") in PAIR_VERDICTS
276
- or sub_verdicts.get("pair_judge") in PAIR_VERDICTS
277
- )
278
-
279
- findings = []
280
- finding_paths = []
281
- merged_path = archive / "verify-merged.findings.jsonl"
282
- if merged_path.is_file():
283
- finding_paths.append(merged_path)
284
- else:
285
- candidates = []
286
- for name in ("verify.findings.jsonl", "verify.pair-judge.findings.jsonl"):
287
- candidates.append(archive / name)
288
- candidates.extend(sorted(archive.glob("verify.findings*.jsonl")))
289
- candidates.extend(sorted(archive.glob("verify.*findings*.jsonl")))
290
- seen = set()
291
- for candidate_path in candidates:
292
- if candidate_path.name == "verify-mechanical.findings.jsonl":
293
- continue
294
- if candidate_path in seen or not candidate_path.is_file():
295
- continue
296
- seen.add(candidate_path)
297
- finding_paths.append(candidate_path)
298
- findings_source = "+".join(path.name for path in finding_paths) if finding_paths else "missing"
299
- finding_severities = {"CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"}
300
- for findings_path in finding_paths:
301
- for line in findings_path.read_text().splitlines():
302
- if line.strip():
303
- try:
304
- parsed = json.loads(line, parse_constant=reject_json_constant)
305
- except json.JSONDecodeError:
306
- continue
307
- if not isinstance(parsed, dict):
308
- continue
309
- sev = str(parsed.get("severity") or parsed.get("level") or "").upper()
310
- if sev not in finding_severities:
311
- continue
312
- findings.append(parsed)
313
- merged = as_dict(verify.get("merged"))
314
- merged_findings_count = sum(
315
- merged.get(k) if strict_nonnegative_int(merged.get(k)) else 0
316
- for k in ("critical", "high", "medium", "low")
317
- )
318
- findings_count = len(findings) if findings else merged_findings_count
319
- severity_counts = {}
320
- for finding in findings:
321
- if isinstance(finding, dict):
322
- sev = str(finding.get("severity") or finding.get("level") or "unknown").upper()
323
- severity_counts[sev] = severity_counts.get(sev, 0) + 1
324
- transcript_path = result_dir / "transcript.txt"
325
- transcript = transcript_path.read_text(errors="replace") if transcript_path.is_file() else ""
326
- invoke_failure_reason = None
327
- if invoke_exit == 124:
328
- invoke_failure_reason = "timeout"
329
- elif "You've hit your limit" in transcript:
330
- invoke_failure_reason = "provider_limit"
331
- summary = {
332
- "elapsed_seconds": elapsed,
333
- "invoke_exit": invoke_exit,
334
- "timed_out": invoke_exit == 124,
335
- "invoke_failure_reason": invoke_failure_reason,
336
- "terminal_verdict": as_dict(phases.get("final_report")).get("verdict"),
337
- "verify_verdict": verify.get("verdict"),
338
- "sub_verdicts": sub_verdicts,
339
- "pair_trigger": pair_trigger,
340
- "pair_mode": has_pair_judge_verdict(sub_verdicts)
341
- or verify.get("pair_mode") is True,
342
- "verify_findings_count": findings_count,
343
- "verify_findings_source": findings_source if finding_paths else (
344
- "state.merged" if merged_findings_count else "missing"
345
- ),
346
- "merged_findings_counts": merged,
347
- "severity_counts": severity_counts,
348
- "verify_findings_severities": [f.get("severity") for f in findings if isinstance(f, dict)],
349
- }
350
- (result_dir / "summary.json").write_text(json.dumps(summary, indent=2) + "\n")
351
- print(json.dumps(summary, indent=2))
352
- PY
353
- }
354
-
355
- copy_base_repo() {
356
- local work_dir="$1"
357
- rm -rf "$work_dir"
358
- mkdir -p "$work_dir"
359
- if [ -d "$BASE_REPO/.git" ]; then
360
- git -C "$BASE_REPO" archive --format=tar HEAD | (cd "$work_dir" && LC_ALL=C tar -xf -)
361
- else
362
- cp -R "$BASE_REPO"/. "$work_dir"/
363
- rm -rf "$work_dir/.git"
364
- fi
365
- }
366
-
367
- run_arm() {
368
- local arm="$1"
369
- local pair_flag="$2"
370
- local result_dir="$RESULT_ROOT/$arm"
371
- local work_dir="/tmp/bench-${RUN_ID}-${FIXTURE}-${arm}"
372
- if [ "$RESUME_COMPLETED_ARMS" -eq 1 ] && [ "$PREPARE_ONLY" -eq 0 ] && [ -f "$result_dir/summary.json" ]; then
373
- if python3 - "$result_dir/summary.json" "$BENCH_ROOT/scripts" <<'PY'
374
- import pathlib
375
- import sys
376
- sys.path.insert(0, sys.argv[2])
377
- from pair_evidence_contract import loads_strict_json_object
378
-
379
- summary = loads_strict_json_object(pathlib.Path(sys.argv[1]).read_text())
380
- raise SystemExit(0 if summary.get("invoke_exit") == 0 else 1)
381
- PY
382
- then
383
- echo "[frozen-verify] $arm: reuse completed summary"
384
- return 0
385
- fi
386
- fi
387
- mkdir -p "$result_dir"
388
- copy_base_repo "$work_dir"
389
-
390
- stage_codex_env "$work_dir" "$arm"
391
-
392
- (cd "$work_dir" && git init -q && git add -A && git -c user.email=b@b -c user.name=b commit -q -m baseline)
393
-
394
- if [ -s "$SETUP" ]; then
395
- chmod +x "$SETUP"
396
- (cd "$work_dir" && "$SETUP") > "$result_dir/setup.log" 2>&1
397
- (cd "$work_dir" && git add -A && git -c user.email=b@b -c user.name=b commit -q --allow-empty -m fixture-setup)
398
- fi
399
-
400
- mkdir -p "$work_dir/docs/roadmap/phase-1" "$work_dir/.devlyn"
401
- cp "$SPEC" "$work_dir/docs/roadmap/phase-1/$FIXTURE.md"
402
- cp "$DIFF_PATH" "$work_dir/.devlyn/external-diff.patch"
403
- python3 - "$EXPECTED" "$work_dir/.devlyn/spec-verify.json" "$BENCH_ROOT/scripts" <<'PY'
404
- import json, os, pathlib, sys
405
- sys.path.insert(0, sys.argv[3])
406
- from pair_evidence_contract import loads_strict_json_object
407
-
408
- expected = loads_strict_json_object(pathlib.Path(sys.argv[1]).read_text())
409
- out_path = sys.argv[2]
410
- commands = expected.get("verification_commands", [])
411
- if not commands:
412
- raise SystemExit(0)
413
- os.makedirs(os.path.dirname(out_path), exist_ok=True)
414
- with open(out_path, "w") as f:
415
- json.dump({"verification_commands": commands}, f, indent=2)
416
- f.write("\n")
417
- PY
418
-
419
- if ! (cd "$work_dir" && git apply .devlyn/external-diff.patch); then
420
- echo "[frozen-verify] $arm: diff failed to apply" >&2
421
- return 1
422
- fi
423
- (cd "$work_dir" && git add -A && git -c user.email=b@b -c user.name=b commit -q -m external-implementation)
424
-
425
- cat > "$result_dir/input.md" <<EOF
426
- Use the \`/devlyn:resolve --verify-only .devlyn/external-diff.patch --spec docs/roadmap/phase-1/$FIXTURE.md --engine claude ${pair_flag}\` skill to run VERIFY-ONLY mode.
427
-
428
- The diff at .devlyn/external-diff.patch represents an external implementation already applied to the work tree. Run PHASE 5 (VERIFY) only — skip PLAN, IMPLEMENT, BUILD_GATE, CLEANUP per the skill's verify-only mode contract.
429
-
430
- Important: \`--engine claude\` selects the primary VERIFY judge only. It must not suppress gated VERIFY pair-mode. If the spec/phase trigger makes pair-mode eligible with non-empty reasons, the skill must spawn the OTHER-engine judge unless Codex is blocked/unavailable at the invocation layer.
431
-
432
- Report the terminal verdict, list of files in the diff, and any findings.
433
- EOF
434
-
435
- if [ "$PREPARE_ONLY" -eq 1 ]; then
436
- echo "[frozen-verify] $arm prepared at $work_dir"
437
- return 0
438
- fi
439
-
440
- local start end elapsed invoke_exit watchdog timeout_flag complete_flag
441
- start=$(date +%s)
442
- timeout_flag="$result_dir/.timed_out"
443
- complete_flag="$result_dir/.completed"
444
- rm -f "$timeout_flag" "$complete_flag"
445
- set +e
446
- set -m
447
- (
448
- cd "$work_dir"
449
- export PATH="$work_dir/.devlyn-bin:$PATH"
450
- [ "$arm" = "solo" ] && export CODEX_BLOCKED=1
451
- export BENCH_WORKDIR="$work_dir"
452
- export BENCH_FIXTURE_DIR="$FIX_DIR"
453
- exec claude \
454
- -p "$(cat "$result_dir/input.md")" \
455
- --dangerously-skip-permissions \
456
- --effort xhigh \
457
- --strict-mcp-config \
458
- --mcp-config '{"mcpServers":{}}' \
459
- --debug-file "$result_dir/claude-debug.log" \
460
- </dev/null
461
- ) > "$result_dir/transcript.txt" 2>&1 &
462
- local child_pid=$!
463
- set +m
464
- (
465
- local deadline now
466
- deadline=$(($(date +%s) + TIMEOUT))
467
- while kill -0 "$child_pid" 2>/dev/null; do
468
- if archive_ready "$work_dir"; then
469
- : > "$complete_flag"
470
- kill -TERM -- "-$child_pid" 2>/dev/null
471
- cleanup_workdir_processes "$work_dir" TERM
472
- sleep 2
473
- kill -KILL -- "-$child_pid" 2>/dev/null
474
- cleanup_workdir_processes "$work_dir" KILL
475
- exit 0
476
- fi
477
- now=$(date +%s)
478
- [ "$now" -lt "$deadline" ] || break
479
- sleep 5
480
- done
481
- if kill -0 "$child_pid" 2>/dev/null; then
482
- : > "$timeout_flag"
483
- kill -TERM -- "-$child_pid" 2>/dev/null
484
- cleanup_workdir_processes "$work_dir" TERM
485
- sleep 5
486
- kill -KILL -- "-$child_pid" 2>/dev/null
487
- cleanup_workdir_processes "$work_dir" KILL
488
- fi
489
- ) &
490
- watchdog=$!
491
- wait "$child_pid"
492
- invoke_exit=$?
493
- kill -TERM "$watchdog" 2>/dev/null || true
494
- wait "$watchdog" 2>/dev/null || true
495
- if [ -f "$timeout_flag" ]; then
496
- invoke_exit=124
497
- rm -f "$timeout_flag"
498
- elif [ -f "$complete_flag" ]; then
499
- invoke_exit=0
500
- rm -f "$complete_flag"
501
- fi
502
- set -e
503
- end=$(date +%s)
504
- elapsed=$((end - start))
505
-
506
- local run_dir
507
- run_dir=$(find "$work_dir/.devlyn/runs" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort | tail -1 || true)
508
- if [ -n "$run_dir" ]; then
509
- rm -rf "$result_dir/run-archive"
510
- cp -R "$run_dir" "$result_dir/run-archive"
511
- [ -f "$result_dir/run-archive/pipeline.state.json" ] \
512
- || [ ! -f "$work_dir/.devlyn/pipeline.state.json" ] \
513
- || cp "$work_dir/.devlyn/pipeline.state.json" "$result_dir/run-archive/pipeline.state.json"
514
- elif [ -d "$work_dir/.devlyn" ]; then
515
- rm -rf "$result_dir/run-archive"
516
- mkdir -p "$result_dir/run-archive"
517
- find "$work_dir/.devlyn" -maxdepth 1 -type f -exec cp {} "$result_dir/run-archive/" \;
518
- fi
519
- if [ -d "$work_dir/.devlyn" ] && [ -d "$result_dir/run-archive" ]; then
520
- find "$work_dir/.devlyn" -maxdepth 1 -type f \
521
- \( -name 'verify.findings*.jsonl' -o -name 'verify.*findings*.jsonl' -o -name 'verify-merged.findings.jsonl' \) \
522
- ! -name 'verify-mechanical.findings.jsonl' \
523
- -exec cp {} "$result_dir/run-archive/" \;
524
- fi
525
- summarize_arm "$result_dir" "$elapsed" "$invoke_exit"
526
- }
527
-
528
- mirror_skills
529
- echo "[frozen-verify] ► solo"
530
- run_arm solo ""
531
- echo "[frozen-verify] ► pair"
532
- if [ "$PAIR_MODE" = "forced" ]; then
533
- run_arm pair "--pair-verify"
534
- else
535
- run_arm pair ""
536
- fi
537
-
538
- python3 - "$RESULT_ROOT" "$PAIR_MODE" "$BENCH_ROOT/scripts" <<'PY'
539
- import json, math, pathlib, sys
540
- sys.path.insert(0, sys.argv[3])
541
- from pair_evidence_contract import loads_strict_json_object
542
-
543
- root = pathlib.Path(sys.argv[1])
544
- pair_mode_requested = sys.argv[2]
545
- out = {}
546
- for arm in ("solo", "pair"):
547
- path = root / arm / "summary.json"
548
- out[arm] = loads_strict_json_object(path.read_text()) if path.is_file() else {"missing": True}
549
- solo = out.get("solo", {})
550
- pair = out.get("pair", {})
551
- rank = {
552
- None: 0,
553
- "PASS": 0,
554
- "PASS_WITH_ISSUES": 1,
555
- "NEEDS_WORK": 2,
556
- "BLOCKED": 3,
557
- }
558
- solo_rank = rank.get(solo.get("verify_verdict"), 0)
559
- pair_rank = rank.get(pair.get("verify_verdict"), 0)
560
- raw_pair_sub = pair.get("sub_verdicts")
561
- pair_sub = raw_pair_sub if isinstance(raw_pair_sub, dict) else {}
562
- pair_primary_verdict = pair_sub.get("judge")
563
- pair_judge_verdict = pair_sub.get("pair_judge")
564
- pair_primary_rank = rank.get(pair_primary_verdict, 0)
565
- pair_judge_rank = rank.get(pair_judge_verdict, 0)
566
- def strict_positive_number(value):
567
- return (
568
- isinstance(value, (int, float))
569
- and not isinstance(value, bool)
570
- and math.isfinite(value)
571
- and value > 0
572
- )
573
-
574
- def elapsed_ratio(pair_elapsed, solo_elapsed):
575
- if not strict_positive_number(pair_elapsed) or not strict_positive_number(solo_elapsed):
576
- return None
577
- return pair_elapsed / solo_elapsed
578
-
579
- def strict_nonnegative_int(value):
580
- return isinstance(value, int) and not isinstance(value, bool) and value >= 0
581
-
582
- def summary_findings_count(data):
583
- value = data.get("verify_findings_count")
584
- return value if strict_nonnegative_int(value) else None
585
-
586
- def severity_count_sum(data):
587
- raw_counts = data.get("severity_counts")
588
- if not isinstance(raw_counts, dict):
589
- return None
590
- total = 0
591
- for key in ("LOW", "MEDIUM", "HIGH", "CRITICAL"):
592
- value = raw_counts.get(key, 0)
593
- if not strict_nonnegative_int(value):
594
- return None
595
- total += value
596
- return total
597
-
598
- def strict_greater(left, right):
599
- return left is not None and right is not None and left > right
600
-
601
- wall_ratio = elapsed_ratio(pair.get("elapsed_seconds"), solo.get("elapsed_seconds"))
602
- pair_mode_true = pair.get("pair_mode") is True
603
- raw_pair_trigger = pair.get("pair_trigger")
604
- pair_trigger = raw_pair_trigger if isinstance(raw_pair_trigger, dict) else {}
605
- pair_findings_count = summary_findings_count(pair)
606
- solo_findings_count = summary_findings_count(solo)
607
- pair_low_or_worse = severity_count_sum(pair)
608
- solo_low_or_worse = severity_count_sum(solo)
609
- out["comparison"] = {
610
- "pair_mode_requested": pair_mode_requested,
611
- "pair_trigger_missed": bool(
612
- pair_mode_requested == "gated"
613
- and pair_trigger.get("eligible") is True
614
- and pair_trigger.get("reasons")
615
- and not pair_mode_true
616
- ),
617
- "pair_found_more_findings": strict_greater(pair_findings_count, solo_findings_count),
618
- "pair_found_more_low_or_worse": strict_greater(pair_low_or_worse, solo_low_or_worse),
619
- "pair_verdict_lift": pair_mode_true and pair_rank > solo_rank and pair_rank >= rank["NEEDS_WORK"],
620
- "pair_internal_verdict_lift": pair_mode_true
621
- and pair_judge_rank > pair_primary_rank
622
- and pair_rank >= rank["NEEDS_WORK"],
623
- "solo_verdict": solo.get("verify_verdict"),
624
- "pair_verdict": pair.get("verify_verdict"),
625
- "pair_primary_verdict": pair_primary_verdict,
626
- "pair_judge_verdict": pair_judge_verdict,
627
- "pair_solo_wall_ratio": wall_ratio,
628
- }
629
- (root / "compare.json").write_text(json.dumps(out, indent=2) + "\n")
630
- print(json.dumps(out, indent=2))
631
-
632
- def fmt_bool(value):
633
- return str(value is True).lower()
634
-
635
- def fmt_ratio(value):
636
- return f"{value:.2f}x" if strict_positive_number(value) else "n/a"
637
-
638
- def fmt_seconds(value):
639
- return f"{value}s" if strict_positive_number(value) else "n/a"
640
-
641
- def fmt_trigger_reasons(value):
642
- if not isinstance(value, dict):
643
- return ""
644
- reasons = value.get("reasons")
645
- if not isinstance(reasons, list) or not all(isinstance(reason, str) for reason in reasons):
646
- return ""
647
- return ",".join(reasons)
648
-
649
- def arm_row(name, data):
650
- return (
651
- f"| {name} | {data.get('verify_verdict') or 'n/a'} | "
652
- f"{fmt_bool(data.get('pair_mode'))} | "
653
- f"{fmt_trigger_reasons(data.get('pair_trigger'))} | "
654
- f"{data.get('verify_findings_count', 'n/a')} | "
655
- f"{fmt_seconds(data.get('elapsed_seconds'))} | {data.get('invoke_exit', 'n/a')} | "
656
- f"{data.get('invoke_failure_reason') or 'n/a'} |"
657
- )
658
-
659
- summary_lines = [
660
- "# Frozen VERIFY Pair Summary",
661
- "",
662
- f"Run id: `{root.name}`",
663
- f"Pair mode requested: `{pair_mode_requested}`",
664
- "",
665
- "| Arm | Verdict | Pair mode | Triggers | Findings | Elapsed | Invoke exit | Failure |",
666
- "|---|---|---:|---|---:|---:|---:|---|",
667
- arm_row("solo", solo),
668
- arm_row("pair", pair),
669
- "",
670
- "| Wall ratio | External lift | Internal lift | Trigger missed |",
671
- "|---:|---:|---:|---:|",
672
- (
673
- f"| {fmt_ratio(wall_ratio)} | "
674
- f"{fmt_bool(out['comparison']['pair_verdict_lift'])} | "
675
- f"{fmt_bool(out['comparison']['pair_internal_verdict_lift'])} | "
676
- f"{fmt_bool(out['comparison']['pair_trigger_missed'])} |"
677
- ),
678
- "",
679
- ]
680
- summary_text = "\n".join(summary_lines)
681
- (root / "compare.md").write_text(summary_text, encoding="utf8")
682
- print(summary_text)
683
- PY