ace-assign 0.71.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/.ace-defaults/assign/catalog/steps/auto-merge.step.yml +8 -8
  3. data/.ace-defaults/assign/catalog/steps/create-pr.step.yml +1 -1
  4. data/.ace-defaults/assign/catalog/steps/mark-pr-ready.step.yml +1 -1
  5. data/.ace-defaults/assign/config.yml +0 -13
  6. data/.ace-defaults/assign/presets/fix-bug.yml +1 -1
  7. data/.ace-defaults/assign/presets/work-on-task-ace-development.yml +1 -1
  8. data/.ace-defaults/assign/presets/work-on-task-auto-merge.yml +1 -1
  9. data/.ace-defaults/assign/presets/work-on-task.yml +1 -1
  10. data/CHANGELOG.md +3 -2119
  11. data/README.md +58 -31
  12. data/docs/exit-codes.md +36 -44
  13. data/docs/getting-started.md +9 -4
  14. data/docs/usage.md +129 -522
  15. data/handbook/skills/as-assign-drive/SKILL.md +1 -4
  16. data/handbook/workflow-instructions/assign/drive.wf.md +47 -195
  17. data/handbook/workflow-instructions/assign/prepare.wf.md +1 -1
  18. data/handbook/workflow-instructions/assign/verify-test-suite.wf.md +8 -2
  19. data/lib/ace/assign/cli/commands/assignment_target.rb +2 -15
  20. data/lib/ace/assign/cli/commands/create.rb +1 -8
  21. data/lib/ace/assign/cli/commands/fail.rb +0 -6
  22. data/lib/ace/assign/cli/commands/finish.rb +2 -23
  23. data/lib/ace/assign/cli/commands/fork_session.rb +0 -1
  24. data/lib/ace/assign/cli/commands/select.rb +0 -1
  25. data/lib/ace/assign/cli/commands/start.rb +0 -2
  26. data/lib/ace/assign/cli/commands/status.rb +1 -31
  27. data/lib/ace/assign/cli/commands/step.rb +1 -3
  28. data/lib/ace/assign/cli.rb +1 -85
  29. data/lib/ace/assign/errors.rb +8 -80
  30. data/lib/ace/assign/models/assignment.rb +5 -28
  31. data/lib/ace/assign/molecules/assignment_manager.rb +0 -26
  32. data/lib/ace/assign/molecules/fork_session_launcher.rb +4 -12
  33. data/lib/ace/assign/molecules/lifecycle_exclusion.rb +15 -112
  34. data/lib/ace/assign/organisms/assignment_executor.rb +0 -6
  35. data/lib/ace/assign/organisms/task_assignment_creator.rb +3 -8
  36. data/lib/ace/assign/version.rb +1 -1
  37. data/lib/ace/assign.rb +0 -6
  38. metadata +4 -176
  39. data/.ace-defaults/assign/presets/close-delivery.yml +0 -57
  40. data/.ace-defaults/assign/presets/deliver-release.yml +0 -60
  41. data/.ace-defaults/assign/presets/integrate-batch.yml +0 -72
  42. data/.ace-defaults/assign/presets/supervise-delivery.yml +0 -69
  43. data/docs/protected-authority.md +0 -282
  44. data/exe/ace-scope-ready +0 -55
  45. data/lib/ace/assign/atoms/assignment_scope.rb +0 -58
  46. data/lib/ace/assign/atoms/attempt_state_machine.rb +0 -84
  47. data/lib/ace/assign/atoms/candidate_limits.rb +0 -20
  48. data/lib/ace/assign/atoms/delivery_parameters.rb +0 -19
  49. data/lib/ace/assign/atoms/evidence_digest.rb +0 -78
  50. data/lib/ace/assign/atoms/fixed_merge_schemas.rb +0 -398
  51. data/lib/ace/assign/atoms/git_blob_batch.rb +0 -59
  52. data/lib/ace/assign/authority/assignment_definition.rb +0 -35
  53. data/lib/ace/assign/authority/assignment_inventory.rb +0 -290
  54. data/lib/ace/assign/authority/campaign_consumer_policy.rb +0 -100
  55. data/lib/ace/assign/authority/campaign_execution.rb +0 -119
  56. data/lib/ace/assign/authority/campaign_round_transfer.rb +0 -82
  57. data/lib/ace/assign/authority/candidate_blob_batch.rb +0 -55
  58. data/lib/ace/assign/authority/candidate_head_comparison.rb +0 -139
  59. data/lib/ace/assign/authority/candidate_transfer.rb +0 -357
  60. data/lib/ace/assign/authority/cleanup_result_protection.rb +0 -53
  61. data/lib/ace/assign/authority/client.rb +0 -257
  62. data/lib/ace/assign/authority/command_execution.rb +0 -180
  63. data/lib/ace/assign/authority/deployment.rb +0 -627
  64. data/lib/ace/assign/authority/deployment_history.rb +0 -146
  65. data/lib/ace/assign/authority/endcap.rb +0 -457
  66. data/lib/ace/assign/authority/endcap_attempts.rb +0 -274
  67. data/lib/ace/assign/authority/endcap_campaign_results.rb +0 -232
  68. data/lib/ace/assign/authority/endcap_campaign_rounds.rb +0 -266
  69. data/lib/ace/assign/authority/endcap_contexts.rb +0 -23
  70. data/lib/ace/assign/authority/endcap_inboxes.rb +0 -37
  71. data/lib/ace/assign/authority/endcap_prepared_work.rb +0 -80
  72. data/lib/ace/assign/authority/endcap_publication.rb +0 -41
  73. data/lib/ace/assign/authority/endcap_results.rb +0 -398
  74. data/lib/ace/assign/authority/endcap_review_requests.rb +0 -183
  75. data/lib/ace/assign/authority/endcap_reviews.rb +0 -130
  76. data/lib/ace/assign/authority/endcap_service_context.rb +0 -38
  77. data/lib/ace/assign/authority/endcap_service_settlement.rb +0 -152
  78. data/lib/ace/assign/authority/evidence_transfer.rb +0 -67
  79. data/lib/ace/assign/authority/execution_scope_observation.rb +0 -903
  80. data/lib/ace/assign/authority/fixed_publication_lifecycle.rb +0 -176
  81. data/lib/ace/assign/authority/fixed_service_lifecycle.rb +0 -594
  82. data/lib/ace/assign/authority/inbox_context_original.rb +0 -113
  83. data/lib/ace/assign/authority/launch_attempt_consumers.rb +0 -51
  84. data/lib/ace/assign/authority/launch_campaign_registration.rb +0 -214
  85. data/lib/ace/assign/authority/launch_control_channel.rb +0 -313
  86. data/lib/ace/assign/authority/launch_control_exclusions.rb +0 -127
  87. data/lib/ace/assign/authority/launch_driver.rb +0 -393
  88. data/lib/ace/assign/authority/launch_input_inhibition.rb +0 -132
  89. data/lib/ace/assign/authority/launch_lifecycle.rb +0 -997
  90. data/lib/ace/assign/authority/launch_prepared_work.rb +0 -122
  91. data/lib/ace/assign/authority/launch_review.rb +0 -91
  92. data/lib/ace/assign/authority/launch_scope_abort.rb +0 -81
  93. data/lib/ace/assign/authority/launch_scope_admission.rb +0 -215
  94. data/lib/ace/assign/authority/launch_scope_close.rb +0 -146
  95. data/lib/ace/assign/authority/launch_scope_parent.rb +0 -44
  96. data/lib/ace/assign/authority/launch_scope_release.rb +0 -859
  97. data/lib/ace/assign/authority/launch_steering.rb +0 -353
  98. data/lib/ace/assign/authority/launch_stop.rb +0 -254
  99. data/lib/ace/assign/authority/maintenance_workspace_retirement.rb +0 -229
  100. data/lib/ace/assign/authority/ordinary_attempt_start.rb +0 -137
  101. data/lib/ace/assign/authority/ordinary_client.rb +0 -70
  102. data/lib/ace/assign/authority/ordinary_completion.rb +0 -104
  103. data/lib/ace/assign/authority/ordinary_effect_settlement.rb +0 -118
  104. data/lib/ace/assign/authority/ordinary_lifecycle.rb +0 -227
  105. data/lib/ace/assign/authority/ordinary_merge_evidence.rb +0 -81
  106. data/lib/ace/assign/authority/ordinary_peer.rb +0 -54
  107. data/lib/ace/assign/authority/ordinary_progress.rb +0 -162
  108. data/lib/ace/assign/authority/ordinary_queue.rb +0 -115
  109. data/lib/ace/assign/authority/ordinary_release_artifacts.rb +0 -143
  110. data/lib/ace/assign/authority/ordinary_results.rb +0 -206
  111. data/lib/ace/assign/authority/ordinary_review_evidence.rb +0 -180
  112. data/lib/ace/assign/authority/ordinary_reviews.rb +0 -214
  113. data/lib/ace/assign/authority/ordinary_server.rb +0 -75
  114. data/lib/ace/assign/authority/ordinary_supervisor.rb +0 -99
  115. data/lib/ace/assign/authority/original_inbox_selection.rb +0 -41
  116. data/lib/ace/assign/authority/posix_acl.rb +0 -59
  117. data/lib/ace/assign/authority/prepared_input.rb +0 -130
  118. data/lib/ace/assign/authority/prepared_queue.rb +0 -185
  119. data/lib/ace/assign/authority/prepared_task_context.rb +0 -116
  120. data/lib/ace/assign/authority/prepared_work.rb +0 -309
  121. data/lib/ace/assign/authority/prepared_worker.rb +0 -69
  122. data/lib/ace/assign/authority/private_directory.rb +0 -33
  123. data/lib/ace/assign/authority/protected_assignment_context.rb +0 -226
  124. data/lib/ace/assign/authority/readiness_hook.rb +0 -120
  125. data/lib/ace/assign/authority/receipt_transfer.rb +0 -48
  126. data/lib/ace/assign/authority/release_artifact_manifest.rb +0 -91
  127. data/lib/ace/assign/authority/retained_input.rb +0 -53
  128. data/lib/ace/assign/authority/router.rb +0 -81
  129. data/lib/ace/assign/authority/server.rb +0 -131
  130. data/lib/ace/assign/authority/service_cleanup_dispatch.rb +0 -88
  131. data/lib/ace/assign/authority/service_cleanup_evidence.rb +0 -180
  132. data/lib/ace/assign/authority/service_delivery_evidence.rb +0 -101
  133. data/lib/ace/assign/authority/service_evidence.rb +0 -286
  134. data/lib/ace/assign/authority/service_publication_evidence.rb +0 -110
  135. data/lib/ace/assign/authority/socket_server.rb +0 -255
  136. data/lib/ace/assign/authority/task_context_entry.rb +0 -32
  137. data/lib/ace/assign/authority/transfer_codec.rb +0 -189
  138. data/lib/ace/assign/cli/commands/attempt/base.rb +0 -84
  139. data/lib/ace/assign/cli/commands/attempt/evidence.rb +0 -28
  140. data/lib/ace/assign/cli/commands/attempt/finish.rb +0 -51
  141. data/lib/ace/assign/cli/commands/attempt/reconcile.rb +0 -49
  142. data/lib/ace/assign/cli/commands/attempt/start.rb +0 -45
  143. data/lib/ace/assign/cli/commands/attempt/status.rb +0 -54
  144. data/lib/ace/assign/cli/commands/authority/inbox_context_principal.rb +0 -25
  145. data/lib/ace/assign/cli/commands/authority/inbox_context_selection.rb +0 -28
  146. data/lib/ace/assign/cli/commands/authority/launch.rb +0 -97
  147. data/lib/ace/assign/cli/commands/authority/serve.rb +0 -31
  148. data/lib/ace/assign/cli/commands/authority/status.rb +0 -26
  149. data/lib/ace/assign/cli/commands/authority/task_context.rb +0 -31
  150. data/lib/ace/assign/cli/commands/authority/task_context_principal.rb +0 -25
  151. data/lib/ace/assign/cli/commands/authority/task_context_selection.rb +0 -30
  152. data/lib/ace/assign/cli/commands/authority/terminate.rb +0 -29
  153. data/lib/ace/assign/cli/commands/authority/worker.rb +0 -23
  154. data/lib/ace/assign/cli/commands/campaign_export_result.rb +0 -55
  155. data/lib/ace/assign/cli/commands/campaign_record_round.rb +0 -57
  156. data/lib/ace/assign/cli/commands/delivery.rb +0 -107
  157. data/lib/ace/assign/cli/commands/inbox_bind.rb +0 -34
  158. data/lib/ace/assign/cli/commands/protected_submission.rb +0 -61
  159. data/lib/ace/assign/cli/commands/resume.rb +0 -38
  160. data/lib/ace/assign/cli/commands/submit_candidate.rb +0 -34
  161. data/lib/ace/assign/cli/commands/submit_result.rb +0 -61
  162. data/lib/ace/assign/models/attempt.rb +0 -178
  163. data/lib/ace/assign/models/attempt_binding.rb +0 -116
  164. data/lib/ace/assign/models/evidence_event.rb +0 -86
  165. data/lib/ace/assign/models/execution_receipt.rb +0 -139
  166. data/lib/ace/assign/molecules/attempt_reconciler.rb +0 -127
  167. data/lib/ace/assign/molecules/attempt_store.rb +0 -201
  168. data/lib/ace/assign/molecules/canonical_attempt_state.rb +0 -151
  169. data/lib/ace/assign/molecules/canonical_evidence.rb +0 -170
  170. data/lib/ace/assign/molecules/canonical_read_commands.rb +0 -84
  171. data/lib/ace/assign/molecules/canonical_read_snapshot.rb +0 -313
  172. data/lib/ace/assign/molecules/evidence_calculator.rb +0 -237
  173. data/lib/ace/assign/molecules/evidence_journal.rb +0 -1899
  174. data/lib/ace/assign/molecules/execution_identity_resolver.rb +0 -137
  175. data/lib/ace/assign/molecules/execution_scope_lineage.rb +0 -345
  176. data/lib/ace/assign/molecules/fixed_effect_reference.rb +0 -31
  177. data/lib/ace/assign/molecules/installed_journal_read.rb +0 -143
  178. data/lib/ace/assign/molecules/journal_input_inhibition.rb +0 -78
  179. data/lib/ace/assign/molecules/journal_mutation.rb +0 -274
  180. data/lib/ace/assign/molecules/journal_prompt_mutation.rb +0 -241
  181. data/lib/ace/assign/molecules/ordinary_merge_cli.rb +0 -68
  182. data/lib/ace/assign/molecules/ordinary_merge_contract.rb +0 -410
  183. data/lib/ace/assign/molecules/original_launch_binding.rb +0 -37
  184. data/lib/ace/assign/molecules/proposal_journal.rb +0 -179
  185. data/lib/ace/assign/molecules/protected_control_exclusion.rb +0 -303
  186. data/lib/ace/assign/molecules/protected_workspace_exclusion.rb +0 -330
  187. data/lib/ace/assign/molecules/protected_workspace_provisioner.rb +0 -164
  188. data/lib/ace/assign/molecules/receipt_verifier.rb +0 -320
  189. data/lib/ace/assign/molecules/terminal_scope_receipt.rb +0 -88
  190. data/lib/ace/assign/organisms/attempt_coordinator.rb +0 -1374
  191. data/lib/ace/assign/organisms/delivery_coordinator.rb +0 -342
  192. data/lib/ace/assign/organisms/ordinary_driver.rb +0 -310
  193. data/lib/ace/assign/organisms/ordinary_merge_consumer.rb +0 -365
  194. data/lib/ace/assign/organisms/prepared_work_builder.rb +0 -194
  195. data/lib/ace/assign/organisms/protected_delivery_coordinator.rb +0 -100
