ace-assign 0.69.0 → 0.71.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.ace-defaults/assign/presets/deliver-release.yml +11 -8
  3. data/.ace-defaults/assign/presets/integrate-batch.yml +10 -5
  4. data/.ace-defaults/assign/presets/supervise-delivery.yml +6 -4
  5. data/CHANGELOG.md +27 -0
  6. data/handbook/skills/as-assign-drive/SKILL.md +5 -2
  7. data/handbook/workflow-instructions/assign/drive.wf.md +77 -0
  8. data/lib/ace/assign/atoms/assignment_scope.rb +5 -0
  9. data/lib/ace/assign/atoms/candidate_limits.rb +20 -0
  10. data/lib/ace/assign/atoms/git_blob_batch.rb +59 -0
  11. data/lib/ace/assign/authority/assignment_definition.rb +35 -0
  12. data/lib/ace/assign/authority/candidate_blob_batch.rb +55 -0
  13. data/lib/ace/assign/authority/candidate_head_comparison.rb +139 -0
  14. data/lib/ace/assign/authority/candidate_transfer.rb +57 -27
  15. data/lib/ace/assign/authority/command_execution.rb +180 -0
  16. data/lib/ace/assign/authority/endcap.rb +4 -2
  17. data/lib/ace/assign/authority/endcap_attempts.rb +1 -1
  18. data/lib/ace/assign/authority/endcap_campaign_rounds.rb +1 -1
  19. data/lib/ace/assign/authority/endcap_publication.rb +0 -166
  20. data/lib/ace/assign/authority/endcap_service_context.rb +38 -0
  21. data/lib/ace/assign/authority/fixed_publication_lifecycle.rb +176 -0
  22. data/lib/ace/assign/authority/{endcap_services.rb → fixed_service_lifecycle.rb} +42 -46
  23. data/lib/ace/assign/authority/launch_control_exclusions.rb +3 -17
  24. data/lib/ace/assign/authority/ordinary_attempt_start.rb +137 -0
  25. data/lib/ace/assign/authority/ordinary_client.rb +70 -0
  26. data/lib/ace/assign/authority/ordinary_completion.rb +104 -0
  27. data/lib/ace/assign/authority/ordinary_effect_settlement.rb +118 -0
  28. data/lib/ace/assign/authority/ordinary_lifecycle.rb +227 -0
  29. data/lib/ace/assign/authority/ordinary_merge_evidence.rb +81 -0
  30. data/lib/ace/assign/authority/ordinary_peer.rb +54 -0
  31. data/lib/ace/assign/authority/ordinary_progress.rb +162 -0
  32. data/lib/ace/assign/authority/ordinary_queue.rb +115 -0
  33. data/lib/ace/assign/authority/ordinary_release_artifacts.rb +143 -0
  34. data/lib/ace/assign/authority/ordinary_results.rb +206 -0
  35. data/lib/ace/assign/authority/ordinary_review_evidence.rb +180 -0
  36. data/lib/ace/assign/authority/ordinary_reviews.rb +214 -0
  37. data/lib/ace/assign/authority/ordinary_server.rb +75 -0
  38. data/lib/ace/assign/authority/ordinary_supervisor.rb +99 -0
  39. data/lib/ace/assign/authority/prepared_work.rb +9 -4
  40. data/lib/ace/assign/authority/protected_assignment_context.rb +3 -3
  41. data/lib/ace/assign/authority/release_artifact_manifest.rb +91 -0
  42. data/lib/ace/assign/authority/retained_input.rb +53 -0
  43. data/lib/ace/assign/authority/router.rb +11 -6
  44. data/lib/ace/assign/authority/server.rb +11 -180
  45. data/lib/ace/assign/authority/socket_server.rb +255 -0
  46. data/lib/ace/assign/authority/transfer_codec.rb +5 -3
  47. data/lib/ace/assign/cli/commands/attempt/evidence.rb +2 -2
  48. data/lib/ace/assign/cli/commands/submit_candidate.rb +1 -1
  49. data/lib/ace/assign/molecules/canonical_evidence.rb +25 -8
  50. data/lib/ace/assign/molecules/canonical_read_commands.rb +84 -0
  51. data/lib/ace/assign/molecules/canonical_read_snapshot.rb +2 -63
  52. data/lib/ace/assign/molecules/evidence_journal.rb +157 -63
  53. data/lib/ace/assign/molecules/installed_journal_read.rb +143 -0
  54. data/lib/ace/assign/molecules/journal_mutation.rb +7 -4
  55. data/lib/ace/assign/molecules/lifecycle_exclusion.rb +13 -2
  56. data/lib/ace/assign/molecules/proposal_journal.rb +32 -4
  57. data/lib/ace/assign/molecules/receipt_verifier.rb +8 -2
  58. data/lib/ace/assign/molecules/runtime_control_surface_runner.rb +2 -1
  59. data/lib/ace/assign/organisms/attempt_coordinator.rb +88 -36
  60. data/lib/ace/assign/organisms/ordinary_driver.rb +310 -0
  61. data/lib/ace/assign/organisms/ordinary_merge_consumer.rb +5 -5
  62. data/lib/ace/assign/version.rb +1 -1
  63. metadata +39 -10
