ace-assign 0.70.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/.ace-defaults/assign/catalog/steps/auto-merge.step.yml +8 -8
  3. data/.ace-defaults/assign/catalog/steps/create-pr.step.yml +1 -1
  4. data/.ace-defaults/assign/catalog/steps/mark-pr-ready.step.yml +1 -1
  5. data/.ace-defaults/assign/config.yml +0 -13
  6. data/.ace-defaults/assign/presets/fix-bug.yml +1 -1
  7. data/.ace-defaults/assign/presets/work-on-task-ace-development.yml +1 -1
  8. data/.ace-defaults/assign/presets/work-on-task-auto-merge.yml +1 -1
  9. data/.ace-defaults/assign/presets/work-on-task.yml +1 -1
  10. data/CHANGELOG.md +3 -2099
  11. data/README.md +58 -31
  12. data/docs/exit-codes.md +36 -44
  13. data/docs/getting-started.md +9 -4
  14. data/docs/usage.md +129 -522
  15. data/handbook/skills/as-assign-drive/SKILL.md +1 -1
  16. data/handbook/workflow-instructions/assign/drive.wf.md +47 -118
  17. data/handbook/workflow-instructions/assign/prepare.wf.md +1 -1
  18. data/handbook/workflow-instructions/assign/verify-test-suite.wf.md +8 -2
  19. data/lib/ace/assign/cli/commands/assignment_target.rb +2 -15
  20. data/lib/ace/assign/cli/commands/create.rb +1 -8
  21. data/lib/ace/assign/cli/commands/fail.rb +0 -6
  22. data/lib/ace/assign/cli/commands/finish.rb +2 -23
  23. data/lib/ace/assign/cli/commands/fork_session.rb +0 -1
  24. data/lib/ace/assign/cli/commands/select.rb +0 -1
  25. data/lib/ace/assign/cli/commands/start.rb +0 -2
  26. data/lib/ace/assign/cli/commands/status.rb +1 -31
  27. data/lib/ace/assign/cli/commands/step.rb +1 -3
  28. data/lib/ace/assign/cli.rb +1 -85
  29. data/lib/ace/assign/errors.rb +8 -80
  30. data/lib/ace/assign/models/assignment.rb +5 -28
  31. data/lib/ace/assign/molecules/assignment_manager.rb +0 -26
  32. data/lib/ace/assign/molecules/fork_session_launcher.rb +4 -12
  33. data/lib/ace/assign/molecules/lifecycle_exclusion.rb +15 -112
  34. data/lib/ace/assign/molecules/runtime_control_surface_runner.rb +2 -1
  35. data/lib/ace/assign/organisms/assignment_executor.rb +0 -6
  36. data/lib/ace/assign/organisms/task_assignment_creator.rb +3 -8
  37. data/lib/ace/assign/version.rb +1 -1
  38. data/lib/ace/assign.rb +0 -6
  39. metadata +4 -161
  40. data/.ace-defaults/assign/presets/close-delivery.yml +0 -57
  41. data/.ace-defaults/assign/presets/deliver-release.yml +0 -60
  42. data/.ace-defaults/assign/presets/integrate-batch.yml +0 -72
  43. data/.ace-defaults/assign/presets/supervise-delivery.yml +0 -69
  44. data/docs/protected-authority.md +0 -282
  45. data/exe/ace-scope-ready +0 -55
  46. data/lib/ace/assign/atoms/assignment_scope.rb +0 -58
  47. data/lib/ace/assign/atoms/attempt_state_machine.rb +0 -84
  48. data/lib/ace/assign/atoms/delivery_parameters.rb +0 -19
  49. data/lib/ace/assign/atoms/evidence_digest.rb +0 -78
  50. data/lib/ace/assign/atoms/fixed_merge_schemas.rb +0 -398
  51. data/lib/ace/assign/authority/assignment_definition.rb +0 -35
  52. data/lib/ace/assign/authority/assignment_inventory.rb +0 -290
  53. data/lib/ace/assign/authority/campaign_consumer_policy.rb +0 -100
  54. data/lib/ace/assign/authority/campaign_execution.rb +0 -119
  55. data/lib/ace/assign/authority/campaign_round_transfer.rb +0 -82
  56. data/lib/ace/assign/authority/candidate_transfer.rb +0 -327
  57. data/lib/ace/assign/authority/cleanup_result_protection.rb +0 -53
  58. data/lib/ace/assign/authority/client.rb +0 -257
  59. data/lib/ace/assign/authority/deployment.rb +0 -627
  60. data/lib/ace/assign/authority/deployment_history.rb +0 -146
  61. data/lib/ace/assign/authority/endcap.rb +0 -455
  62. data/lib/ace/assign/authority/endcap_attempts.rb +0 -274
  63. data/lib/ace/assign/authority/endcap_campaign_results.rb +0 -232
  64. data/lib/ace/assign/authority/endcap_campaign_rounds.rb +0 -266
  65. data/lib/ace/assign/authority/endcap_contexts.rb +0 -23
  66. data/lib/ace/assign/authority/endcap_inboxes.rb +0 -37
  67. data/lib/ace/assign/authority/endcap_prepared_work.rb +0 -80
  68. data/lib/ace/assign/authority/endcap_publication.rb +0 -207
  69. data/lib/ace/assign/authority/endcap_results.rb +0 -398
  70. data/lib/ace/assign/authority/endcap_review_requests.rb +0 -183
  71. data/lib/ace/assign/authority/endcap_reviews.rb +0 -130
  72. data/lib/ace/assign/authority/endcap_service_settlement.rb +0 -152
  73. data/lib/ace/assign/authority/endcap_services.rb +0 -598
  74. data/lib/ace/assign/authority/evidence_transfer.rb +0 -67
  75. data/lib/ace/assign/authority/execution_scope_observation.rb +0 -903
  76. data/lib/ace/assign/authority/inbox_context_original.rb +0 -113
  77. data/lib/ace/assign/authority/launch_attempt_consumers.rb +0 -51
  78. data/lib/ace/assign/authority/launch_campaign_registration.rb +0 -214
  79. data/lib/ace/assign/authority/launch_control_channel.rb +0 -313
  80. data/lib/ace/assign/authority/launch_control_exclusions.rb +0 -127
  81. data/lib/ace/assign/authority/launch_driver.rb +0 -393
  82. data/lib/ace/assign/authority/launch_input_inhibition.rb +0 -132
  83. data/lib/ace/assign/authority/launch_lifecycle.rb +0 -997
  84. data/lib/ace/assign/authority/launch_prepared_work.rb +0 -122
  85. data/lib/ace/assign/authority/launch_review.rb +0 -91
  86. data/lib/ace/assign/authority/launch_scope_abort.rb +0 -81
  87. data/lib/ace/assign/authority/launch_scope_admission.rb +0 -215
  88. data/lib/ace/assign/authority/launch_scope_close.rb +0 -146
  89. data/lib/ace/assign/authority/launch_scope_parent.rb +0 -44
  90. data/lib/ace/assign/authority/launch_scope_release.rb +0 -859
  91. data/lib/ace/assign/authority/launch_steering.rb +0 -353
  92. data/lib/ace/assign/authority/launch_stop.rb +0 -254
  93. data/lib/ace/assign/authority/maintenance_workspace_retirement.rb +0 -229
  94. data/lib/ace/assign/authority/ordinary_attempt_start.rb +0 -137
  95. data/lib/ace/assign/authority/ordinary_client.rb +0 -70
  96. data/lib/ace/assign/authority/ordinary_completion.rb +0 -94
  97. data/lib/ace/assign/authority/ordinary_effect_settlement.rb +0 -118
  98. data/lib/ace/assign/authority/ordinary_lifecycle.rb +0 -191
  99. data/lib/ace/assign/authority/ordinary_peer.rb +0 -54
  100. data/lib/ace/assign/authority/ordinary_progress.rb +0 -162
  101. data/lib/ace/assign/authority/ordinary_queue.rb +0 -115
  102. data/lib/ace/assign/authority/ordinary_results.rb +0 -196
  103. data/lib/ace/assign/authority/ordinary_server.rb +0 -75
  104. data/lib/ace/assign/authority/original_inbox_selection.rb +0 -41
  105. data/lib/ace/assign/authority/posix_acl.rb +0 -59
  106. data/lib/ace/assign/authority/prepared_input.rb +0 -130
  107. data/lib/ace/assign/authority/prepared_queue.rb +0 -185
  108. data/lib/ace/assign/authority/prepared_task_context.rb +0 -116
  109. data/lib/ace/assign/authority/prepared_work.rb +0 -304
  110. data/lib/ace/assign/authority/prepared_worker.rb +0 -69
  111. data/lib/ace/assign/authority/private_directory.rb +0 -33
  112. data/lib/ace/assign/authority/protected_assignment_context.rb +0 -226
  113. data/lib/ace/assign/authority/readiness_hook.rb +0 -120
  114. data/lib/ace/assign/authority/receipt_transfer.rb +0 -48
  115. data/lib/ace/assign/authority/router.rb +0 -81
  116. data/lib/ace/assign/authority/server.rb +0 -131
  117. data/lib/ace/assign/authority/service_cleanup_dispatch.rb +0 -88
  118. data/lib/ace/assign/authority/service_cleanup_evidence.rb +0 -180
  119. data/lib/ace/assign/authority/service_delivery_evidence.rb +0 -101
  120. data/lib/ace/assign/authority/service_evidence.rb +0 -286
  121. data/lib/ace/assign/authority/service_publication_evidence.rb +0 -110
  122. data/lib/ace/assign/authority/socket_server.rb +0 -255
  123. data/lib/ace/assign/authority/task_context_entry.rb +0 -32
  124. data/lib/ace/assign/authority/transfer_codec.rb +0 -187
  125. data/lib/ace/assign/cli/commands/attempt/base.rb +0 -84
  126. data/lib/ace/assign/cli/commands/attempt/evidence.rb +0 -28
  127. data/lib/ace/assign/cli/commands/attempt/finish.rb +0 -51
  128. data/lib/ace/assign/cli/commands/attempt/reconcile.rb +0 -49
  129. data/lib/ace/assign/cli/commands/attempt/start.rb +0 -45
  130. data/lib/ace/assign/cli/commands/attempt/status.rb +0 -54
  131. data/lib/ace/assign/cli/commands/authority/inbox_context_principal.rb +0 -25
  132. data/lib/ace/assign/cli/commands/authority/inbox_context_selection.rb +0 -28
  133. data/lib/ace/assign/cli/commands/authority/launch.rb +0 -97
  134. data/lib/ace/assign/cli/commands/authority/serve.rb +0 -31
  135. data/lib/ace/assign/cli/commands/authority/status.rb +0 -26
  136. data/lib/ace/assign/cli/commands/authority/task_context.rb +0 -31
  137. data/lib/ace/assign/cli/commands/authority/task_context_principal.rb +0 -25
  138. data/lib/ace/assign/cli/commands/authority/task_context_selection.rb +0 -30
  139. data/lib/ace/assign/cli/commands/authority/terminate.rb +0 -29
  140. data/lib/ace/assign/cli/commands/authority/worker.rb +0 -23
  141. data/lib/ace/assign/cli/commands/campaign_export_result.rb +0 -55
  142. data/lib/ace/assign/cli/commands/campaign_record_round.rb +0 -57
  143. data/lib/ace/assign/cli/commands/delivery.rb +0 -107
  144. data/lib/ace/assign/cli/commands/inbox_bind.rb +0 -34
  145. data/lib/ace/assign/cli/commands/protected_submission.rb +0 -61
  146. data/lib/ace/assign/cli/commands/resume.rb +0 -38
  147. data/lib/ace/assign/cli/commands/submit_candidate.rb +0 -34
  148. data/lib/ace/assign/cli/commands/submit_result.rb +0 -61
  149. data/lib/ace/assign/models/attempt.rb +0 -178
  150. data/lib/ace/assign/models/attempt_binding.rb +0 -116
  151. data/lib/ace/assign/models/evidence_event.rb +0 -86
  152. data/lib/ace/assign/models/execution_receipt.rb +0 -139
  153. data/lib/ace/assign/molecules/attempt_reconciler.rb +0 -127
  154. data/lib/ace/assign/molecules/attempt_store.rb +0 -201
  155. data/lib/ace/assign/molecules/canonical_attempt_state.rb +0 -151
  156. data/lib/ace/assign/molecules/canonical_evidence.rb +0 -153
  157. data/lib/ace/assign/molecules/canonical_read_commands.rb +0 -84
  158. data/lib/ace/assign/molecules/canonical_read_snapshot.rb +0 -313
  159. data/lib/ace/assign/molecules/evidence_calculator.rb +0 -237
  160. data/lib/ace/assign/molecules/evidence_journal.rb +0 -1912
  161. data/lib/ace/assign/molecules/execution_identity_resolver.rb +0 -137
  162. data/lib/ace/assign/molecules/execution_scope_lineage.rb +0 -345
  163. data/lib/ace/assign/molecules/fixed_effect_reference.rb +0 -31
  164. data/lib/ace/assign/molecules/installed_journal_read.rb +0 -143
  165. data/lib/ace/assign/molecules/journal_input_inhibition.rb +0 -78
  166. data/lib/ace/assign/molecules/journal_mutation.rb +0 -273
  167. data/lib/ace/assign/molecules/journal_prompt_mutation.rb +0 -241
  168. data/lib/ace/assign/molecules/ordinary_merge_cli.rb +0 -68
  169. data/lib/ace/assign/molecules/ordinary_merge_contract.rb +0 -410
  170. data/lib/ace/assign/molecules/original_launch_binding.rb +0 -37
  171. data/lib/ace/assign/molecules/proposal_journal.rb +0 -179
  172. data/lib/ace/assign/molecules/protected_control_exclusion.rb +0 -303
  173. data/lib/ace/assign/molecules/protected_workspace_exclusion.rb +0 -330
  174. data/lib/ace/assign/molecules/protected_workspace_provisioner.rb +0 -164
  175. data/lib/ace/assign/molecules/receipt_verifier.rb +0 -314
  176. data/lib/ace/assign/molecules/terminal_scope_receipt.rb +0 -88
  177. data/lib/ace/assign/organisms/attempt_coordinator.rb +0 -1337
  178. data/lib/ace/assign/organisms/delivery_coordinator.rb +0 -342
  179. data/lib/ace/assign/organisms/ordinary_merge_consumer.rb +0 -365
  180. data/lib/ace/assign/organisms/prepared_work_builder.rb +0 -194
  181. data/lib/ace/assign/organisms/protected_delivery_coordinator.rb +0 -100
