ace-assign 0.70.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/handbook/skills/as-assign-drive/SKILL.md +5 -2
- data/handbook/workflow-instructions/assign/drive.wf.md +77 -0
- data/lib/ace/assign/atoms/candidate_limits.rb +20 -0
- data/lib/ace/assign/atoms/git_blob_batch.rb +59 -0
- data/lib/ace/assign/authority/candidate_blob_batch.rb +55 -0
- data/lib/ace/assign/authority/candidate_head_comparison.rb +139 -0
- data/lib/ace/assign/authority/candidate_transfer.rb +55 -25
- data/lib/ace/assign/authority/command_execution.rb +180 -0
- data/lib/ace/assign/authority/endcap.rb +4 -2
- data/lib/ace/assign/authority/endcap_campaign_rounds.rb +1 -1
- data/lib/ace/assign/authority/endcap_publication.rb +0 -166
- data/lib/ace/assign/authority/endcap_service_context.rb +38 -0
- data/lib/ace/assign/authority/fixed_publication_lifecycle.rb +176 -0
- data/lib/ace/assign/authority/{endcap_services.rb → fixed_service_lifecycle.rb} +42 -46
- data/lib/ace/assign/authority/ordinary_completion.rb +13 -3
- data/lib/ace/assign/authority/ordinary_lifecycle.rb +40 -4
- data/lib/ace/assign/authority/ordinary_merge_evidence.rb +81 -0
- data/lib/ace/assign/authority/ordinary_release_artifacts.rb +143 -0
- data/lib/ace/assign/authority/ordinary_results.rb +11 -1
- data/lib/ace/assign/authority/ordinary_review_evidence.rb +180 -0
- data/lib/ace/assign/authority/ordinary_reviews.rb +214 -0
- data/lib/ace/assign/authority/ordinary_supervisor.rb +99 -0
- data/lib/ace/assign/authority/prepared_work.rb +7 -2
- data/lib/ace/assign/authority/release_artifact_manifest.rb +91 -0
- data/lib/ace/assign/authority/retained_input.rb +53 -0
- data/lib/ace/assign/authority/transfer_codec.rb +5 -3
- data/lib/ace/assign/cli/commands/submit_candidate.rb +1 -1
- data/lib/ace/assign/molecules/canonical_evidence.rb +25 -8
- data/lib/ace/assign/molecules/evidence_journal.rb +17 -30
- data/lib/ace/assign/molecules/journal_mutation.rb +2 -1
- data/lib/ace/assign/molecules/receipt_verifier.rb +8 -2
- data/lib/ace/assign/molecules/runtime_control_surface_runner.rb +2 -1
- data/lib/ace/assign/organisms/attempt_coordinator.rb +40 -3
- data/lib/ace/assign/organisms/ordinary_driver.rb +310 -0
- data/lib/ace/assign/version.rb +1 -1
- metadata +19 -4
|
@@ -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
|
data/lib/ace/assign/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.71.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
@@ -175,14 +175,14 @@ dependencies:
|
|
|
175
175
|
requirements:
|
|
176
176
|
- - "~>"
|
|
177
177
|
- !ruby/object:Gem::Version
|
|
178
|
-
version: 0.
|
|
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.
|
|
185
|
+
version: 0.61.0
|
|
186
186
|
- !ruby/object:Gem::Dependency
|
|
187
187
|
name: ace-task
|
|
188
188
|
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
|
|
@@ -423,9 +425,12 @@ files:
|
|
|
423
425
|
- lib/ace/assign/authority/campaign_consumer_policy.rb
|
|
424
426
|
- lib/ace/assign/authority/campaign_execution.rb
|
|
425
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
|
|
426
430
|
- lib/ace/assign/authority/candidate_transfer.rb
|
|
427
431
|
- lib/ace/assign/authority/cleanup_result_protection.rb
|
|
428
432
|
- lib/ace/assign/authority/client.rb
|
|
433
|
+
- lib/ace/assign/authority/command_execution.rb
|
|
429
434
|
- lib/ace/assign/authority/deployment.rb
|
|
430
435
|
- lib/ace/assign/authority/deployment_history.rb
|
|
431
436
|
- lib/ace/assign/authority/endcap.rb
|
|
@@ -439,10 +444,12 @@ files:
|
|
|
439
444
|
- lib/ace/assign/authority/endcap_results.rb
|
|
440
445
|
- lib/ace/assign/authority/endcap_review_requests.rb
|
|
441
446
|
- lib/ace/assign/authority/endcap_reviews.rb
|
|
447
|
+
- lib/ace/assign/authority/endcap_service_context.rb
|
|
442
448
|
- lib/ace/assign/authority/endcap_service_settlement.rb
|
|
443
|
-
- lib/ace/assign/authority/endcap_services.rb
|
|
444
449
|
- lib/ace/assign/authority/evidence_transfer.rb
|
|
445
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
|
|
446
453
|
- lib/ace/assign/authority/inbox_context_original.rb
|
|
447
454
|
- lib/ace/assign/authority/launch_attempt_consumers.rb
|
|
448
455
|
- lib/ace/assign/authority/launch_campaign_registration.rb
|
|
@@ -466,11 +473,16 @@ files:
|
|
|
466
473
|
- lib/ace/assign/authority/ordinary_completion.rb
|
|
467
474
|
- lib/ace/assign/authority/ordinary_effect_settlement.rb
|
|
468
475
|
- lib/ace/assign/authority/ordinary_lifecycle.rb
|
|
476
|
+
- lib/ace/assign/authority/ordinary_merge_evidence.rb
|
|
469
477
|
- lib/ace/assign/authority/ordinary_peer.rb
|
|
470
478
|
- lib/ace/assign/authority/ordinary_progress.rb
|
|
471
479
|
- lib/ace/assign/authority/ordinary_queue.rb
|
|
480
|
+
- lib/ace/assign/authority/ordinary_release_artifacts.rb
|
|
472
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
|
|
473
484
|
- lib/ace/assign/authority/ordinary_server.rb
|
|
485
|
+
- lib/ace/assign/authority/ordinary_supervisor.rb
|
|
474
486
|
- lib/ace/assign/authority/original_inbox_selection.rb
|
|
475
487
|
- lib/ace/assign/authority/posix_acl.rb
|
|
476
488
|
- lib/ace/assign/authority/prepared_input.rb
|
|
@@ -482,6 +494,8 @@ files:
|
|
|
482
494
|
- lib/ace/assign/authority/protected_assignment_context.rb
|
|
483
495
|
- lib/ace/assign/authority/readiness_hook.rb
|
|
484
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
|
|
485
499
|
- lib/ace/assign/authority/router.rb
|
|
486
500
|
- lib/ace/assign/authority/server.rb
|
|
487
501
|
- lib/ace/assign/authority/service_cleanup_dispatch.rb
|
|
@@ -576,6 +590,7 @@ files:
|
|
|
576
590
|
- lib/ace/assign/organisms/assignment_executor.rb
|
|
577
591
|
- lib/ace/assign/organisms/attempt_coordinator.rb
|
|
578
592
|
- lib/ace/assign/organisms/delivery_coordinator.rb
|
|
593
|
+
- lib/ace/assign/organisms/ordinary_driver.rb
|
|
579
594
|
- lib/ace/assign/organisms/ordinary_merge_consumer.rb
|
|
580
595
|
- lib/ace/assign/organisms/prepared_work_builder.rb
|
|
581
596
|
- lib/ace/assign/organisms/protected_delivery_coordinator.rb
|