@@ -0,0 +1,310 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+ require "tmpdir"
5
+ require "fileutils"
6
+ require_relative "../authority/retained_input"
7
+ require_relative "../authority/prepared_work"
8
+ require_relative "../authority/transfer_codec"
9
+ require_relative "../molecules/journal_mutation"
10
+ require_relative "../models/execution_receipt"
11
+ require_relative "../models/assignment"
12
+ require_relative "../molecules/queue_scanner"
13
+
14
+ module Ace
15
+ module Assign
16
+ module Organisms
17
+ # Operator protocol over the installed owner supplied by the composition.
18
+ # Files retain requests only; every observation comes from that owner.
19
+ class OrdinaryDriver
20
+ Files = Authority::RetainedInput
21
+ CONTEXT_KEYS = %w[version project_id assignment_id attempt_id scope pane supervisor_pane cwd head provider].freeze
22
+ attr_reader :context, :path
23
+
24
+ def initialize(path:, project:, transport:)
25
+ @path = File.expand_path(path)
26
+ @context = Files.json(@path)
27
+ unless @context.is_a?(Hash) && @context.keys.sort == CONTEXT_KEYS.sort && @context["version"] == 1 &&
28
+ @context["project_id"] == project && %w[project_id assignment_id attempt_id].all? { |key|
29
+ @context[key].is_a?(String) && Molecules::JournalMutation::ID.match?(@context[key]) } &&
30
+ @context["scope"].is_a?(String) && Authority::PreparedWork::SCOPE.match?(@context["scope"]) &&
31
+ %w[pane supervisor_pane].all? { |key| @context[key].is_a?(String) && @context[key].match?(/\A[\w.:-]{1,128}\z/) } &&
32
+ @context["cwd"].is_a?(String) && @context["cwd"].start_with?("/") &&
33
+ File.expand_path(@context["cwd"]) == @context["cwd"] && @context["head"].is_a?(String) &&
34
+ @context["head"].match?(/\A[0-9a-f]{40}\z/) && @context["provider"].is_a?(String) &&
35
+ @context["provider"].bytesize.between?(1, 512)
36
+ raise ArgumentError, "ordinary driver selection differs; retain the original context"
37
+ end
38
+ @root = Authority::PrivateDirectory.verify!(File.dirname(@path))
39
+ @transport = transport
40
+ end
41
+
42
+ def status
43
+ reply = read("result_status", selection)
44
+ data = reply.fetch("data")
45
+ unless data.values_at("project_id", "assignment_id", "attempt_id") == context.values_at("project_id", "assignment_id", "attempt_id")
46
+ raise AttemptErrors::EvidenceUnavailable, "canonical status belongs to another execution"
47
+ end
48
+ data
49
+ end
50
+
51
+ def start(pane:)
52
+ worker!(pane)
53
+ mutate("start", "start_attempt", selection.merge("expected_generation" => 0,
54
+ "pane" => pane, "scope" => context.fetch("scope"), "head" => context.fetch("head")))
55
+ end
56
+
57
+ def supervisor
58
+ data = read("supervisor_status", context.slice("assignment_id")).fetch("data")
59
+ unless data.values_at("project_id", "assignment_id") == context.values_at("project_id", "assignment_id")
60
+ raise AttemptErrors::EvidenceUnavailable, "canonical supervisor belongs to another assignment"
61
+ end
62
+ data
63
+ end
64
+
65
+ def adopt_supervisor(pane:, generation:, previous_binding_sha256:)
66
+ mutate("supervisor-#{generation}", "adopt_supervisor", context.slice("assignment_id").merge(
67
+ "pane" => pane, "expected_generation" => generation, "previous_binding_sha256" => previous_binding_sha256))
68
+ end
69
+
70
+ def queue
71
+ reply, bytes = snapshot("assignment_snapshot", selection.merge("kind" => "queue"))
72
+ data = reply.fetch("data")
73
+ unless data.values_at("project_id", "assignment_id", "attempt_id", "scope") ==
74
+ context.values_at("project_id", "assignment_id", "attempt_id", "scope") &&
75
+ Digest::SHA256.hexdigest(bytes) == data.fetch("sha256")
76
+ raise AttemptErrors::EvidenceUnavailable, "canonical queue belongs to another execution"
77
+ end
78
+ value = JSON.parse(bytes)
79
+ assignment = Models::Assignment.new(id: context.fetch("assignment_id"), name: "ordinary",
80
+ created_at: Time.now.utc, source_config: "canonical", cache_dir: @root)
81
+ state = Molecules::QueueScanner.new.scan_captured(steps: value.fetch("steps"),
82
+ reports: value.fetch("reports"), assignment: assignment)
83
+ scope = context.fetch("scope")
84
+ current = state.current_in_subtree(scope)
85
+ next_step = state.next_workable_in_subtree(scope)
86
+ data.merge("complete" => state.subtree_complete?(scope), "failed" => state.subtree_failed?(scope),
87
+ "current" => step(current), "next" => step(next_step), "reports" => value.fetch("reports"))
88
+ end
89
+
90
+ def bootstrap(output:)
91
+ # Accepted task/context bytes are recovered from the canonical owner,
92
+ # not the worker checkout's possibly older mutable task files.
93
+ reply, bytes = snapshot("assignment_snapshot", selection.merge("attempt_id" => nil, "kind" => "prepared_work"))
94
+ data = reply.fetch("data")
95
+ unless data.values_at("project_id", "assignment_id") == context.values_at("project_id", "assignment_id")
96
+ raise AttemptErrors::EvidenceUnavailable, "canonical preparation belongs to another assignment"
97
+ end
98
+ reference = data.fetch("prepared_work")
99
+ work = Authority::PreparedWork.admit(bytes: bytes, sha256: data.fetch("sha256"), size: data.fetch("bytes"),
100
+ head: reference.fetch("prepared_head"), tree: reference.fetch("prepared_tree"), root: @root,
101
+ deadline: Process.clock_gettime(Process::CLOCK_MONOTONIC) + 30)
102
+ unless work.reference(head: reference.fetch("prepared_head"), tree: reference.fetch("prepared_tree")) == reference &&
103
+ work.manifest.values_at("project_id", "assignment_id", "scope") == context.values_at("project_id", "assignment_id", "scope")
104
+ raise AttemptErrors::EvidenceUnavailable, "canonical prepared scope differs"
105
+ end
106
+ directory = Files.create_output(output)
107
+ inventory = work.manifest.fetch("context").each_with_index.flat_map do |entry, index|
108
+ selected = %w[spec text].map { |kind| [kind, entry.fetch(kind)] } +
109
+ entry.fetch("reports").each_with_index.map { |report, number| ["report-#{number}", report.fetch("file")] }
110
+ selected.map do |kind, source|
111
+ content = work.files.fetch(source.fetch("filename"))
112
+ filename = "context-#{index}-#{kind}.md"
113
+ Files.write_file(directory, filename, content)
114
+ {"task_id" => entry.fetch("task_id"), "kind" => kind, "path" => File.join(directory, filename),
115
+ "sha256" => Digest::SHA256.hexdigest(content), "bytes" => content.bytesize}
116
+ end
117
+ end
118
+ {"project_id" => context.fetch("project_id"), **selection, "scope" => context.fetch("scope"),
119
+ "manifest_sha256" => work.manifest_sha256, "files" => inventory, "journal_commit" => data.fetch("journal_commit")}
120
+ end
121
+
122
+ def progress(operation:, pane:, generation:, step: nil, report: nil, message: nil)
123
+ worker!(pane)
124
+ params = selection.merge("expected_generation" => generation, "pane" => pane)
125
+ parts = []
126
+ case operation
127
+ when "queue_start" then params["step"] = step
128
+ when "queue_finish"
129
+ params["step"] = step
130
+ parts << Files.read_file(report, 65_536)
131
+ when "queue_fail" then params["message"] = message
132
+ else raise ArgumentError, "unknown ordinary queue operation"
133
+ end
134
+ mutate("progress-#{generation}", operation, params, parts)
135
+ end
136
+
137
+ def submit(pane:, generation:, receipt:, artifacts: [])
138
+ worker!(pane)
139
+ bytes = Files.read_file(receipt, 16_384)
140
+ value = JSON.parse(bytes)
141
+ unless value.values_at("project_id", "assignment_id", "attempt_id", "scope") ==
142
+ context.values_at("project_id", "assignment_id", "attempt_id", "scope") &&
143
+ value.fetch("artifacts").size == artifacts.size
144
+ raise ArgumentError, "result receipt differs from ordinary selection"
145
+ end
146
+ parts = artifacts.each_with_index.map do |file, index|
147
+ content = Files.read_file(file, Authority::TransferCodec::LIMITS.fetch(:receipt_artifacts).last)
148
+ unless Digest::SHA256.hexdigest(content) == value.fetch("artifacts").fetch(index).fetch("sha256")
149
+ raise ArgumentError, "result artifact differs from its receipt"
150
+ end
151
+ content
152
+ end
153
+ params = selection.merge("expected_generation" => generation,
154
+ "pane" => pane, "head" => value.fetch("head"), "receipt_sha256" => Digest::SHA256.hexdigest(bytes))
155
+ verify_result_intent!(params, [bytes] + parts)
156
+ observed = status
157
+ if (accepted = observed.fetch("submitted_result"))
158
+ # An accepted result may have lost its reply. Its generation selects
159
+ # the original input; never mint a replacement mutation to recover it.
160
+ original_generation = accepted.fetch("generation") - 1
161
+ input = File.join(@root, "requests", "result-#{original_generation}", "request.json")
162
+ original = Files.json(input)
163
+ expected = document("submit_result", params.merge("expected_generation" => original_generation), nil,
164
+ inventory([bytes] + parts))
165
+ unless original.except("mutation_id") == expected.except("mutation_id")
166
+ raise ArgumentError, "accepted result differs from retained original input"
167
+ end
168
+ return replay(input: input).merge("request" => input)
169
+ end
170
+ unless observed.fetch("state") == "running" && observed.fetch("generation") == generation
171
+ raise AttemptErrors::EvidenceUnavailable, "result requires the current canonical generation; retain original inputs"
172
+ end
173
+ reply = mutate("result-#{generation}", "submit_result", params, [bytes] + parts)
174
+ signal_result(reply.fetch("data"))
175
+ reply
176
+ end
177
+
178
+ def adopt(pane:)
179
+ owner = supervisor
180
+ raise ArgumentError, "ordinary result owner pane differs" unless pane == owner.fetch("binding").fetch("pane")
181
+ observed = status
182
+ return {"status" => "ok", "data" => observed} if %w[succeeded failed].include?(observed.fetch("state"))
183
+ result = observed.fetch("submitted_result")
184
+ raise AttemptErrors::EvidenceUnavailable, "ordinary worker has not submitted a result" unless result
185
+ mutate("adopt-#{owner.fetch('generation')}-#{observed.fetch('generation')}", "finish", selection.merge("pane" => pane,
186
+ "expected_generation" => observed.fetch("generation"),
187
+ **result.slice("result_id", "receipt_digest", "head")))
188
+ end
189
+
190
+ def replay(input:)
191
+ request = Files.json(input)
192
+ expected = request["operation"] == "adopt_supervisor" ? context.slice("assignment_id") : selection
193
+ unless request["project_id"] == context.fetch("project_id") &&
194
+ request.fetch("params").slice("assignment_id", "attempt_id") == expected &&
195
+ File.dirname(File.dirname(File.expand_path(input))) == File.join(@root, "requests")
196
+ raise ArgumentError, "recovery request differs from original execution"
197
+ end
198
+ reply = @transport.request(input: input)
199
+ signal_result(reply.fetch("data")) if request.fetch("operation") == "submit_result"
200
+ reply
201
+ end
202
+
203
+ private
204
+
205
+ def selection = context.slice("assignment_id", "attempt_id")
206
+
207
+ # A filesystem watch hint is neither execution state nor a receipt.
208
+ # Adoption never reads this file, even after restart or forged writes.
209
+ def signal_result(result)
210
+ name = "hint-#{SecureRandom.hex(8)}"
211
+ Files.write_file(@root, name, JSON.generate({"hint_only" => true,
212
+ "project_id" => context.fetch("project_id"), **selection,
213
+ "result_id" => result.fetch("result_id")}))
214
+ File.rename(File.join(@root, name), File.join(@root, "result-hint.json"))
215
+ File.open(@root) { |file| file.fsync }
216
+ ensure
217
+ File.unlink(File.join(@root, name)) if name && File.exist?(File.join(@root, name))
218
+ end
219
+
220
+ def worker!(pane)
221
+ raise ArgumentError, "ordinary worker pane differs" unless pane == context.fetch("pane")
222
+ end
223
+
224
+ def step(value)
225
+ value && {"number" => value.number, "name" => value.name, "status" => value.status.to_s,
226
+ "instructions" => value.instructions, "workflow" => value.workflow, "skill" => value.skill}
227
+ end
228
+
229
+ def read(operation, params)
230
+ Dir.mktmpdir("ordinary-read-", @root) do |directory|
231
+ Files.write_file(directory, "request.json", JSON.generate(document(operation, params, nil, [])))
232
+ @transport.request(input: File.join(directory, "request.json"))
233
+ end
234
+ end
235
+
236
+ def snapshot(operation, params)
237
+ Dir.mktmpdir("ordinary-read-", @root) do |directory|
238
+ Files.write_file(directory, "request.json", JSON.generate(document(operation, params, nil, [])))
239
+ reply = @transport.request(input: File.join(directory, "request.json"), output: File.join(directory, "snapshot"))
240
+ entries = reply.fetch("files")
241
+ raise AttemptErrors::EvidenceUnavailable, "canonical queue snapshot count differs" unless entries.one?
242
+ [reply, Files.read_file(entries.first.fetch("file"), Authority::PreparedWork::MAX_TOTAL)]
243
+ end
244
+ end
245
+
246
+ def mutate(key, operation, params, parts = [])
247
+ request = retain(key, operation, params, parts)
248
+ @transport.request(input: request).merge("request" => request)
249
+ rescue StandardError => error
250
+ raise error.class, "#{error.message}; recover original request #{request || key} before new work"
251
+ end
252
+
253
+ def retain(key, operation, params, parts)
254
+ directory = File.join(@root, "requests")
255
+ begin
256
+ Dir.mkdir(directory, 0o700)
257
+ rescue Errno::EEXIST
258
+ Authority::PrivateDirectory.verify!(directory)
259
+ end
260
+ raise ArgumentError, "ordinary retained operation key is invalid" unless key.match?(/\A[a-z0-9-]{1,128}\z/)
261
+ File.open(File.join(directory, ".lock"), File::RDWR | File::CREAT | File::NOFOLLOW, 0o600) do |lock|
262
+ lock.flock(File::LOCK_EX)
263
+ target = File.join(directory, key)
264
+ value = document(operation, params, nil, inventory(parts))
265
+ if File.exist?(target)
266
+ Authority::PrivateDirectory.verify!(target)
267
+ original = Files.json(File.join(target, "request.json"))
268
+ unless original.except("mutation_id") == value.except("mutation_id")
269
+ raise ArgumentError, "retained operation changed; replay its exact request or reconcile canonical state"
270
+ end
271
+ else
272
+ scratch = Dir.mktmpdir(".prepare-", directory)
273
+ begin
274
+ parts.each_with_index { |bytes, index| Files.write_file(scratch, "part-#{index}", bytes) }
275
+ value["mutation_id"] = SecureRandom.hex(16)
276
+ Files.write_file(scratch, "request.json", JSON.generate(value) + "\n")
277
+ File.rename(scratch, target)
278
+ File.open(directory) { |handle| handle.fsync }
279
+ ensure
280
+ FileUtils.remove_entry(scratch) if File.exist?(scratch)
281
+ end
282
+ end
283
+ File.join(target, "request.json")
284
+ end
285
+ end
286
+
287
+ def document(operation, params, mutation, parts)
288
+ {"version" => 1, "project_id" => context.fetch("project_id"), "operation" => operation,
289
+ "mutation_id" => mutation, "params" => params, "parts" => parts}
290
+ end
291
+
292
+ def inventory(parts)
293
+ parts.each_with_index.map { |bytes, index|
294
+ {"file" => "part-#{index}", "bytes" => bytes.bytesize, "sha256" => Digest::SHA256.hexdigest(bytes)} }
295
+ end
296
+
297
+ def verify_result_intent!(params, parts)
298
+ expected = document("submit_result", params.except("expected_generation"), nil, inventory(parts))
299
+ Dir.glob(File.join(@root, "requests", "result-*", "request.json")).each do |input|
300
+ original = Files.json(input)
301
+ original = original.merge("params" => original.fetch("params").except("expected_generation"))
302
+ unless original.except("mutation_id") == expected.except("mutation_id")
303
+ raise ArgumentError, "result retry changed the retained original intent"
304
+ end
305
+ end
306
+ end
307
+ end
308
+ end
309
+ end
310
+ end
@@ -212,7 +212,7 @@ module Ace
212
212
  return {state: "accepted", reference: ack.fetch("reference"),
213
213
  request_id: ack.fetch("request_id"), input_digest: ack.fetch("input_digest")}