@@ -30,7 +30,7 @@ Hard stop rule:
30
30
  - Treat `ace-assign status --assignment <id>@<root>` as the source of truth for fork completion; quiet terminal output is not enough reason to stop or declare a stall.
31
31
  - If a prior terminal or drive session ended, re-enter from assignment state and continue from the next runnable work instead of depending on the old terminal handle.
32
32
  - Before any final response, re-check pinned assignment status. If any runnable `pending` or `active` work remains, continue driving.
33
- - If unrelated dirty files are generated side effects outside task scope, clean/reset them instead of auto-committing them.
33
+ - Preserve unrelated dirty files; commit only task-owned changes.
34
34
  - Use progress updates for partial status only.
35
35
  - Return a final user-facing completion response only when the assignment is complete or the workflow reaches an explicit blocker/failure stop condition.
36
36
  - If pending work remains runnable, continue driving.
@@ -12,8 +12,8 @@ doc-type: workflow
12
12
  title: Drive Assignment Workflow
13
13
  purpose: workflow instruction for driving ace-assign assignment execution
14
14
  ace-docs:
15
- last-updated: '2026-04-23'
16
- last-checked: '2026-04-23'
15
+ last-updated: '2026-10-19'
16
+ last-checked: '2026-10-19'
17
17
  ---
