ace-assign 0.71.0 → 0.73.1

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 (197) 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 +5 -2116
  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 -4
  16. data/handbook/workflow-instructions/assign/drive.wf.md +47 -195
  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 +6 -2
  35. data/lib/ace/assign/molecules/skill_assign_source_resolver.rb +9 -0
  36. data/lib/ace/assign/organisms/assignment_executor.rb +0 -6
  37. data/lib/ace/assign/organisms/task_assignment_creator.rb +3 -8
  38. data/lib/ace/assign/version.rb +1 -1
  39. data/lib/ace/assign.rb +0 -6
  40. metadata +22 -176
  41. data/.ace-defaults/assign/presets/close-delivery.yml +0 -57
  42. data/.ace-defaults/assign/presets/deliver-release.yml +0 -60
  43. data/.ace-defaults/assign/presets/integrate-batch.yml +0 -72
  44. data/.ace-defaults/assign/presets/supervise-delivery.yml +0 -69
  45. data/docs/protected-authority.md +0 -282
  46. data/exe/ace-scope-ready +0 -55
  47. data/lib/ace/assign/atoms/assignment_scope.rb +0 -58
  48. data/lib/ace/assign/atoms/attempt_state_machine.rb +0 -84
  49. data/lib/ace/assign/atoms/candidate_limits.rb +0 -20
  50. data/lib/ace/assign/atoms/delivery_parameters.rb +0 -19
  51. data/lib/ace/assign/atoms/evidence_digest.rb +0 -78
  52. data/lib/ace/assign/atoms/fixed_merge_schemas.rb +0 -398
  53. data/lib/ace/assign/atoms/git_blob_batch.rb +0 -59
  54. data/lib/ace/assign/authority/assignment_definition.rb +0 -35
  55. data/lib/ace/assign/authority/assignment_inventory.rb +0 -290
  56. data/lib/ace/assign/authority/campaign_consumer_policy.rb +0 -100
  57. data/lib/ace/assign/authority/campaign_execution.rb +0 -119
  58. data/lib/ace/assign/authority/campaign_round_transfer.rb +0 -82
  59. data/lib/ace/assign/authority/candidate_blob_batch.rb +0 -55
  60. data/lib/ace/assign/authority/candidate_head_comparison.rb +0 -139
  61. data/lib/ace/assign/authority/candidate_transfer.rb +0 -357
  62. data/lib/ace/assign/authority/cleanup_result_protection.rb +0 -53
  63. data/lib/ace/assign/authority/client.rb +0 -257
  64. data/lib/ace/assign/authority/command_execution.rb +0 -180
  65. data/lib/ace/assign/authority/deployment.rb +0 -627
  66. data/lib/ace/assign/authority/deployment_history.rb +0 -146
  67. data/lib/ace/assign/authority/endcap.rb +0 -457
  68. data/lib/ace/assign/authority/endcap_attempts.rb +0 -274
  69. data/lib/ace/assign/authority/endcap_campaign_results.rb +0 -232
  70. data/lib/ace/assign/authority/endcap_campaign_rounds.rb +0 -266
  71. data/lib/ace/assign/authority/endcap_contexts.rb +0 -23
  72. data/lib/ace/assign/authority/endcap_inboxes.rb +0 -37
  73. data/lib/ace/assign/authority/endcap_prepared_work.rb +0 -80
  74. data/lib/ace/assign/authority/endcap_publication.rb +0 -41
  75. data/lib/ace/assign/authority/endcap_results.rb +0 -398
  76. data/lib/ace/assign/authority/endcap_review_requests.rb +0 -183
  77. data/lib/ace/assign/authority/endcap_reviews.rb +0 -130
  78. data/lib/ace/assign/authority/endcap_service_context.rb +0 -38
  79. data/lib/ace/assign/authority/endcap_service_settlement.rb +0 -152
  80. data/lib/ace/assign/authority/evidence_transfer.rb +0 -67
  81. data/lib/ace/assign/authority/execution_scope_observation.rb +0 -903
  82. data/lib/ace/assign/authority/fixed_publication_lifecycle.rb +0 -176
  83. data/lib/ace/assign/authority/fixed_service_lifecycle.rb +0 -594
  84. data/lib/ace/assign/authority/inbox_context_original.rb +0 -113
  85. data/lib/ace/assign/authority/launch_attempt_consumers.rb +0 -51
  86. data/lib/ace/assign/authority/launch_campaign_registration.rb +0 -214
  87. data/lib/ace/assign/authority/launch_control_channel.rb +0 -313
  88. data/lib/ace/assign/authority/launch_control_exclusions.rb +0 -127
  89. data/lib/ace/assign/authority/launch_driver.rb +0 -393
  90. data/lib/ace/assign/authority/launch_input_inhibition.rb +0 -132
  91. data/lib/ace/assign/authority/launch_lifecycle.rb +0 -997
  92. data/lib/ace/assign/authority/launch_prepared_work.rb +0 -122
  93. data/lib/ace/assign/authority/launch_review.rb +0 -91
  94. data/lib/ace/assign/authority/launch_scope_abort.rb +0 -81
  95. data/lib/ace/assign/authority/launch_scope_admission.rb +0 -215
  96. data/lib/ace/assign/authority/launch_scope_close.rb +0 -146
  97. data/lib/ace/assign/authority/launch_scope_parent.rb +0 -44
  98. data/lib/ace/assign/authority/launch_scope_release.rb +0 -859
  99. data/lib/ace/assign/authority/launch_steering.rb +0 -353
  100. data/lib/ace/assign/authority/launch_stop.rb +0 -254
  101. data/lib/ace/assign/authority/maintenance_workspace_retirement.rb +0 -229
  102. data/lib/ace/assign/authority/ordinary_attempt_start.rb +0 -137
  103. data/lib/ace/assign/authority/ordinary_client.rb +0 -70
  104. data/lib/ace/assign/authority/ordinary_completion.rb +0 -104
  105. data/lib/ace/assign/authority/ordinary_effect_settlement.rb +0 -118
  106. data/lib/ace/assign/authority/ordinary_lifecycle.rb +0 -227
  107. data/lib/ace/assign/authority/ordinary_merge_evidence.rb +0 -81
  108. data/lib/ace/assign/authority/ordinary_peer.rb +0 -54
  109. data/lib/ace/assign/authority/ordinary_progress.rb +0 -162
  110. data/lib/ace/assign/authority/ordinary_queue.rb +0 -115
  111. data/lib/ace/assign/authority/ordinary_release_artifacts.rb +0 -143
  112. data/lib/ace/assign/authority/ordinary_results.rb +0 -206
  113. data/lib/ace/assign/authority/ordinary_review_evidence.rb +0 -180
  114. data/lib/ace/assign/authority/ordinary_reviews.rb +0 -214
  115. data/lib/ace/assign/authority/ordinary_server.rb +0 -75
  116. data/lib/ace/assign/authority/ordinary_supervisor.rb +0 -99
  117. data/lib/ace/assign/authority/original_inbox_selection.rb +0 -41
  118. data/lib/ace/assign/authority/posix_acl.rb +0 -59
  119. data/lib/ace/assign/authority/prepared_input.rb +0 -130
  120. data/lib/ace/assign/authority/prepared_queue.rb +0 -185
  121. data/lib/ace/assign/authority/prepared_task_context.rb +0 -116
  122. data/lib/ace/assign/authority/prepared_work.rb +0 -309
  123. data/lib/ace/assign/authority/prepared_worker.rb +0 -69
  124. data/lib/ace/assign/authority/private_directory.rb +0 -33
  125. data/lib/ace/assign/authority/protected_assignment_context.rb +0 -226
  126. data/lib/ace/assign/authority/readiness_hook.rb +0 -120
  127. data/lib/ace/assign/authority/receipt_transfer.rb +0 -48
  128. data/lib/ace/assign/authority/release_artifact_manifest.rb +0 -91
  129. data/lib/ace/assign/authority/retained_input.rb +0 -53
  130. data/lib/ace/assign/authority/router.rb +0 -81
  131. data/lib/ace/assign/authority/server.rb +0 -131
  132. data/lib/ace/assign/authority/service_cleanup_dispatch.rb +0 -88
  133. data/lib/ace/assign/authority/service_cleanup_evidence.rb +0 -180
  134. data/lib/ace/assign/authority/service_delivery_evidence.rb +0 -101
  135. data/lib/ace/assign/authority/service_evidence.rb +0 -286
  136. data/lib/ace/assign/authority/service_publication_evidence.rb +0 -110
  137. data/lib/ace/assign/authority/socket_server.rb +0 -255
  138. data/lib/ace/assign/authority/task_context_entry.rb +0 -32
  139. data/lib/ace/assign/authority/transfer_codec.rb +0 -189
  140. data/lib/ace/assign/cli/commands/attempt/base.rb +0 -84
  141. data/lib/ace/assign/cli/commands/attempt/evidence.rb +0 -28
  142. data/lib/ace/assign/cli/commands/attempt/finish.rb +0 -51
  143. data/lib/ace/assign/cli/commands/attempt/reconcile.rb +0 -49
  144. data/lib/ace/assign/cli/commands/attempt/start.rb +0 -45
  145. data/lib/ace/assign/cli/commands/attempt/status.rb +0 -54
  146. data/lib/ace/assign/cli/commands/authority/inbox_context_principal.rb +0 -25
  147. data/lib/ace/assign/cli/commands/authority/inbox_context_selection.rb +0 -28
  148. data/lib/ace/assign/cli/commands/authority/launch.rb +0 -97
  149. data/lib/ace/assign/cli/commands/authority/serve.rb +0 -31
  150. data/lib/ace/assign/cli/commands/authority/status.rb +0 -26
  151. data/lib/ace/assign/cli/commands/authority/task_context.rb +0 -31
  152. data/lib/ace/assign/cli/commands/authority/task_context_principal.rb +0 -25
  153. data/lib/ace/assign/cli/commands/authority/task_context_selection.rb +0 -30
  154. data/lib/ace/assign/cli/commands/authority/terminate.rb +0 -29
  155. data/lib/ace/assign/cli/commands/authority/worker.rb +0 -23
  156. data/lib/ace/assign/cli/commands/campaign_export_result.rb +0 -55
  157. data/lib/ace/assign/cli/commands/campaign_record_round.rb +0 -57
  158. data/lib/ace/assign/cli/commands/delivery.rb +0 -107
  159. data/lib/ace/assign/cli/commands/inbox_bind.rb +0 -34
  160. data/lib/ace/assign/cli/commands/protected_submission.rb +0 -61
  161. data/lib/ace/assign/cli/commands/resume.rb +0 -38
  162. data/lib/ace/assign/cli/commands/submit_candidate.rb +0 -34
  163. data/lib/ace/assign/cli/commands/submit_result.rb +0 -61
  164. data/lib/ace/assign/models/attempt.rb +0 -178
  165. data/lib/ace/assign/models/attempt_binding.rb +0 -116
  166. data/lib/ace/assign/models/evidence_event.rb +0 -86
  167. data/lib/ace/assign/models/execution_receipt.rb +0 -139
  168. data/lib/ace/assign/molecules/attempt_reconciler.rb +0 -127
  169. data/lib/ace/assign/molecules/attempt_store.rb +0 -201
  170. data/lib/ace/assign/molecules/canonical_attempt_state.rb +0 -151
  171. data/lib/ace/assign/molecules/canonical_evidence.rb +0 -170
  172. data/lib/ace/assign/molecules/canonical_read_commands.rb +0 -84
  173. data/lib/ace/assign/molecules/canonical_read_snapshot.rb +0 -313
  174. data/lib/ace/assign/molecules/evidence_calculator.rb +0 -237
  175. data/lib/ace/assign/molecules/evidence_journal.rb +0 -1899
  176. data/lib/ace/assign/molecules/execution_identity_resolver.rb +0 -137
  177. data/lib/ace/assign/molecules/execution_scope_lineage.rb +0 -345
  178. data/lib/ace/assign/molecules/fixed_effect_reference.rb +0 -31
  179. data/lib/ace/assign/molecules/installed_journal_read.rb +0 -143
  180. data/lib/ace/assign/molecules/journal_input_inhibition.rb +0 -78
  181. data/lib/ace/assign/molecules/journal_mutation.rb +0 -274
  182. data/lib/ace/assign/molecules/journal_prompt_mutation.rb +0 -241
  183. data/lib/ace/assign/molecules/ordinary_merge_cli.rb +0 -68
  184. data/lib/ace/assign/molecules/ordinary_merge_contract.rb +0 -410
  185. data/lib/ace/assign/molecules/original_launch_binding.rb +0 -37
  186. data/lib/ace/assign/molecules/proposal_journal.rb +0 -179
  187. data/lib/ace/assign/molecules/protected_control_exclusion.rb +0 -303
  188. data/lib/ace/assign/molecules/protected_workspace_exclusion.rb +0 -330
  189. data/lib/ace/assign/molecules/protected_workspace_provisioner.rb +0 -164
  190. data/lib/ace/assign/molecules/receipt_verifier.rb +0 -320
  191. data/lib/ace/assign/molecules/terminal_scope_receipt.rb +0 -88
  192. data/lib/ace/assign/organisms/attempt_coordinator.rb +0 -1374
  193. data/lib/ace/assign/organisms/delivery_coordinator.rb +0 -342
  194. data/lib/ace/assign/organisms/ordinary_driver.rb +0 -310
  195. data/lib/ace/assign/organisms/ordinary_merge_consumer.rb +0 -365
  196. data/lib/ace/assign/organisms/prepared_work_builder.rb +0 -194
  197. data/lib/ace/assign/organisms/protected_delivery_coordinator.rb +0 -100