214
214
  end
215
- handle_refusal(binding, identity, branch[:payload], expected_digest: digest)
215
+ handle_refusal(binding, identity, branch[:payload], expected_digest: digest, request_id: selectors.fetch(:request_id))
216
216
  end
217
217
 
218
218
  # Closed outer envelope for admission responses: exactly {status,
@@ -241,7 +241,7 @@ module Ace
241
241
  end
242
242
  end
243
243
 
244
- def handle_refusal(binding, identity, error, expected_digest:)
244
+ def handle_refusal(binding, identity, error, expected_digest:, request_id:)
245
245
  refusal = begin
246
246
  Molecules::OrdinaryMergeContract.validate_refusal!(error)
247
247
  rescue ArgumentError
@@ -249,9 +249,9 @@ module Ace
249
249
  "ordinary merge refusal is not the maintained contract; admission stays unconfirmed"
250
250
  end
251
251
  echo = refusal.fetch("input_digest")
252
- if echo && echo != expected_digest
252
+ if refusal.fetch("request_id") != request_id || (echo && echo != expected_digest)
253
253
  raise AttemptErrors::EvidenceUnavailable,
254
- "ordinary merge refusal echoes a different input digest; admission stays unconfirmed"
254
+ "ordinary merge refusal echoes a different request; admission stays unconfirmed"
255
255
  end