18
18
 
19
19
  # Drive Assignment Workflow
@@ -656,130 +656,54 @@ Follow the instructions directly, performing the described work:
656
656
 
657
657
  **Agent Action:** Execute each instruction line as a task.
658
658
 
659
- ### 4. External Action Rule (Attempt-First)
660
-
661
- Every external-facing step (implement, verify, review, merge, publish, deploy, release) runs inside a scoped attempt. The attempt -- not the report and not exit status -- is the delivery record.
662
-
663
- For an original protected PreparedWorker, use its already admitted assignment,
664
- attempt and selected scope. Do not run the local `attempt start`/receipt-file
665
- sequence below, acquire another attempt, or execute an outer preset step. The
666
- delivery step must already belong to the immutable captured subtree. Submit the
667
- actual candidate and obtain the installed independent reviewer acceptance through
668
- the protected commands supplied by the original drive prompt.
669
-
670
- For an authorized protected merge, retain the exact approved head/candidate
671
- generation, structured input file, installed receiver, authorization and stable
672
- request ID. Read current authority generation for the first new request. Invoke
673
- `ace-lab service request` with those original mapping/assignment/attempt/scope
674
- selectors. Inspect `ace-lab service status` with the same request, input digest and
675
- target, then consume succeeded canonical evidence with `ace-assign delivery
676
- --operation merge --service-request REQUEST` and the same selectors. Include
677
- `--artifact-digest` on status and consumption when the original target has one.
678
- Exact retries retain the original generation, mutation/request ID and input bytes;
679
- uncertainty never permits refreshing or resending an effect. The protected delivery
680
- consumer verifies the imported receipt and canonical delivery event without another
681
- provider mutation. Only that succeeded result permits finishing the active queue
682
- step. Refusal, unavailable evidence or uncertainty leaves it unfinished and reports
683
- the exact blocker. Credentials and queue completion do not replace authorization
684
- or canonical evidence. The following local attempt sequence applies only to
685
- ordinary standalone assignments.
686
-
687
- **Step 1: Start the attempt before executing the step.** Actor identity is derived from the execution boundary; never pass actor flags.
659
+ ### 4. Execute the Active Step Directly
688
660
 
