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.
- package/AGENTS.md +2 -2
- package/CLAUDE.md +2 -2
- package/README.md +22 -113
- package/bin/devlyn.js +13 -225
- package/bin/instruction-templates.json +752 -1
- package/bin/instructions.js +101 -17
- 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 +371 -30
- 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 -193
|
@@ -39,6 +39,7 @@ import sys
|
|
|
39
39
|
import tempfile
|
|
40
40
|
|
|
41
41
|
VALID_VERDICTS = {"PASS", "PASS_WITH_ISSUES", "FAIL", "NEEDS_WORK", "BLOCKED"}
|
|
42
|
+
FINAL_VERDICTS = {"PASS", "PASS_WITH_ISSUES", "NEEDS_WORK", "BLOCKED"}
|
|
42
43
|
VALID_TRIGGERS = {"build_gate", "cleanup", "verify"}
|
|
43
44
|
SPAWN_TRIGGERS = VALID_TRIGGERS | {"plan"}
|
|
44
45
|
PHASE_NAMES = {"plan", "probe_derive", "implement", "surface_close", "build_gate", "cleanup", "verify", "final_report"}
|
|
@@ -1682,8 +1683,109 @@ def freeze_roles(state: dict, work: pathlib.Path, default_engine: str) -> dict:
|
|
|
1682
1683
|
return resolved
|
|
1683
1684
|
|
|
1684
1685
|
|
|
1686
|
+
REPAIR_PHASES = ("implement", "build_gate", "cleanup", "verify")
|
|
1687
|
+
|
|
1688
|
+
|
|
1689
|
+
def valid_phase_gate_progress(progress: object) -> bool:
|
|
1690
|
+
if not isinstance(progress, dict):
|
|
1691
|
+
return False
|
|
1692
|
+
total, current, statuses = progress.get("total"), progress.get("current"), progress.get("statuses")
|
|
1693
|
+
return (type(total) is int and total > 1 and type(current) is int and 1 <= current <= total
|
|
1694
|
+
and isinstance(statuses, list) and len(statuses) == total
|
|
1695
|
+
and all(status in ("PASS", "FAIL", None) for status in statuses)
|
|
1696
|
+
and all(status == "PASS" for status in statuses[:current - 1]))
|
|
1697
|
+
|
|
1698
|
+
|
|
1699
|
+
def repair_predecessor(state: dict) -> tuple[str, dict] | None:
|
|
1700
|
+
"""Select the most recent started repair boundary by invocation identity."""
|
|
1701
|
+
phases = state.get("phases", {})
|
|
1702
|
+
selected = None
|
|
1703
|
+
for order, name in enumerate(REPAIR_PHASES):
|
|
1704
|
+
entry = phases.get(name) if isinstance(phases, dict) else None
|
|
1705
|
+
if not isinstance(entry, dict) or entry.get("started_at") is None:
|
|
1706
|
+
continue
|
|
1707
|
+
round_ = entry.get("round")
|
|
1708
|
+
if type(round_) is not int or round_ < 0:
|
|
1709
|
+
raise SystemExit("BLOCKED:repair-edge-invalid")
|
|
1710
|
+
if selected is None or (round_, order) > selected[0]:
|
|
1711
|
+
selected = ((round_, order), name, entry)
|
|
1712
|
+
return None if selected is None else (selected[1], selected[2])
|
|
1713
|
+
|
|
1714
|
+
|
|
1715
|
+
def repair_admission(state: dict, phase: str, round_: int,
|
|
1716
|
+
triggered_by: str | None, source_phase: str | None = None) -> None:
|
|
1717
|
+
if phase not in REPAIR_PHASES:
|
|
1718
|
+
return
|
|
1719
|
+
predecessor = repair_predecessor(state)
|
|
1720
|
+
if phase == "implement":
|
|
1721
|
+
if predecessor is None:
|
|
1722
|
+
if triggered_by not in {None, "plan"}:
|
|
1723
|
+
raise SystemExit("BLOCKED:repair-trigger-mismatch: expected=null supplied=" + triggered_by)
|
|
1724
|
+
expected_round, origin = 0, None
|
|
1725
|
+
else:
|
|
1726
|
+
prior_name, prior = predecessor
|
|
1727
|
+
if prior.get("completed_at") is None or (source_phase is not None and prior_name != source_phase):
|
|
1728
|
+
raise SystemExit("BLOCKED:repair-edge-invalid")
|
|
1729
|
+
verdict = prior.get("verdict")
|
|
1730
|
+
origin = None
|
|
1731
|
+
if prior_name in {"build_gate", "cleanup", "verify"}:
|
|
1732
|
+
valid = (verdict == "NEEDS_WORK" and isinstance(prior.get("merged"), dict)
|
|
1733
|
+
and prior["merged"].get("verdict") == "NEEDS_WORK") if prior_name == "verify" else verdict == "FAIL"
|
|
1734
|
+
if prior_name == "cleanup":
|
|
1735
|
+
valid = valid and orchestrator_phase(prior, "cleanup")
|
|
1736
|
+
if not valid:
|
|
1737
|
+
raise SystemExit("BLOCKED:repair-edge-invalid")
|
|
1738
|
+
origin = prior_name
|
|
1739
|
+
elif prior_name == "implement":
|
|
1740
|
+
progress = prior.get("exec")
|
|
1741
|
+
if not valid_phase_gate_progress(progress):
|
|
1742
|
+
raise SystemExit("BLOCKED:repair-edge-invalid")
|
|
1743
|
+
current, statuses = progress["current"], progress["statuses"]
|
|
1744
|
+
status = statuses[current - 1]
|
|
1745
|
+
if verdict == "FAIL" and status == "FAIL":
|
|
1746
|
+
origin = "phase_gate"
|
|
1747
|
+
elif verdict not in {"PASS", "PASS_WITH_ISSUES"} or current < 2 or status is not None:
|
|
1748
|
+
raise SystemExit("BLOCKED:repair-edge-invalid")
|
|
1749
|
+
else:
|
|
1750
|
+
raise SystemExit("BLOCKED:repair-edge-invalid")
|
|
1751
|
+
expected_round = prior["round"] + 1
|
|
1752
|
+
expected_trigger = origin if origin in VALID_TRIGGERS else None
|
|
1753
|
+
if triggered_by != expected_trigger:
|
|
1754
|
+
supplied = triggered_by if triggered_by is not None else "null"
|
|
1755
|
+
expected = expected_trigger if expected_trigger is not None else "null"
|
|
1756
|
+
raise SystemExit(f"BLOCKED:repair-trigger-mismatch: expected={expected} supplied={supplied}")
|
|
1757
|
+
if round_ != expected_round:
|
|
1758
|
+
raise SystemExit(f"BLOCKED:implement-round-nonmonotonic: expected={expected_round} supplied={round_}")
|
|
1759
|
+
if origin is not None:
|
|
1760
|
+
rounds = state.get("rounds")
|
|
1761
|
+
if (not isinstance(rounds, dict) or type(rounds.get("global")) is not int
|
|
1762
|
+
or rounds["global"] < 0 or type(rounds.get("max_rounds")) is not int
|
|
1763
|
+
or rounds["max_rounds"] < 1):
|
|
1764
|
+
raise SystemExit("BLOCKED:rounds-malformed")
|
|
1765
|
+
if rounds["global"] >= rounds["max_rounds"]:
|
|
1766
|
+
raise SystemExit(
|
|
1767
|
+
f"BLOCKED:repair-budget-exhausted: global={rounds['global']} "
|
|
1768
|
+
f"max_rounds={rounds['max_rounds']} origin={origin}"
|
|
1769
|
+
)
|
|
1770
|
+
rounds["global"] += 1
|
|
1771
|
+
elif phase in {"build_gate", "cleanup", "verify"}:
|
|
1772
|
+
implement = (state.get("phases") or {}).get("implement")
|
|
1773
|
+
expected_round = implement.get("round", 0) if isinstance(implement, dict) and implement.get("started_at") else 0
|
|
1774
|
+
if round_ != expected_round:
|
|
1775
|
+
raise SystemExit(f"BLOCKED:phase-round-mismatch: phase={phase} expected={expected_round} supplied={round_}")
|
|
1776
|
+
|
|
1777
|
+
|
|
1778
|
+
def validate_verdict(phase: str, verdict: str | None) -> None:
|
|
1779
|
+
allowed = (verdict in FINAL_VERDICTS or (
|
|
1780
|
+
isinstance(verdict, str) and verdict.startswith("BLOCKED:") and len(verdict) > 8
|
|
1781
|
+
)) if phase == "final_report" else verdict in VALID_VERDICTS
|
|
1782
|
+
if verdict is not None and not allowed:
|
|
1783
|
+
raise SystemExit(f"error: invalid verdict for phases.{phase}: {verdict}")
|
|
1784
|
+
|
|
1785
|
+
|
|
1685
1786
|
def do_spawn(state: dict, phase: str, round_: int, triggered_by: str | None,
|
|
1686
1787
|
pre_sha: str | None, engine: str | None, model: str | None, *,
|
|
1788
|
+
source_phase: str | None = None,
|
|
1687
1789
|
input_patch_sha256: str | None = None,
|
|
1688
1790
|
prompt_sha256: str | None = None,
|
|
1689
1791
|
untracked_before: list[str] | None = None,
|
|
@@ -1804,6 +1906,7 @@ def do_spawn(state: dict, phase: str, round_: int, triggered_by: str | None,
|
|
|
1804
1906
|
raise SystemExit(
|
|
1805
1907
|
f"error: phases.{phase} has an open span — complete it before respawn"
|
|
1806
1908
|
)
|
|
1909
|
+
repair_admission(state, phase, round_, triggered_by, source_phase)
|
|
1807
1910
|
append_phase_history(entry, phase)
|
|
1808
1911
|
if phase in WORKER_SESSION_ARTIFACT_PHASES:
|
|
1809
1912
|
entry.pop("invocation_receipt", None)
|
|
@@ -1812,7 +1915,10 @@ def do_spawn(state: dict, phase: str, round_: int, triggered_by: str | None,
|
|
|
1812
1915
|
entry["completed_at"] = None
|
|
1813
1916
|
entry["duration_ms"] = None
|
|
1814
1917
|
entry["round"] = round_
|
|
1815
|
-
entry["triggered_by"] =
|
|
1918
|
+
entry["triggered_by"] = (
|
|
1919
|
+
"cleanup" if phase == "implement" and triggered_by is None
|
|
1920
|
+
and entry.get("triggered_by") == "cleanup" else triggered_by
|
|
1921
|
+
)
|
|
1816
1922
|
entry["verdict"] = None
|
|
1817
1923
|
entry["artifacts"] = {"findings_file": None, "log_file": None}
|
|
1818
1924
|
entry["sub_verdicts"] = None
|
|
@@ -1881,6 +1987,7 @@ def do_complete(state: dict, phase: str, verdict: str | None,
|
|
|
1881
1987
|
entry = phases.get(phase)
|
|
1882
1988
|
if not isinstance(entry, dict) or not entry.get("started_at"):
|
|
1883
1989
|
raise SystemExit(f"error: phases.{phase} was never spawned (no started_at) — cannot complete")
|
|
1990
|
+
validate_verdict(phase, verdict)
|
|
1884
1991
|
if phase == "verify" and verdict is not None:
|
|
1885
1992
|
raise SystemExit(
|
|
1886
1993
|
"error: phases.verify.verdict is owned by verify-merge-findings.py "
|
|
@@ -1903,9 +2010,13 @@ def do_complete(state: dict, phase: str, verdict: str | None,
|
|
|
1903
2010
|
["git", "diff", "--quiet", entry["pre_sha"], "--"], cwd=work,
|
|
1904
2011
|
capture_output=True, check=False,
|
|
1905
2012
|
)
|
|
2013
|
+
indexed = subprocess.run(
|
|
2014
|
+
["git", "diff", "--cached", "--quiet", entry["pre_sha"], "--"], cwd=work,
|
|
2015
|
+
capture_output=True, check=False,
|
|
2016
|
+
)
|
|
1906
2017
|
head = subprocess.run(["git", "rev-parse", "HEAD"], cwd=work,
|
|
1907
2018
|
capture_output=True, text=True, check=False)
|
|
1908
|
-
if checked.returncode != 0 or head.returncode != 0 or head.stdout.strip() != post_sha:
|
|
2019
|
+
if checked.returncode != 0 or indexed.returncode != 0 or head.returncode != 0 or head.stdout.strip() != post_sha:
|
|
1909
2020
|
raise SystemExit("BLOCKED:owner-cleanup-source-changed: return code cleanup to IMPLEMENT")
|
|
1910
2021
|
checker = runpy.run_path(pathlib.Path(__file__).with_name("spec-verify-check.py"))
|
|
1911
2022
|
baseline, baseline_error = checker["load_untracked_baseline"](devlyn)
|
|
@@ -1950,6 +2061,13 @@ def do_complete(state: dict, phase: str, verdict: str | None,
|
|
|
1950
2061
|
entry["verdict"] = verdict
|
|
1951
2062
|
else:
|
|
1952
2063
|
raise SystemExit(f"error: --verdict is required to complete phases.{phase}")
|
|
2064
|
+
if phase == "implement" and verdict == "FAIL" and isinstance(entry.get("exec"), dict):
|
|
2065
|
+
progress = entry["exec"]
|
|
2066
|
+
total, current, statuses = progress.get("total"), progress.get("current"), progress.get("statuses")
|
|
2067
|
+
if (type(total) is not int or total <= 1 or type(current) is not int
|
|
2068
|
+
or not 1 <= current <= total or not isinstance(statuses, list) or len(statuses) != total):
|
|
2069
|
+
raise SystemExit("BLOCKED:repair-edge-invalid")
|
|
2070
|
+
statuses[current - 1] = "FAIL"
|
|
1953
2071
|
if phase == "plan":
|
|
1954
2072
|
if state.get("version") == "3.0":
|
|
1955
2073
|
bind_plan_output(state, devlyn)
|
|
@@ -2100,11 +2218,23 @@ def do_transition(
|
|
|
2100
2218
|
"""
|
|
2101
2219
|
if next_phase not in LEGAL_TRANSITIONS.get(phase, set()):
|
|
2102
2220
|
raise SystemExit(f"error: illegal phase transition: {phase} -> {next_phase}")
|
|
2103
|
-
|
|
2104
|
-
|
|
2221
|
+
validate_verdict(phase, verdict)
|
|
2222
|
+
if (phase == "implement" and next_phase != "implement"
|
|
2223
|
+
and state.get("phases", {}).get(phase, {}).get("triggered_by") == "cleanup"):
|
|
2224
|
+
bypasses = state.get("bypasses", [])
|
|
2225
|
+
required = "build_gate" if "build-gate" not in bypasses else (
|
|
2226
|
+
"cleanup" if "cleanup" not in bypasses else "verify"
|
|
2227
|
+
)
|
|
2228
|
+
if next_phase not in {required, "final_report"}:
|
|
2229
|
+
raise SystemExit(f"BLOCKED:owner-cleanup-repair-route: next phase must be {required}")
|
|
2230
|
+
if next_phase != "final_report" and next_round != state["phases"][phase]["round"]:
|
|
2231
|
+
raise SystemExit("BLOCKED:owner-cleanup-repair-route: preserve the IMPLEMENT repair round")
|
|
2232
|
+
if phase == "cleanup":
|
|
2233
|
+
owner = orchestrator_phase(state.get("phases", {}).get(phase), phase)
|
|
2234
|
+
if owner and next_phase == "verify" and verdict not in {"PASS", "PASS_WITH_ISSUES"}:
|
|
2105
2235
|
raise SystemExit("BLOCKED:owner-cleanup-failed: repair before VERIFY")
|
|
2106
|
-
if next_phase == "implement" and (verdict != "FAIL" or next_triggered_by != "cleanup"):
|
|
2107
|
-
raise SystemExit("BLOCKED:owner-cleanup-failed: repair requires FAIL and cleanup trigger")
|
|
2236
|
+
if next_phase == "implement" and (not owner or verdict != "FAIL" or next_triggered_by != "cleanup"):
|
|
2237
|
+
raise SystemExit("BLOCKED:owner-cleanup-failed: repair requires owner FAIL and cleanup trigger")
|
|
2108
2238
|
candidate = copy.deepcopy(state)
|
|
2109
2239
|
attestation_error = do_complete(
|
|
2110
2240
|
candidate, phase, verdict, post_sha, findings_file, log_file,
|
|
@@ -2117,6 +2247,7 @@ def do_transition(
|
|
|
2117
2247
|
do_spawn(
|
|
2118
2248
|
candidate, next_phase, next_round, next_triggered_by,
|
|
2119
2249
|
next_pre_sha, next_engine, next_model,
|
|
2250
|
+
source_phase=phase,
|
|
2120
2251
|
input_patch_sha256=next_input_patch_sha256,
|
|
2121
2252
|
prompt_sha256=next_prompt_sha256,
|
|
2122
2253
|
untracked_before=next_untracked_before,
|
|
@@ -2195,6 +2326,14 @@ def final_report_self_test() -> None:
|
|
|
2195
2326
|
assert result.returncode == 1 and "BLOCKED:final-report-invalid" in result.stderr, (case, result)
|
|
2196
2327
|
assert state_path.read_bytes() == before, case
|
|
2197
2328
|
report.write_bytes(valid)
|
|
2329
|
+
for invalid in ("FAIL", "BLOCKED:", "unknown"):
|
|
2330
|
+
result = subprocess.run(command + ["complete", "--verdict", invalid,
|
|
2331
|
+
"--log-file", ".devlyn/final-report.md"],
|
|
2332
|
+
cwd=work, capture_output=True, text=True, encoding="utf-8")
|
|
2333
|
+
assert result.returncode == 1 and result.stderr.strip() == (
|
|
2334
|
+
f"error: invalid verdict for phases.final_report: {invalid}"
|
|
2335
|
+
), result.stderr
|
|
2336
|
+
assert state_path.read_bytes() == before
|
|
2198
2337
|
result = subprocess.run(command + ["complete", "--verdict", "PASS_WITH_ISSUES", "--log-file", ".devlyn/final-report.md"],
|
|
2199
2338
|
cwd=work, capture_output=True, text=True, encoding="utf-8")
|
|
2200
2339
|
assert result.returncode == 0, result.stderr
|
|
@@ -2240,12 +2379,142 @@ def final_report_self_test() -> None:
|
|
|
2240
2379
|
assert (target / "pipeline.state.json").read_bytes() == completed_bytes
|
|
2241
2380
|
assert not state_path.exists() and not report.exists()
|
|
2242
2381
|
assert outside.read_bytes() == valid
|
|
2243
|
-
print("PASS iter-0126 final report:
|
|
2382
|
+
print("PASS iter-0126 final report: 14 invalid CLI completions preserve state; exact binding/archive; 6 archive refusals preserve artifacts")
|
|
2383
|
+
|
|
2384
|
+
|
|
2385
|
+
def repair_admission_self_test() -> None:
|
|
2386
|
+
stamp = "2026-01-01T00:00:00.000Z"
|
|
2387
|
+
origins = {
|
|
2388
|
+
"build_gate": ({"started_at": stamp, "completed_at": stamp, "round": 0, "verdict": "FAIL"}, "build_gate"),
|
|
2389
|
+
"cleanup": ({"started_at": stamp, "completed_at": stamp, "round": 0, "verdict": "FAIL",
|
|
2390
|
+
"execution_kind": "orchestrator_commands"}, "cleanup"),
|
|
2391
|
+
"verify": ({"started_at": stamp, "completed_at": stamp, "round": 0,
|
|
2392
|
+
"verdict": "NEEDS_WORK", "merged": {"verdict": "NEEDS_WORK"}}, "verify"),
|
|
2393
|
+
"phase_gate": ({"started_at": stamp, "completed_at": stamp, "round": 0, "verdict": "FAIL",
|
|
2394
|
+
"exec": {"total": 2, "current": 1, "statuses": ["FAIL", None]}}, None),
|
|
2395
|
+
}
|
|
2396
|
+
for origin, (entry, trigger) in origins.items():
|
|
2397
|
+
source = "implement" if origin == "phase_gate" else origin
|
|
2398
|
+
initial = {"phases": {source: entry}, "rounds": {"global": 0, "max_rounds": 1}}
|
|
2399
|
+
for wrong in ((None, "plan", "verify") if trigger else ("plan", "verify")):
|
|
2400
|
+
if wrong == trigger:
|
|
2401
|
+
continue
|
|
2402
|
+
candidate = copy.deepcopy(initial)
|
|
2403
|
+
try:
|
|
2404
|
+
do_spawn(candidate, "implement", 1, wrong, None, None, None)
|
|
2405
|
+
except SystemExit as exc:
|
|
2406
|
+
assert "repair-trigger-mismatch" in str(exc), (origin, wrong, exc)
|
|
2407
|
+
else:
|
|
2408
|
+
raise AssertionError((origin, wrong))
|
|
2409
|
+
for malformed in ({"global": True, "max_rounds": 1}, {"global": -1, "max_rounds": 1},
|
|
2410
|
+
{"global": 0, "max_rounds": True}, {"global": 0, "max_rounds": 0}, None):
|
|
2411
|
+
candidate = copy.deepcopy(initial)
|
|
2412
|
+
candidate["rounds"] = malformed
|
|
2413
|
+
try:
|
|
2414
|
+
do_spawn(candidate, "implement", 1, trigger, None, None, None)
|
|
2415
|
+
except SystemExit as exc:
|
|
2416
|
+
assert str(exc) == "BLOCKED:rounds-malformed"
|
|
2417
|
+
else:
|
|
2418
|
+
raise AssertionError((origin, malformed))
|
|
2419
|
+
candidate = copy.deepcopy(initial)
|
|
2420
|
+
try:
|
|
2421
|
+
do_spawn(candidate, "implement", 2, trigger, None, None, None)
|
|
2422
|
+
except SystemExit as exc:
|
|
2423
|
+
assert "implement-round-nonmonotonic" in str(exc)
|
|
2424
|
+
else:
|
|
2425
|
+
raise AssertionError((origin, "skipped round"))
|
|
2426
|
+
candidate = copy.deepcopy(initial)
|
|
2427
|
+
do_spawn(candidate, "implement", 1, trigger, None, None, None)
|
|
2428
|
+
assert candidate["rounds"]["global"] == 1, origin
|
|
2429
|
+
try:
|
|
2430
|
+
do_spawn(candidate, "implement", 1, trigger, None, None, None)
|
|
2431
|
+
except SystemExit:
|
|
2432
|
+
pass
|
|
2433
|
+
else:
|
|
2434
|
+
raise AssertionError((origin, "duplicate admission"))
|
|
2435
|
+
exhausted = copy.deepcopy(initial)
|
|
2436
|
+
exhausted["rounds"]["global"] = 1
|
|
2437
|
+
try:
|
|
2438
|
+
do_spawn(exhausted, "implement", 1, trigger, None, None, None)
|
|
2439
|
+
except SystemExit as exc:
|
|
2440
|
+
assert str(exc) == f"BLOCKED:repair-budget-exhausted: global=1 max_rounds=1 origin={origin}"
|
|
2441
|
+
else:
|
|
2442
|
+
raise AssertionError((origin, "shared exhaustion"))
|
|
2443
|
+
phased = {"rounds": {"global": 0, "max_rounds": 1}, "phases": {}}
|
|
2444
|
+
do_spawn(phased, "implement", 0, None, None, None, None)
|
|
2445
|
+
phased["phases"]["implement"].update({"completed_at": stamp, "verdict": "PASS",
|
|
2446
|
+
"exec": {"total": 2, "current": 2, "statuses": ["PASS", None]}})
|
|
2447
|
+
do_spawn(phased, "implement", 1, None, None, None, None)
|
|
2448
|
+
assert phased["rounds"]["global"] == 0
|
|
2449
|
+
do_complete(phased, "implement", "FAIL", None, None, None, None, None)
|
|
2450
|
+
assert phased["phases"]["implement"]["exec"]["statuses"] == ["PASS", "FAIL"]
|
|
2451
|
+
do_spawn(phased, "implement", 2, None, None, None, None)
|
|
2452
|
+
assert phased["rounds"]["global"] == 1
|
|
2453
|
+
do_complete(phased, "implement", "PASS", None, None, None, None, None)
|
|
2454
|
+
do_spawn(phased, "verify", 2, None, None, None, None)
|
|
2455
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2456
|
+
transition_state = {"rounds": {"global": 0, "max_rounds": 1}, "phases": {}}
|
|
2457
|
+
do_spawn(transition_state, "implement", 0, None, None, None, None)
|
|
2458
|
+
transition_state["phases"]["implement"]["exec"] = {
|
|
2459
|
+
"total": 2, "current": 1, "statuses": [None, None],
|
|
2460
|
+
}
|
|
2461
|
+
transitioned = do_transition(
|
|
2462
|
+
transition_state, "implement", "implement", "FAIL", None, None, None,
|
|
2463
|
+
None, None, None, pathlib.Path(tmp), 1, None, None, None, None,
|
|
2464
|
+
)
|
|
2465
|
+
assert transition_state["rounds"]["global"] == 0
|
|
2466
|
+
assert transitioned["rounds"]["global"] == 1
|
|
2467
|
+
assert transitioned["phases"]["implement"]["exec"]["statuses"][0] == "FAIL"
|
|
2468
|
+
print("PASS repair admission: four origins, trigger/counter/round refusal, phased invocation and last repair")
|
|
2469
|
+
|
|
2470
|
+
|
|
2471
|
+
def cleanup_origin_phase_gate_reentry_self_test() -> None:
|
|
2472
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2473
|
+
stamp = "2026-01-01T00:00:00.000Z"
|
|
2474
|
+
state = {"version": "3.0", "rounds": {"global": 1, "max_rounds": 4}, "phases": {
|
|
2475
|
+
"cleanup": {"started_at": stamp, "completed_at": stamp, "round": 0,
|
|
2476
|
+
"verdict": "FAIL", "execution_kind": "orchestrator_commands"},
|
|
2477
|
+
"implement": {"started_at": stamp, "completed_at": None, "round": 1,
|
|
2478
|
+
"triggered_by": "cleanup", "verdict": None,
|
|
2479
|
+
"exec": {"total": 2, "current": 1, "statuses": [None, None]}},
|
|
2480
|
+
}}
|
|
2481
|
+
try:
|
|
2482
|
+
do_transition(
|
|
2483
|
+
state, "implement", "verify", "PASS", None, None, None,
|
|
2484
|
+
None, None, None, pathlib.Path(tmp), 1, None, None, None, None,
|
|
2485
|
+
)
|
|
2486
|
+
except SystemExit as exc:
|
|
2487
|
+
assert str(exc) == "BLOCKED:owner-cleanup-repair-route: next phase must be build_gate", exc
|
|
2488
|
+
else:
|
|
2489
|
+
raise AssertionError("cleanup repair bypassed BUILD_GATE")
|
|
2490
|
+
transitioned = do_transition(
|
|
2491
|
+
state, "implement", "implement", "FAIL", None, None, None,
|
|
2492
|
+
None, None, None, pathlib.Path(tmp), 2, None, None, None, None,
|
|
2493
|
+
)
|
|
2494
|
+
assert transitioned["rounds"]["global"] == 2
|
|
2495
|
+
assert transitioned["phases"]["implement"]["exec"]["statuses"] == ["FAIL", None]
|
|
2496
|
+
assert transitioned["phases"]["implement"]["triggered_by"] == "cleanup"
|
|
2497
|
+
try:
|
|
2498
|
+
do_transition(
|
|
2499
|
+
transitioned, "implement", "verify", "PASS", None, None, None,
|
|
2500
|
+
None, None, None, pathlib.Path(tmp), 2, None, None, None, None,
|
|
2501
|
+
)
|
|
2502
|
+
except SystemExit as exc:
|
|
2503
|
+
assert str(exc) == "BLOCKED:owner-cleanup-repair-route: next phase must be build_gate", exc
|
|
2504
|
+
else:
|
|
2505
|
+
raise AssertionError("phase-gate retry bypassed BUILD_GATE")
|
|
2506
|
+
spawned = copy.deepcopy(state)
|
|
2507
|
+
do_complete(spawned, "implement", "FAIL", None, None, None, None, None)
|
|
2508
|
+
do_spawn(spawned, "implement", 2, None, None, None, None)
|
|
2509
|
+
assert spawned["rounds"]["global"] == 2
|
|
2510
|
+
assert spawned["phases"]["implement"]["triggered_by"] == "cleanup"
|
|
2244
2511
|
|
|
2245
2512
|
|
|
2246
2513
|
def self_test() -> int:
|
|
2247
2514
|
import time
|
|
2248
2515
|
|
|
2516
|
+
repair_admission_self_test()
|
|
2517
|
+
cleanup_origin_phase_gate_reentry_self_test()
|
|
2249
2518
|
final_report_self_test()
|
|
2250
2519
|
with tempfile.TemporaryDirectory() as tmp:
|
|
2251
2520
|
work = pathlib.Path(tmp); devlyn = work / ".devlyn"; devlyn.mkdir()
|
|
@@ -2521,7 +2790,7 @@ def self_test() -> int:
|
|
|
2521
2790
|
assert archived_legacy == old_receipt
|
|
2522
2791
|
print("PASS iter-0089 PLAN ledger: P-0089-1/2/6")
|
|
2523
2792
|
|
|
2524
|
-
write_state(state_path, {"phases": {}})
|
|
2793
|
+
write_state(state_path, {"phases": {}, "rounds": {"global": 0, "max_rounds": 4}})
|
|
2525
2794
|
|
|
2526
2795
|
# Round 0: spawn -> complete.
|
|
2527
2796
|
state = read_state(state_path)
|
|
@@ -2541,9 +2810,14 @@ def self_test() -> int:
|
|
|
2541
2810
|
expected_ms = round((parse_iso(entry["completed_at"]) - parse_iso(entry["started_at"])).total_seconds() * 1000)
|
|
2542
2811
|
assert entry["duration_ms"] == expected_ms, (entry["duration_ms"], expected_ms)
|
|
2543
2812
|
|
|
2544
|
-
# Round 1:
|
|
2813
|
+
# Round 1: VERIFY finding admits a fix-loop respawn.
|
|
2545
2814
|
time.sleep(0.05)
|
|
2546
2815
|
state = read_state(state_path)
|
|
2816
|
+
do_spawn(state, "verify", 0, None, None, None, None)
|
|
2817
|
+
state["phases"]["verify"].update({
|
|
2818
|
+
"completed_at": now_iso(), "verdict": "NEEDS_WORK",
|
|
2819
|
+
"merged": {"verdict": "NEEDS_WORK"},
|
|
2820
|
+
})
|
|
2547
2821
|
do_spawn(state, "implement", 1, "verify", None, None, None)
|
|
2548
2822
|
write_state(state_path, state)
|
|
2549
2823
|
respawned = read_state(state_path)["phases"]["implement"]
|
|
@@ -2582,6 +2856,10 @@ def self_test() -> int:
|
|
|
2582
2856
|
evidence_spec_dir = evidence_work / "docs" / "evidence"
|
|
2583
2857
|
evidence_devlyn.mkdir(parents=True)
|
|
2584
2858
|
evidence_spec_dir.mkdir(parents=True)
|
|
2859
|
+
subprocess.run(["git", "init", "-q"], cwd=evidence_work, check=True)
|
|
2860
|
+
subprocess.run(["git", "config", "user.name", "Evidence test"], cwd=evidence_work, check=True)
|
|
2861
|
+
subprocess.run(["git", "config", "user.email", "evidence@example.invalid"], cwd=evidence_work, check=True)
|
|
2862
|
+
(evidence_work / ".gitignore").write_text(".devlyn/\n", encoding="utf-8")
|
|
2585
2863
|
(evidence_spec_dir / "spec.md").write_text("# Evidence fixture\n", encoding="utf-8")
|
|
2586
2864
|
(evidence_spec_dir / "spec.expected.json").write_text(json.dumps({
|
|
2587
2865
|
"verification_commands": [{"cmd": "printf build-gate"}],
|
|
@@ -2593,9 +2871,12 @@ def self_test() -> int:
|
|
|
2593
2871
|
"stdout_contains": ["red-before-fix"],
|
|
2594
2872
|
}],
|
|
2595
2873
|
}) + "\n", encoding="utf-8")
|
|
2874
|
+
subprocess.run(["git", "add", "."], cwd=evidence_work, check=True)
|
|
2875
|
+
subprocess.run(["git", "commit", "-qm", "fixture"], cwd=evidence_work, check=True)
|
|
2596
2876
|
evidence_state = {
|
|
2597
2877
|
"run_id": "rs-state-evidence",
|
|
2598
2878
|
"source": {"type": "spec", "spec_path": "docs/evidence/spec.md"},
|
|
2879
|
+
"rounds": {"global": 0, "max_rounds": 4},
|
|
2599
2880
|
"phases": {"implement": None, "build_gate": None},
|
|
2600
2881
|
}
|
|
2601
2882
|
do_spawn(evidence_state, "implement", 0, None, None, "codex", None)
|
|
@@ -2722,11 +3003,28 @@ def self_test() -> int:
|
|
|
2722
3003
|
return build_carrier
|
|
2723
3004
|
|
|
2724
3005
|
build_carrier_0 = write_build_gate_results()
|
|
2725
|
-
completed = build_gate_state_cli("complete", "--verdict", "
|
|
3006
|
+
completed = build_gate_state_cli("complete", "--verdict", "FAIL")
|
|
2726
3007
|
assert completed.returncode == 0, completed.stderr
|
|
2727
3008
|
completed_state = read_state(evidence_state_path)
|
|
2728
3009
|
assert completed_state["process_evidence"] == [carrier, build_carrier_0]
|
|
2729
3010
|
|
|
3011
|
+
repaired = evidence_state_cli("spawn", "--round", "1", "--triggered-by", "build_gate")
|
|
3012
|
+
assert repaired.returncode == 0, repaired.stderr
|
|
3013
|
+
captured = subprocess.run(
|
|
3014
|
+
[sys.executable, runner_script, "--devlyn-dir", ".devlyn", "run",
|
|
3015
|
+
"--phase", "implement", "--id", "red-first"],
|
|
3016
|
+
cwd=evidence_work, capture_output=True, text=True, encoding="utf-8",
|
|
3017
|
+
)
|
|
3018
|
+
assert captured.returncode == 0, captured.stderr
|
|
3019
|
+
completed = evidence_state_cli("complete", "--verdict", "PASS")
|
|
3020
|
+
assert completed.returncode == 0, completed.stderr
|
|
3021
|
+
implement_carrier_1 = read_state(evidence_state_path)["process_evidence"][-1]
|
|
3022
|
+
subprocess.run(["git", "commit", "--allow-empty", "-qm", "chore(pipeline): implement fix round 1"],
|
|
3023
|
+
cwd=evidence_work, check=True)
|
|
3024
|
+
(evidence_devlyn / "build_gate.findings.jsonl").write_text("", encoding="utf-8")
|
|
3025
|
+
durable = evidence_state_cli("durability-enforce", "--round", "1", "--origin-phase", "build_gate")
|
|
3026
|
+
assert durable.returncode == 0, durable.stderr
|
|
3027
|
+
|
|
2730
3028
|
spawned = build_gate_state_cli(
|
|
2731
3029
|
"spawn", "--round", "1", "--triggered-by", "build_gate",
|
|
2732
3030
|
)
|
|
@@ -2734,12 +3032,12 @@ def self_test() -> int:
|
|
|
2734
3032
|
build_carrier_1 = write_build_gate_results()
|
|
2735
3033
|
transitioned = build_gate_state_cli(
|
|
2736
3034
|
"transition", "--verdict", "PASS", "--next-phase", "cleanup",
|
|
2737
|
-
"--next-round", "
|
|
3035
|
+
"--next-round", "1", "--next-pre-sha", "test-pre-sha",
|
|
2738
3036
|
)
|
|
2739
3037
|
assert transitioned.returncode == 0, transitioned.stderr
|
|
2740
3038
|
build_bound_state = read_state(evidence_state_path)
|
|
2741
3039
|
assert build_bound_state["process_evidence"] == [
|
|
2742
|
-
carrier, build_carrier_0, build_carrier_1,
|
|
3040
|
+
carrier, build_carrier_0, implement_carrier_1, build_carrier_1,
|
|
2743
3041
|
]
|
|
2744
3042
|
assert build_bound_state["phases"]["cleanup"]["started_at"] is not None
|
|
2745
3043
|
print("PASS iter-0111 BUILD_GATE evidence: completion/transition state binding")
|
|
@@ -2748,6 +3046,7 @@ def self_test() -> int:
|
|
|
2748
3046
|
# bytes only, so a failed entry or capability denial could still be completed
|
|
2749
3047
|
# with caller-supplied PASS.
|
|
2750
3048
|
build_bound_state["phases"]["build_gate"] = None
|
|
3049
|
+
build_bound_state["phases"]["implement"]["round"] = 2
|
|
2751
3050
|
do_spawn(build_bound_state, "build_gate", 2, "build_gate", None, None, None)
|
|
2752
3051
|
write_state(evidence_state_path, build_bound_state)
|
|
2753
3052
|
mismatch = runner.normalize_obligation({
|
|
@@ -2793,6 +3092,7 @@ def self_test() -> int:
|
|
|
2793
3092
|
assert failed.returncode == 0, failed.stderr
|
|
2794
3093
|
|
|
2795
3094
|
failed_state = read_state(evidence_state_path)
|
|
3095
|
+
failed_state["phases"]["implement"]["round"] = 3
|
|
2796
3096
|
do_spawn(failed_state, "build_gate", 3, "build_gate", None, None, None)
|
|
2797
3097
|
write_state(evidence_state_path, failed_state)
|
|
2798
3098
|
denied = runner.normalize_obligation({
|
|
@@ -2905,7 +3205,7 @@ def self_test() -> int:
|
|
|
2905
3205
|
completed = read_state(state_file)["phases"]["build_gate"]
|
|
2906
3206
|
command_identity(completed)
|
|
2907
3207
|
assert completed["verdict"] == "PASS" and completed["completed_at"]
|
|
2908
|
-
result = cli("build_gate", "spawn", "--round", "
|
|
3208
|
+
result = cli("build_gate", "spawn", "--round", "0")
|
|
2909
3209
|
assert result.returncode == 0, result.stderr
|
|
2910
3210
|
reentered = read_state(state_file)["phases"]["build_gate"]
|
|
2911
3211
|
command_identity(reentered)
|
|
@@ -2954,6 +3254,11 @@ def self_test() -> int:
|
|
|
2954
3254
|
old = legacy_done["phases"]["build_gate"]
|
|
2955
3255
|
assert "execution_kind" not in old and old["model_effective"] is None
|
|
2956
3256
|
assert old["invocation_receipt"]["sandbox_network_access"] is True
|
|
3257
|
+
legacy_done["phases"]["implement"] = {
|
|
3258
|
+
"started_at": now_iso(), "completed_at": now_iso(), "round": 1,
|
|
3259
|
+
"verdict": "PASS",
|
|
3260
|
+
}
|
|
3261
|
+
write_state(state_file, legacy_done)
|
|
2957
3262
|
result = cli("build_gate", "spawn", "--round", "1")
|
|
2958
3263
|
assert result.returncode == 0, result.stderr
|
|
2959
3264
|
fresh = read_state(state_file)["phases"]["build_gate"]
|
|
@@ -3237,6 +3542,10 @@ def self_test() -> int:
|
|
|
3237
3542
|
print("PASS iter-0119 nonzero receipt persists BLOCKED before exit1; transition stays atomic")
|
|
3238
3543
|
|
|
3239
3544
|
candidate = read_state(state_file)
|
|
3545
|
+
candidate["phases"]["implement"] = {
|
|
3546
|
+
"started_at": now_iso(), "completed_at": now_iso(), "round": 1,
|
|
3547
|
+
"verdict": "PASS",
|
|
3548
|
+
}
|
|
3240
3549
|
do_spawn(candidate, "build_gate", 1, None, None, None, None)
|
|
3241
3550
|
write_state(state_file, candidate)
|
|
3242
3551
|
next_relative = runner.manifest_relative_path(candidate, "build_gate")
|
|
@@ -3258,6 +3567,10 @@ def self_test() -> int:
|
|
|
3258
3567
|
# A post-spec denial refresh must preserve earlier failed checks.
|
|
3259
3568
|
refresh_state = copy.deepcopy(fixture)
|
|
3260
3569
|
refresh_state["phases"]["build_gate"] = None
|
|
3570
|
+
refresh_state["phases"]["implement"] = {
|
|
3571
|
+
"started_at": now_iso(), "completed_at": now_iso(), "round": 2,
|
|
3572
|
+
"verdict": "PASS",
|
|
3573
|
+
}
|
|
3261
3574
|
do_spawn(refresh_state, "build_gate", 2, None, None, None, None, devlyn=active)
|
|
3262
3575
|
write_state(state_file, refresh_state)
|
|
3263
3576
|
refresh_relative = runner.manifest_relative_path(refresh_state, "build_gate")
|
|
@@ -3307,7 +3620,7 @@ def self_test() -> int:
|
|
|
3307
3620
|
active.mkdir(parents=True)
|
|
3308
3621
|
state_file = active / "pipeline.state.json"
|
|
3309
3622
|
results_file = active / "spec-verify.results.json"
|
|
3310
|
-
checker = pathlib.Path(__file__).with_name("spec-verify-check.py")
|
|
3623
|
+
checker = pathlib.Path(__file__).resolve().with_name("spec-verify-check.py")
|
|
3311
3624
|
env = {key: value for key, value in os.environ.items() if key not in {
|
|
3312
3625
|
"BENCH_WORKDIR", "SPEC_VERIFY_PHASE", "SPEC_VERIFY_FINDINGS_FILE",
|
|
3313
3626
|
"SPEC_VERIFY_FINDING_PREFIX",
|
|
@@ -3327,7 +3640,10 @@ def self_test() -> int:
|
|
|
3327
3640
|
fixture = {
|
|
3328
3641
|
"version": "3.0", "run_id": "rs-preflight-build-gate",
|
|
3329
3642
|
"source": {"type": "generated", "criteria_path": ".devlyn/criteria.generated.md"},
|
|
3330
|
-
"phases": {"build_gate": None
|
|
3643
|
+
"phases": {"build_gate": None, "implement": {
|
|
3644
|
+
"started_at": now_iso(), "completed_at": now_iso(),
|
|
3645
|
+
"round": round_, "verdict": "PASS",
|
|
3646
|
+
}}, "process_evidence": copy.deepcopy(history) or None,
|
|
3331
3647
|
}
|
|
3332
3648
|
do_spawn(fixture, "build_gate", round_, None, None, None, None)
|
|
3333
3649
|
write_state(state_file, fixture)
|
|
@@ -3609,7 +3925,7 @@ def self_test() -> int:
|
|
|
3609
3925
|
assert state_path.read_bytes() == open_next_before
|
|
3610
3926
|
print("PASS self-test transition open-span guard: rejected without mutation")
|
|
3611
3927
|
|
|
3612
|
-
# A completed FAIL
|
|
3928
|
+
# A completed FAIL span must be retained before a same-invocation respawn
|
|
3613
3929
|
# resets the live record.
|
|
3614
3930
|
write_state(state_path, {"phases": {}})
|
|
3615
3931
|
state = read_state(state_path)
|
|
@@ -3621,7 +3937,7 @@ def self_test() -> int:
|
|
|
3621
3937
|
write_state(state_path, state)
|
|
3622
3938
|
failed_round = read_state(state_path)["phases"]["build_gate"]
|
|
3623
3939
|
state = read_state(state_path)
|
|
3624
|
-
do_spawn(state, "build_gate",
|
|
3940
|
+
do_spawn(state, "build_gate", 0, None, None, None, None)
|
|
3625
3941
|
write_state(state_path, state)
|
|
3626
3942
|
respawned_fail = read_state(state_path)["phases"]["build_gate"]
|
|
3627
3943
|
assert respawned_fail["verdict"] is None
|
|
@@ -3657,7 +3973,7 @@ def self_test() -> int:
|
|
|
3657
3973
|
assert "owned by verify-merge-findings.py" in str(e)
|
|
3658
3974
|
else:
|
|
3659
3975
|
raise AssertionError("complete() must reject an explicit --verdict for VERIFY")
|
|
3660
|
-
do_spawn(state, "verify",
|
|
3976
|
+
do_spawn(state, "verify", 0, None, None, None, None)
|
|
3661
3977
|
assert state["phases"]["verify"]["judge_durations_ms"] is None
|
|
3662
3978
|
|
|
3663
3979
|
# Non-VERIFY phases require --verdict explicitly; complete() must not
|
|
@@ -3726,21 +4042,21 @@ def self_test() -> int:
|
|
|
3726
4042
|
assert (devlyn / "codex-primary-judge.prompt.md").exists(), "judge prompts must survive VERIFY spawn"
|
|
3727
4043
|
assert (devlyn / "spec-verify.json").exists(), "non-VERIFY-round files must survive"
|
|
3728
4044
|
|
|
3729
|
-
#
|
|
4045
|
+
# Normal phase-gated IMPLEMENT advancement must preserve `exec`
|
|
3730
4046
|
# (routing truth for large runs, state-schema.md line 55) — spawn
|
|
3731
4047
|
# merges into the existing entry rather than replacing it wholesale.
|
|
3732
4048
|
write_state(state_path, {"phases": {}})
|
|
3733
4049
|
state = read_state(state_path)
|
|
3734
4050
|
do_spawn(state, "implement", 0, None, None, "claude", None)
|
|
3735
4051
|
state["phases"]["implement"]["exec"] = {
|
|
3736
|
-
"total": 3, "current": 3, "statuses": ["PASS", "PASS",
|
|
4052
|
+
"total": 3, "current": 3, "statuses": ["PASS", "PASS", None], "commits": ["a", "b", "c"],
|
|
3737
4053
|
}
|
|
3738
4054
|
write_state(state_path, state)
|
|
3739
4055
|
state = read_state(state_path)
|
|
3740
4056
|
do_complete(state, "implement", "PASS", None, None, None, None, None)
|
|
3741
4057
|
write_state(state_path, state)
|
|
3742
4058
|
state = read_state(state_path)
|
|
3743
|
-
do_spawn(state, "implement", 1,
|
|
4059
|
+
do_spawn(state, "implement", 1, None, None, None, None)
|
|
3744
4060
|
write_state(state_path, state)
|
|
3745
4061
|
respawned_exec = read_state(state_path)["phases"]["implement"]
|
|
3746
4062
|
assert respawned_exec["exec"]["current"] == 3, "spawn must not clobber unowned fields like exec"
|
|
@@ -3751,6 +4067,7 @@ def self_test() -> int:
|
|
|
3751
4067
|
# Existing history is append-only; a respawn must not clobber prior
|
|
3752
4068
|
# entries that were already preserved from older rounds.
|
|
3753
4069
|
write_state(state_path, {
|
|
4070
|
+
"rounds": {"global": 0, "max_rounds": 4},
|
|
3754
4071
|
"phases": {
|
|
3755
4072
|
"implement": {
|
|
3756
4073
|
"started_at": "2026-01-01T00:00:02.000Z",
|
|
@@ -3759,6 +4076,7 @@ def self_test() -> int:
|
|
|
3759
4076
|
"round": 2,
|
|
3760
4077
|
"triggered_by": "verify",
|
|
3761
4078
|
"verdict": "FAIL",
|
|
4079
|
+
"exec": {"total": 2, "current": 2, "statuses": ["PASS", "FAIL"]},
|
|
3762
4080
|
"engine": "codex",
|
|
3763
4081
|
"history": [{
|
|
3764
4082
|
"started_at": "2026-01-01T00:00:00.000Z",
|
|
@@ -3770,7 +4088,7 @@ def self_test() -> int:
|
|
|
3770
4088
|
}
|
|
3771
4089
|
})
|
|
3772
4090
|
state = read_state(state_path)
|
|
3773
|
-
do_spawn(state, "implement", 3,
|
|
4091
|
+
do_spawn(state, "implement", 3, None, None, None, None)
|
|
3774
4092
|
write_state(state_path, state)
|
|
3775
4093
|
history_preserved = read_state(state_path)["phases"]["implement"]["history"]
|
|
3776
4094
|
assert len(history_preserved) == 2
|
|
@@ -4656,9 +4974,13 @@ def self_test() -> int:
|
|
|
4656
4974
|
)
|
|
4657
4975
|
assert reroute_error and "model reroute" in reroute_error
|
|
4658
4976
|
assert rerouted_state["phases"]["implement"]["verdict"] == "BLOCKED"
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4977
|
+
try:
|
|
4978
|
+
do_spawn(rerouted_state, "implement", 1, None, None, "codex", receipt_model,
|
|
4979
|
+
prompt_sha256=receipt_prompt_sha, devlyn=receipt_devlyn)
|
|
4980
|
+
except SystemExit as exc:
|
|
4981
|
+
assert str(exc) == "BLOCKED:repair-edge-invalid"
|
|
4982
|
+
else:
|
|
4983
|
+
raise AssertionError("BLOCKED IMPLEMENT was admitted as a product repair")
|
|
4662
4984
|
|
|
4663
4985
|
plan_prompt = receipt_devlyn / "plan.prompt.0"
|
|
4664
4986
|
plan_prompt.write_text("plan exactly\n", encoding="utf-8")
|
|
@@ -5144,7 +5466,10 @@ def self_test() -> int:
|
|
|
5144
5466
|
{"a.txt": "old\n"}, "build_gate",
|
|
5145
5467
|
[{"id": "BG", "file": "a.txt", "line": 8}],
|
|
5146
5468
|
)
|
|
5147
|
-
build_state["phases"]["implement"] = {
|
|
5469
|
+
build_state["phases"]["implement"] = {
|
|
5470
|
+
"started_at": now_iso(), "completed_at": now_iso(), "round": 1,
|
|
5471
|
+
"triggered_by": "build_gate", "verdict": "PASS",
|
|
5472
|
+
}
|
|
5148
5473
|
write_state(build_devlyn / "pipeline.state.json", build_state)
|
|
5149
5474
|
subprocess.run(
|
|
5150
5475
|
[sys.executable, str(pathlib.Path(__file__).resolve()), "--devlyn-dir", ".devlyn",
|
|
@@ -5401,7 +5726,7 @@ def self_test() -> int:
|
|
|
5401
5726
|
return 0
|
|
5402
5727
|
|
|
5403
5728
|
|
|
5404
|
-
def
|
|
5729
|
+
def _main_unlocked() -> int:
|
|
5405
5730
|
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
5406
5731
|
ap.add_argument("--devlyn-dir", default=".devlyn")
|
|
5407
5732
|
ap.add_argument("--phase", choices=sorted(PHASE_NAMES))
|
|
@@ -5421,7 +5746,7 @@ def main() -> int:
|
|
|
5421
5746
|
spawn_p.add_argument("--model", default=None)
|
|
5422
5747
|
|
|
5423
5748
|
complete_p = sub.add_parser("complete")
|
|
5424
|
-
complete_p.add_argument("--verdict",
|
|
5749
|
+
complete_p.add_argument("--verdict", default=None)
|
|
5425
5750
|
complete_p.add_argument("--post-sha", default=None)
|
|
5426
5751
|
complete_p.add_argument("--findings-file", default=None)
|
|
5427
5752
|
complete_p.add_argument("--log-file", default=None)
|
|
@@ -5430,7 +5755,7 @@ def main() -> int:
|
|
|
5430
5755
|
complete_p.add_argument("--engine-session-log", default=None)
|
|
5431
5756
|
|
|
5432
5757
|
transition_p = sub.add_parser("transition")
|
|
5433
|
-
transition_p.add_argument("--verdict",
|
|
5758
|
+
transition_p.add_argument("--verdict", default=None)
|
|
5434
5759
|
transition_p.add_argument("--post-sha", default=None)
|
|
5435
5760
|
transition_p.add_argument("--findings-file", default=None)
|
|
5436
5761
|
transition_p.add_argument("--log-file", default=None)
|
|
@@ -5556,7 +5881,8 @@ def main() -> int:
|
|
|
5556
5881
|
spawn_phase in VALID_TRIGGERS and spawn_round >= 1
|
|
5557
5882
|
and isinstance(implement, dict)
|
|
5558
5883
|
and implement.get("round") == spawn_round
|
|
5559
|
-
and (origin == spawn_phase or
|
|
5884
|
+
and (origin == spawn_phase or origin == "cleanup")
|
|
5885
|
+
and (origin != "cleanup" or args.event == "spawn" or args.phase == "implement")
|
|
5560
5886
|
)
|
|
5561
5887
|
if fix_reentry:
|
|
5562
5888
|
enforce_closure_durability_reentry(
|
|
@@ -5643,6 +5969,21 @@ def main() -> int:
|
|
|
5643
5969
|
return 0
|
|
5644
5970
|
|
|
5645
5971
|
|
|
5972
|
+
def main() -> int:
|
|
5973
|
+
if "--self-test" in sys.argv[1:]:
|
|
5974
|
+
return _main_unlocked()
|
|
5975
|
+
selector = argparse.ArgumentParser(add_help=False)
|
|
5976
|
+
selector.add_argument("--devlyn-dir", default=".devlyn")
|
|
5977
|
+
known, _ = selector.parse_known_args()
|
|
5978
|
+
devlyn = pathlib.Path(known.devlyn_dir).resolve()
|
|
5979
|
+
if not devlyn.is_dir():
|
|
5980
|
+
sys.stderr.write(f"error: {devlyn} is not a directory\n")
|
|
5981
|
+
return 1
|
|
5982
|
+
lock = runpy.run_path(str(pathlib.Path(__file__).with_name("platform-support.py")))["file_lock"]
|
|
5983
|
+
with lock(devlyn / "pipeline.state.lock", blocking=True):
|
|
5984
|
+
return _main_unlocked()
|
|
5985
|
+
|
|
5986
|
+
|
|
5646
5987
|
if __name__ == "__main__":
|
|
5647
5988
|
runpy.run_path(str(pathlib.Path(__file__).with_name("platform-support.py")))["configure_utf8"]()
|
|
5648
5989
|
raise SystemExit(main())
|