256
256
  if refusal.fetch("code") == Molecules::OrdinaryMergeContract::UNAVAILABLE_CODE
257
257
  raise AttemptErrors::EvidenceUnavailable,
@@ -259,7 +259,7 @@ module Ace
259
259
  end
260
260
  record_event(binding, identity, {"stage" => RESULT_STAGE, "outcome" => "refused_no_effect",
261
261
  "code" => refusal.fetch("code"), "message" => refusal.fetch("message"),
262
- "request_id" => refusal.fetch("request_id"), "input_digest" => refusal.fetch("input_digest")})
262
+ "request_id" => request_id, "input_digest" => expected_digest})
263
263
  {state: "refused", code: refusal.fetch("code"), message: refusal.fetch("message")}
264
264
  end
265
265
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ace
4
4
  module Assign
5
- VERSION = "0.69.0"
5
+ VERSION = "0.71.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ace-assign
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.69.0
4
+ version: 0.71.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz
@@ -175,42 +175,42 @@ dependencies:
175
175
  requirements:
176
176
  - - "~>"
177
177
  - !ruby/object:Gem::Version
178
- version: 0.60.2
178
+ version: 0.61.0
179
179
  type: :runtime
180
180
  prerelease: false
181
181
  version_requirements: !ruby/object:Gem::Requirement
