devlyn-cli 3.2.1 → 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.
- package/AGENTS.md +2 -2
- package/CLAUDE.md +2 -2
- package/README.md +12 -102
- package/bin/devlyn.js +13 -225
- package/bin/instruction-templates.json +6 -0
- package/config/skills/_shared/adapters/grok.md +1 -2
- package/config/skills/_shared/archive_run.py +15 -3
- package/config/skills/_shared/judge-role-evidence.py +21 -1
- package/config/skills/_shared/runtime-principles.md +1 -1
- package/config/skills/_shared/spec-verify-check.py +0 -653
- package/config/skills/_shared/state-phase-write.py +351 -25
- package/config/skills/_shared/task-complete.py +635 -143
- package/config/skills/_shared/terminal-claim-check.py +229 -4
- package/config/skills/_shared/verify-merge-findings.py +93 -2
- package/config/skills/devlyn:ideate/SKILL.md +3 -4
- package/config/skills/devlyn:ideate/references/elicitation.md +2 -35
- package/config/skills/devlyn:ideate/references/from-spec-mode.md +3 -18
- package/config/skills/devlyn:ideate/references/project-mode.md +1 -16
- package/config/skills/devlyn:ideate/references/spec-template.md +0 -2
- package/config/skills/devlyn:queue/SKILL.md +6 -4
- package/config/skills/devlyn:resolve/SKILL.md +16 -25
- package/config/skills/devlyn:resolve/references/free-form-mode.md +0 -14
- package/config/skills/devlyn:resolve/references/outer-loop.md +1 -1
- package/config/skills/devlyn:resolve/references/phases/build-gate.md +1 -1
- package/config/skills/devlyn:resolve/references/phases/cleanup.md +3 -3
- package/config/skills/devlyn:resolve/references/phases/implement.md +1 -1
- package/config/skills/devlyn:resolve/references/phases/probe-derive.md +1 -16
- package/config/skills/devlyn:resolve/references/phases/verify.md +4 -9
- package/config/skills/devlyn:resolve/references/state-schema.md +9 -7
- package/config/skills/devlyn:resolve/references/task-completion.md +46 -37
- package/{config/skills → optional-skills}/code-health-standards/SKILL.md +4 -13
- package/{config/skills → optional-skills}/code-review-standards/SKILL.md +4 -12
- package/{config/skills → optional-skills}/root-cause-analysis/SKILL.md +4 -12
- package/{config/skills → optional-skills}/ui-implementation-standards/SKILL.md +4 -14
- package/package.json +1 -57
- package/benchmark/auto-resolve/BENCHMARK-DESIGN.md +0 -289
- package/benchmark/auto-resolve/BENCHMARK-RESULTS.md +0 -341
- package/benchmark/auto-resolve/README.md +0 -696
- package/benchmark/auto-resolve/RUBRIC.md +0 -177
- package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/NOTES.md +0 -34
- package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/expected.json +0 -68
- package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/setup.sh +0 -4
- package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/spec.md +0 -44
- package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/task.ko.txt +0 -8
- package/benchmark/auto-resolve/fixtures/F1-cli-trivial-flag/task.txt +0 -8
- package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/NOTES.md +0 -68
- package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/expected.json +0 -60
- package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/setup.sh +0 -17
- package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/spec.md +0 -51
- package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/verifiers/invalid.js +0 -29
- package/benchmark/auto-resolve/fixtures/F10-persist-write-collision/verifiers/parallel.js +0 -50
- package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/NOTES.md +0 -75
- package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/expected.json +0 -52
- package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/setup.sh +0 -171
- package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/spec.md +0 -50
- package/benchmark/auto-resolve/fixtures/F11-batch-import-all-or-nothing/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/NOTES.md +0 -89
- package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/expected.json +0 -74
- package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/setup.sh +0 -251
- package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/spec.md +0 -57
- package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/task.txt +0 -13
- package/benchmark/auto-resolve/fixtures/F12-webhook-raw-body-signature/verifiers/replay-malformed-body.js +0 -64
- package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/NOTES.md +0 -104
- package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/expected.json +0 -46
- package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/setup.sh +0 -336
- package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/spec.md +0 -51
- package/benchmark/auto-resolve/fixtures/F15-frozen-diff-race-review/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/NOTES.md +0 -38
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/expected.json +0 -64
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/setup.sh +0 -32
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/spec.md +0 -63
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/verifiers/exact-success.js +0 -54
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/verifiers/no-hardcoded-pricing.js +0 -47
- package/benchmark/auto-resolve/fixtures/F16-cli-quote-tax-rules/verifiers/stock-error.js +0 -45
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/NOTES.md +0 -57
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/expected-pair-plan-registry.json +0 -170
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/expected.json +0 -84
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/metadata.json +0 -21
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/pair-plan.sample-fail.json +0 -214
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/pair-plan.sample-pass.json +0 -223
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/setup.sh +0 -5
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/spec.md +0 -55
- package/benchmark/auto-resolve/fixtures/F2-cli-medium-subcommand/task.txt +0 -14
- package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/NOTES.md +0 -39
- package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/expected.json +0 -62
- package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/setup.sh +0 -2
- package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/spec.md +0 -67
- package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/verifiers/error-order.js +0 -55
- package/benchmark/auto-resolve/fixtures/F21-cli-scheduler-priority/verifiers/priority-blocked.js +0 -48
- package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/NOTES.md +0 -35
- package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/expected.json +0 -56
- package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/setup.sh +0 -2
- package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/spec.md +0 -64
- package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/verifiers/conflicting-duplicate.js +0 -34
- package/benchmark/auto-resolve/fixtures/F22-cli-ledger-close/verifiers/idempotent-close.js +0 -41
- package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/NOTES.md +0 -39
- package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/expected.json +0 -56
- package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/setup.sh +0 -2
- package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/spec.md +0 -76
- package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/verifiers/priority-rollback.js +0 -64
- package/benchmark/auto-resolve/fixtures/F23-cli-fulfillment-wave/verifiers/single-warehouse-fefo.js +0 -66
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/NOTES.md +0 -40
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/expected.json +0 -66
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/setup.sh +0 -36
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/spec.md +0 -71
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/verifiers/catalog-source.js +0 -57
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/verifiers/exact-success.js +0 -63
- package/benchmark/auto-resolve/fixtures/F25-cli-cart-promotion-rules/verifiers/stock-error.js +0 -34
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/NOTES.md +0 -31
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/expected.json +0 -68
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/setup.sh +0 -17
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/spec.md +0 -68
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/verifiers/conflicting-duplicate.js +0 -29
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/verifiers/exact-payout.js +0 -58
- package/benchmark/auto-resolve/fixtures/F26-cli-payout-ledger-rules/verifiers/rules-source.js +0 -56
- package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/NOTES.md +0 -35
- package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/expected-pair-plan-registry.json +0 -162
- package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/expected.json +0 -67
- package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/metadata.json +0 -19
- package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/setup.sh +0 -4
- package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/spec.md +0 -55
- package/benchmark/auto-resolve/fixtures/F3-backend-contract-risk/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/NOTES.md +0 -34
- package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/expected.json +0 -57
- package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/setup.sh +0 -2
- package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/spec.md +0 -67
- package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/verifiers/duplicate-event-error.js +0 -35
- package/benchmark/auto-resolve/fixtures/F31-cli-seat-rebalance/verifiers/priority-transfer-rollback.js +0 -53
- package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/NOTES.md +0 -38
- package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/expected.json +0 -57
- package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/setup.sh +0 -2
- package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/spec.md +0 -70
- package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/task.txt +0 -3
- package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/verifiers/duplicate-renewal-error.js +0 -42
- package/benchmark/auto-resolve/fixtures/F32-cli-subscription-renewal/verifiers/priority-credit-rollback.js +0 -70
- package/benchmark/auto-resolve/fixtures/F4-web-browser-design/NOTES.md +0 -47
- package/benchmark/auto-resolve/fixtures/F4-web-browser-design/expected.json +0 -57
- package/benchmark/auto-resolve/fixtures/F4-web-browser-design/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F4-web-browser-design/setup.sh +0 -6
- package/benchmark/auto-resolve/fixtures/F4-web-browser-design/spec.md +0 -48
- package/benchmark/auto-resolve/fixtures/F4-web-browser-design/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/NOTES.md +0 -45
- package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/expected.json +0 -65
- package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/setup.sh +0 -55
- package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/spec.md +0 -48
- package/benchmark/auto-resolve/fixtures/F5-fix-loop-red-green/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/NOTES.md +0 -43
- package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/expected.json +0 -77
- package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/setup.sh +0 -4
- package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/spec.md +0 -48
- package/benchmark/auto-resolve/fixtures/F6-dep-audit-native-module/task.txt +0 -10
- package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/NOTES.md +0 -57
- package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/expected.json +0 -76
- package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/setup.sh +0 -36
- package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/spec.md +0 -45
- package/benchmark/auto-resolve/fixtures/F7-out-of-scope-trap/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/NOTES.md +0 -53
- package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/expected.json +0 -63
- package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/setup.sh +0 -4
- package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/spec.md +0 -48
- package/benchmark/auto-resolve/fixtures/F8-known-limit-ambiguous/task.txt +0 -1
- package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/NOTES.md +0 -105
- package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/expected.json +0 -74
- package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/setup.sh +0 -28
- package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/spec.md +0 -59
- package/benchmark/auto-resolve/fixtures/F9-e2e-ideate-to-resolve/task.txt +0 -5
- package/benchmark/auto-resolve/fixtures/SCHEMA.md +0 -188
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/NOTES.md +0 -37
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/RETIRED.md +0 -13
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/expected.json +0 -56
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/setup.sh +0 -18
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/spec.md +0 -69
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/task.txt +0 -7
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/verifiers/exact-proration.js +0 -48
- package/benchmark/auto-resolve/fixtures/retired/F27-cli-subscription-proration/verifiers/rules-source-and-conflict.js +0 -79
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/NOTES.md +0 -54
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/RETIRED.md +0 -7
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/expected.json +0 -67
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/setup.sh +0 -2
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/spec.md +0 -67
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/task.txt +0 -5
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/verifiers/policy-precedence.js +0 -72
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/verifiers/validation-and-immutability.js +0 -43
- package/benchmark/auto-resolve/fixtures/retired/F28-cli-return-authorization/verifiers/validation-boundary.js +0 -116
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/NOTES.md +0 -35
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/RETIRED.md +0 -12
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/expected.json +0 -58
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/setup.sh +0 -2
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/spec.md +0 -73
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/task.txt +0 -17
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/verifiers/mixed-idempotent-settlement.js +0 -53
- package/benchmark/auto-resolve/fixtures/retired/F30-cli-credit-hold-settlement/verifiers/rejection-boundaries.js +0 -74
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/NOTES.md +0 -28
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/RETIRED.md +0 -15
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/expected.json +0 -57
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/setup.sh +0 -50
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/spec.md +0 -59
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/verifiers/ordered-settlement.js +0 -88
- package/benchmark/auto-resolve/fixtures/retired/F34-cli-settle-inflight/verifiers/reject-invalid.js +0 -45
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/NOTES.md +0 -30
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/RETIRED.md +0 -16
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/expected.json +0 -64
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/setup.sh +0 -21
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/spec.md +0 -58
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/verifiers/dup-op.js +0 -54
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/verifiers/priority-apply.js +0 -82
- package/benchmark/auto-resolve/fixtures/retired/F35-cli-apply-journal/verifiers/rollback.js +0 -77
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/NOTES.md +0 -99
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/RETIRED.md +0 -18
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/expected.json +0 -64
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/setup.sh +0 -4
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/spec.md +0 -61
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/verifiers/correctness-small.js +0 -135
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/verifiers/scale.js +0 -100
- package/benchmark/auto-resolve/fixtures/retired/F36-cli-session-admission/verifiers/validation.js +0 -75
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/NOTES.md +0 -93
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/RETIRED.md +0 -16
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/expected.json +0 -65
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/setup.sh +0 -18
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/spec.md +0 -66
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/task.txt +0 -9
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/verifiers/correctness-small.js +0 -84
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/verifiers/scale.js +0 -184
- package/benchmark/auto-resolve/fixtures/retired/F37-cli-rule-lookup/verifiers/validation.js +0 -74
- package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/NOTES.md +0 -60
- package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/RETIRED.md +0 -29
- package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/expected.json +0 -73
- package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/metadata.json +0 -10
- package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/setup.sh +0 -28
- package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/spec.md +0 -58
- package/benchmark/auto-resolve/fixtures/retired/F9-e2e-ideate-to-preflight/task.txt +0 -5
- package/benchmark/auto-resolve/fixtures/test-repo/README.md +0 -12
- package/benchmark/auto-resolve/fixtures/test-repo/bin/cli.js +0 -63
- package/benchmark/auto-resolve/fixtures/test-repo/package-lock.json +0 -823
- package/benchmark/auto-resolve/fixtures/test-repo/package.json +0 -22
- package/benchmark/auto-resolve/fixtures/test-repo/playwright.config.js +0 -17
- package/benchmark/auto-resolve/fixtures/test-repo/server/index.js +0 -37
- package/benchmark/auto-resolve/fixtures/test-repo/tests/cli.test.js +0 -25
- package/benchmark/auto-resolve/fixtures/test-repo/tests/server.test.js +0 -58
- package/benchmark/auto-resolve/fixtures/test-repo/web/index.html +0 -37
- package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.json +0 -25
- package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.md +0 -10
- package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.json +0 -18
- package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.md +0 -9
- package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.json +0 -18
- package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.md +0 -9
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-cli-quote-tax-rules/l2_risk_probes/result.json +0 -28
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F23-cli-fulfillment-wave/l2_risk_probes/result.json +0 -28
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F25-cli-cart-promotion-rules/l2_risk_probes/result.json +0 -30
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/full-pipeline-pair-gate.json +0 -82
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/full-pipeline-pair-gate.md +0 -18
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/headroom-gate.json +0 -46
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/headroom-gate.md +0 -17
- package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/F21-cli-scheduler-priority/l2_risk_probes/result.json +0 -32
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.json +0 -44
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.md +0 -16
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.json +0 -18
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.md +0 -9
- package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.json +0 -28
- package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.md +0 -15
- package/benchmark/auto-resolve/run-real-benchmark.md +0 -303
- package/benchmark/auto-resolve/scripts/audit-headroom-rejections.py +0 -441
- package/benchmark/auto-resolve/scripts/audit-pair-evidence.py +0 -1256
- package/benchmark/auto-resolve/scripts/build-pair-eligible-manifest.py +0 -306
- package/benchmark/auto-resolve/scripts/check-f9-artifacts.py +0 -268
- package/benchmark/auto-resolve/scripts/collect-swebench-predictions.py +0 -108
- package/benchmark/auto-resolve/scripts/compile-report.py +0 -493
- package/benchmark/auto-resolve/scripts/fetch-swebench-instances.py +0 -129
- package/benchmark/auto-resolve/scripts/frozen-verify-gate.py +0 -434
- package/benchmark/auto-resolve/scripts/full-pipeline-pair-gate.py +0 -612
- package/benchmark/auto-resolve/scripts/headroom-gate.py +0 -378
- package/benchmark/auto-resolve/scripts/iter-0033c-compare.py +0 -683
- package/benchmark/auto-resolve/scripts/iter-0033c-l1-summary.py +0 -97
- package/benchmark/auto-resolve/scripts/judge-opus-pass.sh +0 -542
- package/benchmark/auto-resolve/scripts/judge.sh +0 -565
- package/benchmark/auto-resolve/scripts/oracle-scope-tier-a.py +0 -256
- package/benchmark/auto-resolve/scripts/oracle-scope-tier-b.py +0 -287
- package/benchmark/auto-resolve/scripts/oracle-test-fidelity.py +0 -328
- package/benchmark/auto-resolve/scripts/pair-candidate-frontier.py +0 -469
- package/benchmark/auto-resolve/scripts/pair-plan-idgen.py +0 -401
- package/benchmark/auto-resolve/scripts/pair-plan-lint.py +0 -475
- package/benchmark/auto-resolve/scripts/pair-rejected-fixtures.sh +0 -103
- package/benchmark/auto-resolve/scripts/pair_evidence_contract.py +0 -270
- package/benchmark/auto-resolve/scripts/prepare-swebench-frozen-case.py +0 -273
- package/benchmark/auto-resolve/scripts/prepare-swebench-frozen-corpus.py +0 -148
- package/benchmark/auto-resolve/scripts/prepare-swebench-solver-worktree.py +0 -210
- package/benchmark/auto-resolve/scripts/recent-benchmark-summary.py +0 -232
- package/benchmark/auto-resolve/scripts/run-fixture.sh +0 -1024
- package/benchmark/auto-resolve/scripts/run-frozen-verify-pair.sh +0 -683
- package/benchmark/auto-resolve/scripts/run-full-pipeline-pair-candidate.sh +0 -458
- package/benchmark/auto-resolve/scripts/run-headroom-candidate.sh +0 -336
- package/benchmark/auto-resolve/scripts/run-iter-0033c.sh +0 -208
- package/benchmark/auto-resolve/scripts/run-suite.sh +0 -251
- package/benchmark/auto-resolve/scripts/run-swebench-frozen-corpus.sh +0 -310
- package/benchmark/auto-resolve/scripts/run-swebench-solver-batch.sh +0 -257
- package/benchmark/auto-resolve/scripts/ship-gate.py +0 -391
- package/benchmark/auto-resolve/scripts/solo-ceiling-avoidance.py +0 -53
- package/benchmark/auto-resolve/scripts/solo-headroom-hypothesis.py +0 -77
- package/benchmark/auto-resolve/scripts/swebench-frozen-matrix.py +0 -478
- package/benchmark/auto-resolve/scripts/test-audit-headroom-rejections.sh +0 -288
- package/benchmark/auto-resolve/scripts/test-audit-pair-evidence.sh +0 -1672
- package/benchmark/auto-resolve/scripts/test-benchmark-arg-parsing.sh +0 -1015
- package/benchmark/auto-resolve/scripts/test-build-pair-eligible-manifest.sh +0 -491
- package/benchmark/auto-resolve/scripts/test-check-f9-artifacts.sh +0 -91
- package/benchmark/auto-resolve/scripts/test-frozen-verify-gate.sh +0 -517
- package/benchmark/auto-resolve/scripts/test-full-pipeline-pair-gate.sh +0 -610
- package/benchmark/auto-resolve/scripts/test-headroom-gate.sh +0 -401
- package/benchmark/auto-resolve/scripts/test-iter-0033c-compare.sh +0 -525
- package/benchmark/auto-resolve/scripts/test-iter-0033c-l1-summary.sh +0 -254
- package/benchmark/auto-resolve/scripts/test-lint-fixtures.sh +0 -580
- package/benchmark/auto-resolve/scripts/test-pair-candidate-frontier.sh +0 -591
- package/benchmark/auto-resolve/scripts/test-run-full-pipeline-pair-candidate.sh +0 -497
- package/benchmark/auto-resolve/scripts/test-run-headroom-candidate.sh +0 -401
- package/benchmark/auto-resolve/scripts/test-run-swebench-solver-batch.sh +0 -111
- package/benchmark/auto-resolve/scripts/test-ship-gate.sh +0 -1189
- package/benchmark/auto-resolve/scripts/test-swebench-frozen-case.sh +0 -1221
- package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/NOTES.md +0 -28
- package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/expected.json +0 -63
- package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/metadata.json +0 -10
- package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/setup.sh +0 -3
- package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/spec.md +0 -47
- package/benchmark/auto-resolve/shadow-fixtures/S1-cli-lang-flag/task.txt +0 -1
- package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/NOTES.md +0 -34
- package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/expected.json +0 -53
- package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/metadata.json +0 -10
- package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/setup.sh +0 -3
- package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/spec.md +0 -50
- package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/task.txt +0 -1
- package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/verifiers/duplicate-order-error.js +0 -27
- package/benchmark/auto-resolve/shadow-fixtures/S2-cli-inventory-reservation/verifiers/priority-stock-reservation.js +0 -44
- package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/NOTES.md +0 -34
- package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/expected.json +0 -55
- package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/metadata.json +0 -10
- package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/setup.sh +0 -3
- package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/spec.md +0 -52
- package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/task.txt +0 -1
- package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/verifiers/duplicate-ticket-error.js +0 -29
- package/benchmark/auto-resolve/shadow-fixtures/S3-cli-ticket-assignment/verifiers/priority-agent-assignment.js +0 -48
- package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/NOTES.md +0 -34
- package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/expected.json +0 -55
- package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/metadata.json +0 -10
- package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/setup.sh +0 -3
- package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/spec.md +0 -55
- package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/task.txt +0 -1
- package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/verifiers/duplicate-return-error.js +0 -43
- package/benchmark/auto-resolve/shadow-fixtures/S4-cli-return-routing/verifiers/priority-return-routing.js +0 -70
- package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/NOTES.md +0 -37
- package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/expected.json +0 -54
- package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/metadata.json +0 -10
- package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/setup.sh +0 -3
- package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/spec.md +0 -59
- package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/task.txt +0 -1
- package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/verifiers/credit-ledger-priority.js +0 -98
- package/benchmark/auto-resolve/shadow-fixtures/S5-cli-credit-grant-ledger/verifiers/duplicate-charge-error.js +0 -38
- package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/NOTES.md +0 -36
- package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/expected.json +0 -56
- package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/metadata.json +0 -10
- package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/setup.sh +0 -3
- package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/spec.md +0 -59
- package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/task.txt +0 -1
- package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/verifiers/duplicate-refund-error.js +0 -41
- package/benchmark/auto-resolve/shadow-fixtures/S6-cli-refund-window-ledger/verifiers/priority-refund-ledger.js +0 -65
- package/config/skills/_shared/pair-plan-schema.md +0 -298
- package/scripts/lint-fixtures.sh +0 -352
- package/scripts/lint-shadow-fixtures.sh +0 -58
- package/scripts/lint-skills.sh +0 -4265
- package/scripts/test-owner-phases.py +0 -238
|
@@ -1,683 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""iter-0033c gate table — NEW L2 vs NEW L1 on /devlyn:resolve.
|
|
3
|
-
|
|
4
|
-
Reads:
|
|
5
|
-
- manifest (immutable; built by build-pair-eligible-manifest.py)
|
|
6
|
-
- per-fixture judge.json files under <results-dir>/<fixture>/<arm>/judge.json
|
|
7
|
-
- per-fixture timing/result.json files for wall + disqualifier signals
|
|
8
|
-
- per-fixture pipeline.state.json (under <work-dir>/.devlyn/runs/) for
|
|
9
|
-
pair_judge sub-verdict — required for Gate 6 + Gate 8.
|
|
10
|
-
|
|
11
|
-
Emits:
|
|
12
|
-
- gates.json — machine-readable {gate_id, status, evidence}
|
|
13
|
-
- gates.md — human-readable summary table
|
|
14
|
-
|
|
15
|
-
Gates per iter-0033c §"Acceptance gate":
|
|
16
|
-
1a smoke (mode wiring) — recorded externally; pre-suite gate
|
|
17
|
-
1b smoke (codex avail) — recorded externally; pre-suite gate
|
|
18
|
-
1c smoke (impl confound) — recorded externally; pre-suite gate
|
|
19
|
-
2 no-regression vs L1 (gated arm): every fixture (l2_gated − solo) ≥ −3
|
|
20
|
-
3 lift on pair-eligible (gated arm, SHIP-BLOCKER): on frozen pair-eligible set,
|
|
21
|
-
count fixtures with (l2_gated − solo) ≥ +5; require count ≥ gate3_threshold_count.
|
|
22
|
-
4 hard-floor: zero l2_gated disqualifier on previously-clean l1 fixtures;
|
|
23
|
-
zero l2_gated CRITICAL/HIGH design.* / security.* on previously-clean l1;
|
|
24
|
-
zero l2_gated watchdog timeouts (where l1 didn't time out).
|
|
25
|
-
5 efficiency: per-fixture l2_gated_wall / l1_wall ≤ 2.0× (≤ 3.0× allowed only
|
|
26
|
-
when l2 catches a categorical rescue l1 missed).
|
|
27
|
-
6 trigger discipline (fixture-level): for each pair-eligible fixture, if
|
|
28
|
-
l2_forced lifts ≥ +5 OR catches categorical rescue, AND forced is not
|
|
29
|
-
impl-confounded, AND forced.pair_judge present → l2_gated MUST also have
|
|
30
|
-
recognized pair_judge verdict on that fixture.
|
|
31
|
-
7 attribution (4-class, data-only): per-fixture classify into
|
|
32
|
-
{no_material_lift, implementation_confounded, tool_or_trigger_lift,
|
|
33
|
-
deliberation_lift}. Reporting only; not pass/fail.
|
|
34
|
-
8 artifact contract: recognized pair_judge verdict for every fixture where
|
|
35
|
-
pair fired; pair findings distinguishable from solo judge findings.
|
|
36
|
-
|
|
37
|
-
Ship-blockers: 1a, 1b, 1c, 2, 3, 4, 6.
|
|
38
|
-
Quality gates: 5, 8 (failure → root-cause iter; Phase 4 holds).
|
|
39
|
-
Data-only: 7.
|
|
40
|
-
"""
|
|
41
|
-
import argparse
|
|
42
|
-
import json
|
|
43
|
-
import sys
|
|
44
|
-
from pathlib import Path
|
|
45
|
-
|
|
46
|
-
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
47
|
-
if str(SCRIPT_DIR) not in sys.path:
|
|
48
|
-
sys.path.insert(0, str(SCRIPT_DIR))
|
|
49
|
-
|
|
50
|
-
from pair_evidence_contract import (
|
|
51
|
-
is_score,
|
|
52
|
-
is_strict_number,
|
|
53
|
-
loads_strict_json_object,
|
|
54
|
-
reject_json_constant,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
PAIR_VERDICTS = {"PASS", "PASS_WITH_ISSUES", "NEEDS_WORK", "BLOCKED", "FAIL"}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def exact_bool(value: object) -> bool | None:
|
|
61
|
-
return value if isinstance(value, bool) else None
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def bool_flag(value: object, *, default: bool = False) -> bool:
|
|
65
|
-
if value is None:
|
|
66
|
-
return default
|
|
67
|
-
parsed = exact_bool(value)
|
|
68
|
-
return parsed if parsed is not None else True
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def is_pair_judge_verdict(value: object) -> bool:
|
|
72
|
-
return value in PAIR_VERDICTS
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def load_judge(results_dir: Path, fixture: str) -> dict | None:
|
|
76
|
-
p = results_dir / fixture / "judge.json"
|
|
77
|
-
if not p.is_file():
|
|
78
|
-
return None
|
|
79
|
-
try:
|
|
80
|
-
data = loads_strict_json_object(p.read_text())
|
|
81
|
-
except (ValueError, json.JSONDecodeError):
|
|
82
|
-
return None
|
|
83
|
-
return data
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def load_result(results_dir: Path, fixture: str, arm: str) -> dict | None:
|
|
87
|
-
p = results_dir / fixture / arm / "result.json"
|
|
88
|
-
if not p.is_file():
|
|
89
|
-
return None
|
|
90
|
-
try:
|
|
91
|
-
data = loads_strict_json_object(p.read_text())
|
|
92
|
-
except (ValueError, json.JSONDecodeError):
|
|
93
|
-
return None
|
|
94
|
-
return data
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def load_state(work_dir_root: Path, run_id: str, fixture: str, arm: str) -> dict | None:
|
|
98
|
-
"""state.json lives in /tmp/bench-{run_id}-{fixture}-{arm}/.devlyn/runs/<rs-id>/."""
|
|
99
|
-
work = work_dir_root / f"bench-{run_id}-{fixture}-{arm}"
|
|
100
|
-
runs = work / ".devlyn" / "runs"
|
|
101
|
-
if not runs.is_dir():
|
|
102
|
-
return None
|
|
103
|
-
candidates = sorted(runs.glob("*/pipeline.state.json"))
|
|
104
|
-
if not candidates:
|
|
105
|
-
return None
|
|
106
|
-
try:
|
|
107
|
-
data = loads_strict_json_object(candidates[-1].read_text())
|
|
108
|
-
except (ValueError, json.JSONDecodeError):
|
|
109
|
-
return None
|
|
110
|
-
return data
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def archive_run_dir(work_dir_root: Path, run_id: str, fixture: str, arm: str) -> Path | None:
|
|
114
|
-
"""The .devlyn/runs/<rs-id>/ where pipeline archived per-run artifacts."""
|
|
115
|
-
work = work_dir_root / f"bench-{run_id}-{fixture}-{arm}"
|
|
116
|
-
runs = work / ".devlyn" / "runs"
|
|
117
|
-
if not runs.is_dir():
|
|
118
|
-
return None
|
|
119
|
-
cands = sorted(runs.glob("*/pipeline.state.json"))
|
|
120
|
-
if not cands:
|
|
121
|
-
return None
|
|
122
|
-
return cands[-1].parent
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def changed_files(results_dir: Path, fixture: str, arm: str) -> set[str]:
|
|
126
|
-
"""Read changed-files.txt for an arm; returns set of file paths."""
|
|
127
|
-
p = results_dir / fixture / arm / "changed-files.txt"
|
|
128
|
-
if not p.is_file():
|
|
129
|
-
return set()
|
|
130
|
-
return {ln.strip() for ln in p.read_text().splitlines() if ln.strip()}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def pair_findings_distinguishable(work_dir_root: Path, run_id: str, fixture: str, arm: str) -> bool:
|
|
134
|
-
"""True iff archive has at least one per-engine pair-judge artifact for >=2 engines.
|
|
135
|
-
|
|
136
|
-
Gate 8: pair findings must be distinguishable from solo judge findings. The
|
|
137
|
-
orchestrator (Claude reading SKILL.md) was observed across smokes 1a + 1c
|
|
138
|
-
(fixed-diff) writing per-judge artifacts under several naming conventions:
|
|
139
|
-
|
|
140
|
-
* `verify-judge-<engine>.md` (smoke 1a, full pair mode)
|
|
141
|
-
* `verify.judge.<engine>.findings.jsonl` (smoke 1c, verify-only pair mode)
|
|
142
|
-
* `verify.judge.<engine>.summary.json` (verify-only mode auxiliary)
|
|
143
|
-
|
|
144
|
-
Detection treats "two distinct engine identifiers across any of those patterns"
|
|
145
|
-
as distinguishable. archive_run.py moves both `verify-judge-*.md` (added in
|
|
146
|
-
iter-0033c) and any `*.findings.jsonl` (existing pre-iter-0033c) so both
|
|
147
|
-
conventions land in the run dir. Either missing distinct engines = broken.
|
|
148
|
-
"""
|
|
149
|
-
archive = archive_run_dir(work_dir_root, run_id, fixture, arm)
|
|
150
|
-
if archive is None:
|
|
151
|
-
return False
|
|
152
|
-
import re
|
|
153
|
-
# Collect engine identifiers across all observed pair-judge naming patterns.
|
|
154
|
-
patterns = [
|
|
155
|
-
re.compile(r"^verify-judge-(?P<engine>[a-z0-9_]+)\.md$"),
|
|
156
|
-
re.compile(r"^verify\.judge\.(?P<engine>[a-z0-9_]+)\.findings\.jsonl$"),
|
|
157
|
-
re.compile(r"^verify\.judge\.(?P<engine>[a-z0-9_]+)\.summary\.json$"),
|
|
158
|
-
]
|
|
159
|
-
engines = set()
|
|
160
|
-
for f in archive.iterdir():
|
|
161
|
-
if not f.is_file():
|
|
162
|
-
continue
|
|
163
|
-
for pat in patterns:
|
|
164
|
-
m = pat.match(f.name)
|
|
165
|
-
if m:
|
|
166
|
-
engines.add(m.group("engine"))
|
|
167
|
-
break
|
|
168
|
-
return len(engines) >= 2
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def impl_confounded_for_fixture(results_dir: Path, fixture: str) -> bool:
|
|
172
|
-
"""True iff symmetric difference of changed-files between solo_claude and
|
|
173
|
-
l2_forced is non-empty. Drives Gate 7 attribution + Gate 3 carve-out
|
|
174
|
-
decision per Codex R-final-smoke Q5 (option (b): fixed-diff for confounded
|
|
175
|
-
fixtures only, NOT a wholesale pivot).
|
|
176
|
-
|
|
177
|
-
Smoke 1c (2026-05-02) confirmed F2 confounds (solo touched 1 file, l2_forced
|
|
178
|
-
touched 2 — l2_forced added a test file solo skipped) while F3 does not
|
|
179
|
-
(both arms touched the same 2 files).
|
|
180
|
-
"""
|
|
181
|
-
solo = changed_files(results_dir, fixture, "solo_claude")
|
|
182
|
-
forced = changed_files(results_dir, fixture, "l2_forced")
|
|
183
|
-
if not solo or not forced:
|
|
184
|
-
return False # arm absent → can't claim confound
|
|
185
|
-
return solo.symmetric_difference(forced) != set()
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def fixture_short(name: str) -> str:
|
|
189
|
-
return name.split("-", 1)[0] if "-" in name else name
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def find_results_dir_fixtures(results_dir: Path) -> list[str]:
|
|
193
|
-
return sorted(d.name for d in results_dir.iterdir() if d.is_dir())
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def get_score(judge: dict, arm: str) -> int | None:
|
|
197
|
-
"""Score for a given arm, only when the arm is present in `_blind_mapping`.
|
|
198
|
-
|
|
199
|
-
`scores_by_arm` is accepted only as a decoded view of the blind A/B/C slots;
|
|
200
|
-
a score for an arm absent from the blind mapping is not score evidence.
|
|
201
|
-
"""
|
|
202
|
-
if not judge:
|
|
203
|
-
return None
|
|
204
|
-
raw_mapping = judge.get("_blind_mapping")
|
|
205
|
-
mapping = raw_mapping if isinstance(raw_mapping, dict) else {}
|
|
206
|
-
letter = next((k for k, v in mapping.items() if v == arm), None)
|
|
207
|
-
if not letter:
|
|
208
|
-
return None
|
|
209
|
-
raw_scores = judge.get("scores_by_arm")
|
|
210
|
-
sba = raw_scores if isinstance(raw_scores, dict) else {}
|
|
211
|
-
if is_score(sba.get(arm)):
|
|
212
|
-
return sba[arm]
|
|
213
|
-
legacy = judge.get(f"{letter.lower()}_score")
|
|
214
|
-
return legacy if is_score(legacy) else None
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def get_disqualifier(judge: dict, arm: str) -> bool:
|
|
218
|
-
"""DQ flag for a given arm. Prefer `disqualifiers_by_arm` written by judge.sh
|
|
219
|
-
line 314-323; fall back to blind A/B/C with case-correct letter."""
|
|
220
|
-
if not judge:
|
|
221
|
-
return False
|
|
222
|
-
raw_mapping = judge.get("_blind_mapping")
|
|
223
|
-
mapping = raw_mapping if isinstance(raw_mapping, dict) else {}
|
|
224
|
-
letter = next((k for k, v in mapping.items() if v == arm), None)
|
|
225
|
-
if not letter:
|
|
226
|
-
raw_scores = judge.get("scores_by_arm")
|
|
227
|
-
sba = raw_scores if isinstance(raw_scores, dict) else {}
|
|
228
|
-
raw_dba = judge.get("disqualifiers_by_arm")
|
|
229
|
-
if raw_dba is not None and not isinstance(raw_dba, dict):
|
|
230
|
-
return True
|
|
231
|
-
dba = raw_dba if isinstance(raw_dba, dict) else {}
|
|
232
|
-
return arm in sba or arm in dba
|
|
233
|
-
raw_dba = judge.get("disqualifiers_by_arm")
|
|
234
|
-
if raw_dba is not None and not isinstance(raw_dba, dict):
|
|
235
|
-
return True
|
|
236
|
-
dba = raw_dba if isinstance(raw_dba, dict) else {}
|
|
237
|
-
if arm in dba:
|
|
238
|
-
entry = dba[arm]
|
|
239
|
-
return bool_flag(
|
|
240
|
-
entry.get("disqualifier") if isinstance(entry, dict) else entry
|
|
241
|
-
)
|
|
242
|
-
raw_dqs = judge.get("disqualifiers")
|
|
243
|
-
if raw_dqs is not None and not isinstance(raw_dqs, dict):
|
|
244
|
-
return True
|
|
245
|
-
dqs = raw_dqs if isinstance(raw_dqs, dict) else {}
|
|
246
|
-
return bool_flag(dqs.get(letter))
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
def gate_2_no_regression(rows: list[dict]) -> dict:
|
|
250
|
-
failures = []
|
|
251
|
-
for row in rows:
|
|
252
|
-
if row["solo_score"] is None or row["l2_gated_score"] is None:
|
|
253
|
-
continue
|
|
254
|
-
delta = row["l2_gated_score"] - row["solo_score"]
|
|
255
|
-
if delta < -3:
|
|
256
|
-
failures.append({"fixture": row["fixture"], "delta": delta})
|
|
257
|
-
return {
|
|
258
|
-
"gate": "2-no-regression",
|
|
259
|
-
"status": "PASS" if not failures else "FAIL",
|
|
260
|
-
"rule": "every fixture: (l2_gated − solo) ≥ −3",
|
|
261
|
-
"failures": failures,
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
def gate_3_lift(rows: list[dict], manifest: dict) -> dict:
|
|
266
|
-
eligible = set(manifest["fixtures_pair_eligible"])
|
|
267
|
-
threshold = manifest["gate3_threshold_count"]
|
|
268
|
-
total = manifest["gate3_total"]
|
|
269
|
-
counted = []
|
|
270
|
-
for row in rows:
|
|
271
|
-
fx = fixture_short(row["fixture"])
|
|
272
|
-
if fx not in eligible:
|
|
273
|
-
continue
|
|
274
|
-
if row["solo_score"] is None or row["l2_gated_score"] is None:
|
|
275
|
-
continue
|
|
276
|
-
delta = row["l2_gated_score"] - row["solo_score"]
|
|
277
|
-
counted.append({"fixture": row["fixture"], "delta": delta, "lift_ge5": delta >= 5})
|
|
278
|
-
n_lift = sum(1 for c in counted if c["lift_ge5"])
|
|
279
|
-
return {
|
|
280
|
-
"gate": "3-lift-on-pair-eligible",
|
|
281
|
-
"ship_blocker": True,
|
|
282
|
-
"status": "PASS" if n_lift >= threshold else "FAIL",
|
|
283
|
-
"rule": f"lift ≥ +5 on ≥ {threshold} of {total} pair-eligible fixtures",
|
|
284
|
-
"lift_count": n_lift,
|
|
285
|
-
"threshold": threshold,
|
|
286
|
-
"total": total,
|
|
287
|
-
"details": counted,
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
def classify_l2_disqualifier(row: dict, mechanical_findings: list[dict]) -> str:
|
|
292
|
-
"""Bucket why L2 disqualified a previously-clean L1 fixture (Codex R-final-fdfd Q2).
|
|
293
|
-
|
|
294
|
-
Buckets:
|
|
295
|
-
- `mechanical_failed`: deterministic spec-verify gate ALSO flagged a
|
|
296
|
-
disqualifier-class finding → real product defect → Gate 4 FAIL.
|
|
297
|
-
- `target_env_reproduced`: pair-JUDGE finding manually reproduced in the
|
|
298
|
-
target env (post-suite human adjudication). Gate 4 FAIL.
|
|
299
|
-
- `pair_sandbox_only`: pair-JUDGE surfaced a CRITICAL/HIGH finding that
|
|
300
|
-
mechanical did NOT trigger. Could be valid-but-environment-conditional
|
|
301
|
-
(e.g. EPERM handling on systems where ~/.claude is unreadable); Codex's
|
|
302
|
-
smoke 1c-fixed on F2 was textbook of this. Logged as Gate 7 evidence,
|
|
303
|
-
NOT Gate 4 FAIL.
|
|
304
|
-
|
|
305
|
-
Default classification = `pair_sandbox_only` when mechanical didn't fail.
|
|
306
|
-
`target_env_reproduced` requires post-hoc manual override (no auto-reproducer).
|
|
307
|
-
"""
|
|
308
|
-
has_mechanical_dq = any(
|
|
309
|
-
(f.get("severity") in ("CRITICAL", "HIGH")
|
|
310
|
-
and f.get("source") in ("mechanical", "spec-verify"))
|
|
311
|
-
or f.get("disqualifier") is True
|
|
312
|
-
for f in mechanical_findings
|
|
313
|
-
)
|
|
314
|
-
if has_mechanical_dq:
|
|
315
|
-
return "mechanical_failed"
|
|
316
|
-
return "pair_sandbox_only"
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
def load_mechanical_findings(work_dir_root: Path, run_id: str, fixture: str, arm: str) -> list[dict]:
|
|
320
|
-
archive = archive_run_dir(work_dir_root, run_id, fixture, arm)
|
|
321
|
-
if archive is None:
|
|
322
|
-
return []
|
|
323
|
-
p = archive / "verify-mechanical.findings.jsonl"
|
|
324
|
-
if not p.is_file():
|
|
325
|
-
return []
|
|
326
|
-
out = []
|
|
327
|
-
for ln in p.read_text().splitlines():
|
|
328
|
-
ln = ln.strip()
|
|
329
|
-
if not ln:
|
|
330
|
-
continue
|
|
331
|
-
try:
|
|
332
|
-
parsed = json.loads(ln, parse_constant=reject_json_constant)
|
|
333
|
-
except json.JSONDecodeError:
|
|
334
|
-
continue
|
|
335
|
-
if isinstance(parsed, dict):
|
|
336
|
-
out.append(parsed)
|
|
337
|
-
return out
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
def gate_4_hard_floor(rows: list[dict], work_dir_root: Path, run_id: str) -> dict:
|
|
341
|
-
failures = []
|
|
342
|
-
sandbox_only = []
|
|
343
|
-
for row in rows:
|
|
344
|
-
if row["solo_dq"]:
|
|
345
|
-
continue
|
|
346
|
-
if row["l2_gated_dq"]:
|
|
347
|
-
mech = load_mechanical_findings(work_dir_root, run_id, row["fixture"], "l2_gated")
|
|
348
|
-
classification = classify_l2_disqualifier(row, mech)
|
|
349
|
-
entry = {"fixture": row["fixture"], "kind": "l2_gated_dq_on_clean_l1",
|
|
350
|
-
"classification": classification}
|
|
351
|
-
if classification in ("mechanical_failed", "target_env_reproduced"):
|
|
352
|
-
failures.append(entry)
|
|
353
|
-
else:
|
|
354
|
-
sandbox_only.append(entry)
|
|
355
|
-
if row["l2_gated_timeout"] and not row["solo_timeout"]:
|
|
356
|
-
failures.append({"fixture": row["fixture"], "kind": "l2_gated_timeout_only",
|
|
357
|
-
"classification": "timeout"})
|
|
358
|
-
return {
|
|
359
|
-
"gate": "4-hard-floor",
|
|
360
|
-
"ship_blocker": True,
|
|
361
|
-
"status": "PASS" if not failures else "FAIL",
|
|
362
|
-
"rule": ("zero l2_gated dq / timeout on previously-clean l1 fixtures, "
|
|
363
|
-
"where dq is classified as mechanical_failed OR target_env_reproduced "
|
|
364
|
-
"(pair_sandbox_only logged as Gate 7 evidence per Codex R-final-fdfd Q2)"),
|
|
365
|
-
"failures": failures,
|
|
366
|
-
"pair_sandbox_only_logged": sandbox_only,
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
def gate_5_efficiency(rows: list[dict]) -> dict:
|
|
371
|
-
failures = []
|
|
372
|
-
details = []
|
|
373
|
-
for row in rows:
|
|
374
|
-
if row["solo_wall"] is None or row["l2_gated_wall"] is None:
|
|
375
|
-
continue
|
|
376
|
-
if row["solo_wall"] == 0:
|
|
377
|
-
continue
|
|
378
|
-
ratio = row["l2_gated_wall"] / row["solo_wall"]
|
|
379
|
-
details.append({"fixture": row["fixture"], "ratio": round(ratio, 2)})
|
|
380
|
-
if ratio > 2.0:
|
|
381
|
-
failures.append({"fixture": row["fixture"], "ratio": round(ratio, 2)})
|
|
382
|
-
return {
|
|
383
|
-
"gate": "5-efficiency",
|
|
384
|
-
"status": "PASS" if not failures else "FAIL",
|
|
385
|
-
"rule": "per-fixture l2_gated_wall / l1_wall ≤ 2.0×",
|
|
386
|
-
"failures": failures,
|
|
387
|
-
"details": details,
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
def gate_6_trigger_discipline(rows: list[dict], manifest: dict) -> dict:
|
|
392
|
-
eligible = set(manifest["fixtures_pair_eligible"])
|
|
393
|
-
failures = []
|
|
394
|
-
for row in rows:
|
|
395
|
-
fx = fixture_short(row["fixture"])
|
|
396
|
-
if fx not in eligible:
|
|
397
|
-
continue
|
|
398
|
-
if row["l2_forced_score"] is None:
|
|
399
|
-
continue
|
|
400
|
-
forced_lift = (
|
|
401
|
-
row["l2_forced_score"] is not None and row["solo_score"] is not None
|
|
402
|
-
and (row["l2_forced_score"] - row["solo_score"] >= 5)
|
|
403
|
-
)
|
|
404
|
-
forced_rescue = bool(row["solo_dq"] and not row["l2_forced_dq"])
|
|
405
|
-
forced_pair_present = bool(row["l2_forced_pair_judge_present"])
|
|
406
|
-
gated_pair_present = bool(row["l2_gated_pair_judge_present"])
|
|
407
|
-
if (forced_lift or forced_rescue) and forced_pair_present and not gated_pair_present:
|
|
408
|
-
failures.append({
|
|
409
|
-
"fixture": row["fixture"],
|
|
410
|
-
"forced_lift": forced_lift,
|
|
411
|
-
"forced_rescue": forced_rescue,
|
|
412
|
-
"gated_pair_judge_present": gated_pair_present,
|
|
413
|
-
})
|
|
414
|
-
return {
|
|
415
|
-
"gate": "6-trigger-discipline",
|
|
416
|
-
"ship_blocker": True,
|
|
417
|
-
"status": "PASS" if not failures else "FAIL",
|
|
418
|
-
"rule": "if forced lifts ≥ +5 (or rescues) → gated must also fire pair on that fixture",
|
|
419
|
-
"failures": failures,
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
def gate_7_attribution(rows: list[dict], manifest: dict) -> dict:
|
|
424
|
-
"""4-class classification per fixture; data-gathering only.
|
|
425
|
-
|
|
426
|
-
no_material_lift — solo and l2 verdicts equivalent within ±2
|
|
427
|
-
implementation_confounded — IMPLEMENT diffs differ materially (smoke 1c flagged)
|
|
428
|
-
tool_or_trigger_lift — mechanical/coverage finding caused axis change
|
|
429
|
-
deliberation_lift — pair_judge surfaces verdict-binding finding absent from solo
|
|
430
|
-
"""
|
|
431
|
-
classes = []
|
|
432
|
-
for row in rows:
|
|
433
|
-
fx = fixture_short(row["fixture"])
|
|
434
|
-
cls = "no_material_lift" # default
|
|
435
|
-
if row["impl_confounded"]:
|
|
436
|
-
cls = "implementation_confounded"
|
|
437
|
-
elif row["solo_score"] is not None and row["l2_gated_score"] is not None:
|
|
438
|
-
delta = row["l2_gated_score"] - row["solo_score"]
|
|
439
|
-
if abs(delta) <= 2:
|
|
440
|
-
cls = "no_material_lift"
|
|
441
|
-
elif row["pair_judge_unique_finding"]:
|
|
442
|
-
cls = "deliberation_lift"
|
|
443
|
-
elif row["mechanical_finding_drove_change"]:
|
|
444
|
-
cls = "tool_or_trigger_lift"
|
|
445
|
-
else:
|
|
446
|
-
cls = "deliberation_lift" if delta >= 5 else "no_material_lift"
|
|
447
|
-
classes.append({"fixture": row["fixture"], "class": cls,
|
|
448
|
-
"pair_eligible": fx in set(manifest["fixtures_pair_eligible"])})
|
|
449
|
-
return {
|
|
450
|
-
"gate": "7-attribution",
|
|
451
|
-
"data_only": True,
|
|
452
|
-
"status": "DATA",
|
|
453
|
-
"classes": classes,
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
def gate_8_artifact_contract(rows: list[dict]) -> dict:
|
|
458
|
-
failures = []
|
|
459
|
-
for row in rows:
|
|
460
|
-
# If pair fired (forced arm has pair_judge present) but artifact missing
|
|
461
|
-
if row["pair_fired"] and not row["pair_findings_distinguishable"]:
|
|
462
|
-
failures.append({"fixture": row["fixture"],
|
|
463
|
-
"missing": "pair_judge_findings_distinguishable"})
|
|
464
|
-
return {
|
|
465
|
-
"gate": "8-artifact-contract",
|
|
466
|
-
"status": "PASS" if not failures else "FAIL",
|
|
467
|
-
"rule": "recognized pair_judge verdict when fired; pair findings distinguishable from solo",
|
|
468
|
-
"failures": failures,
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
def build_rows(results_dir: Path, work_dir_root: Path, run_id: str) -> list[dict]:
|
|
473
|
-
fixtures = find_results_dir_fixtures(results_dir)
|
|
474
|
-
rows = []
|
|
475
|
-
for fx in fixtures:
|
|
476
|
-
judge = load_judge(results_dir, fx)
|
|
477
|
-
solo_r = load_result(results_dir, fx, "solo_claude")
|
|
478
|
-
gated_r = load_result(results_dir, fx, "l2_gated")
|
|
479
|
-
forced_r = load_result(results_dir, fx, "l2_forced")
|
|
480
|
-
gated_state = load_state(work_dir_root, run_id, fx, "l2_gated")
|
|
481
|
-
forced_state = load_state(work_dir_root, run_id, fx, "l2_forced")
|
|
482
|
-
|
|
483
|
-
def pair_judge_present(state: dict | None) -> bool:
|
|
484
|
-
if not isinstance(state, dict):
|
|
485
|
-
return False
|
|
486
|
-
phases = state.get("phases")
|
|
487
|
-
if not isinstance(phases, dict):
|
|
488
|
-
return False
|
|
489
|
-
verify = phases.get("verify")
|
|
490
|
-
if not isinstance(verify, dict):
|
|
491
|
-
return False
|
|
492
|
-
sub = verify.get("sub_verdicts")
|
|
493
|
-
if not isinstance(sub, dict):
|
|
494
|
-
return False
|
|
495
|
-
return is_pair_judge_verdict(sub.get("pair_judge"))
|
|
496
|
-
|
|
497
|
-
# Pair findings distinguishability — checked from archive of whichever
|
|
498
|
-
# arm fired pair-mode. l2_forced always fires (when present); l2_gated
|
|
499
|
-
# only on natural triggers. Use l2_forced as the audit anchor when
|
|
500
|
-
# available; fall back to l2_gated.
|
|
501
|
-
pair_anchor_arm = "l2_forced" if forced_state else (
|
|
502
|
-
"l2_gated" if gated_state else None
|
|
503
|
-
)
|
|
504
|
-
pair_findings_ok = (
|
|
505
|
-
pair_findings_distinguishable(work_dir_root, run_id, fx, pair_anchor_arm)
|
|
506
|
-
if pair_anchor_arm else False
|
|
507
|
-
)
|
|
508
|
-
rows.append({
|
|
509
|
-
"fixture": fx,
|
|
510
|
-
"solo_score": get_score(judge, "solo_claude"),
|
|
511
|
-
"l2_gated_score": get_score(judge, "l2_gated"),
|
|
512
|
-
"l2_forced_score": get_score(judge, "l2_forced"),
|
|
513
|
-
"solo_dq": get_disqualifier(judge, "solo_claude"),
|
|
514
|
-
"l2_gated_dq": get_disqualifier(judge, "l2_gated"),
|
|
515
|
-
"l2_forced_dq": get_disqualifier(judge, "l2_forced"),
|
|
516
|
-
"solo_wall": strict_elapsed_seconds(solo_r),
|
|
517
|
-
"l2_gated_wall": strict_elapsed_seconds(gated_r),
|
|
518
|
-
"solo_timeout": timeout_flag(solo_r),
|
|
519
|
-
"l2_gated_timeout": timeout_flag(gated_r),
|
|
520
|
-
"l2_gated_pair_judge_present": pair_judge_present(gated_state),
|
|
521
|
-
"l2_forced_pair_judge_present": pair_judge_present(forced_state),
|
|
522
|
-
"pair_fired": pair_judge_present(gated_state) or pair_judge_present(forced_state),
|
|
523
|
-
"pair_findings_distinguishable": pair_findings_ok,
|
|
524
|
-
"impl_confounded": impl_confounded_for_fixture(results_dir, fx),
|
|
525
|
-
# Below remain conservative defaults — populating them needs cross-
|
|
526
|
-
# finding diffs (verify.findings.jsonl from each pair-judge file)
|
|
527
|
-
# that are out of scope for this iter's compare script. Recorded
|
|
528
|
-
# as TODO for follow-up; iter-0033c attribution downgrades fixtures
|
|
529
|
-
# with these defaults to no_material_lift unless the score delta
|
|
530
|
-
# itself is ≥+5 (then deliberation_lift), so the conservative
|
|
531
|
-
# default never inflates the count.
|
|
532
|
-
"pair_judge_unique_finding": False,
|
|
533
|
-
"mechanical_finding_drove_change": False,
|
|
534
|
-
})
|
|
535
|
-
return rows
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
def strict_elapsed_seconds(result: dict | None) -> float | int | None:
|
|
539
|
-
if not result:
|
|
540
|
-
return None
|
|
541
|
-
value = result.get("elapsed_seconds")
|
|
542
|
-
return value if is_strict_number(value) else None
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
def timeout_flag(result: dict | None) -> bool:
|
|
546
|
-
if not result:
|
|
547
|
-
return False
|
|
548
|
-
return bool_flag(result.get("timed_out"))
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
def validate_manifest(manifest: object) -> tuple[dict | None, str | None]:
|
|
552
|
-
if not isinstance(manifest, dict):
|
|
553
|
-
return None, "manifest malformed: expected object"
|
|
554
|
-
raw_eligible = manifest.get("fixtures_pair_eligible")
|
|
555
|
-
if not isinstance(raw_eligible, list) or not all(isinstance(fx, str) for fx in raw_eligible):
|
|
556
|
-
return None, "manifest malformed: fixtures_pair_eligible must be a string array"
|
|
557
|
-
if not raw_eligible:
|
|
558
|
-
return None, "manifest malformed: fixtures_pair_eligible must not be empty"
|
|
559
|
-
threshold = manifest.get("gate3_threshold_count")
|
|
560
|
-
total = manifest.get("gate3_total")
|
|
561
|
-
if not isinstance(threshold, int) or isinstance(threshold, bool) or threshold <= 0:
|
|
562
|
-
return None, "manifest malformed: gate3_threshold_count must be a positive integer"
|
|
563
|
-
if not isinstance(total, int) or isinstance(total, bool) or total <= 0:
|
|
564
|
-
return None, "manifest malformed: gate3_total must be a positive integer"
|
|
565
|
-
if total != len(raw_eligible):
|
|
566
|
-
return None, "manifest malformed: gate3_total must equal fixtures_pair_eligible length"
|
|
567
|
-
if threshold > total:
|
|
568
|
-
return None, "manifest malformed: gate3_threshold_count must be <= gate3_total"
|
|
569
|
-
rule = manifest.get("selection_rule")
|
|
570
|
-
if rule is not None:
|
|
571
|
-
if not isinstance(rule, dict):
|
|
572
|
-
return None, "manifest malformed: selection_rule must be an object"
|
|
573
|
-
rejected = rule.get("rejected_excluded")
|
|
574
|
-
reasons = rule.get("rejected_excluded_reasons")
|
|
575
|
-
if rejected is not None:
|
|
576
|
-
if not isinstance(rejected, list) or not all(isinstance(fx, str) for fx in rejected):
|
|
577
|
-
return None, "manifest malformed: selection_rule.rejected_excluded must be a string array"
|
|
578
|
-
if reasons is not None:
|
|
579
|
-
if (
|
|
580
|
-
not isinstance(reasons, dict)
|
|
581
|
-
or not all(isinstance(fx, str) and isinstance(reason, str) and reason for fx, reason in reasons.items())
|
|
582
|
-
):
|
|
583
|
-
return None, "manifest malformed: selection_rule.rejected_excluded_reasons must map fixture ids to non-empty strings"
|
|
584
|
-
if rejected is not None and set(reasons) != set(rejected):
|
|
585
|
-
return None, "manifest malformed: selection_rule.rejected_excluded_reasons keys must match rejected_excluded"
|
|
586
|
-
return manifest, None
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
def render_markdown(gates: list[dict], rows: list[dict]) -> str:
|
|
590
|
-
lines = ["# iter-0033c gate table\n"]
|
|
591
|
-
lines.append("| fixture | solo | l2_gated | Δ | l2_forced | l2g pair? | l2f pair? | wall_ratio |")
|
|
592
|
-
lines.append("|---|---|---|---|---|---|---|---|")
|
|
593
|
-
for r in rows:
|
|
594
|
-
delta = (
|
|
595
|
-
r["l2_gated_score"] - r["solo_score"]
|
|
596
|
-
if r["l2_gated_score"] is not None and r["solo_score"] is not None
|
|
597
|
-
else None
|
|
598
|
-
)
|
|
599
|
-
ratio = (
|
|
600
|
-
round(r["l2_gated_wall"] / r["solo_wall"], 2)
|
|
601
|
-
if r["l2_gated_wall"] is not None and r["solo_wall"]
|
|
602
|
-
else None
|
|
603
|
-
)
|
|
604
|
-
lines.append(
|
|
605
|
-
f"| {r['fixture']} | {r['solo_score']} | {r['l2_gated_score']} | "
|
|
606
|
-
f"{('+' if delta and delta > 0 else '') + str(delta) if delta is not None else '-'} | "
|
|
607
|
-
f"{r['l2_forced_score']} | "
|
|
608
|
-
f"{'✓' if r['l2_gated_pair_judge_present'] else '✗'} | "
|
|
609
|
-
f"{'✓' if r['l2_forced_pair_judge_present'] else '✗'} | "
|
|
610
|
-
f"{ratio if ratio is not None else '-'} |"
|
|
611
|
-
)
|
|
612
|
-
lines.append("\n## Gates\n")
|
|
613
|
-
for g in gates:
|
|
614
|
-
ship = " (SHIP-BLOCKER)" if g.get("ship_blocker") else ""
|
|
615
|
-
lines.append(f"- **{g['gate']}{ship}**: {g['status']} — {g.get('rule', '')}")
|
|
616
|
-
if g.get("failures"):
|
|
617
|
-
for f in g["failures"]:
|
|
618
|
-
lines.append(f" - FAIL: {f}")
|
|
619
|
-
return "\n".join(lines) + "\n"
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
def main() -> int:
|
|
623
|
-
ap = argparse.ArgumentParser()
|
|
624
|
-
ap.add_argument("--manifest", required=True)
|
|
625
|
-
ap.add_argument("--results-dir", required=True)
|
|
626
|
-
ap.add_argument("--work-dir-root", default="/tmp",
|
|
627
|
-
help="parent dir of bench-* WORK_DIRs (default: /tmp)")
|
|
628
|
-
ap.add_argument("--run-id", required=True,
|
|
629
|
-
help="benchmark run id used by run-fixture.sh (matches WORK_DIR prefix)")
|
|
630
|
-
ap.add_argument("--out-json", required=True)
|
|
631
|
-
ap.add_argument("--out-md", required=True)
|
|
632
|
-
args = ap.parse_args()
|
|
633
|
-
|
|
634
|
-
try:
|
|
635
|
-
raw_manifest = json.loads(
|
|
636
|
-
Path(args.manifest).read_text(),
|
|
637
|
-
parse_constant=reject_json_constant,
|
|
638
|
-
)
|
|
639
|
-
except (ValueError, json.JSONDecodeError) as exc:
|
|
640
|
-
print(f"error: manifest malformed: invalid JSON: {exc}", file=sys.stderr)
|
|
641
|
-
return 2
|
|
642
|
-
manifest, manifest_error = validate_manifest(raw_manifest)
|
|
643
|
-
if manifest is None:
|
|
644
|
-
print(f"error: {manifest_error}", file=sys.stderr)
|
|
645
|
-
return 2
|
|
646
|
-
rows = build_rows(Path(args.results_dir), Path(args.work_dir_root), args.run_id)
|
|
647
|
-
|
|
648
|
-
gates = [
|
|
649
|
-
gate_2_no_regression(rows),
|
|
650
|
-
gate_3_lift(rows, manifest),
|
|
651
|
-
gate_4_hard_floor(rows, Path(args.work_dir_root), args.run_id),
|
|
652
|
-
gate_5_efficiency(rows),
|
|
653
|
-
gate_6_trigger_discipline(rows, manifest),
|
|
654
|
-
gate_7_attribution(rows, manifest),
|
|
655
|
-
gate_8_artifact_contract(rows),
|
|
656
|
-
]
|
|
657
|
-
|
|
658
|
-
out = {
|
|
659
|
-
"iter": "0033c",
|
|
660
|
-
"manifest_sha256": manifest["manifest_sha256"],
|
|
661
|
-
"manifest_head": manifest.get("head"),
|
|
662
|
-
"rows": rows,
|
|
663
|
-
"gates": gates,
|
|
664
|
-
"ship_blockers_failed": [g["gate"] for g in gates
|
|
665
|
-
if g.get("ship_blocker") and g["status"] == "FAIL"],
|
|
666
|
-
"quality_gates_failed": [g["gate"] for g in gates
|
|
667
|
-
if not g.get("ship_blocker") and g["status"] == "FAIL"],
|
|
668
|
-
}
|
|
669
|
-
Path(args.out_json).write_text(json.dumps(out, indent=2) + "\n")
|
|
670
|
-
Path(args.out_md).write_text(render_markdown(gates, rows))
|
|
671
|
-
|
|
672
|
-
print(f"[compare] gates -> {args.out_json}")
|
|
673
|
-
print(f"[compare] markdown -> {args.out_md}")
|
|
674
|
-
failed = out["ship_blockers_failed"]
|
|
675
|
-
if failed:
|
|
676
|
-
print(f"[compare] SHIP-BLOCKER FAIL: {failed}")
|
|
677
|
-
return 1
|
|
678
|
-
print("[compare] all ship-blockers PASS")
|
|
679
|
-
return 0
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
if __name__ == "__main__":
|
|
683
|
-
sys.exit(main())
|