689
- ```bash
690
- ATTEMPT_JSON=$(ace-assign attempt start --assignment "$ASSIGNMENT_ID" --step "$STEP_NUMBER" --project "$PROJECT_ID")
691
- echo "$ATTEMPT_JSON"
692
- ```
693
-
694
- - A repeated identical start returns the same attempt; a conflicting start fails (exit 5). Never launch a second writer for an owned subtree.
695
- - `base_head` is captured exactly once at start. Record the `attempt_id`.
696
-
697
- **Step 2: Execute the step command(s).** If blocked, capture concrete evidence:
698
-
699
- - command attempted
700
- - exact error output
701
- - why the step cannot proceed
702
-
703
- Mark the step failed with evidence (do not report synthetic completion):
704
-
705
- ```bash
706
- ace-assign fail --message "Command failed: <cmd>. Error: <exact stderr>" --assignment "$ASSIGNMENT_TARGET"
707
- ```
708
-
709
- **Step 3: Submit a structured receipt -- never prose -- to close the attempt.**
710
-
711
- ```bash
712
- cat > /tmp/attempt-receipt.json << 'EOF'
713
- {
714
- "attempt_id": "<ATTEMPT_ID>",
715
- "assignment_id": "<ASSIGNMENT_ID>",
716
- "project_id": "<PROJECT_ID>",
717
- "scope": "<STEP_NUMBER>",
718
- "operation": "implement",
719
- "producer": {"actor": "<boundary-actor>", "role": "worker", "runtime": "<boundary-runtime>"},
720
- "head": "<exact tested/reviewed HEAD sha>",
721
- "verdict": "succeeded",
722
- "artifacts": [{"path": "report.md", "sha256": "<sha256>"}],
723
- "checks": [{"name": "ace-test", "verdict": "passed"}],
724
- "review": {"reviewer": {"actor": "<independent-reviewer>", "runtime": "<reviewer-runtime>"}, "verdict": "approved", "head": "<same HEAD sha>"}
725
- }
726
- EOF
727
-
728
- ace-assign attempt finish --attempt "$ATTEMPT_ID" --receipt /tmp/attempt-receipt.json
729
- ```
730
-
731
- Receipt rules enforced by the coordinator:
732
-
733
- - `succeeded` verdicts require verifiable artifact digests, passing checks, and trusted coordinator/service authority; worker runtimes may submit attributable results but cannot self-approve.
734
- - Review approval requires an executed independent reviewer verdict for the exact current head; same author/reviewer and report-only existence are rejected.
735
- - Receipts carrying credentials, environment dumps, or terminal output are rejected outright.
736
- - External effects (`merge`, `publish`, `deploy`, `release`) additionally require an accepted independent review receipt for the current head. Taskless assignments cannot record external effects.
737
-
738
- **Step 4: Handle interruptions by classifying and reconciling -- never by assuming.**
661
+ Execute the active step's instructions directly, run the checks it requires, and
662
+ record the real results in the step report.
739
663
 