182
182
  requirements:
183
183
  - - "~>"
184
184
  - !ruby/object:Gem::Version
185
- version: 0.60.2
185
+ version: 0.61.0
186
186
  - !ruby/object:Gem::Dependency
187
187
  name: ace-task
188
188
  requirement: !ruby/object:Gem::Requirement
189
189
  requirements:
190
190
  - - "~>"
191
191
  - !ruby/object:Gem::Version
192
- version: '0.37'
192
+ version: '0.40'
193
193
  type: :runtime
194
194
  prerelease: false
195
195
  version_requirements: !ruby/object:Gem::Requirement
196
196
  requirements:
197
197
  - - "~>"
198
198
  - !ruby/object:Gem::Version
199
- version: '0.37'
199
+ version: '0.40'
200
200
  - !ruby/object:Gem::Dependency
201
201
  name: ace-bundle
202
202
  requirement: !ruby/object:Gem::Requirement
203
203
  requirements:
204
204
  - - "~>"
205
205
  - !ruby/object:Gem::Version
206
- version: '0.45'
206
+ version: 0.45.1
207
207
  type: :runtime
208
208
  prerelease: false
209
209
  version_requirements: !ruby/object:Gem::Requirement
210
210
  requirements:
211
211
  - - "~>"
212
212
  - !ruby/object:Gem::Version
