okstra 0.219.1 → 0.220.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/dist/cli-registry.mjs +18 -0
- package/dist/cli-registry.mjs.map +1 -1
- package/docs/cli.md +3 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/prompts/lead/okstra-lead-contract.md +4 -1
- package/runtime/python/okstra_ctl/blocking_checks.py +8 -0
- package/runtime/python/okstra_ctl/convergence_provenance.py +8 -2
- package/runtime/python/okstra_ctl/correction_cli.py +59 -0
- package/runtime/python/okstra_ctl/correction_round.py +168 -0
- package/runtime/python/okstra_ctl/dispatch_core.py +18 -0
- package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md +29 -6
- package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-verifier.md +2 -0
- package/runtime/python/okstra_ctl/phases/implementation/profile.md +2 -1
- package/runtime/python/okstra_ctl/phases/implementation/report_assets/implementation.template.html +6 -0
- package/runtime/python/okstra_ctl/phases/implementation/spec.md +2 -1
- package/runtime/python/okstra_ctl/phases/implementation/validation.py +62 -1
- package/runtime/python/okstra_ctl/stage_done.py +183 -0
- package/runtime/python/okstra_ctl/stage_fail.py +114 -0
- package/runtime/python/okstra_ctl/stage_reopen.py +12 -8
- package/runtime/schemas/final-report-v3.0.schema.json +78 -0
- package/runtime/templates/reports/html/i18n/en.json +6 -0
- package/runtime/templates/reports/html/i18n/ko.json +6 -0
- package/runtime/validators/validate-run.py +2 -0
package/dist/cli-registry.mjs
CHANGED
|
@@ -145,6 +145,24 @@ export const COMMAND_REGISTRY = [
|
|
|
145
145
|
category: "admin",
|
|
146
146
|
summary: ["Reopen a done implementation stage for a fix run"],
|
|
147
147
|
},
|
|
148
|
+
{
|
|
149
|
+
name: "correction",
|
|
150
|
+
python: { target: { module: "okstra_ctl.correction_cli" } },
|
|
151
|
+
category: "admin",
|
|
152
|
+
summary: ["Print a correction-round prompt body for an implementation run"],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "stage-done",
|
|
156
|
+
python: { target: { module: "okstra_ctl.stage_done" } },
|
|
157
|
+
category: "admin",
|
|
158
|
+
summary: ["Settle a passing implementation stage: carry sidecar and done row"],
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "stage-fail",
|
|
162
|
+
python: { target: { module: "okstra_ctl.stage_fail" } },
|
|
163
|
+
category: "admin",
|
|
164
|
+
summary: ["Record a FAIL-ended implementation stage as failed"],
|
|
165
|
+
},
|
|
148
166
|
{
|
|
149
167
|
name: "discussion",
|
|
150
168
|
python: { target: { module: "okstra_ctl.phases.discussion.cli" }, inject: ["okstra-cli"] },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-registry.mjs","sourceRoot":"","sources":["../src/cli-registry.mts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli-registry.mjs","sourceRoot":"","sources":["../src/cli-registry.mts"],"names":[],"mappings":"AAOA,MAAM,cAAc,GAAG,EAAE,CAAC;AAE1B,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B;QACE,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,kCAAkC;QAC1C,MAAM,EAAE,YAAY;QACpB,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,0DAA0D,CAAC;KACtE;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,kCAAkC;QAC1C,MAAM,EAAE,oBAAoB;QAC5B,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,0DAA0D,CAAC;KACtE;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,oCAAoC;QAC5C,MAAM,EAAE,cAAc;QACtB,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,0DAA0D,CAAC;KACtE;IACD;QACE,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,gCAAgC;QACxC,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,qDAAqD,CAAC;KACjE;IACD;QACE,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,iCAAiC;QACzC,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE;YACP,sEAAsE;SACvE;KACF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,wCAAwC;QAChD,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,2DAA2D,CAAC;KACvE;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,oCAAoC;QAC5C,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,qDAAqD,CAAC;KACjE;IACD;QACE,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,iCAAiC;QACzC,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,sDAAsD,CAAC;KAClE;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,EAAE;QAC/D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,wCAAwC,CAAC;KACpD;IACD;QACE,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE;QACpD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,0DAA0D,CAAC;KACtE;IACD;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,wBAAwB,EAAE,EAAE;QACxD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,0DAA0D,CAAC;KACtE;IACD;QACE,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,2BAA2B,EAAE,EAAE;QAC3D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,oDAAoD,CAAC;KAChE;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAE,EAAE;QAC7D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,oDAAoD,CAAC;KAChE;IACD;QACE,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE;QACtD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,kDAAkD,CAAC;KAC9D;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,EAAE,MAAM,EAAE,CAAC,gBAAgB,EAAE,YAAY,CAAC,EAAE;QACtG,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,iDAAiD,CAAC;KAC7D;IACD;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,EAAE,MAAM,EAAE,CAAC,gBAAgB,CAAC,EAAE;QACxF,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,wDAAwD,CAAC;KACpE;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,EAAE;QAC/D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE;YACP,uDAAuD;YACvD,gDAAgD;SACjD;KACF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,8BAA8B,EAAE,EAAE;QAC9D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,kEAAkE,CAAC;KAC9E;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE;QAC1D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,+DAA+D,CAAC;KAC3E;IACD;QACE,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE;QACpD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,6DAA6D,CAAC;KACzE;IACD;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,wBAAwB,EAAE,EAAE;QACxD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,sDAAsD,CAAC;KAClE;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE;QACzD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,kDAAkD,CAAC;KAC9D;IACD;QACE,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,2BAA2B,EAAE,EAAE;QAC3D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,gEAAgE,CAAC;KAC5E;IACD;QACE,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,uBAAuB,EAAE,EAAE;QACvD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,mEAAmE,CAAC;KAC/E;IACD;QACE,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,uBAAuB,EAAE,EAAE;QACvD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,oDAAoD,CAAC;KAChE;IACD;QACE,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,kCAAkC,EAAE,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE;QAC1F,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,yEAAyE,CAAC;KACrF;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,EAAE;QAC5D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,gDAAgD,CAAC;KAC5D;IACD;QACE,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,gCAAgC;QACxC,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE;YACP,oEAAoE;SACrE;KACF;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE;QAC1D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,8CAA8C,CAAC;KAC1D;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE;QAC1D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,oDAAoD,CAAC;KAChE;IACD;QACE,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE;QACzD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,4DAA4D,CAAC;KACxE;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE;QAC1D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,+DAA+D,CAAC;KAC3E;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE;QACzD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,mDAAmD,CAAC;KAC/D;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAE,EAAE;QAC7D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,gEAAgE,CAAC;KAC5E;IACD;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,EAAE;QAC/D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,qFAAqF,CAAC;KACjG;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,8BAA8B,EAAE,EAAE;QAC9D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,0EAA0E,CAAC;KACtF;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,EAAE;QAC5D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,4DAA4D,CAAC;KACxE;IACD;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,wBAAwB,EAAE,EAAE;QACxD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,2DAA2D,CAAC;KACvE;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE;QACzD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,2DAA2D,CAAC;KACvE;IACD;QACE,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,uBAAuB,EAAE,EAAE;QACvD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,6DAA6D,CAAC;KACzE;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,EAAE;QAC/D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,iEAAiE,CAAC;KAC7E;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,EAAE;QAC5D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,4DAA4D,CAAC;KACxE;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,gCAAgC,EAAE,EAAE;QAChE,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,oGAAoG,CAAC;KAChH;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE;QACzD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,0DAA0D,CAAC;KACtE;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE;QACtD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,mDAAmD,CAAC;KAC/D;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE;QACtD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,wDAAwD,CAAC;KACpE;IACD;QACE,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE;QAClD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,sEAAsE,CAAC;KAClF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE;QAC1D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,gEAAgE,CAAC;KAC5E;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE;QAC1D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,wFAAwF,CAAC;KACpG;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,8BAA8B,EAAE,EAAE;QAC9D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,4EAA4E,CAAC;KACxF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,wBAAwB,EAAE,EAAE;QACxD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,4DAA4D,CAAC;KACxE;IACD;QACE,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAE,EAAE;QACnD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,oEAAoE,CAAC;KAChF;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE;QACtD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,sDAAsD,CAAC;KAClE;IACD;QACE,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,wBAAwB,EAAE,EAAE,MAAM,EAAE,CAAC,gBAAgB,CAAC,EAAE;QACpF,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,mCAAmC,CAAC;KAC/C;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,gCAAgC,EAAE,EAAE;QAChE,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,4CAA4C,CAAC;KACxD;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,gCAAgC,EAAE,EAAE;QAChE,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,4DAA4D,CAAC;KACxE;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,8BAA8B,EAAE,EAAE;QAC9D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,qDAAqD,CAAC;KACjE;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,sCAAsC;QAC9C,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,mDAAmD;YACnD,0CAA0C;SAC3C;KACF;IACD;QACE,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE;QACzD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,0DAA0D;YAC1D,yCAAyC;SAC1C;KACF;IACD;QACE,IAAI,EAAE,KAAK;QACX,MAAM,EAAE,4BAA4B;QACpC,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,sCAAsC,CAAC;KAClD;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,eAAe,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,gBAAgB,CAAC,EAAE;QAClI,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,8CAA8C;YAC9C,4CAA4C;SAC7C;KACF;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,EAAE,MAAM,EAAE,CAAC,gBAAgB,EAAE,YAAY,CAAC,EAAE;QACtG,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,sDAAsD,CAAC;KAClE;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE;QACzD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,+CAA+C,CAAC;KAC3D;IACD;QACE,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,CAAC,gBAAgB,EAAE,YAAY,CAAC,EAAE;QAC3F,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,2DAA2D,CAAC;KACvE;IACD;QACE,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,+BAA+B;QACvC,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,sDAAsD;YACtD,4CAA4C;SAC7C;KACF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,uBAAuB,EAAE,EAAE;QACvD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,oDAAoD;YACpD,gDAAgD;YAChD,mCAAmC;SACpC;KACF;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,EAAE;QAC/D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,8DAA8D,CAAC;KAC1E;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,2BAA2B,EAAE,EAAE;QAC3D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,8DAA8D,CAAC;KAC1E;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE;QAC1D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,4DAA4D;YAC5D,+CAA+C;SAChD;KACF;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,EAAE;QAC/D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,4CAA4C,CAAC;KACxD;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE;QACzD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,mDAAmD;YACnD,qDAAqD;SACtD;KACF;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,EAAE;QAC5D,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,CAAC,2DAA2D,CAAC;KACvE;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,EAAE,MAAM,EAAE,CAAC,gBAAgB,CAAC,EAAE;QACxF,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,oDAAoD;YACpD,qDAAqD;YACrD,6CAA6C;SAC9C;KACF;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,EAAE;QAC/D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,yDAAyD,CAAC;KACrE;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,EAAE;QAC/D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,0DAA0D,CAAC;KACtE;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,2BAA2B,EAAE,EAAE;QAC3D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,mDAAmD,CAAC;KAC/D;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,qBAAqB,EAAE,EAAE;QACrD,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,8CAA8C,CAAC;KAC1D;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,8BAA8B,EAAE,EAAE;QAC9D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,oEAAoE,CAAC;KAChF;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,8BAA8B,EAAE,EAAE;QAC9D,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,CAAC,qEAAqE,CAAC;KACjF;IACD;QACE,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,8BAA8B;QACtC,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,oDAAoD;YACpD,wBAAwB;SACzB;KACF;IACD;QACE,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,0BAA0B;QAClC,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,yDAAyD;SAC1D;KACF;IACD;QACE,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,sBAAsB;QAC9B,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE;YACP,oDAAoD;YACpD,sCAAsC;SACvC;KACF;CACqC,CAAC;AAEzC,iDAAiD;AACjD,0CAA0C;AAC1C,MAAM,CAAC,MAAM,cAAc,GACxB,gBAAiD;KAC/C,MAAM,CAAC,CAAC,CAAC,EAAgC,EAAE,CAAC,QAAQ,IAAI,CAAC,CAAC;KAC1D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAEjC,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,UAA6B;IACtD,8CAA8C;IAC9C,qDAAqD;IACrD,iCAAiC;IACjC,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;QACtE,OAAO,gBAAgB,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC;IACD,MAAM,YAAY,GAAY,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,oCAAoC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,mCAAmC,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,EAAE,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAC7B,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC1B,CAAC,CAAC,IAAI;IACN,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;CACrB,CAAC,CACH,CAAC;AAEF,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;CAgBhB,CAAC;AAEF,MAAM,cAAc,GAAG;yCACkB,CAAC;AAE1C,MAAM,MAAM,GAAG;;;;CAId,CAAC;AAEF,SAAS,SAAS,CAAC,OAA0B;IAC3C,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IACpE,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5E,OAAO,CAAC,IAAI,EAAE,GAAG,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,UAAU,CAAC,QAAuC;IACzD,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC;SAC3D,GAAG,CAAC,SAAS,CAAC;SACd,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAChB,QAAQ;IACR,qBAAqB;IACrB,UAAU,CAAC,OAAO,CAAC;IACnB,2FAA2F;IAC3F,UAAU,CAAC,eAAe,CAAC;IAC3B,uBAAuB;IACvB,cAAc;IACd,MAAM,CAAC"}
|
package/docs/cli.md
CHANGED
|
@@ -889,6 +889,9 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
889
889
|
| `okstra stage-map <task-key> [--cwd <dir>\|--project <dir>]` | Dump the task's implementation-planning Stage Map as JSON: `{ ok, taskKey, taskRoot, state, sourcePlanPath, stages:[{stage_number,title,depends_on,step_count,cancelled}], doneStages:[int] }`. Each stage row carries `cancelled: true` when the plan marks that Stage Map row `status: cancelled`; such a stage is never selected, cannot be closed, and is left out of whole-task final verification and release handoff. `sourcePlanPath` is the task's latest implementation-planning report — the authority on which stages exist, so a plan amendment's added stages are selectable as soon as the amended plan lands. `state` is `ready` for a resolved source and `missing` when no Stage Map exists; a corrupt source returns a structured non-zero error instead of silently selecting another report. `doneStages` is read from the implementation-planning stage consumer state (with carry recovery). This is the read-side source `/okstra-schedule-gen [task-group]` uses to derive selectable unfinished stages and their completed dependency closure |
|
|
890
890
|
| `okstra stage-close <task-key> --stage <N> --from-commit <sha> [--supersede-failed <reason>] [--cwd <dir>\|--project <dir>]` | Record the `done` stage-consumer row an implementation run would have written, for a stage whose work is already committed but which never registered as done — the run ended before writing its carry sidecar, and `backfill_done_from_carry` recovers only from that file. Without it `stage-map` reports `doneStages: []` while the branch carries the commit, the next plan re-describes the stage, and every RED expectation it produces is unreachable. Refuses unless the Stage Map has that stage and does not mark it cancelled, no `done`/`failed` row exists for it, `--from-commit` resolves to a commit in the project repo, and the stage's conformance gate permits progress — the same `decide_conformance_gate` the run validator uses, so a stage closed here is not one the validator would have blocked. `--supersede-failed <reason>` closes a stage whose last row is `failed` under the same checks, for a failure that no longer applies (the checks ran in the wrong environment and the commit needs no product edit); the `done` row records `superseded_status`, the reason, the latest plan path and the conformance verdict. Closing also moves the `stage-<N>-exit` tag and releases the stage reservation, exactly as a normal stage completion does. Emits `{ ok, taskKey, taskRoot, stage, headCommit, conformance, consumersPath, supersededFailed, sourcePlanPath }` |
|
|
891
891
|
| `okstra stage-reopen <task-key> --stage <N> --reason <why> [--evidence <path>] [--cwd <dir>\|--project <dir>]` | Append a `failed` stage-consumer row after a stage's `done` row, so `/okstra-run` offers that stage again for a fix run and its dependents stop branching from the withdrawn head. Use it when a later verification found a defect in a done stage — a single-stage final-verification that ended `blocked` and points at `implementation` is the case the wizard otherwise refuses. The row records the reason, `reopened_by: stage-reopen`, the head it withdraws and, with `--evidence`, the project-relative report path. Refuses a stage that is not in the latest Stage Map, is cancelled, or whose last row is not `done`. Emits `{ ok, taskKey, stage, headCommit, reason, evidencePath, consumersPath }` |
|
|
892
|
+
| `okstra correction prompt --run-manifest <path> --round <N> --role <executor\|verifier> --base <sha> --finding <F-id> [--finding <F-id> ...]` | Print the instruction body for one correction-round prompt of an implementation run, built from the run's convergence record: the findings to fix, the stage HEAD before the round, and the executor's or verifiers' rules. Pass it to `okstra agent-prompt materialize --dispatch-kind correction-r<N>`. At most 2 rounds; exit 1 on an unknown finding or round. |
|
|
893
|
+
| `okstra stage-done <task-key> --stage <N> --carry <carry.json> --report <path> [--cwd <dir>\|--project <dir>]` | Settle an implementation stage whose verdict is not FAIL: write the executor's Stage Carry Evidence JSON to the flat `runs/implementation/carry/stage-<N>.json`, then append the `done` row with that carry path, the report path relative to its run directory, the carry head and the completion time. A reopened stage's previous sidecar moves to `carry/superseded/stage-<N>-from-<task-type>-<seq>.json`. Refuses a carry for another stage, a failed carry, and a stage already done at another head; a repeat with the same carry writes nothing new. Prints JSON; exit 1 on a refusal. |
|
|
894
|
+
| `okstra stage-fail <task-key> --stage <N> --head-commit <sha> --report <path> --reason <why> [--cwd <dir>\|--project <dir>]` | Append the `failed` stage-consumer row an implementation run writes when its verdict is FAIL or no verifier returned a result. Dependents stay blocked and the stage becomes selectable for a fix run. Refuses a stage missing from or cancelled in the latest Stage Map, or already `done` (use `stage-reopen`). Prints JSON; exit 1 on a refusal. |
|
|
892
895
|
| `okstra discussion <confirm-subject\|ask\|address\|answer\|decide> <task-key> … --run-manifest <path>` / `okstra discussion draft <task-key>` | The facilitator's only way to write a discussion task's record under `<task-root>/discussion/`: the confirmed subject and question, questions for the user (`ask`), the user's question to one worker (`address`), answers and user decisions. `--run-manifest` must be a discussion run manifest of the same task; authors are `leader` or a worker of that run, and only a question's addressee answers it. A resent record returns the stored one (`created: false`). Every write rebuilds `draft.json`; `draft` prints it as the fixed text every participant reads. Write commands emit `{ ok, created, record, pendingForUser, pendingForParticipants }`. `add-material --kind <evidence|alternative>` records new evidence or a new alternative, and `status` prints the phase, the next question for the user, unrecovered failures and remaining disagreements |
|
|
893
896
|
| `okstra discussion <cycle-open\|settle\|cycle-close> <task-key> --run-manifest <path>` / `okstra discussion recover <task-key> --failure <X-NNNN> --choice <retry\|replace\|reduce> --run-manifest <path>` / `okstra discussion <question-prompt\|collect-answer> <task-key> --question <Q-NNNN> --run-manifest <path>` | The research, refutation and question cycle of a discussion, one research cycle per run. `cycle-open` writes the research instruction from the record and records its input references (start inputs, subject, answers, materials), or returns why nothing is dispatched: `await-user`, `await-participant`, `await-recovery`, `present-options` (the references equal the last closed cycle's) or `prepare-run` (the next cycle needs a run prepared with `--discussion-start <task-key>`). `settle` records each analyser's `initial` result and each failure the dispatcher left after its retry loop (`start` when the batch could not launch, `after-retries` otherwise); `recover` records the user's choice for one failure. `cycle-close` validates the run's convergence final state and imports its findings as claims with their origin worker and verdicts. `question-prompt` writes one direct question's instruction and `agent-prompt materialize --batch` file (dispatch kind `discussion-question`), and `collect-answer` records the addressee's whole result as the answer |
|
|
894
897
|
| `okstra discussion <add-requirement\|add-scope> <task-key> --text <what> --author <user\|leader\|worker-id> --run-manifest <path>` / `okstra discussion confirm-completion <task-key> --draft-version <sha256:…> --direction <text> --risk <text> --run-manifest <path>` / `okstra discussion reopen <task-key> --revision <task-key/revision-NNN> --reason <text> --run-manifest <path>` / `okstra discussion <revisions\|record> <task-key>` / `okstra discussion revision-show <task-key> --revision <id>` / `okstra discussion memory-sync <task-key> [--revision <id> [--summary-file <path>]]` | User completion of a discussion. `add-requirement` (`--applies-to <common\|follow-up label>`) and `add-scope --kind <in-scope\|excluded>` record the current draft's requirements and scope; an item the draft already holds is returned instead of added twice. After `reopen` the draft starts with the reopened revision's requirements and scope under their original record ids, marked with that revision, so unchanged items are not entered again; `okstra discussion withdraw <task-key> --item <N-NNNN\|B-NNNN> --reason <text> --run-manifest <path>` removes one item with the user's reason, and replacing an item is a withdrawal followed by an addition. `confirm-completion` binds the user's direction and risk confirmation to the draft version `status` prints, refuses a stale version or a draft missing its subject, a requirement, a scope entry, a closed research cycle, an answer or a failure choice, and publishes one read-only revision `<task-root>/discussion/revisions/revision-NNN.json` (id `<task-key>/revision-NNN`); a resent confirmation returns it. A completed discussion takes only `reopen`, which names the latest revision and the reason; the next revision carries both and lists under `itemChanges` the items it carried, added and withdrawn. `revisions` lists the publications, `revision-show` prints one revision byte-for-byte, `record` prints the draft read model with every research result in full. The run's final report references the revision only by id and content digest. After publication, `confirm-completion` registers the revision in the Memory Book without a prompt (`okstra memory add --source-key discussion:<revision-id>`): a summary of decisions, disagreements, risks and unverified scope with the revision id, content digest, project and task, kept with its registration state in `<task-root>/discussion/memory/`; its `memory` field names the entry or the state. A failed registration leaves the revision published and `pending`; `status` lists it under `memoryRegistration`, and `okstra discussion memory-sync <task-key>` retries it with the same source key. A summary refused as a likely secret is `refused` and is not retried until `memory-sync --revision <id> --summary-file <path>` supplies a changed summary |
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -180,6 +180,9 @@ Every `okstra` command the lead documents cite, grouped by phase, each spelled w
|
|
|
180
180
|
|---|---|---|
|
|
181
181
|
| `okstra report-finalize --project-root <dir> --run-manifest <path> --report <path>` | Run the whole Phase 7 sequence; do not run its steps separately. Without `--only` it records `phase-7-persist` first; emit its `progressLines` | `report-writer` "Phase 6 → Phase 7 execution sequence" |
|
|
182
182
|
| `okstra handoff record-verified --plan-run-root <dir> --stage <N> --report-path <path> --data-json <path>` | Record an accepted final-verification against its stage. `report-finalize` runs it in its `record-verified` step; run it by hand only to repair a registry after that step failed | `report-writer` "Phase 6 → Phase 7 execution sequence" |
|
|
183
|
+
| `okstra correction prompt --run-manifest <path> --round <N> --role <executor\|verifier> --base <sha> --finding <F-id>` | Write a correction-round instruction body; materialize it with dispatch kind `correction-r<N>` | `_implementation-deliverable.md` "Correction round" |
|
|
184
|
+
| `okstra stage-done <task-key> --stage <N> --carry <carry.json> --report <path>` | Settle an implementation stage whose synthesised verdict is not FAIL: writes the flat `runs/implementation/carry/stage-<N>.json` sidecar and appends the `done` row — never write either by hand | `_implementation-deliverable.md` "Lead post-stage persistence" |
|
|
185
|
+
| `okstra stage-fail <task-key> --stage <N> --head-commit <sha> --report <path> --reason <why>` | Record an implementation stage whose synthesised verdict is FAIL, or that ended with no verifier result, as `failed` — never call `append_consumer` from python | `_implementation-deliverable.md` "Lead post-stage persistence" |
|
|
183
186
|
| `okstra team teardown --project-root <dir> --run-manifest <path>` | Close every recorded pane at the end of the run | cmux adapter "Semantic operation mapping" |
|
|
184
187
|
|
|
185
188
|
**Names that do not exist.** Lead sessions have called these; each fails with `unknown command`. Use the command on the right.
|
|
@@ -390,7 +393,7 @@ For `--task-type implementation` runs, the task bundle additionally pins one of
|
|
|
390
393
|
|
|
391
394
|
Lead MUST dispatch Edit/Write-bearing work only through that executor binding: use the host primitive with `hostModelValue` for `runner=native-session`. For `runner=cli-wrapper`, use `okstra team dispatch` when `terminalBackend` is `cmux-pane`, or `okstra worker-dispatch` with `modelExecutionValue` otherwise. The other providers in the roster still run as read-only verifiers in the same run; the executor's own provider does not, because its worker ID materializes as the executor on every dispatch — so the diff is reviewed context-isolated by the remaining verifiers. Session isolation is the primary self-review safeguard — a verifier reusing the executor's model variant is acceptable in a distinct session. A different model variant (e.g. executor=opus / Claude verifier=sonnet) is recommended but not mandatory.
|
|
392
395
|
|
|
393
|
-
The one exception is the **lead minor fix**: after the verifier round and Phase 5.5 convergence, and before the report-writer dispatch, the lead edits and commits in the stage worktree itself to fix verifier FAIL findings that meet every eligibility rule in `scripts/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md` "Lead minor fix" — a local fix at the cited location, at most 30 changed lines in total, no change to a test's expected values, dependencies, schemas, migrations or config of record, only files inside the stage's planned paths or already changed by the executor, one pass per run. It then re-runs the covering checks through `okstra worktree-lock --worktree <dir> --command <text>` and records them in `implementation.leadFixes`. No worker dispatch is open at that point, so no read-only worker's mutation audit window covers the edit. Any finding outside those rules goes through the executor in a fix run. **Enforced:** `validators/validate-run.py` `_validate_lead_fixes` fails a fix recorded as passing with a failing check, a fix over 30 lines, and a stage settled over a FAIL that no passing fix answers; the remaining eligibility rules are instructions only.
|
|
396
|
+
The one exception is the **lead minor fix**: after the verifier round and Phase 5.5 convergence, and before the report-writer dispatch, the lead edits and commits in the stage worktree itself to fix verifier FAIL findings that meet every eligibility rule in `scripts/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md` "Lead minor fix" — a local fix at the cited location, at most 30 changed lines in total, no change to a test's expected values, dependencies, schemas, migrations or config of record, only files inside the stage's planned paths or already changed by the executor, one pass per run. It then re-runs the covering checks through `okstra worktree-lock --worktree <dir> --command <text>` and records them in `implementation.leadFixes`. No worker dispatch is open at that point, so no read-only worker's mutation audit window covers the edit. Any finding outside those rules goes through the executor — first in a correction round inside this run (`_implementation-deliverable.md` "Correction round", at most 2), and in a fix run only when the finding needs a plan change or the rounds are spent. **Enforced:** `validators/validate-run.py` `_validate_lead_fixes` fails a fix recorded as passing with a failing check, a fix over 30 lines, and a stage settled over a FAIL that no passing fix answers; the remaining eligibility rules are instructions only.
|
|
394
397
|
|
|
395
398
|
Executor is chosen at run-prep time via `--executor <claude|codex|antigravity>` (or `OKSTRA_DEFAULT_EXECUTOR`, fallback `claude`); the model used by the executor is taken from the corresponding worker model flag (`--claude-model` / `--codex-model` / `--antigravity-model`). For CLI-backed executors, the underlying file mutation happens inside the executor CLI's own auto-edit mode (e.g. `codex exec --sandbox danger-full-access`), not through the lead runtime's `write_artifact` operation.
|
|
396
399
|
|
|
@@ -227,6 +227,14 @@ _BLOCKING: tuple[tuple[str, str], ...] = (
|
|
|
227
227
|
"stage_fix_carry.py 는 통과로 기록된 리드 수정이 답한 FAIL 을 다시 "
|
|
228
228
|
"fix run 으로 넘기지 않는다.",
|
|
229
229
|
),
|
|
230
|
+
# 수정 라운드의 FAIL 은 correctionRounds 에만 남는다(`_implementation-deliverable.md`
|
|
231
|
+
# "Correction round"). 기록이 원장과 어긋나면 그 FAIL 이 보고서에서 사라진다.
|
|
232
|
+
(
|
|
233
|
+
"correction-round BLOCKING:",
|
|
234
|
+
"수정 라운드 기록이 실제 dispatch 나 마지막 재검증 verdict 와 어긋난다 — "
|
|
235
|
+
"verifierResults 가 마지막 라운드의 verdict 가 아니면 release_gate.py 와 "
|
|
236
|
+
"stage_fix_carry.py 가 다른 라운드의 판정으로 stage 를 정착시키거나 fix run 을 연다.",
|
|
237
|
+
),
|
|
230
238
|
(
|
|
231
239
|
"implementation run declares stage-",
|
|
232
240
|
"stage 캐리 사이드카가 디스크에 없다 — consumers.py 의 "
|
|
@@ -21,6 +21,7 @@ from pathlib import Path
|
|
|
21
21
|
from typing import Mapping
|
|
22
22
|
|
|
23
23
|
from okstra_ctl.convergence_engine import grouped_input_digest
|
|
24
|
+
from okstra_ctl.correction_round import correction_round
|
|
24
25
|
from okstra_ctl.execution_identity import Attempt, ExecutionManifest
|
|
25
26
|
from okstra_ctl.execution_manifest import read_execution_manifest_view
|
|
26
27
|
from okstra_ctl.json_boundary import (
|
|
@@ -101,7 +102,11 @@ def groups_digest_ok(state_dir: Path, suffix: str, document: dict) -> bool:
|
|
|
101
102
|
|
|
102
103
|
|
|
103
104
|
def discovery_attempts(manifest: ExecutionManifest) -> dict[str, list[Attempt]]:
|
|
104
|
-
"""교정
|
|
105
|
+
"""교정 실행과 수정 라운드 재검증은 발견 결과를 대체하지만 재검증 투표는 발견 출처가 아니다.
|
|
106
|
+
|
|
107
|
+
수정 라운드(`correction-r<N>`) 뒤 수렴을 다시 시작하면 마지막 라운드의 verifier 결과가
|
|
108
|
+
출처여야 한다. 빠지면 고치기 전 FAIL 결과로 다시 수렴한다.
|
|
109
|
+
"""
|
|
105
110
|
latest: dict[str, Attempt] = {}
|
|
106
111
|
for attempt in manifest.attempts:
|
|
107
112
|
current = latest.get(attempt.invocation_ref)
|
|
@@ -109,7 +114,8 @@ def discovery_attempts(manifest: ExecutionManifest) -> dict[str, list[Attempt]]:
|
|
|
109
114
|
latest[attempt.invocation_ref] = attempt
|
|
110
115
|
by_role: dict[str, list[Attempt]] = {}
|
|
111
116
|
for invocation in manifest.invocations:
|
|
112
|
-
if invocation.dispatch_kind not in {"initial", "correction"}
|
|
117
|
+
if (invocation.dispatch_kind not in {"initial", "correction"}
|
|
118
|
+
and correction_round(invocation.dispatch_kind) is None):
|
|
113
119
|
continue
|
|
114
120
|
attempt = latest.get(invocation.invocation_ref)
|
|
115
121
|
if attempt is not None:
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""`okstra correction` CLI — prints one correction-round instruction body (`correction_round`)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from .convergence import canonical_run_state_artifact, validated_run_authority
|
|
9
|
+
from .correction_round import CorrectionRoundError, correction_instruction
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
_CLI_EPILOG = r"""Usage:
|
|
13
|
+
okstra correction prompt --run-manifest <path> --round <N> --role <executor|verifier> \
|
|
14
|
+
--base <sha> --finding <F-id> [--finding <F-id> ...]
|
|
15
|
+
|
|
16
|
+
Prints the instruction body for one correction-round prompt; pass it to
|
|
17
|
+
`okstra agent-prompt materialize --instruction` with --dispatch-kind correction-r<N>.
|
|
18
|
+
Findings are read from the run's convergence record. Exit 1 on a refusal.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main(argv: list[str] | None = None) -> int:
|
|
23
|
+
parser = argparse.ArgumentParser(
|
|
24
|
+
prog="okstra correction",
|
|
25
|
+
description="Fix confirmed verifier findings inside the same implementation run.",
|
|
26
|
+
epilog=_CLI_EPILOG,
|
|
27
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
28
|
+
)
|
|
29
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
30
|
+
prompt = commands.add_parser("prompt", help="print one correction-round instruction body")
|
|
31
|
+
prompt.add_argument("--run-manifest", type=Path, required=True)
|
|
32
|
+
prompt.add_argument("--round", type=int, required=True)
|
|
33
|
+
prompt.add_argument("--role", choices=("executor", "verifier"), required=True)
|
|
34
|
+
prompt.add_argument("--base", required=True,
|
|
35
|
+
help="the stage HEAD before this round")
|
|
36
|
+
prompt.add_argument("--finding", action="append", default=[], required=True,
|
|
37
|
+
help="a convergence finding id to fix; repeat for several")
|
|
38
|
+
args = parser.parse_args(argv)
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
authority = validated_run_authority(args.run_manifest)
|
|
42
|
+
if authority.task_type != "implementation":
|
|
43
|
+
raise CorrectionRoundError("correction rounds exist only in implementation runs")
|
|
44
|
+
convergence_path = canonical_run_state_artifact(
|
|
45
|
+
authority, manifest_field="convergenceStatePath", prefix="convergence",
|
|
46
|
+
label="convergence state",
|
|
47
|
+
)
|
|
48
|
+
print(correction_instruction(
|
|
49
|
+
convergence_path=convergence_path, round_number=args.round, role=args.role,
|
|
50
|
+
base=args.base, finding_ids=args.finding,
|
|
51
|
+
))
|
|
52
|
+
except (CorrectionRoundError, OSError, ValueError) as exc:
|
|
53
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
54
|
+
return 1
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""`okstra correction` — fix confirmed verifier findings inside the same implementation run.
|
|
2
|
+
|
|
3
|
+
A verifier FAIL used to end the run: FAIL report, `failed` row, finalize, a new wizard pass and
|
|
4
|
+
a fix run that repeated the executor, every verifier and the report writer. Measured
|
|
5
|
+
2026-10-17 (figma-plugin dev-11377 stage 1): one field rename (2 source lines, 24 test
|
|
6
|
+
expectations) cost that whole cycle, because the lead minor fix may not change test
|
|
7
|
+
expectations. A correction round sends the executor a bounded fix and the verifiers a
|
|
8
|
+
re-verification of that fix, then the run writes its report once.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Mapping, Sequence
|
|
15
|
+
|
|
16
|
+
from .execution_identity import ExecutionManifest
|
|
17
|
+
from .json_boundary import load_owned_object
|
|
18
|
+
|
|
19
|
+
MAX_CORRECTION_ROUNDS = 2
|
|
20
|
+
CORRECTION_DISPATCH_KIND_PREFIX = "correction-r"
|
|
21
|
+
_ROUND_RE = re.compile(r"^correction-r([1-9][0-9]*)$")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CorrectionRoundError(ValueError):
|
|
25
|
+
"""A correction dispatch or instruction request that the run cannot accept."""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def correction_round(dispatch_kind: str) -> int | None:
|
|
29
|
+
"""`correction-r2` → 2; any other dispatch kind → None."""
|
|
30
|
+
match = _ROUND_RE.match(dispatch_kind)
|
|
31
|
+
return int(match.group(1)) if match else None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def validate_correction_dispatch(
|
|
35
|
+
manifest: ExecutionManifest, jobs: Sequence[object],
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Refuse a correction dispatch that skips a step or exceeds the round cap.
|
|
38
|
+
|
|
39
|
+
The executor fix of round N comes after round N-1 was re-verified, and the verifiers of
|
|
40
|
+
round N re-verify only after the executor of round N returned a result; otherwise a
|
|
41
|
+
verifier reads a tree the fix has not reached, as the executor/verifier batch split
|
|
42
|
+
already guards for the initial round.
|
|
43
|
+
"""
|
|
44
|
+
roles = {row.role_execution_ref: row.role for row in manifest.role_executions}
|
|
45
|
+
finished_ok = {
|
|
46
|
+
row.invocation_ref for row in manifest.attempts
|
|
47
|
+
if row.finished_at is not None and row.status == "ok"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
def completed(round_number: int, role: str) -> bool:
|
|
51
|
+
return any(
|
|
52
|
+
correction_round(row.dispatch_kind) == round_number
|
|
53
|
+
and roles.get(row.role_execution_ref) == role
|
|
54
|
+
and row.invocation_ref in finished_ok
|
|
55
|
+
for row in manifest.invocations
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
for job in jobs:
|
|
59
|
+
round_number = correction_round(getattr(job, "dispatch_kind", ""))
|
|
60
|
+
if round_number is None:
|
|
61
|
+
continue
|
|
62
|
+
if round_number > MAX_CORRECTION_ROUNDS:
|
|
63
|
+
raise CorrectionRoundError(
|
|
64
|
+
f"{job.dispatch_kind}: a run holds at most {MAX_CORRECTION_ROUNDS} correction "
|
|
65
|
+
"rounds; end the run FAIL and let a fix run take the remaining findings"
|
|
66
|
+
)
|
|
67
|
+
audience = getattr(job, "audience", "")
|
|
68
|
+
if audience == "implementation-executor":
|
|
69
|
+
if round_number > 1 and not completed(round_number - 1, "verifier"):
|
|
70
|
+
raise CorrectionRoundError(
|
|
71
|
+
f"{job.dispatch_kind}: correction round {round_number - 1} has no "
|
|
72
|
+
"re-verification result yet; await its verifiers first"
|
|
73
|
+
)
|
|
74
|
+
if completed(round_number, "implementer"):
|
|
75
|
+
raise CorrectionRoundError(
|
|
76
|
+
f"{job.dispatch_kind}: the executor already returned this round's fix; "
|
|
77
|
+
"dispatch the verifiers, or start the next round"
|
|
78
|
+
)
|
|
79
|
+
elif audience == "implementation-verifier":
|
|
80
|
+
if not completed(round_number, "implementer"):
|
|
81
|
+
raise CorrectionRoundError(
|
|
82
|
+
f"{job.dispatch_kind}: the executor has not returned this round's fix; "
|
|
83
|
+
"dispatch and await it before re-verifying"
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
raise CorrectionRoundError(
|
|
87
|
+
f"{job.dispatch_kind} is an implementation executor or verifier dispatch, "
|
|
88
|
+
f"not {audience or 'this audience'}"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _finding_lines(findings: Sequence[Mapping[str, object]]) -> list[str]:
|
|
93
|
+
lines = []
|
|
94
|
+
for finding in findings:
|
|
95
|
+
workers = ", ".join(str(w) for w in finding.get("consensusWorkers") or []) or str(
|
|
96
|
+
finding.get("originWorker") or "")
|
|
97
|
+
lines.append(
|
|
98
|
+
f"- `{finding['findingId']}` ({finding.get('classification', '')}; {workers}): "
|
|
99
|
+
f"{finding.get('summary', '')} — evidence: {finding.get('originEvidence', '')}"
|
|
100
|
+
)
|
|
101
|
+
return lines
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def correction_instruction(
|
|
105
|
+
*, convergence_path: Path, round_number: int, role: str, base: str,
|
|
106
|
+
finding_ids: Sequence[str],
|
|
107
|
+
) -> str:
|
|
108
|
+
"""The instruction body one correction-round prompt carries, read from the convergence record."""
|
|
109
|
+
if not 1 <= round_number <= MAX_CORRECTION_ROUNDS:
|
|
110
|
+
raise CorrectionRoundError(f"--round must be 1..{MAX_CORRECTION_ROUNDS}")
|
|
111
|
+
if not finding_ids:
|
|
112
|
+
raise CorrectionRoundError("name at least one --finding")
|
|
113
|
+
if not base.strip():
|
|
114
|
+
raise CorrectionRoundError("--base is required: the stage HEAD before this round")
|
|
115
|
+
record = load_owned_object(convergence_path, artifact="convergence record")
|
|
116
|
+
by_id = {
|
|
117
|
+
str(row.get("findingId")): row for row in record.get("findings") or []
|
|
118
|
+
if isinstance(row, Mapping)
|
|
119
|
+
}
|
|
120
|
+
missing = [fid for fid in finding_ids if fid not in by_id]
|
|
121
|
+
if missing:
|
|
122
|
+
raise CorrectionRoundError(
|
|
123
|
+
f"findings not in {convergence_path.name}: {', '.join(missing)}; "
|
|
124
|
+
f"it holds {', '.join(sorted(by_id)) or 'none'}"
|
|
125
|
+
)
|
|
126
|
+
findings = [by_id[fid] for fid in finding_ids]
|
|
127
|
+
results_dir = convergence_path.parent.parent / "worker-results"
|
|
128
|
+
header = [
|
|
129
|
+
f"- Convergence record: `{convergence_path}`",
|
|
130
|
+
f"- Verifier results (each finding's suggested fix): `{results_dir}`",
|
|
131
|
+
f"- Stage HEAD before this round: `{base.strip()}`",
|
|
132
|
+
"- Findings:",
|
|
133
|
+
*(" " + line for line in _finding_lines(findings)),
|
|
134
|
+
"",
|
|
135
|
+
]
|
|
136
|
+
if role == "executor":
|
|
137
|
+
return "\n".join([
|
|
138
|
+
f"## Correction Round {round_number} — fix confirmed verifier findings",
|
|
139
|
+
"",
|
|
140
|
+
*header,
|
|
141
|
+
"Rules:",
|
|
142
|
+
"- Change only what these findings require, inside this stage's planned paths or "
|
|
143
|
+
"files this stage already changed. A finding that needs a new plan step, a new "
|
|
144
|
+
"dependency, or a schema or migration change is not fixed here: stop and say so.",
|
|
145
|
+
"- Update a test's expected value only where the finding shows the oracle itself is "
|
|
146
|
+
"wrong; never weaken or delete an assertion to make a test pass.",
|
|
147
|
+
"- Follow the executor sidecar's TDD, pre-commit diff review and self-check, and "
|
|
148
|
+
"commit with a Conventional Commit whose body names the finding ids.",
|
|
149
|
+
"- Re-run the plan validation commands that cover the fix, and end with a "
|
|
150
|
+
"`### Stage Carry Evidence` block whose `stageCommitRange.head` is the new HEAD.",
|
|
151
|
+
])
|
|
152
|
+
if role == "verifier":
|
|
153
|
+
return "\n".join([
|
|
154
|
+
f"## Correction Round {round_number} — re-verify the fix",
|
|
155
|
+
"",
|
|
156
|
+
*header,
|
|
157
|
+
"Rules:",
|
|
158
|
+
f"- For each finding, state `fixed` or `not fixed` against `git diff {base.strip()}..HEAD`, "
|
|
159
|
+
"with `path:line` evidence.",
|
|
160
|
+
"- Apply the static review's blocking checks to the correction diff only; the rest of "
|
|
161
|
+
"the stage was reviewed in the initial round.",
|
|
162
|
+
"- Re-run every plan validation command, as the verifier sidecar's Fix-run "
|
|
163
|
+
"incremental scope requires.",
|
|
164
|
+
"- Verdict `PASS` when every finding is fixed and no blocking check hits the "
|
|
165
|
+
"correction diff; otherwise `FAIL`, with each remaining or new finding in the "
|
|
166
|
+
"usual format.",
|
|
167
|
+
])
|
|
168
|
+
raise CorrectionRoundError("--role must be executor or verifier")
|
|
@@ -74,6 +74,11 @@ from .domain.worker_runtime import (
|
|
|
74
74
|
)
|
|
75
75
|
from .ports.worker_runtime import WorkerRuntimePort
|
|
76
76
|
from .execution_identity import Attempt, ExecutionManifest, Invocation, RoleExecution
|
|
77
|
+
from .correction_round import (
|
|
78
|
+
CorrectionRoundError,
|
|
79
|
+
correction_round,
|
|
80
|
+
validate_correction_dispatch,
|
|
81
|
+
)
|
|
77
82
|
from .execution_manifest import (
|
|
78
83
|
ExecutionManifestError,
|
|
79
84
|
finish_attempt_mutation,
|
|
@@ -403,6 +408,7 @@ def build_dispatch_plan(
|
|
|
403
408
|
# Ahead of the per-prompt checks: a batch the lead must split is a plan-shape
|
|
404
409
|
# problem, and reporting a prompt-header error for a doomed batch buries it.
|
|
405
410
|
_validate_implementation_phase_order(jobs)
|
|
411
|
+
_validate_correction_rounds(manifest_path, jobs)
|
|
406
412
|
_validate_dispatch_prompts(manifest, active_context, jobs)
|
|
407
413
|
_reject_stale_schema_excerpt(project_root, manifest, jobs)
|
|
408
414
|
return DispatchPlan(
|
|
@@ -434,6 +440,7 @@ def dispatch_plan(
|
|
|
434
440
|
plan = _ensure_runtime_chain(plan)
|
|
435
441
|
_validate_report_writer_isolation(plan.jobs)
|
|
436
442
|
_validate_implementation_phase_order(plan.jobs)
|
|
443
|
+
_validate_correction_rounds(plan.manifest_path, plan.jobs)
|
|
437
444
|
_revalidate_plan_role_executions(plan)
|
|
438
445
|
pane_backends = sorted(
|
|
439
446
|
{job.backend for job in plan.jobs if job.backend == BACKEND_CMUX_PANE}
|
|
@@ -538,6 +545,7 @@ def dispatch_cli_wrapper_plan(
|
|
|
538
545
|
plan = _ensure_runtime_chain(plan)
|
|
539
546
|
_validate_report_writer_isolation(plan.jobs)
|
|
540
547
|
_validate_implementation_phase_order(plan.jobs)
|
|
548
|
+
_validate_correction_rounds(plan.manifest_path, plan.jobs)
|
|
541
549
|
_revalidate_plan_role_executions(plan)
|
|
542
550
|
if before_start is not None:
|
|
543
551
|
before_start(plan)
|
|
@@ -628,6 +636,16 @@ def _validate_implementation_phase_order(jobs: Sequence[WorkerJob]) -> None:
|
|
|
628
636
|
)
|
|
629
637
|
|
|
630
638
|
|
|
639
|
+
def _validate_correction_rounds(manifest_path: Path, jobs: Sequence[WorkerJob]) -> None:
|
|
640
|
+
"""A `correction-r<N>` job runs only in its round order and within the round cap."""
|
|
641
|
+
if not any(correction_round(job.dispatch_kind) is not None for job in jobs):
|
|
642
|
+
return
|
|
643
|
+
try:
|
|
644
|
+
validate_correction_dispatch(read_execution_manifest(manifest_path), jobs)
|
|
645
|
+
except CorrectionRoundError as exc:
|
|
646
|
+
raise DispatchError(str(exc)) from exc
|
|
647
|
+
|
|
648
|
+
|
|
631
649
|
def _named_role(worker_ids: Sequence[str], role: str) -> str:
|
|
632
650
|
"""`verifier codex` for one, `verifiers codex, antigravity` for several.
|
|
633
651
|
|
package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md
CHANGED
|
@@ -13,11 +13,12 @@ are collected and convergence finished. Phase 1-5 do not need it.
|
|
|
13
13
|
- **Plan link & approval evidence**: path to the approved `final-report.md`, the exact quoted approval marker, AND the executed stage number / title quoted from the Stage Map row. For a selected-direction plan, also quote `selectedDirectionRef.optionId`, `snapshotPath`, and the validated snapshot digest; for a legacy plan, quote the effective `implementation-option` or the Recommended Option fallback.
|
|
14
14
|
- **Commit list**: each commit's SHA (or short SHA), message, and the plan step(s) / TDD cycle it satisfies. A lead minor fix commit is listed too, with `planStep` `Lead minor fix (<finding ids>)`.
|
|
15
15
|
- **Lead minor fixes**: when the lead fixed verifier findings in this run, pass each `implementation.leadFixes[]` entry to the report writer as recorded (§"Lead minor fix"). Omit the field when there was none.
|
|
16
|
+
- **Correction rounds**: when this run ran correction rounds, pass one `implementation.correctionRounds[]` entry per round to the report writer — `round`, `findingIds`, `baseCommit`, `commit`, each verifier's re-verification `verifierVerdicts`, and `result` (§"Correction round"). `verifierResults` then carries the last round's verdicts. Omit the field when there was none.
|
|
16
17
|
- **Diff summary**: capture `git diff --stat <base>..<captured-head>` and `git diff --numstat <base>..<captured-head>` for the full implementation stage, including after a fix run. Supply both outputs to the report writer; put each file's added/deleted counts alone in `diffSummary.files[].lines` (`+150/-0`) and one sentence on what the change in that file does in `diffSummary.files[].summary` — the report renders `summary` as the file's "what it does" column and `lines` as a separate number column. Do not substitute a fix-run aggregate or carry forward older statistics. If the captured commits are unavailable, identify the missing reference in the evidence instead of inventing counts.
|
|
17
18
|
- **Change narrative scope**: `userNarrative.changeExplanation` describes the same scope as `diffSummary` — the whole stage from its base, every file the table lists. On a fix run, state what the fix run itself changed (its commits and files) as a separate sentence; never present the fix-run delta as the stage's change.
|
|
18
19
|
- **Out-of-plan edits block**: every file edited that was not in the approved plan's file list, with rationale (empty block is acceptable and preferred)
|
|
19
20
|
- **Clarification answers carried in**: when `instruction-set/clarification-response.md` exists, it holds the user's answers to the approved plan's `## 1. Clarification Items` rows. The report MUST render the `## 0. Clarification Response Carried In From Previous Run` section (set `clarificationCarryIn.sourceFile` to that path) and, for every carried-over `## 1.` row whose answer appears there, record the answer in the `User input` cell and flip `Status` to `resolved`. A row left `open`/`answered` despite a matching user answer is a contract violation; an answer that materially changes scope beyond the approved plan is routed to a new `implementation-planning` run, not silently executed.
|
|
20
|
-
- **Stage sidecar evidence**: set `stageSidecarEvidence.carryJson` to the
|
|
21
|
+
- **Stage sidecar evidence**: set `stageSidecarEvidence.carryJson` to the `carryPath` that `okstra stage-done` printed — the flat `runs/implementation/carry/stage-<N>.json`, never a path under the run's `stage-<N>/` directory — followed by a one-line summary of its payload — stage number, step results by status, stage commit range, number of files changed. Do not paste the payload itself: the file on disk is the record (`_validate_stage_carry_sidecar_exists` checks that it exists), and a pasted one-line JSON is unreadable in the report. Quote the `consumers.jsonl` rows this run appended line-by-line in `consumerRows`.
|
|
21
22
|
- **Validation evidence**: actual command output (stdout/stderr) for every `pre / mid / post` validation command from the plan. Truncated output is acceptable but the command line and exit code MUST be exact. No paraphrasing of test results. Set `checkId` to the plan's `validationChecklist` id (`VC-007`) when the row runs a checklist command, and `advisory: true` on a row whose check is advisory (an external Tier 3 conformance entry, for example) so a non-zero exit there is not shown as a failure.
|
|
22
23
|
- **TDD evidence (when applicable)**: for steps that should be TDD-ordered, show the failing-test output captured BEFORE the merged commit and the passing-test output after, citing the single `feat|fix` commit SHA (test and implementation share one commit).
|
|
23
24
|
- **Verifier results**: a section per verifier present in the resolved roster (`Claude verifier`, `Codex verifier`, and `Antigravity verifier` when opted in) containing:
|
|
@@ -46,7 +47,7 @@ are collected and convergence finished. Phase 1-5 do not need it.
|
|
|
46
47
|
|
|
47
48
|
When the synthesised verdict would be `FAIL` only because of verifier findings that are small and local, the lead fixes them itself in this run instead of ending it and opening a fix run. Decide after Phase 5.5 convergence, before building the report-writer dispatch prompt and before "Lead post-stage persistence" below. No worker dispatch is open then, so the edit falls inside no read-only worker's mutation audit window. Never edit while a verifier, convergence, or report-writer dispatch is running: its audit reports `readonly source changed` and discards that worker's result.
|
|
48
49
|
|
|
49
|
-
**Eligibility.** Every rule holds for every blocking finding of the round, or the lead fixes none of them and the
|
|
50
|
+
**Eligibility.** Every rule holds for every blocking finding of the round, or the lead fixes none of them and §"Correction round" decides whether the executor fixes them in this run:
|
|
50
51
|
|
|
51
52
|
1. The fix is a code change at, or next to, the location the verifier cited.
|
|
52
53
|
2. The lead's total diff is at most 30 changed lines (added plus deleted, `git diff --numstat`).
|
|
@@ -65,10 +66,32 @@ A finding that needs no code change (convergence settled it as a verifier misrea
|
|
|
65
66
|
|
|
66
67
|
**Record.** One `implementation.leadFixes[]` entry per fixed finding group: `findingIds`, `verifiers` (the `verifierResults[].verifier` names whose FAIL it answers — every `FAIL` row is named by a passing entry before the stage may settle), `summary` (one sentence on what changed), `commit` (full SHA), `files`, `changedLines`, `commands[]` (`command`, `exitCode`, `outputTail`), and `result`. Keep each verifier's `FAIL` row as written. Leave the fixed findings out of `humanSummary.blockers`, and state in `userNarrative.validationExplanation` that the lead fixed them in this run.
|
|
67
68
|
|
|
68
|
-
**Persistence after a passing fix.** The executor's `### Stage Carry Evidence` was emitted before the fix and names the pre-fix head. Before
|
|
69
|
+
**Persistence after a passing fix.** The executor's `### Stage Carry Evidence` was emitted before the fix and names the pre-fix head. Before passing the carry to `okstra stage-done`, set `stageCommitRange.head` to the post-fix HEAD (`git rev-parse HEAD` in the stage worktree), add the fixed files to `filesChanged`, and append one `notes` line naming the lead commit and the finding ids. `stepResults` stays as the executor wrote it: a lead fix is not a plan step. Append the `done` row after the fix commit, so its `head_commit` is the post-fix HEAD, and capture `diffSummary` against the same head.
|
|
69
70
|
|
|
70
71
|
**Enforced:** `validators/validate-run.py` `_validate_lead_fixes` (blocking) fails an entry recorded `pass` whose command exited non-zero or that has no command, an entry over 30 changed lines, and a settled stage holding a `result: fail` entry; it reports (advisory) a settled stage whose `FAIL` row no passing entry names in `verifiers` — advisory because validate-run runs after the `done` row is appended, so blocking would undo nothing. `_validate_lead_fix_carry_head` (advisory) reports a carry sidecar whose head is not a passing lead fix commit. Eligibility rules 1, 3, 4 and 5 and the match between findings and `findingIds` are instructions only: the report carries no structured finding id or planned-path list to compare against.
|
|
71
72
|
|
|
73
|
+
## Correction round (decided after convergence, before the report-writer dispatch)
|
|
74
|
+
|
|
75
|
+
When the synthesised verdict is `FAIL` and the lead minor fix does not apply, the executor fixes the confirmed findings in this run and the verifiers re-verify the fix, instead of ending the run and opening a fix run. At most **2** rounds per run.
|
|
76
|
+
|
|
77
|
+
**Entry.** Every blocking finding of the round meets all of these, or the run ends `FAIL` as before:
|
|
78
|
+
|
|
79
|
+
1. A verifier cited where it is (`path:line`) and what the correct result is.
|
|
80
|
+
2. The fix stays inside this stage's `plannedPaths` or files the executor already changed.
|
|
81
|
+
3. It needs no new plan step, dependency, schema, migration, or config of record — a finding that does is a plan change: end the run `FAIL` and route by `prompts/lead/phase-routing.md`.
|
|
82
|
+
|
|
83
|
+
Changing a test's expected value is allowed here when the finding shows the oracle is wrong, because the verifiers re-verify the fix.
|
|
84
|
+
|
|
85
|
+
**Procedure for round `<N>`.**
|
|
86
|
+
|
|
87
|
+
1. Record the stage HEAD as `<base>` (`git rev-parse HEAD` in the stage worktree).
|
|
88
|
+
2. Write the executor instruction with `okstra correction prompt --run-manifest <path> --round <N> --role executor --base <base> --finding <F-id> [--finding <F-id> ...]` into a file under the run's `state/`, then materialize it with `okstra agent-prompt materialize` — `--audience implementation-executor`, `--assignment-ref initial/<executor worker id>`, `--dispatch-kind correction-r<N>`, a new `--invocation-id` ending `-correction-r<N>-<executor worker id>`, and a result path `<executor worker id>-worker-correction-r<N>-implementation-<seq>.md`. Build a jobs file with `okstra agent-prompt jobs --dispatch-kind correction-r<N>`, dispatch it alone with `okstra team dispatch --jobs-file <path> --dispatch-kind correction-r<N>`, and settle it with `okstra team await`.
|
|
89
|
+
3. Do the same for every verifier with `--role verifier`, `--audience implementation-verifier`, its own `initial/<verifier worker id>` assignment, and result `<verifier worker id>-worker-correction-r<N>-implementation-<seq>.md`; dispatch the verifiers in one batch without the executor.
|
|
90
|
+
4. Converge the re-verification results the way the initial round was converged, restarting Phase 5.5 with `okstra convergence seed ... --restart-from-round0`.
|
|
91
|
+
5. No re-verification verdict is `FAIL`: the round `result` is `pass` and the run continues to persistence with the post-fix head. Otherwise `result: fail`; start round `<N+1>` if the cap allows and the entry rules still hold, or end the run `FAIL`.
|
|
92
|
+
|
|
93
|
+
**Enforced:** `scripts/okstra_ctl/dispatch_core.py` `_validate_correction_rounds` (via `correction_round.validate_correction_dispatch`) refuses a round past the cap, a verifier dispatch before that round's executor returned an `ok` result, a second executor fix in the same round, and round `<N+1>` before round `<N>` was re-verified. `validators/validate-run.py` `_validate_correction_rounds` (blocking) fails a report whose `correctionRounds` differ from the correction rounds the run dispatched, whose rounds are not 1, 2 in order, whose `result` contradicts its verdicts, or whose `verifierResults` are not the last round's verdicts. The entry rules are instructions only.
|
|
94
|
+
|
|
72
95
|
## Self-review pass before finalising the report (the Okstra lead runs this; do not delegate it)
|
|
73
96
|
|
|
74
97
|
1. **Plan coverage** — for a selected-direction plan, every step in the approved `plan-ready` stage must point to a commit (or an explicit `Skipped: <reason>` entry), and the diff must preserve the selected snapshot's mechanism and invariants. For a legacy plan, every step in the effective implementation option (explicit frontmatter value or Recommended Option fallback) must point to a commit or an explicit skip. List gaps. A `RED:` step and its `GREEN:` step pointing to the same merged commit SHA is NOT a coverage gap — one SHA may be shared by both.
|
|
@@ -90,10 +113,10 @@ A finding that needs no code change (convergence settled it as a verifier misrea
|
|
|
90
113
|
|
|
91
114
|
- Parse the executor's `### Stage Carry Evidence` JSON block. If absent or unparsable, end with status `contract-violated` and route to a follow-up `error-analysis`.
|
|
92
115
|
- The `### Stage Carry Evidence` JSON may include `designPrepEvidence[]`. Emit a row only when this stage produced concrete evidence that refines an effective PREP item: `itemId`, the injected `assessmentFingerprint`, `resolution`, and non-empty `evidence[]` are required; `overrides` is optional and only records observed, non-authoritative refinements. Carry evidence never represents user approval. Downstream resolution accepts it only from transitive dependency stages with the matching fingerprint.
|
|
93
|
-
- **A `FAIL` synthesised verdict withholds the two writes below.** A verifier `FAIL` that a passing lead minor fix answered does not make the verdict `FAIL` (§"Lead minor fix"); persist with the post-fix head it names. They are what marks the stage `done`, so performing them on a stage whose verifier found a blocking defect stacks the next stage on a confirmed regression. When the synthesised verdict is `FAIL`: write NO carry sidecar, and append a `status:"failed"` row in place of the `done` row
|
|
116
|
+
- **A `FAIL` synthesised verdict withholds the two writes below.** A verifier `FAIL` that a passing lead minor fix answered does not make the verdict `FAIL` (§"Lead minor fix"); persist with the post-fix head it names. They are what marks the stage `done`, so performing them on a stage whose verifier found a blocking defect stacks the next stage on a confirmed regression. When the synthesised verdict is `FAIL`: write NO carry sidecar, and append a `status:"failed"` row in place of the `done` row with `okstra stage-fail <impl-task-key> --stage <N> --head-commit <HEAD sha> --report <this run's final-report path> --reason "<blocking finding ids>"` (it calls `append_consumer`, so the consumers lock and the registry release apply; do not call python directly). That row is terminal *without* completion: dependent stages stay blocked because this stage is not done, while its worktree-registry occupancy is released so a fix run can re-enter the same stage number — `--stage <N>` reuses the preserved worktree and branch instead of provisioning a new one. State the reason in the report's `Stage sidecar evidence` section as `withheld`. **Enforced:** `validators/validate-run.py` `_validate_stage_carry_sidecar_exists` accepts a missing carry file only when that field is non-empty, so silently skipping the sidecar still fails the run.
|
|
94
117
|
- **A run that ends with no verifier result still closes.** When the stage ends before any verifier returned a verdict — the executor stopped without a change and the user chose not to verify, or every dispatched verifier ended without a result — append the `failed` row as above, record each roster verifier `not-run` with its reason (`okstra worker-state transition --team-state <path> --worker <worker-id> --status not-run --reason <text>`; a worker the dispatch skipped already carries one), and write the convergence state with `okstra convergence skip --run-manifest <path> --reason <text>` before dispatching the report writer. Without that state the report-writer packet refuses with `convergence … required source is missing`. The command refuses while any analyser, verifier, or critic attempt returned a result or is still running; such a run converges normally. In the report, write each verifier's `verifierResults[]` row as `verdict: not-run`, and state the reason under `Stage sidecar evidence` as `withheld`.
|
|
95
|
-
- On a non-`FAIL` verdict, for this run's single stage:
|
|
96
|
-
-
|
|
118
|
+
- On a non-`FAIL` verdict, for this run's single stage: save the executor's `### Stage Carry Evidence` JSON (after a passing lead minor fix, with the head, files, and note that §"Lead minor fix" adds; after a correction round, the last round's executor block) to a file under this run's `state/`, then run `okstra stage-done <impl-task-key> --stage <N> --carry <that file> --report <this run's final-report path>`. It writes the sidecar to the flat `runs/implementation/carry/stage-<N>.json` (the readers glob `carry/stage-*.json`: `okstra_ctl.stage_map`, `okstra_ctl.consumers.backfill_done_from_carry`, and validate-run's `RunRef.carry`), refuses to replace another head's sidecar of a stage that was never settled, and for a stage reopened after a `done` row (see "Reopening a settled stage" below) moves the previous sidecar unchanged to `carry/superseded/stage-<N>-from-<task-type>-<seq>.json` first. Name the `carryPath` and any `supersededCarryPath` it prints in `Stage sidecar evidence`. A reopened stage whose run ends `FAIL` writes nothing and leaves the old file where it is.
|
|
119
|
+
- The same `okstra stage-done` call appends the `status:"done"` row to `runs/<plan-task-key>/consumers.jsonl` with `completed_at`, `carry_path`, `report_path` (relative to the report's run directory) and the carry's head, through `append_consumer` — so the consumers lock applies and this stage's worktree-registry occupancy is released. Never call `append_consumer` from python. `report_path` lets `final-verification` cite each stage's originating report when assembling its Source Implementation Report list.
|
|
97
120
|
- **Automatic stage worktree cleanup:** after the report passes finalization, `report-finalize` reclaims this completed stage's clean worktree. It compares the report's final commit with the completion ledger and branch tip, preserves active or unfinished stages and dirty or nested worktrees, and keeps the branch and registry base for dependency rebases and later re-entry. Never remove the directory by hand before finalization. A later implementation or final-verification entry restores it from the preserved branch. After finalization, use the main project root or absolute artifact paths: this run's stage cwd may no longer exist. Enforcement: `report_finalize._teardown_stage_worktrees`, `stage_targets.teardown_completed_stage_worktrees`, and the cleanup/restoration tests in `tests/worktree/test_stage_rebase.py`.
|
|
98
121
|
- **Reopening a settled stage.** Appending a `status:"failed"` row after a `done` one withdraws that stage: `--stage N` accepts it again, its dependents stop resolving a base from the withdrawn head, and whole-task final-verification blocks until it is settled again. Write it with `okstra stage-reopen <task-key> --stage <N> --reason "<why>" [--evidence <report>]`, which records the reason and the report that found the defect, and re-run the stage rather than repairing the tree outside okstra — a stage reverted outside the ledger leaves the recorded `head_commit` and the carry sidecar naming a tree that no longer exists, and the next stage branches from it.
|
|
99
122
|
- The verifier round, Phase 5.5 convergence, and this Phase 6 report run **once per run** over this stage's diff — NOT per step.
|
package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-verifier.md
CHANGED
|
@@ -220,6 +220,8 @@ Re-running commands proves the diff *builds and passes*; it does NOT prove the d
|
|
|
220
220
|
|
|
221
221
|
### Fix-run incremental scope (applies when the profile carries a "Fix-Run Carry" block)
|
|
222
222
|
|
|
223
|
+
A correction-round re-verification (`--dispatch-kind correction-r<N>`, a "Correction Round" block in the task instructions) takes the same scope: the block's findings and the correction diff it names, with every validation command re-run.
|
|
224
|
+
|
|
223
225
|
A fix run re-verifies a stage whose previous run already passed a full static
|
|
224
226
|
sweep and failed only on cited blocking findings. Re-sweeping the whole stage
|
|
225
227
|
diff re-buys wall-clock without new information, so the static scope narrows —
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# Implementation Profile
|
|
2
2
|
|
|
3
3
|
- Purpose: realise the approved `implementation-planning` deliverable as actual source changes, with cross-model verification, while keeping the run reversible
|
|
4
|
-
- **Run-level fixed cost:** the verifier set
|
|
4
|
+
- **Run-level fixed cost:** the verifier set and Phase 5.5 convergence run once per implementation run over this run's single stage diff — never once per step — plus once per correction round; the Phase 6 report-writer runs exactly once.
|
|
5
5
|
- **Fix run (profile carries a "Fix-Run Carry" block):** the executor's scope is the carried blocking findings plus the previous routing recommendation — it MUST NOT re-execute plan steps the previous run completed. Verifiers apply the "Fix-run incremental scope" section of `_implementation-verifier.md`. The full validation-command re-run is NOT reduced.
|
|
6
6
|
- **Lead minor fix:** a verifier FAIL whose findings are small and local is fixed by the lead inside this run, after convergence and before the report-writer dispatch, under `_implementation-deliverable.md` "Lead minor fix"; a passing fix settles the stage without a fix run.
|
|
7
|
+
- **Correction round:** a verifier FAIL whose findings are confirmed, located, and inside the stage's plan is fixed by the executor and re-verified inside this run, at most 2 rounds, under `_implementation-deliverable.md` "Correction round"; a finding that needs a plan change still ends the run `FAIL`.
|
|
7
8
|
- **Executor binding (resolved at run-prep time, fixed for this run):**
|
|
8
9
|
- Executor display name: `{{EXECUTOR_DISPLAY_NAME}}`
|
|
9
10
|
- Executor worker ID: `{{EXECUTOR_WORKER_ID}}`
|
package/runtime/python/okstra_ctl/phases/implementation/report_assets/implementation.template.html
CHANGED
|
@@ -32,6 +32,12 @@
|
|
|
32
32
|
{% for row in implementation.leadFixes %}<article class="summary-card tone-{{ 'neutral' if row.result == 'pass' else 'important' }}"><p class="eyebrow">{{ row.findingIds | join(', ') | inline_code }} · <span class="status status-{{ row.result }}">{{ t('tasks.implementation.lead-fix-result-' ~ row.result) }}</span></p><p>{{ row.summary | inline_code }}</p><table><tbody><tr><th>{{ t('tasks.implementation.commit') }}</th><td><code>{{ row.commit }}</code></td></tr><tr><th>{{ t('tasks.implementation.lead-fix-verifiers') }}</th><td>{{ row.verifiers | join(', ') | inline_code }}</td></tr><tr><th>{{ t('tasks.implementation.files') }}</th><td>{% for path in row.files %}<code>{{ path }}</code>{% if not loop.last %}, {% endif %}{% endfor %}</td></tr><tr><th>{{ t('tasks.implementation.lead-fix-changed-lines') }}</th><td class="figure">{{ row.changedLines }}</td></tr></tbody></table>{% for command in row.commands %}<details><summary><code title="{{ command.command }}">{{ command.command }}</code> · {{ t('tasks.implementation.exit-code') }} {{ command.exitCode }}</summary><pre>{{ command.outputTail }}</pre></details>{% endfor %}</article>{% endfor %}
|
|
33
33
|
</section>{% endif %}
|
|
34
34
|
|
|
35
|
+
{% if implementation.get("correctionRounds") %}<section data-report-section="correction-rounds" data-report-field="implementation.correctionRounds">
|
|
36
|
+
<h2>{{ t('tasks.implementation.correction-rounds') }}</h2>
|
|
37
|
+
<p>{{ t('tasks.implementation.correction-rounds-intro') }}</p>
|
|
38
|
+
{% for row in implementation.correctionRounds %}<article class="summary-card tone-{{ 'neutral' if row.result == 'pass' else 'important' }}"><p class="eyebrow">{{ t('tasks.implementation.correction-round') }} {{ row.round }} · {{ row.findingIds | join(', ') | inline_code }} · <span class="status status-{{ row.result }}">{{ t('tasks.implementation.correction-result-' ~ row.result) }}</span></p><table><tbody><tr><th>{{ t('tasks.implementation.correction-range') }}</th><td><code>{{ row.baseCommit }}</code>..<code>{{ row.commit }}</code></td></tr>{% for verdict in row.verifierVerdicts %}<tr><th>{{ verdict.verifier | inline_code }}</th><td><span class="status status-{{ verdict.verdict | lower }}">{{ verdict.verdict }}</span></td></tr>{% endfor %}</tbody></table></article>{% endfor %}
|
|
39
|
+
</section>{% endif %}
|
|
40
|
+
|
|
35
41
|
<section data-report-section="remaining-issues">
|
|
36
42
|
<h2>{{ t('tasks.implementation.what-is-left') }}</h2>
|
|
37
43
|
{{ render_narrative(narrative.remainingIssues, "implementation.userNarrative.remainingIssues") }}
|
|
@@ -148,7 +148,7 @@ flowchart TD
|
|
|
148
148
|
Verdict --> Report[Final report preserves dissent]
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
Only the executor may mutate project files, with one exception: after the verifier round and convergence, the lead may fix small, local verifier FAIL findings itself (at most 30 changed lines, no test-expectation, dependency, schema, migration or config-of-record change), re-run the checks that found them, and settle the stage when they pass, instead of opening a fix run (`instructions/_implementation-deliverable.md` "Lead minor fix"). The verifier independently re-runs the diff and validation command read-only in the same worktree. Even a verifier with the same provider as the executor runs again in a separate fresh CLI session. This is to prevent a structure where the same session approves a diff the same session wrote.
|
|
151
|
+
Only the executor may mutate project files, with one exception: after the verifier round and convergence, the lead may fix small, local verifier FAIL findings itself (at most 30 changed lines, no test-expectation, dependency, schema, migration or config-of-record change), re-run the checks that found them, and settle the stage when they pass, instead of opening a fix run (`instructions/_implementation-deliverable.md` "Lead minor fix"). Findings outside those limits but inside the stage's plan go to a correction round: the executor fixes them under dispatch kind `correction-r<N>` and the verifiers re-verify the fix, at most 2 rounds per run, before the report is written once (`"Correction round"`). The verifier independently re-runs the diff and validation command read-only in the same worktree. Even a verifier with the same provider as the executor runs again in a separate fresh CLI session. This is to prevent a structure where the same session approves a diff the same session wrote.
|
|
152
152
|
|
|
153
153
|
## 5. stage and consumers
|
|
154
154
|
|
|
@@ -200,6 +200,7 @@ The final report requires at least the following.
|
|
|
200
200
|
- TDD failing-then-passing evidence
|
|
201
201
|
- per-verifier independent validation rerun result
|
|
202
202
|
- lead minor fixes, when any: finding ids, commit, files, changed lines, and re-run checks (`implementation.leadFixes`)
|
|
203
|
+
- correction rounds, when any: round, finding ids, fix commit range, each verifier's re-verification verdict, and result (`implementation.correctionRounds`)
|
|
203
204
|
- `carry/stage-<N>.json` evidence sidecar and `consumers.jsonl` started/done row
|
|
204
205
|
- rollback verification
|
|
205
206
|
- `implementation.manualUserTest` finalized against the actual diff and whether it is executable
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import re
|
|
5
|
-
from collections.abc import Callable
|
|
5
|
+
from collections.abc import Callable, Mapping
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from ...correction_round import correction_round
|
|
6
9
|
|
|
7
10
|
_PASSING_VERDICT_TOKENS = frozenset({"accepted", "conditional-accept"})
|
|
8
11
|
_CHECKLIST_ID_RE = re.compile(r"\bVC-\d{3,}\b")
|
|
@@ -266,6 +269,64 @@ def _validate_lead_fixes(data: dict, failures: list[str]) -> None:
|
|
|
266
269
|
)
|
|
267
270
|
|
|
268
271
|
|
|
272
|
+
_CORRECTION_BLOCKING = "correction-round BLOCKING:"
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _validate_correction_rounds(
|
|
276
|
+
data: dict, run_manifest: Mapping[str, Any], failures: list[str],
|
|
277
|
+
) -> None:
|
|
278
|
+
"""수정 라운드 기록을 실제 dispatch 와, 마지막 라운드 verdict 를 verifierResults 와 맞춘다.
|
|
279
|
+
|
|
280
|
+
`_implementation-deliverable.md` "Correction round": verifierResults 는 마지막 라운드의
|
|
281
|
+
verdict 이고 앞선 FAIL 은 correctionRounds 에만 남는다. 원장에 있는 라운드가 기록에서
|
|
282
|
+
빠지면 그 FAIL 이 보고서에서 사라진다.
|
|
283
|
+
"""
|
|
284
|
+
implementation = data.get("implementation")
|
|
285
|
+
if not isinstance(implementation, dict):
|
|
286
|
+
return
|
|
287
|
+
rows = [row for row in implementation.get("correctionRounds") or [] if isinstance(row, dict)]
|
|
288
|
+
recorded = [row.get("round") for row in rows]
|
|
289
|
+
dispatched = sorted({
|
|
290
|
+
number for invocation in run_manifest.get("invocations") or []
|
|
291
|
+
if isinstance(invocation, Mapping)
|
|
292
|
+
and (number := correction_round(str(invocation.get("dispatchKind") or ""))) is not None
|
|
293
|
+
})
|
|
294
|
+
if sorted(recorded) != dispatched:
|
|
295
|
+
failures.append(
|
|
296
|
+
f"{_CORRECTION_BLOCKING} implementation.correctionRounds records rounds "
|
|
297
|
+
f"{sorted(recorded)} but the run dispatched correction rounds {dispatched}. "
|
|
298
|
+
"Record one entry per dispatched round, with its re-verification verdicts."
|
|
299
|
+
)
|
|
300
|
+
if recorded != list(range(1, len(recorded) + 1)):
|
|
301
|
+
failures.append(
|
|
302
|
+
f"{_CORRECTION_BLOCKING} implementation.correctionRounds rounds are {recorded}; "
|
|
303
|
+
"they run 1, 2 in order."
|
|
304
|
+
)
|
|
305
|
+
for row in rows:
|
|
306
|
+
verdicts = [v for v in row.get("verifierVerdicts") or [] if isinstance(v, dict)]
|
|
307
|
+
any_fail = any(v.get("verdict") == "FAIL" for v in verdicts)
|
|
308
|
+
if (row.get("result") == "pass") == any_fail:
|
|
309
|
+
failures.append(
|
|
310
|
+
f"{_CORRECTION_BLOCKING} implementation.correctionRounds round "
|
|
311
|
+
f"{row.get('round')} records `result: {row.get('result')}` but its "
|
|
312
|
+
f"re-verification verdicts are {[v.get('verdict') for v in verdicts]}; "
|
|
313
|
+
"`pass` means no verdict is FAIL."
|
|
314
|
+
)
|
|
315
|
+
if not rows:
|
|
316
|
+
return
|
|
317
|
+
last = {
|
|
318
|
+
str(v.get("verifier")): v.get("verdict")
|
|
319
|
+
for v in rows[-1].get("verifierVerdicts") or [] if isinstance(v, dict)
|
|
320
|
+
}
|
|
321
|
+
reported = {who: row.get("verdict") for who, row in _verifier_rows(data)}
|
|
322
|
+
if last != reported:
|
|
323
|
+
failures.append(
|
|
324
|
+
f"{_CORRECTION_BLOCKING} implementation.verifierResults verdicts {reported} differ "
|
|
325
|
+
f"from the last correction round's {last}. verifierResults carries the last "
|
|
326
|
+
"round's verdicts; earlier ones stay in correctionRounds."
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
269
330
|
def _validate_verifier_fail_blocks_verdict(data: dict, failures: list[str]) -> None:
|
|
270
331
|
"""A verifier FAIL cannot be dropped during synthesis.
|
|
271
332
|
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""`okstra stage-done` — settle a passing implementation stage: carry sidecar, then `done` row.
|
|
2
|
+
|
|
3
|
+
Both writes were lead hand-work. The `done` row needed a python call to `append_consumer`,
|
|
4
|
+
which Claude Code auto mode blocks, and the carry path in `_implementation-deliverable.md`
|
|
5
|
+
(`runs/<impl-task-key>/carry/stage-<N>.json`) read as the staged run directory: measured
|
|
6
|
+
2026-10-17 (figma-plugin dev-11377 run 002), the lead wrote
|
|
7
|
+
`runs/implementation/stage-1/carry/stage-1.json`, validate-run looked for the flat
|
|
8
|
+
`runs/implementation/carry/stage-1.json`, and the `done` row kept the wrong `carry_path`.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import re
|
|
15
|
+
from datetime import datetime, timezone
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from okstra_project import ResolverError, StateError, resolve_project_root
|
|
19
|
+
|
|
20
|
+
from .consumers import (
|
|
21
|
+
FAILED_CARRY_STATUSES,
|
|
22
|
+
append_consumer,
|
|
23
|
+
carry_head_commit,
|
|
24
|
+
read_consumers,
|
|
25
|
+
)
|
|
26
|
+
from .json_boundary import JsonBoundaryError, load_owned_object, write_owned_object_atomic
|
|
27
|
+
from .paths import RunRef
|
|
28
|
+
from .stage_reopen import resolve_planned_stage
|
|
29
|
+
|
|
30
|
+
_REPORT_LABEL_RE = re.compile(r"^final-report-(?P<label>[a-z-]+-\d+)\.")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _read_carry(carry_file: Path, stage: int) -> dict:
|
|
34
|
+
try:
|
|
35
|
+
carry = load_owned_object(carry_file, artifact="implementation stage carry")
|
|
36
|
+
except (JsonBoundaryError, OSError) as exc:
|
|
37
|
+
raise StateError(
|
|
38
|
+
f"--carry must name the executor's `### Stage Carry Evidence` JSON saved under "
|
|
39
|
+
f"this run's .okstra tree: {exc}", stage="carry") from exc
|
|
40
|
+
recorded = carry.get("stage", carry.get("stageNumber"))
|
|
41
|
+
if isinstance(recorded, int) and recorded != stage:
|
|
42
|
+
raise StateError(f"--carry records stage {recorded}, not {stage}", stage="carry")
|
|
43
|
+
if str(carry.get("status") or "").lower() in FAILED_CARRY_STATUSES:
|
|
44
|
+
raise StateError(
|
|
45
|
+
f"--carry records status {carry['status']!r}; a failed stage is recorded with "
|
|
46
|
+
"`okstra stage-fail`", stage="carry")
|
|
47
|
+
if not carry_head_commit(carry):
|
|
48
|
+
raise StateError("--carry names no head commit (stageCommitRange.head)", stage="carry")
|
|
49
|
+
return carry
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _supersede(target: Path, rows: list[dict], stage: int) -> Path:
|
|
53
|
+
"""Move the sidecar of the run that first settled a reopened stage aside, unchanged."""
|
|
54
|
+
settled = [r for r in rows if r.get("stage") == stage and r.get("status") == "done"]
|
|
55
|
+
if not settled:
|
|
56
|
+
raise StateError(
|
|
57
|
+
f"{target} exists but stage {stage} was never settled — one stage holds one "
|
|
58
|
+
"sidecar; inspect it before replacing it by hand", stage="carry")
|
|
59
|
+
match = _REPORT_LABEL_RE.match(Path(str(settled[-1].get("report_path") or "")).name)
|
|
60
|
+
if not match:
|
|
61
|
+
raise StateError(
|
|
62
|
+
f"cannot name the superseded sidecar: the earlier done row's report_path "
|
|
63
|
+
f"{settled[-1].get('report_path')!r} is not a final-report path", stage="carry")
|
|
64
|
+
moved = target.parent / "superseded" / f"stage-{stage}-from-{match['label']}.json"
|
|
65
|
+
if moved.exists():
|
|
66
|
+
raise StateError(f"{moved} already exists", stage="carry")
|
|
67
|
+
moved.parent.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
target.rename(moved)
|
|
69
|
+
return moved
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def done_stage(
|
|
73
|
+
project_root: Path, task_key: str, stage: int, carry_file: Path, report: Path,
|
|
74
|
+
) -> dict:
|
|
75
|
+
"""Write the stage's carry sidecar at its canonical path and append the `done` row."""
|
|
76
|
+
identity, plan_run_root = resolve_planned_stage(project_root, task_key, stage)
|
|
77
|
+
carry = _read_carry(carry_file, stage)
|
|
78
|
+
head = carry_head_commit(carry)
|
|
79
|
+
report = report if report.is_absolute() else project_root / report
|
|
80
|
+
try:
|
|
81
|
+
report_rel = report.relative_to(RunRef.from_report_path(report).run_dir).as_posix()
|
|
82
|
+
except ValueError as exc:
|
|
83
|
+
raise StateError(f"--report is not a final-report path: {report}", stage="report") from exc
|
|
84
|
+
|
|
85
|
+
rows = read_consumers(plan_run_root)
|
|
86
|
+
last = [r for r in rows if r.get("stage") == stage and r.get("status") in ("done", "failed")]
|
|
87
|
+
if last and last[-1].get("status") == "done" and last[-1].get("head_commit") != head:
|
|
88
|
+
raise StateError(
|
|
89
|
+
f"stage {stage} is already done at {last[-1].get('head_commit')}; withdraw it with "
|
|
90
|
+
"`okstra stage-reopen` before settling another head", stage="consumers")
|
|
91
|
+
|
|
92
|
+
task_root = Path(identity["taskRoot"])
|
|
93
|
+
target = RunRef.from_task_root(task_root, "implementation").carry(stage)
|
|
94
|
+
superseded = None
|
|
95
|
+
if target.exists():
|
|
96
|
+
existing = load_owned_object(target, artifact="implementation stage carry")
|
|
97
|
+
if carry_head_commit(existing) != head:
|
|
98
|
+
superseded = _supersede(target, rows, stage)
|
|
99
|
+
if not target.exists():
|
|
100
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
write_owned_object_atomic(target, carry, artifact="implementation stage carry")
|
|
102
|
+
carry_rel = target.relative_to(task_root).as_posix()
|
|
103
|
+
append_consumer(
|
|
104
|
+
plan_run_root,
|
|
105
|
+
impl_task_key=identity["taskKey"],
|
|
106
|
+
stage=stage,
|
|
107
|
+
status="done",
|
|
108
|
+
head_commit=head,
|
|
109
|
+
carry_path=carry_rel,
|
|
110
|
+
report_path=report_rel,
|
|
111
|
+
completed_at=datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
112
|
+
)
|
|
113
|
+
return {
|
|
114
|
+
"taskKey": identity["taskKey"],
|
|
115
|
+
"stage": stage,
|
|
116
|
+
"headCommit": head,
|
|
117
|
+
"carryPath": str(target),
|
|
118
|
+
"supersededCarryPath": str(superseded) if superseded else "",
|
|
119
|
+
"reportPath": report_rel,
|
|
120
|
+
"consumersPath": str(plan_run_root / "consumers.jsonl"),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
_CLI_EPILOG = r"""Usage:
|
|
125
|
+
okstra stage-done <task-key> --stage <N> --carry <carry.json> --report <final-report path>
|
|
126
|
+
|
|
127
|
+
Settles an implementation stage whose synthesised verdict is not FAIL. Writes the
|
|
128
|
+
executor's `### Stage Carry Evidence` JSON (saved by the lead under the run's
|
|
129
|
+
.okstra tree, with the post-fix head after a lead minor fix) to the stage's
|
|
130
|
+
canonical sidecar `runs/implementation/carry/stage-<N>.json`, then appends the
|
|
131
|
+
`done` row with that carry path, the report path relative to its run directory,
|
|
132
|
+
the carry's head and the completion time. A reopened stage's previous sidecar
|
|
133
|
+
is moved to `carry/superseded/stage-<N>-from-<task-type>-<seq>.json` first.
|
|
134
|
+
Refuses a carry for another stage, a failed carry, and a stage already done at
|
|
135
|
+
another head. Re-running with the same carry writes nothing new.
|
|
136
|
+
|
|
137
|
+
Output: JSON { ok, taskKey, stage, headCommit, carryPath, supersededCarryPath,
|
|
138
|
+
reportPath, consumersPath }. Exit 1 on a refusal, 2 when
|
|
139
|
+
PROJECT_ROOT cannot be resolved.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def main(argv: list[str] | None = None) -> int:
|
|
144
|
+
parser = argparse.ArgumentParser(
|
|
145
|
+
description="Settle a passing implementation stage (carry sidecar + done row).",
|
|
146
|
+
epilog=_CLI_EPILOG,
|
|
147
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
148
|
+
prog="okstra stage-done")
|
|
149
|
+
parser.add_argument("task_key", metavar="task-key",
|
|
150
|
+
help="project-id:task-group:task-id")
|
|
151
|
+
parser.add_argument("--stage", type=int, required=True,
|
|
152
|
+
help="the Stage Map number this run implemented")
|
|
153
|
+
parser.add_argument("--carry", type=Path, required=True,
|
|
154
|
+
help="the Stage Carry Evidence JSON saved under the run's .okstra tree")
|
|
155
|
+
parser.add_argument("--report", type=Path, required=True,
|
|
156
|
+
help="this run's final-report path")
|
|
157
|
+
parser.add_argument("--project-root", "--project", default="",
|
|
158
|
+
help="use this directory as PROJECT_ROOT")
|
|
159
|
+
parser.add_argument("--cwd", default=".",
|
|
160
|
+
help="resolve PROJECT_ROOT starting from here")
|
|
161
|
+
args = parser.parse_args(argv)
|
|
162
|
+
|
|
163
|
+
def emit(payload: dict) -> None:
|
|
164
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
resolved = resolve_project_root(explicit_root=args.project_root, cwd=args.cwd)
|
|
168
|
+
except ResolverError as exc:
|
|
169
|
+
emit({"ok": False, "stage": "resolve", "reason": str(exc)})
|
|
170
|
+
return 2
|
|
171
|
+
try:
|
|
172
|
+
settled = done_stage(Path(resolved), args.task_key, args.stage,
|
|
173
|
+
args.carry, args.report)
|
|
174
|
+
except StateError as exc:
|
|
175
|
+
emit({"ok": False, "stage": getattr(exc, "stage", None) or "stage-done",
|
|
176
|
+
"reason": str(exc)})
|
|
177
|
+
return 1
|
|
178
|
+
emit({"ok": True, **settled})
|
|
179
|
+
return 0
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
if __name__ == "__main__":
|
|
183
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""`okstra stage-fail` — FAIL 로 끝난 implementation run 의 stage 에 `failed` 행을 남긴다.
|
|
2
|
+
|
|
3
|
+
종합 verdict 가 FAIL 이면 리드는 carry sidecar 대신 `failed` 행을 써야 한다
|
|
4
|
+
(`_implementation-deliverable.md` §"Lead post-stage persistence"). 그 행을 쓰는 명령이
|
|
5
|
+
없어 리드가 `append_consumer` 를 python 으로 직접 불렀고, Claude Code auto-mode 가 그
|
|
6
|
+
호출을 막아 사용자가 손으로 실행해야 했다 — 실측(2026-10-17, figma-plugin dev-11377).
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import json
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from okstra_project import ResolverError, StateError, resolve_project_root
|
|
15
|
+
|
|
16
|
+
from .consumers import append_consumer, last_lifecycle_status_by_stage, read_consumers
|
|
17
|
+
from .stage_reopen import resolve_planned_stage
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def fail_stage(
|
|
21
|
+
project_root: Path, task_key: str, stage: int, head_commit: str, report_path: str,
|
|
22
|
+
reason: str,
|
|
23
|
+
) -> dict:
|
|
24
|
+
"""아직 `done` 이 아닌 stage 에 `failed` 행을 붙인다."""
|
|
25
|
+
for flag, value in (("--head-commit", head_commit), ("--report", report_path),
|
|
26
|
+
("--reason", reason)):
|
|
27
|
+
if not value.strip():
|
|
28
|
+
raise StateError(f"{flag} is required", stage=flag.lstrip("-"))
|
|
29
|
+
identity, plan_run_root = resolve_planned_stage(project_root, task_key, stage)
|
|
30
|
+
recorded = last_lifecycle_status_by_stage(read_consumers(plan_run_root)).get(stage)
|
|
31
|
+
if recorded == "done":
|
|
32
|
+
raise StateError(
|
|
33
|
+
f"stage {stage} is recorded 'done' — withdraw a settled stage with "
|
|
34
|
+
"`okstra stage-reopen`, which records the done head it withdraws",
|
|
35
|
+
stage="consumers",
|
|
36
|
+
)
|
|
37
|
+
append_consumer(
|
|
38
|
+
plan_run_root,
|
|
39
|
+
impl_task_key=identity["taskKey"],
|
|
40
|
+
stage=stage,
|
|
41
|
+
status="failed",
|
|
42
|
+
head_commit=head_commit.strip(),
|
|
43
|
+
report_path=report_path.strip(),
|
|
44
|
+
reason=reason.strip(),
|
|
45
|
+
)
|
|
46
|
+
return {
|
|
47
|
+
"taskKey": identity["taskKey"],
|
|
48
|
+
"stage": stage,
|
|
49
|
+
"headCommit": head_commit.strip(),
|
|
50
|
+
"reportPath": report_path.strip(),
|
|
51
|
+
"reason": reason.strip(),
|
|
52
|
+
"consumersPath": str(plan_run_root / "consumers.jsonl"),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
_CLI_EPILOG = r"""Usage:
|
|
57
|
+
okstra stage-fail <task-key> --stage <N> --head-commit <sha> --report <path> --reason "<why>"
|
|
58
|
+
|
|
59
|
+
Appends the `failed` row an implementation run writes when its synthesised verdict
|
|
60
|
+
is FAIL, or when it ends with no verifier result: dependents stay blocked, the
|
|
61
|
+
stage's worktree occupancy is released, and `/okstra-run` offers the stage for a
|
|
62
|
+
fix run that reuses its worktree and branch. --report is this run's final-report
|
|
63
|
+
path as the `done` row would record it. Refuses a stage that is not in the latest
|
|
64
|
+
Stage Map, is cancelled, or is already `done` (use `okstra stage-reopen`).
|
|
65
|
+
Appending the same row twice writes it once.
|
|
66
|
+
|
|
67
|
+
Output: JSON { ok, taskKey, stage, headCommit, reportPath, reason, consumersPath }.
|
|
68
|
+
Exit 1 on a refusal, 2 when PROJECT_ROOT cannot be resolved.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def main(argv: list[str] | None = None) -> int:
|
|
73
|
+
parser = argparse.ArgumentParser(
|
|
74
|
+
description="Record a FAIL-ended implementation stage as failed.",
|
|
75
|
+
epilog=_CLI_EPILOG,
|
|
76
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
77
|
+
prog="okstra stage-fail")
|
|
78
|
+
parser.add_argument("task_key", metavar="task-key",
|
|
79
|
+
help="project-id:task-group:task-id")
|
|
80
|
+
parser.add_argument("--stage", type=int, required=True,
|
|
81
|
+
help="the Stage Map number this run implemented")
|
|
82
|
+
parser.add_argument("--head-commit", required=True,
|
|
83
|
+
help="the stage worktree HEAD at the end of this run")
|
|
84
|
+
parser.add_argument("--report", required=True,
|
|
85
|
+
help="this run's final-report path, as a done row records it")
|
|
86
|
+
parser.add_argument("--reason", required=True,
|
|
87
|
+
help="why the stage failed; recorded on the row")
|
|
88
|
+
parser.add_argument("--project-root", "--project", default="",
|
|
89
|
+
help="use this directory as PROJECT_ROOT")
|
|
90
|
+
parser.add_argument("--cwd", default=".",
|
|
91
|
+
help="resolve PROJECT_ROOT starting from here")
|
|
92
|
+
args = parser.parse_args(argv)
|
|
93
|
+
|
|
94
|
+
def emit(payload: dict) -> None:
|
|
95
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
resolved = resolve_project_root(explicit_root=args.project_root, cwd=args.cwd)
|
|
99
|
+
except ResolverError as exc:
|
|
100
|
+
emit({"ok": False, "stage": "resolve", "reason": str(exc)})
|
|
101
|
+
return 2
|
|
102
|
+
try:
|
|
103
|
+
failed = fail_stage(Path(resolved), args.task_key, args.stage,
|
|
104
|
+
args.head_commit, args.report, args.reason)
|
|
105
|
+
except StateError as exc:
|
|
106
|
+
emit({"ok": False, "stage": getattr(exc, "stage", None) or "stage-fail",
|
|
107
|
+
"reason": str(exc)})
|
|
108
|
+
return 1
|
|
109
|
+
emit({"ok": True, **failed})
|
|
110
|
+
return 0
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
raise SystemExit(main())
|
|
@@ -31,16 +31,10 @@ from .paths import RunRef
|
|
|
31
31
|
from .stage_map import StageMapError, load_latest_plan_stage_map
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
) -> dict:
|
|
37
|
-
"""마지막 행이 `done` 인 stage 에 `failed` 행을 붙이고 그 근거를 돌려준다."""
|
|
38
|
-
if not reason.strip():
|
|
39
|
-
raise StateError("--reason is required: say why the stage is reopened",
|
|
40
|
-
stage="reason")
|
|
34
|
+
def resolve_planned_stage(project_root: Path, task_key: str, stage: int) -> tuple[dict, Path]:
|
|
35
|
+
"""task identity 와 plan run root 를 돌려준다. 최신 Stage Map 에 없거나 취소된 stage 는 거절한다."""
|
|
41
36
|
identity = resolve_task_identity(project_root, task_key)
|
|
42
37
|
task_root = Path(identity["taskRoot"])
|
|
43
|
-
plan_run_root = RunRef.from_task_root(task_root, "implementation-planning").run_dir
|
|
44
38
|
try:
|
|
45
39
|
stage_map = load_latest_plan_stage_map(task_root)
|
|
46
40
|
except StageMapError as exc:
|
|
@@ -50,7 +44,17 @@ def reopen_stage(
|
|
|
50
44
|
raise StateError(f"stage {stage} is not in this task's Stage Map", stage="stage-map")
|
|
51
45
|
if any(row.get("stage_number") == stage and row.get("cancelled") for row in rows):
|
|
52
46
|
raise StateError(f"stage {stage} is cancelled in the latest plan", stage="stage-map")
|
|
47
|
+
return identity, RunRef.from_task_root(task_root, "implementation-planning").run_dir
|
|
48
|
+
|
|
53
49
|
|
|
50
|
+
def reopen_stage(
|
|
51
|
+
project_root: Path, task_key: str, stage: int, reason: str, evidence: str = "",
|
|
52
|
+
) -> dict:
|
|
53
|
+
"""마지막 행이 `done` 인 stage 에 `failed` 행을 붙이고 그 근거를 돌려준다."""
|
|
54
|
+
if not reason.strip():
|
|
55
|
+
raise StateError("--reason is required: say why the stage is reopened",
|
|
56
|
+
stage="reason")
|
|
57
|
+
identity, plan_run_root = resolve_planned_stage(project_root, task_key, stage)
|
|
54
58
|
consumers = read_consumers(plan_run_root)
|
|
55
59
|
recorded = last_lifecycle_status_by_stage(consumers).get(stage)
|
|
56
60
|
if recorded != "done":
|
|
@@ -1355,6 +1355,14 @@
|
|
|
1355
1355
|
"$ref": "#/$defs/LeadFixRow"
|
|
1356
1356
|
}
|
|
1357
1357
|
},
|
|
1358
|
+
"correctionRounds": {
|
|
1359
|
+
"type": "array",
|
|
1360
|
+
"description": "Correction rounds run in this run after a verifier FAIL (`_implementation-deliverable.md` \"Correction round\"): each sends the executor a bounded fix and the verifiers a re-verification. `verifierResults` holds the last round's verdicts; earlier FAIL verdicts stay here. Optional so reports of tasks already in flight keep validating.",
|
|
1361
|
+
"maxItems": 2,
|
|
1362
|
+
"items": {
|
|
1363
|
+
"$ref": "#/$defs/CorrectionRoundRow"
|
|
1364
|
+
}
|
|
1365
|
+
},
|
|
1358
1366
|
"rollbackVerification": {
|
|
1359
1367
|
"type": "array",
|
|
1360
1368
|
"minItems": 1,
|
|
@@ -10159,6 +10167,76 @@
|
|
|
10159
10167
|
}
|
|
10160
10168
|
}
|
|
10161
10169
|
},
|
|
10170
|
+
"CorrectionRoundRow": {
|
|
10171
|
+
"type": "object",
|
|
10172
|
+
"description": "One correction round: the findings it fixed, the executor's commit range, and each verifier's re-verification verdict.",
|
|
10173
|
+
"required": [
|
|
10174
|
+
"round",
|
|
10175
|
+
"findingIds",
|
|
10176
|
+
"baseCommit",
|
|
10177
|
+
"commit",
|
|
10178
|
+
"verifierVerdicts",
|
|
10179
|
+
"result"
|
|
10180
|
+
],
|
|
10181
|
+
"additionalProperties": false,
|
|
10182
|
+
"properties": {
|
|
10183
|
+
"round": {
|
|
10184
|
+
"type": "integer",
|
|
10185
|
+
"minimum": 1,
|
|
10186
|
+
"maximum": 2
|
|
10187
|
+
},
|
|
10188
|
+
"findingIds": {
|
|
10189
|
+
"type": "array",
|
|
10190
|
+
"minItems": 1,
|
|
10191
|
+
"items": {
|
|
10192
|
+
"type": "string",
|
|
10193
|
+
"minLength": 1
|
|
10194
|
+
}
|
|
10195
|
+
},
|
|
10196
|
+
"baseCommit": {
|
|
10197
|
+
"description": "Stage HEAD before the round.",
|
|
10198
|
+
"type": "string",
|
|
10199
|
+
"pattern": "^[0-9a-f]{7,40}$"
|
|
10200
|
+
},
|
|
10201
|
+
"commit": {
|
|
10202
|
+
"description": "Stage HEAD after the executor's fix.",
|
|
10203
|
+
"type": "string",
|
|
10204
|
+
"pattern": "^[0-9a-f]{7,40}$"
|
|
10205
|
+
},
|
|
10206
|
+
"verifierVerdicts": {
|
|
10207
|
+
"type": "array",
|
|
10208
|
+
"minItems": 1,
|
|
10209
|
+
"items": {
|
|
10210
|
+
"type": "object",
|
|
10211
|
+
"required": [
|
|
10212
|
+
"verifier",
|
|
10213
|
+
"verdict"
|
|
10214
|
+
],
|
|
10215
|
+
"additionalProperties": false,
|
|
10216
|
+
"properties": {
|
|
10217
|
+
"verifier": {
|
|
10218
|
+
"type": "string",
|
|
10219
|
+
"minLength": 1
|
|
10220
|
+
},
|
|
10221
|
+
"verdict": {
|
|
10222
|
+
"enum": [
|
|
10223
|
+
"PASS",
|
|
10224
|
+
"CONCERNS",
|
|
10225
|
+
"FAIL"
|
|
10226
|
+
]
|
|
10227
|
+
}
|
|
10228
|
+
}
|
|
10229
|
+
}
|
|
10230
|
+
},
|
|
10231
|
+
"result": {
|
|
10232
|
+
"description": "`pass` when no re-verification verdict is FAIL.",
|
|
10233
|
+
"enum": [
|
|
10234
|
+
"pass",
|
|
10235
|
+
"fail"
|
|
10236
|
+
]
|
|
10237
|
+
}
|
|
10238
|
+
}
|
|
10239
|
+
},
|
|
10162
10240
|
"LeadFixRow": {
|
|
10163
10241
|
"type": "object",
|
|
10164
10242
|
"description": "One lead minor fix: the verifier findings it answers, the commit that carries it, and the re-run checks that decide whether the run may settle the stage. `changedLines` has no schema maximum on purpose: an over-limit fix must still be recordable, and `_validate_lead_fixes` reports it.",
|
|
@@ -678,6 +678,12 @@
|
|
|
678
678
|
"lead-fix-changed-lines": "Changed lines",
|
|
679
679
|
"lead-fix-result-pass": "checks pass",
|
|
680
680
|
"lead-fix-result-fail": "checks still fail",
|
|
681
|
+
"correction-rounds": "Corrected within this run",
|
|
682
|
+
"correction-rounds-intro": "Verifiers rejected the change. Instead of starting a fix run, the executor fixed the confirmed findings in this run and the verifiers checked the fix again.",
|
|
683
|
+
"correction-round": "Round",
|
|
684
|
+
"correction-range": "Fix range",
|
|
685
|
+
"correction-result-pass": "re-verification passed",
|
|
686
|
+
"correction-result-fail": "re-verification failed",
|
|
681
687
|
"entry-count": "{count} entries",
|
|
682
688
|
"manual-user-test": "Manual user test",
|
|
683
689
|
"environment": "Environment:",
|
|
@@ -678,6 +678,12 @@
|
|
|
678
678
|
"lead-fix-changed-lines": "바뀐 줄 수",
|
|
679
679
|
"lead-fix-result-pass": "검사 통과",
|
|
680
680
|
"lead-fix-result-fail": "검사 여전히 실패",
|
|
681
|
+
"correction-rounds": "이 run 안에서 고친 것",
|
|
682
|
+
"correction-rounds-intro": "검증자가 변경을 거부했습니다. fix run 을 새로 여는 대신 이 run 안에서 실행자가 확인된 finding 을 고치고, 검증자가 그 수정을 다시 검증했습니다.",
|
|
683
|
+
"correction-round": "라운드",
|
|
684
|
+
"correction-range": "수정 범위",
|
|
685
|
+
"correction-result-pass": "재검증 통과",
|
|
686
|
+
"correction-result-fail": "재검증 실패",
|
|
681
687
|
"entry-count": "{count}개 항목",
|
|
682
688
|
"manual-user-test": "수동 사용자 테스트",
|
|
683
689
|
"environment": "환경:",
|
|
@@ -40,6 +40,7 @@ from okstra_ctl.phases.implementation.validation import (
|
|
|
40
40
|
_validate_verifier_reran_independently,
|
|
41
41
|
_validate_verifier_discrepancy_is_not_passed,
|
|
42
42
|
_validate_verifier_fail_blocks_verdict,
|
|
43
|
+
_validate_correction_rounds,
|
|
43
44
|
_validate_lead_fixes,
|
|
44
45
|
_validate_verifier_command_log_is_read_only as validate_verifier_command_log_is_read_only,
|
|
45
46
|
_validate_verifier_discrepancy_names_checklist_phase as validate_verifier_discrepancy_names_checklist_phase,
|
|
@@ -3187,6 +3188,7 @@ def validate_final_report_data(
|
|
|
3187
3188
|
_validate_stage_carry_sidecar_exists(data, report_path, failures)
|
|
3188
3189
|
_validate_lead_fixes(data, failures)
|
|
3189
3190
|
_validate_lead_fix_carry_head(data, report_path, failures)
|
|
3191
|
+
_validate_correction_rounds(data, manifest, failures)
|
|
3190
3192
|
_validate_lead_authored_report(data, report_path, failures)
|
|
3191
3193
|
if task_type == "error-analysis":
|
|
3192
3194
|
_validate_error_analysis_consistency(data, failures)
|