@@ -1,69 +0,0 @@
1
- # Delivery queue supervision over existing producer tasks.
2
- # Usage: ace-assign create --task TASK[,TASK...] --preset supervise-delivery
3
-
4
- name: supervise-delivery
5
- description: Supervise dependency-aware integration and release decisions for several PR-ready producer tasks
6
-
7
- parameters:
8
- taskrefs:
9
- required: true
10
- type: array
11
- description: Existing producer task references to observe as delivery queue entries
12
-
13
- steps:
14
- - name: reconcile-delivery-queue
15
- number: "010"
16
- instructions: |
17
- Reconcile the current canonical Assign attempts, task evidence, candidate heads,
18
- dependency state, and project delivery guide for producer task references:
19
- {{taskrefs}}.
20
-
21
- These are references to producer tasks; never reparent, duplicate, reopen, or
22
- change producer task status. A PR-ready worker remains terminal even while this
23
- delivery assignment stays open. A local objective queue may store goals, next actions, blockers and references;
24
- no second execution queue, journal, daemon, or cache may be created. Treat an empty observation as current input only: Transiently empty
25
- is not accepted completion.
26
-
27
- - name: supervise-delivery-queue
28
- number: "020"
29
- instructions: |
30
- Act as the one running supervisory step for producer task references {{taskrefs}}.
31
- Apply the resolved project decision guide to dependency readiness, integration
32
- grouping, evidence freshness, release/demo/production policy, and available
33
- authority. Integration order follows dependencies and policy, never completion
34
- order or worker finish timestamps.
35
-
36
- Before every integration effect, write a canonical step report containing all
37
- mandatory decision-record fields:
38
- - ordered eligible set;
39
- - selected next entry;
40
- - deferred entries, with a reason for every skipped candidate;
41
- - decision actor and timestamp;
42
- - policy/plan revision and evidence references used for the decision.
43
-
44
- For every entry, evaluate dependency state, exact candidate head SHA, fresh
45
- tests, initial independent review and a documented accepted-head assessment.
46
- An identical rebase needs executed content-identity proof; a minor safe correction
47
- needs integrator reasoning and tests; material or uncertain delta needs independent
48
- delta review. Evaluate required authority, transport and grouping constraints. Re-record the decision after dependency,
49
- candidate head, evidence, authority, transport, or target-branch movement.
50
-
51
- - name: reconcile-integration-operation
52
- number: "030"
53
- instructions: |
54
- Reconcile each requested integration through its original canonical operation.
55
- Use WAIT(reference, next-check) only after an authorized request has a durable
56
- operation reference and an exact public poll/reconcile path. Use
57
- BLOCKED(provision, owner) when authority, transport, provisioning, or the durable
58
- result path is absent. A lost or uncertain response without a durable path is
59
- BLOCKED with the responsible host owner; never invent WAIT and never blindly
60
- repeat launch, merge, publication, or deployment.
61
-
62
- - name: decide-delivery-continuation
63
- number: "040"
64
- instructions: |
65
- Record the explicit project-policy decision to integrate more candidates, cut a
66
- release from the current accepted set, deploy through a separately authorized
67
- project workflow, or keep this delivery open. Preserve callbacks and resume from
68
- canonical state. Producer completion alone never closes this assignment.
69
-
@@ -1,282 +0,0 @@
1
- ---
2
- doc-type: user
3
- purpose: Fixed protected authority deployment and canonical launch lifecycle
4
- ace-docs:
5
- last-updated: 2026-10-05
6
- last-checked: 2026-10-05
7
- subject:
8
- - code:
9
- diff:
10
- paths:
11
- - ace-assign/lib/ace/assign/authority/**/*.rb
12
- - ace-assign/lib/ace/assign/molecules/execution_scope_lineage.rb
13
- - ace-runtime/lib/ace/runtime/molecules/systemd_scope_manager.rb
14
- ---
15
-
16
- # Protected native launch
17
-
18
- `ace-assign authority serve --authority AUTHORITY` runs the standalone launch
19
- composition. Lab owns the services composition using the same Assign server,
20
- router, lifecycle, journal and endpoint. Its full-service startup guard remains
21
- closed while required finish, recovery, inbox and no-effect handlers are incomplete.
22
- The installed `composition` must match the entrypoint. A project has exactly one
23
- configured authority owner; duplicate project owners or endpoints fail before
24
- listener creation.
25
-
26
- An administrator provisions `/etc/ace/assignment-authorities.json`. There is no
27
- caller-selected configuration path or local fallback. The outer object contains
28
- `schema: "ace.assign.authorities/v2"`, `authorities`, `projects`, and
29
- `launch_mappings`; unknown fields are refused. The fixed schema is implemented
30
- by `Ace::Assign::Authority::Deployment`:
31
-
32
- | Installed object | Required fields |
33
- | --- | --- |
34
- | `authorities.ID` | `uid`, `gid`, sorted unique `groups`, `socket_path`, `state_root`, `composition` (`launch` or `services`) |
35
- | `projects.ID` | `journal_repository`, `evidence_git_ref` (`refs/ace/execution`), `evidence_checkout_root`, `assignment_root`, `candidate_root`, `campaign_repository`, `campaign_store_root`, `launcher_uids`, `reviewer_uids`, `worker_uids`, `service_executor_uids`, `supervisor_uids`, `peer_credentials`, optional `service_receivers` |
36
- | `projects.ID.peer_credentials.UID` | `gid`, sorted unique `groups`, `scratch_root`; every configured role UID has one fixed entry |
37
- | `launch_mappings.ID` | `project_id`, `authority_id`, `launcher_uid`, `launcher_gid`, `launcher_groups`, `worker_uid`, `worker_gid`, `worker_groups`, `worker_actor`, `worker_cwd`, `worker_entry`, `worker_env`, `bootstrap`, `bootstrap_sha256`, `native`, `execution_scope`, `task_context_entry` |
38
- | `launch_mappings.ID.native` | `socket_path`, `executable`, `executable_sha256`, `version` (`0.9.3`), `protocol` (`22`), canonical `workspace_id` (`wN`) |
39
- | `launch_mappings.ID.execution_scope` | `backend` (`linux_systemd_cgroup_v2`), `slot_id`, `slice_unit`, `service_unit`, `unit_manifest_sha256`, `boundary_manifest_sha256`, `root_directory`, `runtime_directory`, `network_namespace_path` |
40
-
41
- A services composition requires a nonempty installed `service_receivers` map; launch composition may omit it. Each fixed service ID maps to exactly `{executor_uid, socket_path, staging_root}`. The positive nonroot executor UID belongs to the project's executor allowlist and cannot also be any configured authority, launcher, reviewer, worker or supervisor. This keeps kernel role selection unambiguous and private authority journals inaccessible to executors.
42
-
43
- Receiver socket and staging paths are canonical absolute paths with root-or-executor owned, nonwritable ancestry. Staging is executor-owned mode0700 and disjoint from other receiver staging and authority state roots. The endpoint resides outside private staging, where the actual authority can traverse its ancestry and inspect it. A pre-existing endpoint must be an executor-owned socket with its installed GID and no permissions for others. Duplicate receiver/authority endpoints, substituted paths and unreadable placement refuse before the authority opens its listener or creates journal state. These mappings select identity and placement; operation argv and grants remain the existing Lab ServicePolicy.
44
-
45
- All paths are canonical and absolute. The native socket identity is the observed
46
- `[device, inode, worker_uid]`. The server identity is the exact observed object
47
- `{pid, uid, gid, groups, parent_pid, started_at, host}`, where `started_at` is
48
- `linux:BOOT_ID:START_TICKS`. These observations must be made after the root-owned
49
- native service starts; they cannot be invented, copied from a previous boot, or
50
- supplied by a worker. The immutable per-attempt native stage owns these facts;
51
- the deployment record contains no persisted live server/socket tuple. A replacement
52
- cannot be repinned into the original generation.
53
- The root-installed native service, its executable, environment and configuration
54
- are trusted. Merely running arbitrary worker-supplied server code under the worker
55
- account does not meet this deployment contract.
56
-
57
- The authority, launcher and worker are distinct non-root accounts. Authority
58
- journal/cache/import/candidate/assignment/state roots are authority-owned 0700
59
- with protected ancestry. Peer scratch roots are private to their mapped account.
60
- The authority socket's directory prevents worker/launcher replacement; its group
61
- and narrow installer ACL must permit the configured peers to connect. Native
62
- socket ACL permits the trusted launcher to use the pinned Herdr API. The
63
- bootstrap, payload executable, native executable, mapping and their ancestors are
64
- root-owned and non-writable by the worker. Payload argv/cwd/environment are fixed
65
- installed data; loader and interpreter injection environment fields are refused.
66
-
67
- Linux Yama `ptrace_scope=2`, empty Inh/Prm/Eff/Bnd/Amb capabilities,
68
- `NoNewPrivs=1`, fixed real/effective/saved/filesystem UID/GID and supplementary
69
- groups are mandatory for every participant, including the pinned native server.
70
- The shipped [native build/install instructions](../../ace-runtime/native/README.md)
71
- describe architecture, distro dependencies, immutable artifact digest and service
72
- unit requirements. ACE verifies and refuses missing policy; it does not modify
73
- sysctls, create accounts, change another user's Herdr, or install service policy.
74
-
75
- After installation, the trusted launcher preflights without any mutation or
76
- native creation:
77
-
78
- ```sh
79
- ace-assign authority launch --mapping MAPPING --dry-run
80
- ```
81
-
82
- Launch one managed definition using a stable invocation ID:
83
-
84
- ```sh
85
- ace-assign authority launch --mapping MAPPING --assignment ASSIGNMENT \
86
- --definition /absolute/prepared-definition.json \
87
- --prepared-bundle /absolute/prepared-input.bundle --step 010 \
88
- --base-head EXACT_40_CHARACTER_COMMIT --mutation INVOCATION_ID
89
- ```
90
-
91
- The final definition (maximum 32 KiB) includes the exact `prepared_work` Git
92
- head/tree, manifest and selected subtree reference, with matching `session_id`,
93
- `task_id` and installed `project_id`. `--prepared-bundle` is mandatory: it supplies
94
- the original complete prepared-input Git bundle, bounded to 64 MiB. Both inputs
95
- are read from held regular files with bounded reads and no final symlink following
96
- before launch effects. The authority derives the final definition from the verified
97
- prepared tree and commits it with the exact received bundle in one journal mutation.
98
- Reusing the same definition with different bundle bytes refuses. The owner-private
99
- definition cache remains separate from the worker queue. An active attempt blocks
100
- changed definitions. A fresh reservation creates canonical intent/provisioning,
101
- then the owner activates and binds its independent parent under the slot exclusion.
102
- It pins existing resource objects, the authority mount namespace and the installed
103
- nsfs network namespace. Parent binding selects protected network evidence references
104
- without asserting policy readiness or requiring an available report.
105
-
106
- Native service admission is a separate private canonical CAS after all required
107
- readiness evidence succeeds. Only its fresh winner may start the fixed service;
108
- replay and lost replies never permit another start. Native and original-child
109
- bindings remain separate immutable stages before payload release.
110
-
111
- The original authenticated native layout response fixes workspace/tab/pane and
112
- exact child lineage. Record captures that original child; bind creates the running
113
- attempt without payload permission. The immutable native bootstrap connects once,
114
- sets non-dumpable before admission, and waits for the separate release. Release
115
- commits issuance before one framed permission. Replay returns canonical issuance
116
- without sending another frame. Reply loss after issuance is potentially executed.
117
- A worker-controlled native input/close path can deny or interrupt launch, but cannot
118
- replace the authenticated origin or forge authority release.
119
-
120
- Inspect or request exact native termination through the same installed mapping.
121
- Once the original launcher process has exited, run these commands as a mapped
122
- recovery supervisor with the installed native close ACL; a new process under the
123
- launcher UID does not inherit the original launcher incarnation:
124
-
125
- ```sh
126
- ace-assign authority status --mapping MAPPING --assignment ASSIGNMENT --attempt ATTEMPT
127
- ace-assign authority terminate --mapping MAPPING --assignment ASSIGNMENT --attempt ATTEMPT
128
- ```
129
-
130
- A child pidfd proving exit cannot release the whole parent reservation. The
131
- connected never-native-admitted path seals the original parent before fixed service
132
- stop, records fresh exact recursive-empty/no-pending/resource closure, selects that
133
- canonical proof in the guarded pre-release abort, then privately commits reservation
134
- release after service/inbox settlement at the same immutable journal commit. A lost
135
- reply keeps the original accepted response. Restart can resume a missing private
136
- release without issuing native or payload permission. A new reservation first retires
137
- its exactly released predecessor through the same owner and slot exclusion.
138
-
139
- `observe_execution_scope` is read-only. `close_execution_scope` is an ordinary
140
- canonical mutation: the first fresh call seals, a later fresh call records closure
141
- when verifiable. A fresh sealed close can resume a lost fixed service stop; replay
142
- performs no manager I/O. The private `scope_service_admission` and
143
- `scope_reservation_release` operations are absent from the public allowlist.
144
- Reserve/close RPCs have a fixed 90-second ceiling for bounded manager waits;
145
- other control calls retain their existing ceiling.
146
-
147
- This source checkpoint proves the connected never-native-admitted failure/recovery
148
- path with controlled native-owner observations and real canonical journals. Full
149
- native hook/readiness and post-native writer observation, admitted-but-unbound
150
- cleanup, non-abort terminal release, and complete original/candidate installation
151
- maintenance remain separate required implementation work. The current maintenance
152
- helpers do not yet implement the accepted candidate-deployment union contract.
153
- No source fixture establishes installed namespace, network policy or containment
154
- acceptance; every installed SC remains open.
155
-
156
- Control replies are at most 16 KiB. Source-selected service transfer operations use
157
- a 16 KiB authenticated header followed by bounded raw bytes, a shared 30-second
158
- deadline, exact hashes, upload write-EOF and at most two active transfers. Exact
159
- origin/role admission happens before private spool allocation and is revalidated
160
- before canonical mutation. The standalone launch composition exposes no transfer
161
- operations.
162
-
163
- Source tests and Linux primitive fixtures are separate from installed deployment
164
- acceptance. A Docker kernel with Yama=0 is expected to refuse the product gate;
165
- it does not establish the required positive protected launch proof.
166
-
167
- Protected launch uses only `layout.apply` in the installed workspace. `workspace.get` checks that exact workspace ID before creation; its reply must echo the ID even when another workspace is active. Missing or replaced containers refuse without fallback. Container contents supply no worker evidence. The original fresh layout reply remains the source of the new tab/pane identity.
168
-
169
- Receiver admission reads Linux `system.posix_acl_access` on every directory from
170
- the endpoint parent and private staging root to `/`, and evaluates search access
171
- for the installed executor UID, primary GID and supplemental groups. Named user
172
- entries override group/other entries; the ACL mask constrains named user and
173
- group entries. Absence of an access ACL uses ordinary mode permissions;
174
- unsupported, unreadable or malformed ACL data refuses startup. The authority
175
- must also actually traverse the endpoint and staging parents. This inspection
176
- does not claim an executor readiness handshake or bypass additional LSM policy;
177
- the installed receiver still performs its own bind and private staging checks.
178
-
179
- ## Canonical result Client API
180
-
181
- The source-owned services handlers accept a live mapped worker's bounded result
182
- without terminalizing the attempt or releasing scope. The public seam is
183
- `Ace::Assign::Authority::Client`; no result CLI is introduced. Launch-only
184
- `attempt_status` retains its existing schema without a result selector. These
185
- source handlers and their deterministic tests do not establish installed
186
- full-service deployment acceptance.
187
-
188
- From an admitted services attempt, discover its current candidate and authority
189
- generation, then upload receipt JSON bytes followed by its declared artifact
190
- bytes in order:
191
-
192
- ```ruby
193
- require "ace/assign"
194
- require "json"
195
- require "digest"
196
-
197
- client = Ace::Assign::Authority::Client.new(mapping_id: mapping_id)
198
- binding = {"assignment_id" => assignment_id, "attempt_id" => attempt_id}
199
- status = client.call("attempt_status", binding.merge(
200
- "result_candidate_generation" => nil
201
- )).data
202
- receipt_bytes = File.binread(local_receipt_path)
203
- receipt = JSON.parse(receipt_bytes)
204
- artifacts = receipt.fetch("artifacts").map { |ref| File.binread(ref.fetch("path")) }
205
- params = binding.merge(
206
- "expected_generation" => status.fetch("authority_generation"),
207
- "candidate_generation" => status.fetch("result_candidate_generation"),
208
- "head" => receipt.fetch("head"),
209
- "receipt_sha256" => Digest::SHA256.hexdigest(receipt_bytes)
210
- )
211
- reply = client.call("submit_result", params, mutation_id: persisted_mutation_id,
212
- upload_parts: [receipt_bytes, *artifacts], purpose: :receipt_artifacts, timeout: 30)
213
- result = reply.data
214
- ```
215
-
216
- Only local byte strings cross the boundary; receipt paths are declarations, not
217
- authority filesystem access. The authority checks exact canonical worker
218
- attribution, original receipt digest and SHA256, candidate, native lineage and
219
- current visibility. It normalizes artifact references and writes private
220
- `result_submitted` metadata, imported blobs and a sanitized mutation reply in one
221
- Git CAS. Failed results may have `artifacts: []`; no synthetic artifact is added.
222
- Campaign receipts refuse until the trusted campaign owner is integrated.
223
-
224
- Persist the exact params, mutation ID and ordered byte strings before submission.
225
- An exact retry while the worker remains live and the attempt active returns the
226
- same result without another import. A changed input or fresh mutation ID for the
227
- same candidate conflicts. Correcting a result requires a new candidate generation
228
- even at unchanged HEAD; both records remain immutable. Submission creates no
229
- `receipt_accepted` event or terminal transition.
230
-
231
- The reply contains result ID, head, candidate generation, verdict, ordered
232
- canonical `{path, sha256}` references, generation and journal commit. Its
233
- `uploaded_receipt_sha256`, `original_receipt_digest` and normalized
234
- `receipt_digest` are distinct values. Private receipt, producer and process
235
- binding are excluded from fresh and replay result replies.
236
-
237
- After reply loss or worker exit, the exact owning launcher or mapped supervisor
238
- can discover the retained result and fetch one referenced artifact:
239
-
240
- ```ruby
241
- status = client.call("attempt_status", binding.merge(
242
- "result_candidate_generation" => retained_generation # nil selects latest
243
- )).data
244
- result = status.fetch("submitted_result")
245
- if result && (reference = result.fetch("artifacts").first)
246
- fetched = client.call("evidence_fetch", binding.merge(
247
- "kind" => "result", "purpose_id" => result.fetch("result_id"),
248
- "artifact_id" => reference.fetch("path").delete_prefix("evidence/imports/")
249
- ), download: true, purpose: :artifacts, timeout: 30)
250
- artifact_bytes = fetched.parts.fetch(0)
251
- end
252
- ```
253
-
254
- Client closes its request write side for services status and evidence fetch;
255
- Server refuses extra body bytes before exposing either read projection. Status
256
- reads launch and result projections from one immutable canonical commit.
257
- `authority_generation` is the current CAS generation; a known candidate without
258
- a result has `submitted_result: null`. Unknown selected generation is `missing`;
259
- corrupt or missing referenced provenance is `evidence_unavailable`. Disposable
260
- caches and requester files never supply evidence.
261
-
262
- Fetch returns exactly `descriptor`, `generation`, `journal_commit` and the
263
- Server-generated `transfer` descriptor, with one binary part. Client validates
264
- the closed canonical descriptor, exact selected purpose, one-part framing,
265
- aggregate length and SHA256 before exposing bytes. Owning workers read only
266
- their own results; assigned reviewers read their exact retained review and
267
- same-candidate result under their live process binding; recorded executors read
268
- only their own service evidence. Exact owning launchers and mapped supervisors
269
- read permitted attempt evidence, including retained terminal history. Current
270
- visibility and peer authorization apply to every read. Reassignment revokes the
271
- old reviewer purpose. Inbox and observation evidence refuse until their existing
272
- signer and observer owners provide complete canonical provenance.
273
-
274
- The fixed worker entry is the closed `{interpreter: REF, wrapper: REF}` pair, with
275
- exact path/bytes/SHA256 references (interpreter<=32MiB, wrapper<=1MiB). The
276
- existing installed unit manifest associates the wrapper with `worker_executable`
277
- and the interpreter uniquely with `runtime_dependency`. The wrapper is source,
278
- so it need not carry executable permission; the selected interpreter must. The
279
- original retained mapping pair is part of the authenticated compact release.
280
- The native gate hashes held files, seals a readonly code snapshot, and uses the
281
- fixed isolated Python FD4/FD5 command while preserving operational stdio. No
282
- worker argv/shebang/PATH fallback remains. Native installed acceptance is separate.
data/exe/ace-scope-ready DELETED
@@ -1,55 +0,0 @@
1
- #!/usr/bin/ruby
2
- # frozen_string_literal: true
3
- # Private fixed interpreter action; the unit supplies --disable=gems,rubyopt.
4
- abort "fixed readiness requires one slot" unless ARGV.length == 1 && ARGV.first.match?(/\A[A-Za-z0-9][A-Za-z0-9._-]{0,127}\z/)
5
- abort "readiness startup features differ" if defined?(Gem) || ENV.keys.any? { |key| key.match?(/\A(?:RUBY|GEM|BUNDLE)/) }
6
- protected_path = lambda do |path, directory|
7
- abort "readiness path substituted" unless path.start_with?("/") && File.expand_path(path) == path && File.realpath(path) == path
8
- current = path
9
- loop do
10
- stat = File.lstat(current)
11
- abort "readiness path is writable" unless stat.uid.zero? && !stat.symlink? && (stat.mode & 0o022).zero?
12
- abort "readiness directory differs" if current == path && directory && !stat.directory?
13
- break if current == "/"
14
- current = File.dirname(current)
15
- end
16
- end
17
- $LOAD_PATH.each { |path| protected_path.call(path, true) }
18
- require "json"
19
- require "digest"
20
- path = "/etc/ace/execution-slots/#{ARGV.first}/readiness.json"
21
- protected_path.call(path, false)
22
- bytes = File.open(path, File::RDONLY | File::NOFOLLOW) { |file| file.read(65_537) }
23
- abort "readiness configuration bound differs" unless bytes.bytesize.between?(1, 65_536)
24
- config = JSON.parse(bytes.force_encoding(Encoding::UTF_8), create_additions: false, max_nesting: 8,
25
- allow_duplicate_key: false, allow_comments: false)
26
- runtime = config.fetch("runtime")
27
- references = runtime.fetch("dependencies")
28
- abort "readiness runtime closure oversized" unless references.is_a?(Array) && references.size.between?(1, 256)
29
- total = 0
30
- references.each do |ref|
31
- abort "readiness dependency reference differs" unless ref.is_a?(Hash) && ref.keys.sort == %w[bytes path sha256] &&
32
- ref["path"].is_a?(String) && ref["path"].bytesize.between?(1, 4096) && !ref["path"].include?("\0") &&
33
- ref["bytes"].is_a?(Integer) && ref["bytes"].between?(1, 1_048_576) &&
34
- ref["sha256"].is_a?(String) && ref["sha256"].match?(/\A[0-9a-f]{64}\z/)
35
- total += ref.fetch("bytes")
36
- abort "readiness runtime closure byte bound differs" if total > 16_777_216
37
- protected_path.call(ref.fetch("path"), false)
38
- content = File.open(ref.fetch("path"), File::RDONLY | File::NOFOLLOW) { |file| file.read(ref.fetch("bytes") + 1) }
39
- abort "readiness dependency changed" unless content.bytesize == ref.fetch("bytes") && Digest::SHA256.hexdigest(content) == ref.fetch("sha256")
40
- end
41
- builtins = %w[enumerator.so thread.rb fiber.so rational.so complex.so ruby2_keywords.rb]
42
- $LOADED_FEATURES.each do |feature|
43
- abort "readiness startup loaded undeclared code" unless builtins.include?(feature) || references.any? { |ref| ref.fetch("path") == feature }
44
- end
45
- paths = runtime.fetch("load_paths")
46
- abort "readiness load paths oversized" unless paths.is_a?(Array) && paths.size.between?(1, 16)
47
- paths.each { |selected| protected_path.call(selected, true) }
48
- $LOAD_PATH.replace(paths)
49
- require "ace/runtime/molecules/readiness_configuration"
50
- require "ace/runtime/molecules/readiness_runtime"
51
- configuration = Ace::Runtime::Molecules::ReadinessConfiguration.decode(bytes, slot: ARGV.first)
52
- Ace::Runtime::Molecules::ReadinessRuntime.new(configuration: configuration.data).activate!
53
- require "ace/assign/errors"
54
- require "ace/assign/authority/readiness_hook"
55
- Ace::Assign::Authority::ReadinessHook.new(slot: ARGV.first, configuration: configuration).run
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ace
4
- module Assign
5
- module Atoms
6
- # Pure validation and canonicalization of attempt scopes.
7
- #
8
- # An attempt scope is the step/subtree an attempt owns, expressed as a
9
- # step number ("010", "010.01"). Scopes are canonicalized before they
10
- # key ownership locks, journal paths, or binding comparisons so that
11
- # cosmetic differences cannot create a second writer.
12
- module AssignmentScope
13
- SCOPE_PATTERN = /\A\d+(?:\.\d+)*\z/.freeze
14
-
15
- # Canonicalize and validate a step/subtree scope.
16
- #
17
- # @param step [String] Step or subtree root number
18
- # @return [String] Canonical scope
19
- # @raise [Ace::Assign::AttemptErrors::InvalidScope] if blank or malformed
20
- def self.canonicalize(step)
21
- scope = step.to_s.strip
22
- if scope.empty? || !scope.match?(SCOPE_PATTERN)
23
- raise Ace::Assign::AttemptErrors::InvalidScope,
24
- "Invalid attempt scope '#{step}': expected a step number such as 010 or 010.01"
25
- end
26
-
27
- scope
28
- end
29
-
30
- # Filesystem-safe token for an assignment/scope pair, used to key
31
- # active-attempt ownership records.
32
- #
33
- # @param assignment_id [String] Assignment ID
34
- # @param scope [String] Canonical scope
35
- # @return [String] Ownership key token
36
- def self.ownership_key(assignment_id, scope)
37
- "#{assignment_id}-#{canonicalize(scope)}.json"
38
- end
39
-
40
- # Compare two scopes for binding identity.
41
- #
42
- # @param left [String] First scope
43
- # @param right [String] Second scope
44
- # @return [Boolean] True if both canonicalize to the same scope
45
- def self.equal?(left, right)
46
- canonicalize(left) == canonicalize(right)
47
- rescue Ace::Assign::AttemptErrors::InvalidScope
48
- false
49
- end
50
-
51
- # An owner of a subtree also owns every descendant scope.
52
- def self.overlap?(left, right)
53
- equal?(left, right) || left.start_with?("#{right}.") || right.start_with?("#{left}.")
54
- end
55
- end
56
- end
57
- end
58
- end
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ace
4
- module Assign
5
- module Atoms
6
- # Pure state machine for assignment attempt lifecycles.
7
- #
8
- # Legal transitions:
9
- # - reserved -> running
10
- # - running -> succeeded | failed | stopped | uncertain
11
- # - uncertain -> succeeded | failed (only via reconciliation)
12
- #
13
- # Terminal states are succeeded, failed, and stopped. Terminal attempts
14
- # never accept new transitions, effects, or receipts; accepted history is
15
- # immutable. A stop is never success, and an uncertain attempt must be
16
- # resolved through explicit reconciliation, never automatic replay.
17
- module AttemptStateMachine
18
- STATES = %w[reserved running succeeded failed stopped uncertain].freeze
19
- TERMINAL_STATES = %w[succeeded failed stopped].freeze
20
- RESOLVED_STATES = %w[succeeded failed].freeze
21
-
22
- TRANSITIONS = {
23
- "reserved" => %w[running].freeze,
24
- "running" => %w[succeeded failed stopped uncertain].freeze,
25
- "uncertain" => RESOLVED_STATES.freeze
26
- }.freeze
27
-
28
- # @return [Array<String>] All known attempt states
29
- def self.states
30
- STATES
31
- end
32
-
33
- # @param state [String] State to inspect
34
- # @return [Boolean] True if the state is terminal (no further transitions)
35
- def self.terminal?(state)
36
- TERMINAL_STATES.include?(state.to_s)
37
- end
38
-
39
- # @param state [String] State to inspect
40
- # @return [Boolean] True if the state awaits reconciliation
41
- def self.uncertain?(state)
42
- state.to_s == "uncertain"
43
- end
44
-
45
- # Check whether a transition is legal without raising.
46
- #
47
- # @param from [String] Current state
48
- # @param to [String] Requested next state
49
- # @return [Boolean] True if the transition is legal
50
- def self.can_transition?(from, to)
51
- TRANSITIONS.fetch(from.to_s, []).include?(to.to_s)
52
- end
53
-
54
- # Return the legal next states for a state.
55
- #
56
- # @param from [String] Current state
57
- # @return [Array<String>] Legal next states (empty for unknown/terminal)
58
- def self.next_states(from)
59
- TRANSITIONS.fetch(from.to_s, [])
60
- end
61
-
62
- # Source-owned cessation, invoked only after original no-writers and
63
- # exhaustive independent settlement proof. This does not broaden the
64
- # ordinary uncertain receipt-reconciliation transition table.
65
- def self.proof_stopped_transition!(state)
66
- return "stopped" if %w[running uncertain].include?(state.to_s)
67
- raise AttemptErrors::InvalidTransition, "Proof-linked stop requires an active bound attempt"
68
- end
69
-
70
- # Validate a transition.
71
- #
72
- # @param from [String] Current state
73
- # @param to [String] Requested next state
74
- # @raise [Ace::Assign::AttemptErrors::InvalidTransition] if illegal
75
- def self.transition!(from, to)
76
- return to.to_s if can_transition?(from, to)
77
-
78
- raise Ace::Assign::AttemptErrors::InvalidTransition,
79
- "Illegal attempt transition #{from} -> #{to} (legal from #{from}: #{next_states(from).join(', ')})"
80
- end
81
- end
82
- end
83
- end
84
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ace
4
- module Assign
5
- module Atoms
6
- # Closed candidate-purpose budgets. Reports and release gems retain their
7
- # separate bounds; callers cannot select a larger wire/storage ceiling.
8
- module CandidateLimits
9
- BYTES = 128 * 1024 * 1024
10
- PREPARED_BYTES = 64 * 1024 * 1024
11
- REVIEW_SNAPSHOT_BYTES = 64 * 1024 * 1024
12
- # Explicit finite path shape (PATH_MAX/NAME_MAX-sized) so a hostile
13
- # tree entry cannot push unbounded path bytes into inventories,
14
- # filesystem prefix creation or per-component scans.
15
- PATH_BYTES = 4096
16
- PATH_COMPONENT_BYTES = 255
17
- end
18
- end
19
- end
20
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
- require "ace/git/atoms/delivery_parameters"
3
-
4
- module Ace
5
- module Assign
6
- module Atoms
7
- # Assignment configuration consumes the shared forge-neutral owner.
8
- module DeliveryParameters
9
- def self.validate(input)
10
- Ace::Git::Atoms::DeliveryParameters.validate(input)
11
- end
12
-
13
- def self.validate_url!(url)
14
- Ace::Git::Atoms::DeliveryParameters.validate_url!(url)
15
- end
16
- end
17
- end
18
- end
19
- end