213
- version: '0.45'
213
+ version: 0.45.1
214
214
  - !ruby/object:Gem::Dependency
215
215
  name: ace-runtime
216
216
  requirement: !ruby/object:Gem::Requirement
@@ -245,14 +245,14 @@ dependencies:
245
245
  requirements:
246
246
  - - "~>"
247
247
  - !ruby/object:Gem::Version
248
- version: 0.5.1
248
+ version: '0.6'
249
249
  type: :runtime
250
250
  prerelease: false
251
251
  version_requirements: !ruby/object:Gem::Requirement
252
252
  requirements:
253
253
  - - "~>"
254
254
  - !ruby/object:Gem::Version
255
- version: 0.5.1
255
+ version: '0.6'
256
256
  - !ruby/object:Gem::Dependency
257
257
  name: ace-support-test-helpers
258
258
  requirement: !ruby/object:Gem::Requirement
@@ -405,11 +405,13 @@ files:
405
405
  - lib/ace/assign/atoms/assign_frontmatter_parser.rb
406
406
  - lib/ace/assign/atoms/assignment_scope.rb
407
407
  - lib/ace/assign/atoms/attempt_state_machine.rb
408
+ - lib/ace/assign/atoms/candidate_limits.rb
408
409
  - lib/ace/assign/atoms/catalog_loader.rb