740
- ```bash
741
- ace-assign attempt status --assignment "$ASSIGNMENT_ID" --format json
742
- ace-assign attempt reconcile --attempt "$ATTEMPT_ID"
743
- ace-assign attempt reconcile --attempt "$ATTEMPT_ID" --receipt /tmp/attempt-receipt.json
744
- ```
745
-
746
- - A lost receipt after a possible effect is `uncertain`; it resolves only against a verified receipt attributed to the recorded execution boundary.
747
- - Running attempts stay running only while their recorded process is verifiably live; anything else becomes `stopped` or `uncertain`.
748
- - Never replay `merge`, `publish`, or `deploy` automatically. Reconciliation records evidence; it never re-executes effects.
664
+ - If the work is blocked, capture the command you ran, the exact error output,
665
+ and why the step cannot proceed, then fail the step with that evidence (see
666
+ [Handle Failures](#7-handle-failures)).
667
+ - Record actual test and review results for the exact candidate head in the
668
+ assignment report (or the project task folder) before advancing. A report or
669
+ exit code alone is not proof by itself; report only what was actually run.
670
+ - Never replay `merge`, `publish`, or `deploy` automatically. An uncertain
671
+ external effect is reconciled against the authoritative remote/owner first;
672
+ reconciliation never re-executes the effect by itself.
749
673
 
750
674
  #### Integration Gate and Typed Outcomes (every integration invocation)
751
675
 
752
676
  These gates apply at EVERY integration entry point — a native integrate
753
- command, a service invocation, or an assignment integration step — with
754
- shared contract validation so no entry point bypasses them.
677
+ command or an assignment integration step — with shared contract validation so
678
+ no entry point bypasses them.
755
679
 
756
680
  - Before any mutation, resolve FRESH repository, PR, candidate exact head,
757
681
  target base/head, review/test evidence and the authorized executor; recheck
758
682
  target/head immediately before the mutation. A detected race invalidates
759
683
  eligibility for that invocation.
760
- - The low-level privileged integrator ENFORCES the gates and returns one typed
684
+ - The low-level integrator ENFORCES the gates and returns one typed
761
685
  outcome: `merged`, `needs-rebase`, `blocked` or `uncertain`. It never
762
686
  authors, rebases or reviews its own candidate. Relay alone is not
763
- execution: the queue owner monitors until receipt and continuation.
687
+ execution: the integrating agent monitors the actual result and continuation.
764
688
  - If the target (current main) is NOT an ancestor of the candidate head, the
765
- outcome is `needs-rebase`: never merge and never silently rewrite. The queue
766
- owner delegates `wfi://git/rebase` (as-git-rebase, including CHANGELOG
767
- preservation) in the candidate's isolated worktree, obtains refreshed
768
- exact-head checks plus independent review of the NEW head, updates the PR,
769
- verifies remote candidate identity and resubmits. A common old base does
770
- NOT make sibling heads sequentially fast-forwardable.
771
- - Integration is serial in PREPARATION as well as in effect: the accepted
772
- receipt for one candidate causes preparation of ONLY the next selected
773
- candidate — never a mass rebase of the remaining queue. Each candidate, on
774
- its turn: resolve fresh target main; delegate `wfi://git/rebase` in that
775
- candidate's isolated worktree IF needed; run the applicable checks; obtain
776
- an INDEPENDENT EXPLICIT review of the resulting exact head (patch identity
777
- may support a short delta review but never substitutes the explicit
778
- independent head approval); verify the remote PR head/base; issue ONE
779
- scoped integrator request; wait/reconcile the actual integration receipt;
780
- refresh main; select and prepare ONLY the next candidate. Queued later
781
- PRs keep their existing branches/heads untouched until their turn; prior
782
- batch work is never rolled back or reset.
689
+ outcome is `needs-rebase`: never merge and never silently rewrite. The
690
+ integrating agent delegates `wfi://git/rebase` (as-git-rebase, including
691
+ CHANGELOG preservation) in the candidate's isolated worktree, obtains
692
+ refreshed exact-head checks plus independent review of the NEW head, updates
693
+ the PR, verifies remote candidate identity and resubmits. A common old base
694
+ does NOT make sibling heads sequentially fast-forwardable.
695
+ - Integration is serial in PREPARATION as well as in effect: the confirmed
696
+ integration result for one candidate causes preparation of ONLY the next
697
+ selected candidate — never a mass rebase of the remaining queue. Each
698
+ candidate, on its turn: resolve fresh target main; delegate `wfi://git/rebase`
699
+ in that candidate's isolated worktree IF needed; run the applicable checks;
700
+ obtain an INDEPENDENT EXPLICIT review of the resulting exact head (patch
701
+ identity may support a short delta review but never substitutes the explicit
702
+ independent head approval); verify the remote PR head/base; issue ONE scoped
703
+ integrator request; wait/reconcile the actual integration outcome; refresh
704
+ main; select and prepare ONLY the next candidate. Queued later PRs keep their
705
+ existing branches/heads untouched until their turn; prior batch work is never
706
+ rolled back or reset.
783
707
  - `uncertain` triggers reconciliation against the original durable reference;
784
708
  it never permits blind retry.
785
709
  - Never push directly to main; never switch the canonical checkout to a topic
@@ -831,7 +755,9 @@ For a blocked step:
831
755
 
832
756
  ### 5. Write Report (Only After Real Execution)
833
757
 
834
- After the attempt accepted a receipt (or the step was failed with evidence), write a brief report summarizing what was accomplished. The report advances the queue; the accepted attempt receipt carries the delivery evidence:
758
+ After executing the step (or failing it with concrete evidence), write a brief report summarizing what was accomplished. The report is the local record: state what was actually run and link or paste the actual test/review evidence for the exact head.
759
+
760
+ **Re-read state before every finish.** In forked assignment subtrees, queued child steps can auto-advance between status checks, and a report submitted against a stale view can land on the wrong step number. Immediately before every `ace-assign finish --message` (and every `ace-assign fail`), re-run `ace-assign status --assignment "$ASSIGNMENT_TARGET"` and confirm the step you are reporting on is still the active step. If the active step moved, re-target or re-plan the report instead of submitting it against the old step.
835
761
 
836
762
  ```bash
837
763
  # Write report content to a temp file
@@ -842,20 +768,23 @@ Completed the setup step successfully:
842
768
 
843
769
  - Installed all dependencies via npm install
844
770
  - Configured PostgreSQL database connection
845
- - Verified installation with health check
771
+ - Verified installation with health check (command + observed output)
846
772
 
847
773
  All setup prerequisites are now satisfied.
848
774
  EOF
849
775
 
776
+ # Re-check active state immediately before submitting the report
777
+ ace-assign status --assignment "$ASSIGNMENT_TARGET"
778
+
850
779
  # Submit report to advance the queue
851
780
  ace-assign finish --message /tmp/step-report.md --assignment "$ASSIGNMENT_TARGET"
852
781
  ```
853
782
 
854
783
  Prohibited:
855
784
 
856
- - Advancing a step when its attempt has no accepted receipt (or recorded failure evidence).
857
- - Treating a written report, exit 0, or prose as proof of completion. Check `ace-assign attempt status --assignment "$ASSIGNMENT_ID" --format json` for accepted evidence and unresolved effects.
858
- - Reporting `uncertain` attempts as complete; reconcile them first.
785
+ - Advancing a step that was not executed or whose result has no recorded evidence.
786
+ - Treating a written report, exit 0, or prose as proof when the required tests or review were not run.
787
+ - Reporting an uncertain external effect as complete; reconcile the original effect first.
859
788
 
860
789
  ### 6. Verify State Transition (Required)
861
790
 
@@ -1003,7 +932,7 @@ When executing a step with a `skill:` field:
1003
932
  | Step fails | Attempt first, then use `fail` with command/error evidence; decide retry/add/ask |
1004
933
  | Skill not found | Execute instructions directly without skill |
1005
934
  | Unclear instructions | Ask user for clarification |
1006
- | Provider/tool unavailable | For fork steps: see Provider-Unavailability Recovery. For inline steps: attempt with alternate model, then fail with evidence |
935
+ | Provider/tool unavailable | For fork steps: see Provider-Unavailability Recovery. For inline steps: retry with an alternate model, then fail with evidence |
1007
936
 
1008
937
  ## Assignment State Reference
1009
938
 
@@ -334,7 +334,7 @@ steps:
334
334
 
335
335
  ### 8. Output Result
336
336
 
337
- Default output: `<task>/jobs/<timestamp>-job.yml` (e.g., `.ace-task/v.0.9.0/tasks/229-xxx/jobs/k5abc123-job.yml`)
337
+ Default output: `<task>/jobs/<timestamp>-job.yml` (e.g., `.ace-tasks/<task-folder>/jobs/k5abc123-job.yml`)
338
338
 
339
339
  Custom output: Use `--output path/to/custom.yaml`
340
340
 
@@ -3,8 +3,8 @@ doc-type: workflow
3
3
  title: Assign Verify Test Suite Workflow
4
4
  purpose: Narrow deterministic verification contract for ace-assign orchestration
5
5
  ace-docs:
6
- last-updated: 2026-04-13
7
- last-checked: 2026-04-13
6
+ last-updated: 2026-10-19
7
+ last-checked: 2026-10-19
8
8
  ---
9
9
 
10
10
  # Verify Test Suite Workflow
@@ -25,6 +25,12 @@ Do not run `ace-test-e2e` or `ace-test-e2e-suite` from this workflow.
25
25
  4. Run `ace-test <package> all --profile 6` for each modified package.
26
26
  5. Run `ace-test-suite --target all`.
27
27
 
28
+ ## Hermetic Environment Rule (Forked Drive Sessions)
29
+
30
+ Package verification frequently runs inside forked assignment drive sessions, where the launcher exports fork-runtime variables (`ACE_ASSIGN_DEFAULT_TARGET`, `ACE_ASSIGN_CURRENT_ASSIGNMENT_ID`, `ACE_ASSIGN_CURRENT_FORK_ROOT`, `ACE_RUNTIME`, `ACE_ASSIGN_LAUNCH_MODE`, `ACE_ASSIGN_FORK_WINDOW`, `ACE_ASSIGN_CALLBACK_PANE`, `PROJECT_ROOT_PATH`) and ambient tmux session variables (`TMUX`, `TMUX_PANE`) may also be present. Do not scrub these by hand and never bypass the runner with raw `bundle exec rake`/`ruby` inside a forked subtree.
31
+
32
+ Always verify through `ace-test` / `ace-test-suite`: the deterministic test runner applies a hermetic environment policy that drops all ambient `ACE_*` and `LAB_*` runtime configuration (including every `ACE_ASSIGN_*` fork-runtime variable) before any test executes, in-process and for spawned subprocesses. Verification results are therefore identical whether the command runs from a clean shell or from inside a forked drive session; any other invocation forfeits that guarantee.
33
+
28
34
  ## Skip Guidance
29
35
 
30
36
  Skip only when all modified files are documentation, retrospectives, task specs, or similarly non-runnable metadata.
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require_relative "../../authority/protected_assignment_context"
3
2
 
4
3
  module Ace
5
4
  module Assign
@@ -12,16 +11,11 @@ module Ace
12
11
  # - <assignment-id>@<step-number>
13
12
  module AssignmentTarget
14
13
  DEFAULT_TARGET_ENV = "ACE_ASSIGN_DEFAULT_TARGET"
15
- Target = Struct.new(:assignment_id, :scope, :prepared_input, keyword_init: true)
14
+ Target = Struct.new(:assignment_id, :scope, keyword_init: true)
16
15
  View = Struct.new(:assignment, :state, :scoped_state, :active_steps, :next_step, :focus_step, :scope_root, keyword_init: true)
17
16
 
18
17
  private
19
18
 
20
- def refuse_protected_graph_mutation!(options)
21
- context = @protected_assignment_context ||= Ace::Assign::Authority::ProtectedAssignmentContext.load
22
- context.refuse_graph_mutation!(options: options)
23
- end
24
-
25
19
  def resolve_assignment_target(options)
26
20
  assignment_raw = options[:assignment]
27
21
  explicit_target = unless assignment_raw.nil? || assignment_raw.to_s.strip.empty?
@@ -35,13 +29,7 @@ module Ace
35
29
  "does not match #{DEFAULT_TARGET_ENV}=#{target_identity(env_target)}"
36
30
  end
37
31
 
38
- target = explicit_target || env_target || Target.new(assignment_id: nil, scope: nil)
39
- context = @protected_assignment_context ||= Ace::Assign::Authority::ProtectedAssignmentContext.load
40
- target.prepared_input = context.resolve(options: options, assignment_id: target.assignment_id, scope: target.scope)
41
- if target.prepared_input && ![Status, Step, Start, Finish, Fail, Resume].any? { |command| is_a?(command) }
42
- raise AttemptErrors::EvidenceUnavailable, "protected queue command requires a reviewed new prepared version and attempt"
43
- end
44
- target
32
+ explicit_target || env_target || Target.new(assignment_id: nil, scope: nil)
45
33
  end
46
34
 
47
35
  def parse_assignment_target(raw)
@@ -75,7 +63,6 @@ module Ace
75
63
  end
76
64
 
77
65
  def build_executor_for_target(target)
78
- return Ace::Assign::Authority::PreparedExecutor.new(target.prepared_input) if target.prepared_input
79
66
  return Organisms::AssignmentExecutor.new unless target.assignment_id
80
67
 
81
68
  manager = Molecules::AssignmentManager.new
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require "json"
3
2
 
4
3
  module Ace
5
4
  module Assign
@@ -12,7 +11,6 @@ module Ace
12
11
 
13
12
  desc "Create a new workflow assignment"
14
13
 
15
- option :delivery_parameters, desc: "JSON file with forge selection and explicit PR provenance (task mode)"
16
14
  option :yaml, desc: "Path to job.yaml config file"
17
15
  option :task, aliases: ["-t"], type: :array,
18
16
  desc: "Task reference(s), repeatable and comma-separated"
@@ -21,17 +19,14 @@ module Ace
21
19
  option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
22
20
 
23
21
  def call(yaml: nil, task: nil, preset: nil, **options)
24
- refuse_protected_graph_mutation!(options)
25
22
  validate_modes!(yaml, task, preset)
26
- raise Ace::Support::Cli::Error, "--delivery-parameters requires --task" if yaml && options[:delivery_parameters]
27
23
 
28
24
  result = if yaml
29
25
  Organisms::AssignmentExecutor.new.start(yaml)
30
26
  else
31
27
  Organisms::TaskAssignmentCreator.new.call(
32
28
  task_refs: task,
33
- preset_name: preset || Organisms::TaskAssignmentCreator::DEFAULT_PRESET,
34
- delivery_parameters: options[:delivery_parameters] && JSON.parse(File.read(options[:delivery_parameters]))
29
+ preset_name: preset || Organisms::TaskAssignmentCreator::DEFAULT_PRESET
35
30
  )
36
31
  end
37
32
 
@@ -40,8 +35,6 @@ module Ace
40
35
  print_assignment_header(result[:assignment])
41
36
  print_step_instructions(result[:current] || result[:state]&.next_workable)
42
37
  end
43
- rescue JSON::ParserError, Errno::ENOENT
44
- raise Ace::Support::Cli::Error, "Delivery parameters file unavailable or invalid JSON"
45
38
  rescue ArgumentError => e
46
39
  raise Ace::Support::Cli::Error, e.message
47
40
  end
@@ -12,8 +12,6 @@ module Ace
12
12
  desc "Mark current step as failed"
13
13
 
14
14
  option :message, aliases: ["-m"], required: true, desc: "Error message"
15
- option :mapping, desc: "Installed protected launch mapping ID"
16
- option :attempt, desc: "Original protected attempt ID"
17
15
  option :assignment, desc: "Target specific assignment ID"
18
16
  option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
19
17
  option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
@@ -30,10 +28,6 @@ module Ace
30
28
  puts "Step #{failed.number} (#{failed.name}) marked as failed"
31
29
  puts "Updated: #{File.basename(failed.file_path)}"
32
30
  puts "Error: #{message}"
33
- if target.prepared_input
34
- puts "Further work requires a reviewed new prepared version and attempt."
35
- return
36
- end
37
31
  puts
38
32
  puts "Options:"
39
33
  puts "- ace-assign add \"fix-step\" to add a fix step"
@@ -13,8 +13,6 @@ module Ace
13
13
 
14
14
  argument :step, required: false, desc: "Step number to finish (active assignment only)"
15
15
  option :message, aliases: ["-m"], desc: "Report content: string, file path, or pipe stdin"
16
- option :mapping, desc: "Installed protected launch mapping ID"
17
- option :attempt, desc: "Original protected attempt ID"
18
16
  option :assignment, desc: "Target specific assignment ID"
19
17
  option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
20
18
  option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
@@ -26,7 +24,7 @@ module Ace
26
24
 
27
25
  target = resolve_assignment_target(options)
28
26
  executor = build_executor_for_target(target)
29
- report_content = resolve_report_content(options, protected: !target.prepared_input.nil?)
27
+ report_content = resolve_report_content(options)
30
28
  result = executor.finish_step(
31
29
  report_content: report_content,
32
30
  step_number: step,
@@ -74,27 +72,8 @@ module Ace
74
72
 
75
73
  private
76
74
 
77
- def resolve_report_content(options, protected: false)
75
+ def resolve_report_content(options)
78
76
  message = options[:message]&.strip
79
- if protected
80
- limit = Ace::Assign::Authority::PreparedWork::MAX_TEXT
81
- if message && !message.empty? && File.exist?(message)
82
- return File.open(message, File::RDONLY | File::NOFOLLOW | File::NONBLOCK) do |file|
83
- before = file.stat
84
- raise Error, "Report input must be a bounded regular file" unless before.file? && before.size.between?(1, limit)
85
- bytes = file.read(limit + 1)
86
- after = file.stat
87
- unless bytes.bytesize == before.size && [before.dev, before.ino, before.size, before.mtime, before.ctime] ==
88
- [after.dev, after.ino, after.size, after.mtime, after.ctime]
89
- raise Error, "Report input changed"
90
- end
91
- bytes
92
- end
93
- end
94
- bytes = message && !message.empty? ? message : $stdin.read(limit + 1)
95
- raise Error, "Report input exceeds captured text bound" unless bytes && bytes.bytesize.between?(1, limit)
96
- return bytes
97
- end
98
77
  return File.read(message) if message && !message.empty? && File.exist?(message)
99
78
  return message if message && !message.empty?
100
79
 
@@ -26,7 +26,6 @@ module Ace
26
26
  end
27
27
 
28
28
  def call(**options)
29
- refuse_protected_graph_mutation!(options)
30
29
  launcher.launch_provider_session(
31
30
  assignment_id: options[:assignment],
32
31
  fork_root: options[:root],
@@ -23,7 +23,6 @@ module Ace
23
23
  option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
24
24
 
25
25
  def call(id: nil, **options)
26
- refuse_protected_graph_mutation!(options)
27
26
  manager = Molecules::AssignmentManager.new
28
27
 
29
28
  if options[:clear]
@@ -12,8 +12,6 @@ module Ace
12
12
  desc "Start next workable pending step"
13
13
 
14
14
  argument :step, required: false, desc: "Step number to start (active assignment only)"
15
- option :mapping, desc: "Installed protected launch mapping ID"
16
- option :attempt, desc: "Original protected attempt ID"
17
15
  option :assignment, desc: "Target specific assignment ID"
18
16
  option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
19
17
  option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
@@ -41,8 +41,6 @@ module Ace
41
41
  option :format, desc: "Output format (table, json)", default: "table"
42
42
  option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
43
43
  option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
44
- option :mapping, desc: "Installed protected launch mapping ID"
45
- option :attempt, desc: "Original protected attempt ID"
46
44
  option :assignment, desc: "Show status for specific assignment ID"
47
45
  option :all, aliases: ["-a"], type: :boolean, default: false, desc: "Include completed assignments in other assignments section"
48
46
 
@@ -87,14 +85,9 @@ module Ace
87
85
  def status_to_h(assignment, state, active_steps, next_step, target:, scope_root:)
88
86
  # Extract auto_merge config if present in assignment settings or preset
89
87
  auto_merge = false
90
- preset_name = Ace::Assign::Molecules::PresetInferrer.infer_from_assignment(assignment) unless target.prepared_input
88
+ preset_name = Ace::Assign::Molecules::PresetInferrer.infer_from_assignment(assignment)
91
89
  auto_merge = true if preset_name && preset_name.start_with?("work-on-task-auto-merge")
92
90
 
93
- evidence = Ace::Assign::Molecules::EvidenceCalculator.calculate(
94
- auto_merge: auto_merge,
95
- assignment_id: assignment.id
96
- )
97
-
98
91
  payload = {
99
92
  assignment: {
100
93
  id: assignment.id,
@@ -108,9 +101,6 @@ module Ace
108
101
 
109
102
  payload[:next_step] = step_to_h(next_step, effective_fork_provider: effective_fork_provider_for(next_step, scoped_fork_metadata_step(state, next_step, target.scope, scope_root))) if active_steps.empty? && next_step
110
103
 
111
- # Merge exact head evidence into root payload
112
- payload.merge!(evidence)
113
-
114
104
  payload
115
105
  end
116
106
 
@@ -137,10 +127,6 @@ module Ace
137
127
  lines = []
138
128
  lines.concat(compact_summary_lines(view.assignment, view.scoped_state, view.active_steps, view.next_step))
139
129
 
140
- if !target.prepared_input && (attempt_line = compact_attempt_line(view.assignment.id))
141
- lines.insert(1, attempt_line)
142
- end
143
-
144
130
  unless target.assignment_id
145
131
  other_line = compact_other_assignments_line(view.assignment.id, include_completed: include_completed)
146
132
  lines << other_line if other_line
@@ -149,22 +135,6 @@ module Ace
149
135
  puts lines.take(10).join("\n")
150
136
  end
151
137
 
152
- # Active attempt summary projected from the coordinator authority.
153
- def compact_attempt_line(assignment_id)
154
- projection = Organisms::AttemptCoordinator.new.status(assignment_id)
155
- return nil unless projection
156
-
157
- base = projection["base_head"].to_s[0, 7]
158
- candidate = projection["candidate_head"].to_s[0, 7]
159
- line = "Attempt: #{projection['attempt_id']} #{projection['state']}"
160
- line += " | base:#{base}" unless base.to_s.empty?
161
- line += " | cand:#{candidate.empty? ? 'none' : candidate}"
162
- line += " | unresolved: #{projection['unresolved_effects'].join(',')}" if projection["unresolved_effects"].any?
163
- line
164
- rescue Ace::Assign::Error, Ace::Support::Cli::Error
165
- nil
166
- end
167
-
168
138
  def compact_summary_lines(assignment, state, active_steps, next_step)
169
139
  lines = [
170
140
  compact_assignment_line(assignment, state, active_steps, next_step),
@@ -12,8 +12,6 @@ module Ace
12
12
  desc "Show instructions for the active, next, or explicit step"
13
13
 
14
14
  argument :step, required: false, desc: "Exact step number to inspect"
15
- option :mapping, desc: "Installed protected launch mapping ID"
16
- option :attempt, desc: "Original protected attempt ID"
17
15
  option :assignment, desc: "Target specific assignment ID"
18
16
  option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
19
17
  option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
@@ -26,7 +24,7 @@ module Ace
26
24
  return if options[:quiet]
27
25
 
28
26
  if inspected
29
- puts(target.prepared_input ? target.prepared_input.render(inspected.instructions) : inspected.instructions)
27
+ puts(inspected.instructions)
30
28
  else
31
29
  puts no_work_message(view)
32
30
  end