@@ -1,176 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ace
4
- module Assign
5
- module Authority
6
- module FixedPublicationLifecycle
7
- def publication_executor_identity?(project:, uid:)
8
- service_project!(project).fetch("service_executor_uids").include?(uid)
9
- end
10
-
11
- def with_publication_hitl!(binding:, project:, peer:)
12
- params = binding.slice("mapping_id", "assignment_id", "attempt_id", "request_id", "claim_binding", "input_digest", "candidate_generation", "head")
13
- map = service_mapping!(params.fetch("mapping_id"))
14
- raise AttemptErrors::UnauthorizedIdentity, "publication project differs" unless map.fetch("project_id") == project
15
- with_service_scope(params: params, map: map) do |journal, _registration|
16
- service_journal!(journal)
17
- record = publication_record!(journal, params, map, peer, :executor)
18
- unless record["dispatch_phase"] == "otp_pending" && record["publication_challenge_digest"] == binding.fetch("challenge_digest")
19
- raise AttemptErrors::Conflict, "publication HITL challenge is no longer pending"
20
- end
21
- ServiceEvidence.new(journal: journal).publication_challenge!(record)
22
- selection = settlement_immutable({"executor_process_binding" => record.fetch("executor_process_binding"),
23
- "challenge_ref" => record.fetch("publication_challenge_ref").fetch("ref")})
24
- yield selection
25
- end
26
- end
27
-
28
- def authorize_publication_update!(journal:, existing:, replacement:, pending:)
29
- operation = pending.fetch(:operation)
30
- allowed = ServicePublicationEvidence::PUBLICATION_FIELDS + ["dispatch_phase"]
31
- unless existing.except(*allowed) == replacement.except(*allowed) && existing["state"] == "uncertain"
32
- raise AttemptErrors::InvalidState, "publication transition changed original binding"
33
- end
34
- owner = ServiceEvidence.new(journal: journal)
35
- if operation == "publication_challenge"
36
- unless %w[dispatch_started issuing].include?(existing["dispatch_phase"]) && replacement["dispatch_phase"] == "otp_pending" &&
37
- replacement["publication_issuing_event_digest"] == existing["publication_issuing_event_digest"]
38
- raise AttemptErrors::InvalidState, "publication need has no source-owned rejected push"
39
- end
40
- need = owner.publication_challenge!(replacement, pending: pending)
41
- unless need["previous_challenge_digest"] == existing["publication_challenge_digest"]
42
- raise AttemptErrors::InvalidState, "publication need predecessor differs"
43
- end
44
- elsif operation == "publication_continue"
45
- unless existing["dispatch_phase"] == "otp_pending" && replacement["dispatch_phase"] == "issuing" &&
46
- (allowed - %w[dispatch_phase publication_issuing_event_digest]).all? { |key| existing[key] == replacement[key] }
47
- raise AttemptErrors::InvalidState, "publication continuation is not a unique pending challenge"
48
- end
49
- owner.publication_challenge!(replacement, pending: pending)
50
- events = pending.fetch(:current_events) + pending.fetch(:pending_events)
51
- event = events.find { |row| row["digest"] == replacement["publication_issuing_event_digest"] }
52
- unless event && event["type"] == "service_publication_issuing" &&
53
- %w[request_id input_digest claim_binding publication_challenge_digest].all? { |key| event.dig("payload", key) == replacement[key] }
54
- raise AttemptErrors::EvidenceUnavailable, "publication issuing event is unavailable"
55
- end
56
- else
57
- raise AttemptErrors::InvalidState, "publication transition has no fixed source owner"
58
- end
59
- true
60
- end
61
-
62
- def publication_record!(journal, params, map, peer, role, events: nil)
63
- record = journal.service_request(params.fetch("request_id"))
64
- unless record && record["operation"] == "publish" && record["state"] == "uncertain" &&
65
- %w[dispatch_started otp_pending issuing].include?(record["dispatch_phase"]) &&
66
- %w[claim_binding input_digest candidate_generation].all? { |key| record[key] == params[key] } &&
67
- record["candidate_head"] == params["head"] && record["mapping_id"] == params["mapping_id"]
68
- raise AttemptErrors::Conflict, "publication original tuple or phase differs"
69
- end
70
- service_executor!(peer, role, record)
71
- service_ticket!(record, params, map, peer)
72
- events ||= attempt_events(journal, params)
73
- current = exact_candidate!(candidate(events), params)
74
- origin = service_origin!(events, params)
75
- service_worker!(record.fetch("worker_process_binding"), :worker, map, origin)
76
- service_review!(journal, events, params, map, current)
77
- service_scope_open!(events: events, params: params, map: map)
78
- service_policy!.authorize!(record)
79
- ServiceEvidence.new(journal: journal).context(record)
80
- record
81
- end
82
-
83
- def authorize_publication_transfer!(request, params, map, peer, role)
84
- with_service_scope(params: params, map: map) do |journal, _registration|
85
- service_journal!(journal)
86
- publication_record!(journal, params, map, peer, role)
87
- end
88
- true
89
- end
90
-
91
- def dispatch_publication(request, params, map, peer, role, transfer)
92
- authorize_publication_transfer!(request, params, map, peer, role)
93
- challenge = request.fetch("operation") == "publication_challenge"
94
- bytes = nil
95
- if challenge
96
- unless transfer && transfer.count == 1
97
- raise ArgumentError, "publication need requires one bounded artifact"
98
- end
99
- bytes = transfer.bytes.dup.freeze
100
- unless Digest::SHA256.hexdigest(bytes) == params.fetch("receipt_sha256")
101
- raise AttemptErrors::ReceiptRejected, "publication need transfer digest differs"
102
- end
103
- elsif transfer
104
- raise ArgumentError, "publication continuation forbids upload"
105
- end
106
- with_service_scope(params: params, map: map) do |journal, _registration|
107
- publication_record!(journal, params, map, peer, role)
108
- result = journal.mutate(assignment_id: params.fetch("assignment_id"), attempt_id: params.fetch("attempt_id"),
109
- mutation_id: request.fetch("mutation_id"), operation: request.fetch("operation"),
110
- parameters_digest: Atoms::EvidenceDigest.digest(params), expected_generation: params.fetch("expected_generation"),
111
- with_replay: true) do |events, _commit, generation|
112
- record = publication_record!(journal, params, map, peer, role, events: events)
113
- if challenge
114
- publication_challenge_plan(journal, events, record, params, bytes, generation)
115
- else
116
- publication_continue_plan(journal, events, record, params, generation)
117
- end
118
- end
119
- if !challenge && result.fetch(:replayed)
120
- result = result.merge(data: result.fetch(:data).merge("invocation" => "already_issued"))
121
- end
122
- result
123
- end
124
- end
125
-
126
- def publication_challenge_plan(journal, events, record, params, bytes, generation)
127
- owner = ServiceEvidence.new(journal: journal)
128
- digest = Digest::SHA256.hexdigest(bytes)
129
- if record["dispatch_phase"] == "otp_pending"
130
- owner.publication_challenge!(record)
131
- raise AttemptErrors::Conflict, "publication pending challenge differs" unless record["publication_challenge_digest"] == digest
132
- return {data: service_projection(record).merge("challenge" => "retained")}
133
- end
134
- unless %w[dispatch_started issuing].include?(record["dispatch_phase"])
135
- raise AttemptErrors::InvalidState, "publication has no rejected push"
136
- end
137
- previous = record["publication_challenge_digest"]
138
- owner.publication_challenge!(record) if previous
139
- owner.publication_need!(bytes, record, previous: previous)
140
- payload = record.slice("request_id", "input_digest", "claim_binding").merge(
141
- "challenge_digest" => digest, "previous_challenge_digest" => previous, "generation" => generation + 1)
142
- time = Time.now.utc
143
- event = Models::EvidenceEvent.build(type: "service_publication_challenge", attempt_id: record.fetch("attempt_id"),
144
- payload: payload, previous_digest: events.last&.fetch("digest"), recorded_at: time)
145
- plan = Molecules::CanonicalEvidence.new(journal: journal).import_plan(**owner.context(record),
146
- artifacts: [bytes], admitted_after_event_digest: event.fetch("digest"))
147
- replacement = record.merge("dispatch_phase" => "otp_pending", "publication_challenge_digest" => digest,
148
- "publication_challenge_ref" => plan.fetch(:references).fetch(0),
149
- "publication_challenge_event_digest" => event.fetch("digest"), "publication_challenge_generation" => generation + 1)
150
- plan.merge(events: [{type: "service_publication_challenge", payload: payload, recorded_at: time}] + plan.fetch(:events),
151
- data: service_projection(replacement).merge("challenge" => "created"), service_updates: [{request_id: record.fetch("request_id"),
152
- expected: record, replacement: replacement, event_type: "service_transition"}])
153
- end
154
-
155
- def publication_continue_plan(journal, events, record, params, generation)
156
- ServiceEvidence.new(journal: journal).publication_challenge!(record)
157
- unless record["publication_challenge_digest"] == params.fetch("challenge_digest")
158
- raise AttemptErrors::Conflict, "publication continuation challenge differs"
159
- end
160
- if record["dispatch_phase"] == "issuing"
161
- return {data: service_projection(record).merge("invocation" => "already_issued")}
162
- end
163
- raise AttemptErrors::InvalidState, "publication is not pending" unless record["dispatch_phase"] == "otp_pending"
164
- payload = record.slice("request_id", "input_digest", "claim_binding", "publication_challenge_digest").merge("generation" => generation + 1)
165
- time = Time.now.utc
166
- event = Models::EvidenceEvent.build(type: "service_publication_issuing", attempt_id: record.fetch("attempt_id"),
167
- payload: payload, previous_digest: events.last&.fetch("digest"), recorded_at: time)
168
- replacement = record.merge("dispatch_phase" => "issuing", "publication_issuing_event_digest" => event.fetch("digest"))
169
- {events: [{type: "service_publication_issuing", payload: payload, recorded_at: time}],
170
- data: service_projection(replacement).merge("invocation" => "permitted"), service_updates: [{request_id: record.fetch("request_id"),
171
- expected: record, replacement: replacement, event_type: "service_transition"}]}
172
- end
173
- end
174
- end
175
- end
176
- end