409
410
  - lib/ace/assign/atoms/composition_rules.rb
410
411
  - lib/ace/assign/atoms/delivery_parameters.rb
411
412
  - lib/ace/assign/atoms/evidence_digest.rb
412
413
  - lib/ace/assign/atoms/fixed_merge_schemas.rb
414
+ - lib/ace/assign/atoms/git_blob_batch.rb
413
415
  - lib/ace/assign/atoms/number_generator.rb
414
416
  - lib/ace/assign/atoms/preset_expander.rb
415
417
  - lib/ace/assign/atoms/preset_loader.rb
@@ -418,13 +420,17 @@ files:
418
420
  - lib/ace/assign/atoms/step_numbering.rb
419
421
  - lib/ace/assign/atoms/step_sorter.rb
420
422
  - lib/ace/assign/atoms/tree_formatter.rb
423
+ - lib/ace/assign/authority/assignment_definition.rb
421
424
  - lib/ace/assign/authority/assignment_inventory.rb
422
425
  - lib/ace/assign/authority/campaign_consumer_policy.rb
423
426
  - lib/ace/assign/authority/campaign_execution.rb
424
427
  - lib/ace/assign/authority/campaign_round_transfer.rb
428
+ - lib/ace/assign/authority/candidate_blob_batch.rb
429
+ - lib/ace/assign/authority/candidate_head_comparison.rb
425
430
  - lib/ace/assign/authority/candidate_transfer.rb
426
431
  - lib/ace/assign/authority/cleanup_result_protection.rb
427
432
  - lib/ace/assign/authority/client.rb
433
+ - lib/ace/assign/authority/command_execution.rb
428
434
  - lib/ace/assign/authority/deployment.rb
429
435
  - lib/ace/assign/authority/deployment_history.rb
430
436
  - lib/ace/assign/authority/endcap.rb
@@ -438,10 +444,12 @@ files:
438
444
  - lib/ace/assign/authority/endcap_results.rb
439
445
  - lib/ace/assign/authority/endcap_review_requests.rb
440
446
  - lib/ace/assign/authority/endcap_reviews.rb
447
+ - lib/ace/assign/authority/endcap_service_context.rb
441
448
  - lib/ace/assign/authority/endcap_service_settlement.rb
442
- - lib/ace/assign/authority/endcap_services.rb
443
449
  - lib/ace/assign/authority/evidence_transfer.rb
444
450
  - lib/ace/assign/authority/execution_scope_observation.rb
451
+ - lib/ace/assign/authority/fixed_publication_lifecycle.rb
452
+ - lib/ace/assign/authority/fixed_service_lifecycle.rb
445
453
  - lib/ace/assign/authority/inbox_context_original.rb
446
454
  - lib/ace/assign/authority/launch_attempt_consumers.rb
447
455
  - lib/ace/assign/authority/launch_campaign_registration.rb
@@ -460,6 +468,21 @@ files:
460
468
  - lib/ace/assign/authority/launch_steering.rb
