ace-assign 0.64.0 → 0.66.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.
- checksums.yaml +4 -4
- data/.ace-defaults/assign/catalog/steps/auto-merge.step.yml +11 -0
- data/CHANGELOG.md +25 -0
- data/docs/protected-authority.md +23 -7
- data/docs/usage.md +117 -4
- data/exe/ace-scope-ready +55 -0
- data/handbook/workflow-instructions/assign/drive.wf.md +26 -1
- data/lib/ace/assign/atoms/attempt_state_machine.rb +8 -0
- data/lib/ace/assign/atoms/delivery_parameters.rb +4 -39
- data/lib/ace/assign/authority/assignment_inventory.rb +290 -0
- data/lib/ace/assign/authority/campaign_consumer_policy.rb +100 -0
- data/lib/ace/assign/authority/campaign_execution.rb +119 -0
- data/lib/ace/assign/authority/campaign_round_transfer.rb +82 -0
- data/lib/ace/assign/authority/candidate_transfer.rb +169 -2
- data/lib/ace/assign/authority/cleanup_result_protection.rb +53 -0
- data/lib/ace/assign/authority/client.rb +156 -6
- data/lib/ace/assign/authority/deployment.rb +201 -39
- data/lib/ace/assign/authority/deployment_history.rb +146 -0
- data/lib/ace/assign/authority/endcap.rb +131 -18
- data/lib/ace/assign/authority/endcap_attempts.rb +274 -0
- data/lib/ace/assign/authority/endcap_campaign_results.rb +232 -0
- data/lib/ace/assign/authority/endcap_campaign_rounds.rb +266 -0
- data/lib/ace/assign/authority/endcap_contexts.rb +23 -0
- data/lib/ace/assign/authority/endcap_inboxes.rb +3 -280
- data/lib/ace/assign/authority/endcap_prepared_work.rb +80 -0
- data/lib/ace/assign/authority/endcap_publication.rb +207 -0
- data/lib/ace/assign/authority/endcap_results.rb +36 -18
- data/lib/ace/assign/authority/endcap_review_requests.rb +183 -0
- data/lib/ace/assign/authority/endcap_reviews.rb +130 -0
- data/lib/ace/assign/authority/endcap_service_settlement.rb +152 -0
- data/lib/ace/assign/authority/endcap_services.rb +221 -18
- data/lib/ace/assign/authority/execution_scope_observation.rb +468 -41
- data/lib/ace/assign/authority/inbox_context_original.rb +113 -0
- data/lib/ace/assign/authority/launch_attempt_consumers.rb +51 -0
- data/lib/ace/assign/authority/launch_campaign_registration.rb +214 -0
- data/lib/ace/assign/authority/launch_control_channel.rb +313 -0
- data/lib/ace/assign/authority/launch_control_exclusions.rb +141 -0
- data/lib/ace/assign/authority/launch_driver.rb +298 -19
- data/lib/ace/assign/authority/launch_input_inhibition.rb +132 -0
- data/lib/ace/assign/authority/launch_lifecycle.rb +275 -100
- data/lib/ace/assign/authority/launch_prepared_work.rb +122 -0
- data/lib/ace/assign/authority/launch_review.rb +91 -0
- data/lib/ace/assign/authority/launch_scope_abort.rb +0 -7
- data/lib/ace/assign/authority/launch_scope_admission.rb +136 -5
- data/lib/ace/assign/authority/launch_scope_close.rb +68 -37
- data/lib/ace/assign/authority/launch_scope_release.rb +696 -17
- data/lib/ace/assign/authority/launch_steering.rb +353 -0
- data/lib/ace/assign/authority/launch_stop.rb +254 -0
- data/lib/ace/assign/authority/maintenance_workspace_retirement.rb +229 -0
- data/lib/ace/assign/authority/original_inbox_selection.rb +41 -0
- data/lib/ace/assign/authority/posix_acl.rb +5 -2
- data/lib/ace/assign/authority/prepared_input.rb +130 -0
- data/lib/ace/assign/authority/prepared_queue.rb +185 -0
- data/lib/ace/assign/authority/prepared_task_context.rb +116 -0
- data/lib/ace/assign/authority/prepared_work.rb +304 -0
- data/lib/ace/assign/authority/prepared_worker.rb +69 -0
- data/lib/ace/assign/authority/protected_assignment_context.rb +226 -0
- data/lib/ace/assign/authority/readiness_hook.rb +120 -0
- data/lib/ace/assign/authority/router.rb +24 -2
- data/lib/ace/assign/authority/server.rb +103 -33
- data/lib/ace/assign/authority/service_cleanup_dispatch.rb +88 -0
- data/lib/ace/assign/authority/service_cleanup_evidence.rb +180 -0
- data/lib/ace/assign/authority/service_delivery_evidence.rb +101 -0
- data/lib/ace/assign/authority/service_evidence.rb +243 -12
- data/lib/ace/assign/authority/service_publication_evidence.rb +110 -0
- data/lib/ace/assign/authority/task_context_entry.rb +32 -0
- data/lib/ace/assign/authority/transfer_codec.rb +44 -12
- data/lib/ace/assign/cli/commands/assignment_target.rb +15 -2
- data/lib/ace/assign/cli/commands/attempt/base.rb +49 -0
- data/lib/ace/assign/cli/commands/attempt/finish.rb +20 -4
- data/lib/ace/assign/cli/commands/attempt/reconcile.rb +11 -0
- data/lib/ace/assign/cli/commands/authority/inbox_context_principal.rb +25 -0
- data/lib/ace/assign/cli/commands/authority/inbox_context_selection.rb +28 -0
- data/lib/ace/assign/cli/commands/authority/launch.rb +58 -6
- data/lib/ace/assign/cli/commands/authority/serve.rb +2 -1
- data/lib/ace/assign/cli/commands/authority/status.rb +1 -1
- data/lib/ace/assign/cli/commands/authority/task_context.rb +31 -0
- data/lib/ace/assign/cli/commands/authority/task_context_principal.rb +25 -0
- data/lib/ace/assign/cli/commands/authority/task_context_selection.rb +30 -0
- data/lib/ace/assign/cli/commands/authority/worker.rb +23 -0
- data/lib/ace/assign/cli/commands/campaign_export_result.rb +55 -0
- data/lib/ace/assign/cli/commands/campaign_record_round.rb +57 -0
- data/lib/ace/assign/cli/commands/create.rb +2 -0
- data/lib/ace/assign/cli/commands/delivery.rb +54 -4
- data/lib/ace/assign/cli/commands/fail.rb +6 -0
- data/lib/ace/assign/cli/commands/finish.rb +23 -2
- data/lib/ace/assign/cli/commands/fork_session.rb +6 -2
- data/lib/ace/assign/cli/commands/inbox_bind.rb +34 -0
- data/lib/ace/assign/cli/commands/protected_submission.rb +61 -0
- data/lib/ace/assign/cli/commands/resume.rb +12 -0
- data/lib/ace/assign/cli/commands/select.rb +2 -0
- data/lib/ace/assign/cli/commands/start.rb +2 -0
- data/lib/ace/assign/cli/commands/status.rb +4 -2
- data/lib/ace/assign/cli/commands/step.rb +3 -1
- data/lib/ace/assign/cli/commands/submit_candidate.rb +34 -0
- data/lib/ace/assign/cli/commands/submit_result.rb +61 -0
- data/lib/ace/assign/cli.rb +36 -5
- data/lib/ace/assign/errors.rb +139 -0
- data/lib/ace/assign/models/assignment.rb +26 -4
- data/lib/ace/assign/models/evidence_event.rb +3 -3
- data/lib/ace/assign/molecules/assignment_manager.rb +12 -2
- data/lib/ace/assign/molecules/attempt_reconciler.rb +20 -0
- data/lib/ace/assign/molecules/canonical_attempt_state.rb +151 -0
- data/lib/ace/assign/molecules/canonical_evidence.rb +5 -2
- data/lib/ace/assign/molecules/canonical_read_snapshot.rb +374 -0
- data/lib/ace/assign/molecules/evidence_journal.rb +720 -44
- data/lib/ace/assign/molecules/execution_scope_lineage.rb +27 -9
- data/lib/ace/assign/molecules/fork_session_launcher.rb +16 -6
- data/lib/ace/assign/molecules/journal_input_inhibition.rb +78 -0
- data/lib/ace/assign/molecules/journal_mutation.rb +82 -13
- data/lib/ace/assign/molecules/journal_prompt_mutation.rb +241 -0
- data/lib/ace/assign/molecules/lifecycle_exclusion.rb +178 -26
- data/lib/ace/assign/molecules/original_launch_binding.rb +37 -0
- data/lib/ace/assign/molecules/protected_control_exclusion.rb +303 -0
- data/lib/ace/assign/molecules/protected_workspace_exclusion.rb +330 -0
- data/lib/ace/assign/molecules/protected_workspace_provisioner.rb +164 -0
- data/lib/ace/assign/molecules/queue_scanner.rb +26 -11
- data/lib/ace/assign/molecules/receipt_verifier.rb +21 -15
- data/lib/ace/assign/molecules/step_writer.rb +27 -5
- data/lib/ace/assign/molecules/terminal_scope_receipt.rb +88 -0
- data/lib/ace/assign/organisms/assignment_executor.rb +4 -4
- data/lib/ace/assign/organisms/attempt_coordinator.rb +66 -76
- data/lib/ace/assign/organisms/prepared_work_builder.rb +194 -0
- data/lib/ace/assign/organisms/protected_delivery_coordinator.rb +100 -0
- data/lib/ace/assign/organisms/task_assignment_creator.rb +4 -2
- data/lib/ace/assign/version.rb +1 -1
- data/lib/ace/assign.rb +1 -112
- metadata +90 -11
- data/lib/ace/assign/cli/commands/inbox_reconcile.rb +0 -36
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f3a7677c3fb1ce863011485e2d0b2274f447f444292eecd60dc19a5b6df2a53a
|
|
4
|
+
data.tar.gz: 4519d9fd2fac314f8f2769e63e13a06d05b915061ef1993147ce56c352262f06
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b7cc2b8df1826250baa869d8ecac05474ee2cc0762737b3cf848e51f310436df47517a8370ffced04a82cd398f8b817f63b1fc9de9e081efcfd0331e7c2f339
|
|
7
|
+
data.tar.gz: 3003f3e3cf8729d99d1810aa5cb152c58dd6a50f182f8321b782a7dcd5f96e89fd9558bfe582e213b5108add78d8a213c2b4f5d0317e85a07a12e3f8d3f643d5
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
name: auto-merge
|
|
2
|
+
description: Consume an authorized exact-candidate merge through the delivery owner
|
|
3
|
+
workflow: wfi://assign/drive
|
|
4
|
+
instructions: |
|
|
5
|
+
Merge only when separately authorized and the existing merge checks pass.
|
|
6
|
+
For an original protected worker, follow the protected delivery rule in
|
|
7
|
+
wfi://assign/drive using the admitted assignment, attempt and scope. Retain
|
|
8
|
+
exact approved candidate and request selectors. Request the installed service,
|
|
9
|
+
inspect canonical status, and consume its succeeded result with ace-assign
|
|
10
|
+
delivery. Never execute another provider effect during result consumption.
|
|
11
|
+
Refused, unavailable or uncertain delivery leaves this step unfinished.
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.66.1] - 2026-10-10
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Require the published producer and consumer patch versions containing the protected context and managed-attempt APIs; exclude incompatible prior dependency graphs.
|
|
15
|
+
|
|
16
|
+
## [0.66.0] - 2026-10-08
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Connect protected PR delivery and parent/child campaign results to the canonical assignment owner, with current candidate checks, independent review and original operation authorization.
|
|
21
|
+
- Launch authenticated prepared workers through the existing ace-llm provider CLI in the original terminal.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Remove message-read proofs, observation/signing APIs and Inbox settlement requirements from finish, recovery and stop. Retain actual service/result/review evidence and whole-scope writer checks.
|
|
26
|
+
- Reuse verified immutable journal inventories only within a single operation while retaining fresh admission and compare-and-swap checks.
|
|
27
|
+
- Preserve original workspace leases when provider ownership or shutdown is uncertain.
|
|
28
|
+
|
|
29
|
+
## [0.65.0] - 2026-10-06
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- Source-only protected original/candidate deployment inventory and shared execution-slot exclusions with immutable journal snapshots; full maintenance eligibility and retirement remain unavailable until historical authentication and current inventory verification are connected.
|
|
34
|
+
|
|
10
35
|
## [0.64.0] - 2026-10-05
|
|
11
36
|
|
|
12
37
|
### Added
|
data/docs/protected-authority.md
CHANGED
|
@@ -32,9 +32,9 @@ by `Ace::Assign::Authority::Deployment`:
|
|
|
32
32
|
| Installed object | Required fields |
|
|
33
33
|
| --- | --- |
|
|
34
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`, `launcher_uids`, `reviewer_uids`, `worker_uids`, `service_executor_uids`, `supervisor_uids`, `peer_credentials`, optional `service_receivers` |
|
|
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
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`, `
|
|
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
38
|
| `launch_mappings.ID.native` | `socket_path`, `executable`, `executable_sha256`, `version` (`0.9.3`), `protocol` (`22`), canonical `workspace_id` (`wN`) |
|
|
39
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
40
|
|
|
@@ -83,14 +83,20 @@ Launch one managed definition using a stable invocation ID:
|
|
|
83
83
|
|
|
84
84
|
```sh
|
|
85
85
|
ace-assign authority launch --mapping MAPPING --assignment ASSIGNMENT \
|
|
86
|
-
--definition /absolute/
|
|
86
|
+
--definition /absolute/prepared-definition.json \
|
|
87
|
+
--prepared-bundle /absolute/prepared-input.bundle --step 010 \
|
|
87
88
|
--base-head EXACT_40_CHARACTER_COMMIT --mutation INVOCATION_ID
|
|
88
89
|
```
|
|
89
90
|
|
|
90
|
-
The definition
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
94
100
|
changed definitions. A fresh reservation creates canonical intent/provisioning,
|
|
95
101
|
then the owner activates and binds its independent parent under the slot exclusion.
|
|
96
102
|
It pins existing resource objects, the authority mount namespace and the installed
|
|
@@ -264,3 +270,13 @@ read permitted attempt evidence, including retained terminal history. Current
|
|
|
264
270
|
visibility and peer authorization apply to every read. Reassignment revokes the
|
|
265
271
|
old reviewer purpose. Inbox and observation evidence refuse until their existing
|
|
266
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/docs/usage.md
CHANGED
|
@@ -89,7 +89,9 @@ ace-assign add --yaml .ace-local/assign/jobs/add-task.yml --after 010 --child
|
|
|
89
89
|
|
|
90
90
|
Execution evidence lives in assignment attempts, not in reports. An attempt binds an immutable ID to an assignment, step/subtree scope, project, boundary-derived actor/role/runtime, source task, and `base_head`; the deliverable `candidate_head` is pinned only when accepted evidence is submitted, and the evidence journal commit is tracked separately from both.
|
|
91
91
|
|
|
92
|
-
###
|
|
92
|
+
### Ordinary local attempt lifecycle
|
|
93
|
+
|
|
94
|
+
Lifecycle exclusion uses the selected repository's actual Git common directory, shared by linked worktrees. `CACHE_BASE` changes assignment cache storage but cannot split creator and prune locks into a separate namespace. A missing Git repository or malformed retained removal fence refuses admission; it does not create a fallback lock root.
|
|
93
95
|
|
|
94
96
|
```bash
|
|
95
97
|
ace-assign attempt start --assignment ASSIGNMENT --step STEP --project PROJECT
|
|
@@ -103,6 +105,20 @@ ace-assign attempt reconcile --attempt ATTEMPT --receipt receipt.json
|
|
|
103
105
|
- `attempt finish` accepts a structured receipt: operation, attributed producer, exact tested/reviewed head, verdict, artifact paths with SHA-256 digests, executed checks, and -- for review operations -- an executed independent reviewer verdict for that head.
|
|
104
106
|
- `attempt reconcile` classifies interrupted attempts (`uncertain` when launch or effect completion cannot be proven either way, still `running` only for verifiably live processes) and resolves uncertainty only against a verified receipt attributed to the recorded execution boundary. Merge, publish, and deploy effects are never replayed automatically.
|
|
105
107
|
|
|
108
|
+
### Protected completion, recovery and Inbox registration
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
ace-assign attempt finish --mapping MAP --assignment ASSIGNMENT --attempt ATTEMPT --result RESULT --head SHA --candidate-generation N --mutation ID --expected-generation N
|
|
112
|
+
ace-assign attempt reconcile --mapping MAP --assignment ASSIGNMENT --attempt ATTEMPT --mutation ID --expected-generation N
|
|
113
|
+
ace-assign inbox-bind --mapping MAP --assignment ASSIGNMENT --attempt ATTEMPT --event EVENT --inbox-context CONTEXT --mutation ID --expected-generation N
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The installed authority authenticates the current caller. Finish and recovery require the original launcher or an authorized mapped supervisor; Inbox binding requires the original worker or its authenticated descendant and an open execution scope. Installed current or retained authority, service and Inbox accounts also stay on the protected path: unsupported roles refuse rather than opening local authority.
|
|
117
|
+
|
|
118
|
+
Protected finish selects an already submitted canonical result. A succeeded result requires accepted independent review for that exact candidate, prior no-writers proof and complete service settlement. It does not close the scope or accept `--receipt`. Protected recovery observes one original attempt; unresolved service effects remain unresolved. Terminal/released recovery returns authenticated retained selectors without creating another mutation or restarting execution. Inbox binding retains the original event/attempt attribution; fresh binding after scope seal refuses.
|
|
119
|
+
|
|
120
|
+
Keep the original `--mutation` and `--expected-generation` for exact retries. Authority generation is distinct from `--candidate-generation`; rereading a newer generation changes the request. Assignment, attempt and mapping hints must agree with explicit selection. Commands print canonical JSON metadata and never resend effects during recovery.
|
|
121
|
+
|
|
106
122
|
### State machine
|
|
107
123
|
|
|
108
124
|
`reserved -> running -> succeeded | failed | stopped | uncertain`; reconciliation may resolve `uncertain -> succeeded | failed`. Terminal attempts accept no new effects, and accepted history is append-only.
|
|
@@ -422,14 +438,19 @@ See [exit-codes.md](exit-codes.md) for complete descriptions.
|
|
|
422
438
|
```bash
|
|
423
439
|
ace-assign resume --assignment ID --dry-run
|
|
424
440
|
ace-assign resume --assignment ID
|
|
425
|
-
ace-assign inbox-reconcile --attempt ID --event ID --receipt proof.json
|
|
426
441
|
```
|
|
427
442
|
|
|
428
|
-
|
|
443
|
+
Resume returns JSON with task goal, checkpoint, attempts, pending HITL references and unresolved effect/inbox references. Each attempt reports `adopt`, `restart-required` or `reconcile-required`, liveness, recovery reason and its last verified observation. Dry-run writes nothing. Actual resume journals a bounded observation; unproven running attempts become uncertain and keep their writer slot. Intent-only reservations remain `reserved` with `reconcile-required`: absent process-start history never proves that a child did not launch. `attempt start` refuses to reuse an unbound reservation, and `attempt reconcile` reports that protected launch reconciliation requires positive no-execution/no-surviving-writer proof before abort. The protected launch authority owns that proof and abort path; these source primitives do not implement it. Finish also rejects an unbound reservation before accepting any receipt, even if a stale local cache says running. Imported canonical evidence stores the exact submitted bytes without Git clean filters or line-ending conversions; immutable reuse compares the accepted Git blob. It never launches a new process or resends a payload. Restart goes through a new `attempt start` only after the previous attempt ends with accepted evidence.
|
|
429
444
|
|
|
430
445
|
Managed agents invoking attempt start inside tmux/Herdr obtain a runtime-owned process binding. Recovery compares PID, UID, OS start time, host, exact pane/native session and Herdr terminal/native thread. A surviving shell is not the agent. Missing, unreadable or reused identity remains unknown. A plain local CLI establishes its actor through its effective UID's OS account, requiring equal real/effective UIDs, but supplies no durable agent identity; trusted service executors may supply `process_pid` in their configured identity JSON. Process observation never grants service privilege or effect authority.
|
|
431
446
|
|
|
432
|
-
Pending HITL references retain their exact scope/attempt and are not rebound by
|
|
447
|
+
Pending HITL references retain their exact scope/attempt and are not rebound by
|
|
448
|
+
resume. Uncertain external effects require their actual owner/result evidence;
|
|
449
|
+
message submission cannot establish business success. `AttemptCoordinator#bind_inbox`
|
|
450
|
+
retains original event attribution only. There is no agent-read reconciliation
|
|
451
|
+
or signing-key requirement for ending or recovering an attempt. Inspect current
|
|
452
|
+
agent progress at its original Herdr/tmux panel; uncertain sends are not repeated
|
|
453
|
+
automatically.
|
|
433
454
|
|
|
434
455
|
Installed Herdr/Pi compaction and writing-child stop/close acceptance must be recorded separately from deterministic fixture coverage before Lab cutover.
|
|
435
456
|
|
|
@@ -498,3 +519,95 @@ its candidate/target binding and verified receipt, never an older PR result.
|
|
|
498
519
|
The fixed installed authority exposes `ace-assign authority serve`, `launch`,
|
|
499
520
|
`status` and `terminate`. See [protected authority](protected-authority.md) for
|
|
500
521
|
OS policy, native artifact installation, canonical launch stages and safe replay.
|
|
522
|
+
|
|
523
|
+
## Source-owned installation maintenance inventory
|
|
524
|
+
|
|
525
|
+
The trusted installation owner loads exact protected content references for the
|
|
526
|
+
original and staged candidate descriptor using `Authority::Deployment.load_artifact`.
|
|
527
|
+
This Ruby-only source interface validates immutable authenticated descriptor bytes;
|
|
528
|
+
it does not establish installed network or native readiness and is not exposed
|
|
529
|
+
through worker transport or a CLI selector.
|
|
530
|
+
|
|
531
|
+
`LaunchLifecycle#with_execution_slots(mapping_ids:, candidate_deployment:)` holds
|
|
532
|
+
the same slot exclusions as normal admission while yielding frozen fixed
|
|
533
|
+
mapping/journal/commit contexts. Changed, added and removed mappings cannot be
|
|
534
|
+
omitted. Removed mappings retain their original journal selection; new mappings
|
|
535
|
+
use the staged selection. Existing mappings and physical slots cannot be recycled
|
|
536
|
+
to hide history. Ref changes, unreadable roots and conflicting aliases refuse.
|
|
537
|
+
|
|
538
|
+
Full `slot_reusable!` maintenance eligibility and parent retirement remain
|
|
539
|
+
unavailable until complete historical authentication and actual current inventory
|
|
540
|
+
verification are connected. The inventory block grants neither policy publication
|
|
541
|
+
nor positive maintenance readiness. Finish/stop wiring and installed acceptance
|
|
542
|
+
remain separate unfinished 9c2 requirements. Existing normal admission and guarded
|
|
543
|
+
abort/release behavior retain their current checks.
|
|
544
|
+
|
|
545
|
+
## Authenticated readiness and terminal scope closure
|
|
546
|
+
|
|
547
|
+
The source-owned fixed ExecStartPost readiness hook uploads one bounded report
|
|
548
|
+
through the authenticated authority connection, closes its write side and waits
|
|
549
|
+
for acknowledgement. The authority joins the exact manager-selected hook/server
|
|
550
|
+
actors, immutable runtime/configuration dependencies, original boot/network
|
|
551
|
+
proofs and complete live mount/IPC/resource observations before binding native
|
|
552
|
+
admission. The hook’s observed server network namespace must match both the original
|
|
553
|
+
parent selection and the canonical network installation admission. A missing,
|
|
554
|
+
malformed or different identity refuses native binding before child release.
|
|
555
|
+
Unknown writable projections, writable API descendants, changed
|
|
556
|
+
socket endpoints and incomplete evidence refuse. A read-only socket mount does
|
|
557
|
+
not authorize messages.
|
|
558
|
+
|
|
559
|
+
Original service issuance remains tracked while the manager command runs outside
|
|
560
|
+
the callback's exclusions. Sealing cannot publish an empty-scope proof while an
|
|
561
|
+
original issuer can still start the service. Admitted-but-unbound starts use the
|
|
562
|
+
same positive cleanup and worker baseline as bound starts; an inactive snapshot
|
|
563
|
+
does not assert that execution never happened.
|
|
564
|
+
|
|
565
|
+
After the genuine terminal owner accepts authenticated result evidence, the
|
|
566
|
+
existing release producer joins that receipt to the exact sealed empty scope.
|
|
567
|
+
Current activation, jobs, recursive population, original resource identities,
|
|
568
|
+
native directory absence and outside worker UID writers are checked again before
|
|
569
|
+
publishing or consuming the proof. Empty scope alone supplies no terminal result.
|
|
570
|
+
|
|
571
|
+
The required per-boot host proof is selected before parent activation and retained
|
|
572
|
+
in canonical `scope_bound.boot_baseline_selection`; later reads authenticate that
|
|
573
|
+
original immutable artifact rather than a current pointer. Domain gad.8/gad.b
|
|
574
|
+
still must deliver trusted cold-start/boot refresh and activation inhibition.
|
|
575
|
+
These source interfaces and controlled tests do not establish installed native,
|
|
576
|
+
network or boot acceptance, and task 9c2 remains in progress through integration
|
|
577
|
+
and independent review.
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
### Protected sealed-service no-effect settlement
|
|
581
|
+
|
|
582
|
+
For the fixed original executor, `service_status` includes a closed immutable `settlement_context` containing the authenticated original request, execution binding and accepted current challenge (or null). Full original mapping/project/receiver credentials are checked before this private context is exposed. Ordinary status roles retain their existing projection. Terminal status still authenticates the imported original receipt through the canonical reader.
|
|
583
|
+
|
|
584
|
+
The fixed original executor uses `claim_service_settlement` against the sealed original request. The authority records an acyclic challenge selecting the latest canonical uncertain/failed outcome. `complete_no_effect` uploads the exact original receipt and bounded inspection artifact through the existing private transfer. It authenticates the accepted challenge, original dispatch binding and imported artifact before atomically reaching `failed-settled`. Exact retries retain their first reply and do not invoke a new effect. A later genuine failure needs a fresh challenge; missing/orphan/stale challenges and changed input refuse.
|
|
585
|
+
|
|
586
|
+
This generic authority path attributes the closed inspection report to the recorded executor. Actual operation-specific target absence, handler termination and surviving-writer inspection are an open gad.b producer obligation; a closed scope or timeout does not prove no effect. The current protected ingress atomically accepts a request and executor claim, so an absent canonical request cannot be converted into a requested-but-unclaimed settlement record.
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
### Protected original worker submission
|
|
590
|
+
|
|
591
|
+
Run under the actual original prepared worker while its lineage is live. Read
|
|
592
|
+
`ace-assign authority status --mapping M --assignment A --attempt T` and save
|
|
593
|
+
`authority_generation` for the next new mutation. Candidate submission uses
|
|
594
|
+
current `result_candidate_generation` (zero if null), then returns the next
|
|
595
|
+
positive candidate generation. Review/result use that returned generation.
|
|
596
|
+
|
|
597
|
+
```sh
|
|
598
|
+
ace-assign submit-candidate --mapping M --assignment A --attempt T --head H \
|
|
599
|
+
--candidate-generation CURRENT --expected-generation G --mutation CANDIDATE --bundle candidate.bundle
|
|
600
|
+
ace-assign submit-result --mapping M --assignment A --attempt T --head H \
|
|
601
|
+
--candidate-generation ACCEPTED --expected-generation G --mutation RESULT --receipt result.json \
|
|
602
|
+
--artifact first-evidence --artifact second-evidence
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
The actual worker builds `Ace::Assign::Models::ExecutionReceipt` from its original
|
|
606
|
+
assignment/project/scope, installed worker actor, tested head and actual executed
|
|
607
|
+
checks/artifact digests. Failed receipts may have zero artifacts; succeeded
|
|
608
|
+
receipts require evidence. Captured queue completion does not create a receipt or
|
|
609
|
+
canonical acceptance. Independent installed reviewers use the existing
|
|
610
|
+
`ace-overseer review` consumer for that exact candidate. Result submission obtains
|
|
611
|
+
a new generation after review; exact retries retain the original generation,
|
|
612
|
+
mutation and identical ordered bytes. Supervisor finish still revalidates result,
|
|
613
|
+
review, writer exclusion and settlement. A lost reply never causes automatic resend.
|
data/exe/ace-scope-ready
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
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
|
|
@@ -40,7 +40,8 @@ If this workflow is invoked with an argument (for example `/as-assign-drive abc1
|
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
# Set once from workflow argument or internal scoped default (empty when neither is provided)
|
|
43
|
-
|
|
43
|
+
DEFAULT_ASSIGNMENT_TARGET="${ACE_ASSIGN_DEFAULT_TARGET:-}"
|
|
44
|
+
ASSIGNMENT_TARGET="${1:-$DEFAULT_ASSIGNMENT_TARGET}"
|
|
44
45
|
|
|
45
46
|
# Resolve and pin assignment identity for the full drive loop
|
|
46
47
|
if [ -n "$ASSIGNMENT_TARGET" ]; then
|
|
@@ -659,6 +660,30 @@ Follow the instructions directly, performing the described work:
|
|
|
659
660
|
|
|
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.
|
|
661
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
|
+
|
|
662
687
|
**Step 1: Start the attempt before executing the step.** Actor identity is derived from the execution boundary; never pass actor flags.
|
|
663
688
|
|
|
664
689
|
```bash
|
|
@@ -59,6 +59,14 @@ module Ace
|
|
|
59
59
|
TRANSITIONS.fetch(from.to_s, [])
|
|
60
60
|
end
|
|
61
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
|
+
|
|
62
70
|
# Validate a transition.
|
|
63
71
|
#
|
|
64
72
|
# @param from [String] Current state
|
|
@@ -1,52 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require "ace/git/atoms/
|
|
2
|
+
require "ace/git/atoms/delivery_parameters"
|
|
3
3
|
|
|
4
4
|
module Ace
|
|
5
5
|
module Assign
|
|
6
6
|
module Atoms
|
|
7
|
-
#
|
|
7
|
+
# Assignment configuration consumes the shared forge-neutral owner.
|
|
8
8
|
module DeliveryParameters
|
|
9
|
-
PROVENANCE_FIELDS = %w[mode head_repository_url head_ref base_repository_url base_ref].freeze
|
|
10
9
|
def self.validate(input)
|
|
11
|
-
|
|
12
|
-
unless (input.keys - %w[forge_server forge_default pr_provenance]).empty?
|
|
13
|
-
raise ArgumentError, "Unexpected delivery parameter fields"
|
|
14
|
-
end
|
|
15
|
-
default = input.fetch("forge_default", false)
|
|
16
|
-
raise ArgumentError, "forge_default must be boolean" unless [true, false].include?(default)
|
|
17
|
-
server = input["forge_server"]
|
|
18
|
-
if server && (!server.is_a?(String) || !server.match?(/\A[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}\z/))
|
|
19
|
-
raise ArgumentError, "Invalid forge_server"
|
|
20
|
-
end
|
|
21
|
-
raise ArgumentError, "forge_server and forge_default are mutually exclusive" if server && default
|
|
22
|
-
provenance = input["pr_provenance"]
|
|
23
|
-
unless provenance.is_a?(Hash) && provenance.keys.sort == PROVENANCE_FIELDS.sort &&
|
|
24
|
-
%w[fork canonical].include?(provenance["mode"])
|
|
25
|
-
raise ArgumentError, "Explicit complete fork or canonical PR provenance is required"
|
|
26
|
-
end
|
|
27
|
-
%w[head_repository_url base_repository_url].each { |key| validate_url!(provenance[key]) }
|
|
28
|
-
%w[head_ref base_ref].each do |key|
|
|
29
|
-
ref = provenance[key]
|
|
30
|
-
unless ref.is_a?(String) && ref.match?(/\A[a-zA-Z0-9][a-zA-Z0-9_\/.\-]{0,255}\z/) &&
|
|
31
|
-
!ref.include?("..") && !ref.include?("//") && !ref.end_with?("/", ".", ".lock")
|
|
32
|
-
raise ArgumentError, "Invalid PR ref"
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
if provenance["mode"] == "canonical" && !Ace::Git::Atoms::ServerUrl.match?(
|
|
36
|
-
provenance["head_repository_url"], provenance["base_repository_url"])
|
|
37
|
-
raise ArgumentError, "Canonical provenance requires matching head and base repositories"
|
|
38
|
-
end
|
|
39
|
-
{"forge_server" => server, "forge_default" => default,
|
|
40
|
-
"pr_provenance" => provenance.transform_values(&:dup)}
|
|
10
|
+
Ace::Git::Atoms::DeliveryParameters.validate(input)
|
|
41
11
|
end
|
|
42
12
|
|
|
43
13
|
def self.validate_url!(url)
|
|
44
|
-
|
|
45
|
-
(url.match?(%r{\Ahttps?://[a-zA-Z0-9.:-]+/[a-zA-Z0-9_./-]+\z}) ||
|
|
46
|
-
url.match?(%r{\Agit@[a-zA-Z0-9.-]+:[a-zA-Z0-9_./-]+\z}) ||
|
|
47
|
-
url.match?(%r{\Assh://git@[a-zA-Z0-9.:-]+/[a-zA-Z0-9_./-]+\z}))
|
|
48
|
-
raise ArgumentError, "PR repository URL must contain a repository and no credentials or query"
|
|
49
|
-
end
|
|
14
|
+
Ace::Git::Atoms::DeliveryParameters.validate_url!(url)
|
|
50
15
|
end
|
|
51
16
|
end
|
|
52
17
|
end
|