461
469
  - lib/ace/assign/authority/launch_stop.rb
462
470
  - lib/ace/assign/authority/maintenance_workspace_retirement.rb
471
+ - lib/ace/assign/authority/ordinary_attempt_start.rb
472
+ - lib/ace/assign/authority/ordinary_client.rb
473
+ - lib/ace/assign/authority/ordinary_completion.rb
474
+ - lib/ace/assign/authority/ordinary_effect_settlement.rb
475
+ - lib/ace/assign/authority/ordinary_lifecycle.rb
476
+ - lib/ace/assign/authority/ordinary_merge_evidence.rb
477
+ - lib/ace/assign/authority/ordinary_peer.rb
478
+ - lib/ace/assign/authority/ordinary_progress.rb
479
+ - lib/ace/assign/authority/ordinary_queue.rb
480
+ - lib/ace/assign/authority/ordinary_release_artifacts.rb
481
+ - lib/ace/assign/authority/ordinary_results.rb
482
+ - lib/ace/assign/authority/ordinary_review_evidence.rb
483
+ - lib/ace/assign/authority/ordinary_reviews.rb
484
+ - lib/ace/assign/authority/ordinary_server.rb
485
+ - lib/ace/assign/authority/ordinary_supervisor.rb
463
486
  - lib/ace/assign/authority/original_inbox_selection.rb
464
487
  - lib/ace/assign/authority/posix_acl.rb
465
488
  - lib/ace/assign/authority/prepared_input.rb
@@ -471,6 +494,8 @@ files:
471
494
  - lib/ace/assign/authority/protected_assignment_context.rb
472
495
  - lib/ace/assign/authority/readiness_hook.rb
473
496
  - lib/ace/assign/authority/receipt_transfer.rb
497
+ - lib/ace/assign/authority/release_artifact_manifest.rb
498
+ - lib/ace/assign/authority/retained_input.rb
474
499
  - lib/ace/assign/authority/router.rb
475
500
  - lib/ace/assign/authority/server.rb
476
501
  - lib/ace/assign/authority/service_cleanup_dispatch.rb
@@ -478,6 +503,7 @@ files:
478
503
  - lib/ace/assign/authority/service_delivery_evidence.rb
479
504
  - lib/ace/assign/authority/service_evidence.rb
480
505
  - lib/ace/assign/authority/service_publication_evidence.rb
506
+ - lib/ace/assign/authority/socket_server.rb
481
507
  - lib/ace/assign/authority/task_context_entry.rb
482
508
  - lib/ace/assign/authority/transfer_codec.rb
483
509
  - lib/ace/assign/cli.rb
@@ -533,6 +559,7 @@ files:
533
559
  - lib/ace/assign/molecules/attempt_store.rb
534
560
  - lib/ace/assign/molecules/canonical_attempt_state.rb
535
561
  - lib/ace/assign/molecules/canonical_evidence.rb
562
+ - lib/ace/assign/molecules/canonical_read_commands.rb
536
563
  - lib/ace/assign/molecules/canonical_read_snapshot.rb
537
564
  - lib/ace/assign/molecules/evidence_calculator.rb
538
565
  - lib/ace/assign/molecules/evidence_journal.rb
@@ -540,6 +567,7 @@ files:
540
567
  - lib/ace/assign/molecules/execution_scope_lineage.rb
541
568
  - lib/ace/assign/molecules/fixed_effect_reference.rb
542
569
  - lib/ace/assign/molecules/fork_session_launcher.rb
570
+ - lib/ace/assign/molecules/installed_journal_read.rb
543
571
  - lib/ace/assign/molecules/journal_input_inhibition.rb
544
572
  - lib/ace/assign/molecules/journal_mutation.rb
545
573
  - lib/ace/assign/molecules/journal_prompt_mutation.rb
@@ -562,6 +590,7 @@ files:
562
590
  - lib/ace/assign/organisms/assignment_executor.rb
563
591
  - lib/ace/assign/organisms/attempt_coordinator.rb
564
592
  - lib/ace/assign/organisms/delivery_coordinator.rb
593
+ - lib/ace/assign/organisms/ordinary_driver.rb
565
594
  - lib/ace/assign/organisms/ordinary_merge_consumer.rb
566
595
  - lib/ace/assign/organisms/prepared_work_builder.rb
567
596
  - lib/ace/assign/organisms/protected_delivery_coordinator.rb