@astrosheep/keiyaku 4.5.20 → 4.5.21

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 (154) hide show
  1. package/README.md +4 -4
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +22 -8
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +237 -0
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +6 -7
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +2 -3
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -3
  8. package/build/src/akuma/akuma-handle.d.ts +5 -1
  9. package/build/src/akuma/akuma-handle.js +4 -1
  10. package/build/src/akuma/akuma-instance.d.ts +7 -2
  11. package/build/src/akuma/akuma-instance.js +14 -7
  12. package/build/src/akuma/akuma-observe.d.ts +11 -0
  13. package/build/src/akuma/akuma-observe.js +22 -0
  14. package/build/src/akuma/akuma-product.d.ts +1 -0
  15. package/build/src/akuma/akuma-product.js +3 -0
  16. package/build/src/akuma/akuma.d.ts +1 -0
  17. package/build/src/akuma/body.d.ts +25 -5
  18. package/build/src/akuma/body.js +65 -8
  19. package/build/src/akuma/call-request.d.ts +2 -0
  20. package/build/src/akuma/call-request.js +2 -0
  21. package/build/src/akuma/fleet-execution.d.ts +28 -0
  22. package/build/src/akuma/fleet-execution.js +36 -4
  23. package/build/src/akuma/fleet-request.d.ts +10 -0
  24. package/build/src/akuma/fleet-request.js +11 -2
  25. package/build/src/akuma/heart/facts.d.ts +2 -0
  26. package/build/src/akuma/heart/index.d.ts +1 -0
  27. package/build/src/akuma/heart/index.js +4 -1
  28. package/build/src/akuma/heart/rows.d.ts +2 -0
  29. package/build/src/akuma/heart/rows.js +7 -5
  30. package/build/src/akuma/heart/schema.d.ts +1 -1
  31. package/build/src/akuma/heart/schema.js +3 -1
  32. package/build/src/akuma/heart/tells.js +6 -5
  33. package/build/src/akuma/heart/timeline.js +1 -1
  34. package/build/src/akuma/provider.d.ts +1 -1
  35. package/build/src/akuma/provider.js +1 -1
  36. package/build/src/akuma/providers/acp/core.js +3 -6
  37. package/build/src/akuma/providers/claude/index.js +9 -12
  38. package/build/src/akuma/providers/codex-app-server/index.js +4 -11
  39. package/build/src/akuma/providers/execution-environment.d.ts +6 -0
  40. package/build/src/akuma/providers/execution-environment.js +24 -0
  41. package/build/src/akuma/providers/opencode-sdk/index.js +30 -23
  42. package/build/src/akuma/providers/opencode-sdk/session.d.ts +8 -1
  43. package/build/src/akuma/providers/opencode-sdk/session.js +6 -5
  44. package/build/src/akuma/providers/pi/events.js +7 -2
  45. package/build/src/akuma/providers/pi/index.js +3 -2
  46. package/build/src/akuma/request-rendezvous.js +8 -3
  47. package/build/src/akuma/turn-drive.d.ts +1 -0
  48. package/build/src/akuma/turn-drive.js +2 -0
  49. package/build/src/akuma-body.js +2 -0
  50. package/build/src/body/amend.js +6 -4
  51. package/build/src/body/decode.d.ts +3 -1
  52. package/build/src/body/decode.js +53 -17
  53. package/build/src/body/region.d.ts +9 -1
  54. package/build/src/body/region.js +87 -12
  55. package/build/src/body/render.js +1 -1
  56. package/build/src/body/verification.d.ts +3 -1
  57. package/build/src/body/verification.js +4 -1
  58. package/build/src/cli/accepted.js +19 -2
  59. package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
  60. package/build/src/cli/commands/akuma-invoke.js +133 -13
  61. package/build/src/cli/commands/akuma.js +11 -4
  62. package/build/src/cli/commands/contract-help.js +17 -4
  63. package/build/src/cli/commands/contract.js +6 -4
  64. package/build/src/cli/commands/status-set.js +15 -24
  65. package/build/src/cli/main.js +5 -0
  66. package/build/src/cli/parse.d.ts +2 -0
  67. package/build/src/cli/parse.js +5 -0
  68. package/build/src/cli/render/akuma-activity.d.ts +99 -2
  69. package/build/src/cli/render/akuma-activity.js +484 -40
  70. package/build/src/cli/render/akuma.d.ts +10 -0
  71. package/build/src/cli/render/akuma.js +28 -21
  72. package/build/src/cli/render/audit.js +1 -1
  73. package/build/src/cli/render/board.js +1 -1
  74. package/build/src/cli/render/catalog.js +16 -13
  75. package/build/src/cli/render/contract-history.js +39 -10
  76. package/build/src/cli/render/contract-observation.js +10 -6
  77. package/build/src/cli/render/contract.js +109 -106
  78. package/build/src/cli/render/execution-progress.d.ts +23 -1
  79. package/build/src/cli/render/execution-progress.js +151 -28
  80. package/build/src/cli/render/kanshi-akuma.js +27 -39
  81. package/build/src/cli/render/kanshi.js +33 -26
  82. package/build/src/cli/render/nuke.js +1 -1
  83. package/build/src/cli/render/receipt.d.ts +1 -1
  84. package/build/src/cli/render/receipt.js +5 -5
  85. package/build/src/cli/render/refusal.js +10 -7
  86. package/build/src/cli/render/region.js +1 -1
  87. package/build/src/cli/render/settings.js +12 -2
  88. package/build/src/cli/render/status-line.d.ts +30 -0
  89. package/build/src/cli/render/status-line.js +58 -0
  90. package/build/src/cli/render/status-set.js +1 -1
  91. package/build/src/cli/render/task.d.ts +2 -0
  92. package/build/src/cli/render/task.js +11 -7
  93. package/build/src/cli/render/terminal.d.ts +0 -1
  94. package/build/src/cli/render/terminal.js +47 -15
  95. package/build/src/cli/result.d.ts +1 -0
  96. package/build/src/cli/runtime.d.ts +2 -0
  97. package/build/src/cli/runtime.js +13 -7
  98. package/build/src/cli/usage.js +2 -2
  99. package/build/src/cli/version.d.ts +1 -0
  100. package/build/src/cli/version.js +25 -0
  101. package/build/src/git/workspace.d.ts +1 -1
  102. package/build/src/git/workspace.js +1 -1
  103. package/build/src/identity/mint.d.ts +13 -0
  104. package/build/src/identity/mint.js +26 -0
  105. package/build/src/identity/normalize.d.ts +4 -0
  106. package/build/src/identity/normalize.js +30 -0
  107. package/build/src/index.d.ts +2 -0
  108. package/build/src/index.js +1 -0
  109. package/build/src/kanshi/read.js +17 -4
  110. package/build/src/kanshi/report.d.ts +1 -0
  111. package/build/src/library/akuma-creation.d.ts +2 -0
  112. package/build/src/library/akuma-creation.js +33 -17
  113. package/build/src/library/bind.js +18 -16
  114. package/build/src/library/contract-bind.d.ts +3 -1
  115. package/build/src/library/contract-bind.js +5 -3
  116. package/build/src/library/contract-operations.d.ts +2 -2
  117. package/build/src/library/contract-operations.js +1 -1
  118. package/build/src/library/contract-types.d.ts +1 -0
  119. package/build/src/library/fleet.d.ts +4 -1
  120. package/build/src/library/fleet.js +32 -8
  121. package/build/src/plugin/akuma-signals.d.ts +6 -0
  122. package/build/src/plugin/akuma-signals.js +8 -0
  123. package/build/src/plugin/public.d.ts +4 -0
  124. package/build/src/plugin/runtime.js +4 -1
  125. package/build/src/protocol/amend.js +4 -3
  126. package/build/src/protocol/attempt.d.ts +2 -0
  127. package/build/src/protocol/bind.js +41 -14
  128. package/build/src/protocol/completion.d.ts +3 -0
  129. package/build/src/protocol/completion.js +7 -1
  130. package/build/src/protocol/deliver.js +165 -92
  131. package/build/src/protocol/execution-observation.d.ts +0 -4
  132. package/build/src/protocol/intent.d.ts +15 -20
  133. package/build/src/protocol/intent.js +29 -17
  134. package/build/src/protocol/operations.d.ts +2 -0
  135. package/build/src/protocol/placement.js +5 -1
  136. package/build/src/protocol/read/status.d.ts +1 -0
  137. package/build/src/protocol/read/status.js +10 -2
  138. package/build/src/protocol/reintegrate.d.ts +1 -1
  139. package/build/src/protocol/reintegrate.js +70 -43
  140. package/build/src/protocol/result-codec.js +9 -7
  141. package/build/src/protocol/review.js +53 -30
  142. package/build/src/protocol/run.d.ts +83 -36
  143. package/build/src/protocol/run.js +90 -75
  144. package/build/src/runtime/proc/windows-launch.exe +0 -0
  145. package/build/src/settings.js +5 -14
  146. package/build/src/task/document.d.ts +5 -1
  147. package/build/src/task/document.js +6 -1
  148. package/build/src/verification/execution.d.ts +0 -1
  149. package/build/src/verification/execution.js +0 -24
  150. package/build/src/verification/observation.d.ts +0 -4
  151. package/build/src/verification/observation.js +1 -2
  152. package/package.json +3 -1
  153. package/build/src/git/verification-environment.d.ts +0 -10
  154. package/build/src/git/verification-environment.js +0 -281
@@ -2,7 +2,7 @@ import { materializeIntegrationSnapshot, materializeJudgedConflict, planIntegrat
2
2
  import { captureTender, dirtyTenderRefusal, materializeTenderSnapshot, prepareDeliveryCommitMetadata, } from "../git/tender.js";
3
3
  import { checkoutDetachedSnapshot, recordConflictHandoff, retireConflictHandoff, workspaceMergeStatePresent, worktreePath, conflictRecovery, } from "../git/workspace.js";
4
4
  import { observeContractsForAdmissionAt } from "../git/observe.js";
5
- import { matchingPrivateRootObservation, privateStateSeatAttempt, sameSpeculativeWorktreeInput, } from "./run.js";
5
+ import { contractStateWitness, privateStateSeatAttempt, sameWorktreeWitness, STALE_PRIVATE_STATE_PREPARATION, } from "./run.js";
6
6
  import { contractState } from "../core/facts/observation.js";
7
7
  import { decideDeliver } from "../core/verbs/deliver.js";
8
8
  import { currentVerifiedAttestation } from "./intent.js";
@@ -134,52 +134,132 @@ function hasSupersedingVerification(state, journal) {
134
134
  const verificationIndex = journal.findIndex((entry) => entry.entry === current.entry);
135
135
  return deliveryIndex >= 0 && verificationIndex > deliveryIndex;
136
136
  }
137
- async function speculateDelivery(input) {
137
+ /**
138
+ * Repeatable physical delivery work outside the publication seat: locate the appointed worktree from
139
+ * one non-authoritative private-state read, capture its bytes, and materialize the prepared artifacts.
140
+ */
141
+ async function prepareExternalDelivery(input) {
138
142
  const observation = await observeContractsForAdmissionAt(input.scope, input.channel, [input.contractId]);
139
143
  const state = contractState(observation.decision, input.contractId);
140
- const derivation = state === null ? undefined : input.deriveDocument(state);
141
- if (state === null || derivation === undefined) {
142
- return { observation, state, preparation: { kind: "unavailable" } };
144
+ if (state === null)
145
+ return { kind: "unavailable" };
146
+ return {
147
+ kind: "artifacts",
148
+ witness: contractStateWitness(state),
149
+ artifacts: await prepareDeliveryArtifacts(input, observation, state),
150
+ };
151
+ }
152
+ async function prepareDeliveryArtifacts(input, observation, state) {
153
+ const derivation = input.deriveDocument(state);
154
+ if (derivation.verification.kind === "refused")
155
+ return { kind: "defer" };
156
+ if (reusesCurrentCandidate(input, state, derivation))
157
+ return { kind: "defer" };
158
+ if (input.materializeConflict === true && state.terminal === null)
159
+ return { kind: "defer" };
160
+ const captured = await captureAuthorizedDeliveryTender(input.scope, { contractId: state.id, coordinates: state.coordinates }, input.includeDirty);
161
+ if (captured.kind === "refused")
162
+ return { kind: "refused", refusal: captured.refusal };
163
+ const worktree = await worktreeInput(input.scope, state, captured.data);
164
+ if (state.terminal === null &&
165
+ state.delivery !== null &&
166
+ worktree.changeId === state.delivery.data.integration.changeId &&
167
+ !hasSupersedingVerification(state, observation.journals.get(state.id)?.entries ?? [])) {
168
+ return {
169
+ kind: "continuation",
170
+ worktree,
171
+ };
143
172
  }
173
+ const prepared = await mechanicalDeliveryPreparation(input, state, derivation, captured.data);
174
+ return prepared.kind === "prepared"
175
+ ? { kind: "mechanical", data: prepared.data, worktree: prepared.worktree }
176
+ : { kind: "refused", refusal: prepared.refusal };
177
+ }
178
+ /**
179
+ * Assemble the in-custody decision input from the fresh Contract. State-derived choices are recomputed
180
+ * here; artifacts the fresh state cannot justify are spent, which restarts the whole preparation.
181
+ */
182
+ async function assembleDeliveryAttempt(input, observation, external) {
183
+ const state = contractState(observation.decision, input.contractId);
184
+ if (external.kind === "unavailable") {
185
+ return state === null
186
+ ? { kind: "assembled", state: null, preparation: { kind: "unavailable" } }
187
+ : { kind: "stale" };
188
+ }
189
+ if (state === null)
190
+ return { kind: "stale" };
191
+ if (external.witness.head !== state.head)
192
+ return { kind: "stale" };
193
+ const derivation = input.deriveDocument(state);
144
194
  if (derivation.verification.kind === "refused") {
145
195
  return {
146
- observation,
196
+ kind: "assembled",
147
197
  state,
148
198
  derivation,
149
199
  preparation: { kind: "refused", document: derivation.document, refusal: derivation.verification.refusal },
150
200
  };
151
201
  }
152
202
  if (reusesCurrentCandidate(input, state, derivation))
153
- return { observation, state, derivation };
154
- if (input.materializeConflict === true && state.terminal === null)
155
- return { observation, state, derivation };
156
- const captured = await captureAuthorizedDeliveryTender(input.scope, { contractId: state.id, coordinates: state.coordinates }, input.includeDirty);
157
- if (captured.kind === "refused") {
203
+ return { kind: "assembled", state, derivation };
204
+ const artifacts = external.artifacts;
205
+ if (artifacts.kind === "defer")
206
+ return await completeDeferredDelivery(input, state, derivation);
207
+ if (artifacts.kind === "refused") {
158
208
  return {
159
- observation,
209
+ kind: "assembled",
160
210
  state,
161
211
  derivation,
162
- preparation: { kind: "refused", document: derivation.document, refusal: captured.refusal },
212
+ preparation: { kind: "refused", document: derivation.document, refusal: artifacts.refusal },
163
213
  };
164
214
  }
165
- const capturedWorktree = await worktreeInput(input.scope, state, captured.data);
166
- if (state.terminal === null &&
167
- state.delivery !== null &&
168
- capturedWorktree.changeId === state.delivery.data.integration.changeId &&
169
- !hasSupersedingVerification(state, observation.journals.get(state.id)?.entries ?? [])) {
215
+ if (!sameWorktreeWitness(artifacts.worktree, await recaptureDeliveryWorktree(input, state))) {
216
+ return { kind: "stale" };
217
+ }
218
+ if (artifacts.kind === "continuation") {
219
+ const delivery = state.delivery;
220
+ if (delivery === null)
221
+ return { kind: "stale" };
170
222
  return {
171
- observation,
223
+ kind: "assembled",
172
224
  state,
173
225
  derivation,
174
- preparation: { kind: "prepared", document: derivation.document, data: state.delivery.data },
175
- worktree: capturedWorktree,
226
+ preparation: { kind: "prepared", document: derivation.document, data: delivery.data },
176
227
  continuation: true,
177
228
  };
178
229
  }
179
- const prepared = await mechanicalDeliveryPreparation(input, state, derivation, captured.data);
180
- return prepared.kind === "prepared"
181
- ? { observation, state, derivation, preparation: prepared, worktree: prepared.worktree }
182
- : { observation, state, derivation, preparation: prepared };
230
+ return {
231
+ kind: "assembled",
232
+ state,
233
+ derivation,
234
+ preparation: { kind: "prepared", document: derivation.document, data: artifacts.data },
235
+ };
236
+ }
237
+ /**
238
+ * Complete a preparation the outside phase could not settle. A requested conflict materialization
239
+ * must retire its owned handoff and then capture the worktree that follows, so it only runs under
240
+ * this custody; every other deferred state is decided by reuse above or refuses on its own.
241
+ */
242
+ async function completeDeferredDelivery(input, state, derivation) {
243
+ if (input.materializeConflict !== true || state.terminal !== null)
244
+ return { kind: "assembled", state, derivation };
245
+ const materialization = await materializationMergeStateRefusal(input);
246
+ if (materialization !== undefined) {
247
+ return {
248
+ kind: "assembled",
249
+ state,
250
+ derivation,
251
+ preparation: { kind: "refused", document: derivation.document, refusal: materialization },
252
+ };
253
+ }
254
+ const prepared = await mechanicalDeliveryPreparation(input, state, derivation);
255
+ return {
256
+ kind: "assembled",
257
+ state,
258
+ derivation,
259
+ preparation: prepared.kind === "prepared"
260
+ ? { kind: "prepared", document: derivation.document, data: prepared.data }
261
+ : prepared,
262
+ };
183
263
  }
184
264
  function reusesCurrentCandidate(input, state, derivation) {
185
265
  return (input.overwrite !== true &&
@@ -189,60 +269,54 @@ function reusesCurrentCandidate(input, state, derivation) {
189
269
  derivation.verification.data !== null &&
190
270
  currentVerifiedAttestation(state) === undefined);
191
271
  }
192
- async function resolveDeliveryPreparation(input, speculated) {
193
- if (speculated.preparation !== undefined)
194
- return speculated.preparation;
195
- if (speculated.state === null || speculated.derivation === undefined)
196
- return { kind: "unavailable" };
197
- const materialization = await materializationMergeStateRefusal(input);
198
- if (materialization !== undefined) {
199
- return { kind: "refused", document: speculated.derivation.document, refusal: materialization };
200
- }
201
- const prepared = await mechanicalDeliveryPreparation(input, speculated.state, speculated.derivation);
202
- return prepared.kind === "prepared"
203
- ? { kind: "prepared", document: prepared.document, data: prepared.data }
204
- : prepared;
272
+ /** Accept a delivery whose current candidate is already admitted, without admitting it again. */
273
+ function currentCandidateDeliveryDecision(input, observation, assembled) {
274
+ const state = assembled.state;
275
+ if (state === null || assembled.derivation === undefined)
276
+ return undefined;
277
+ if (!reusesCurrentCandidate(input, state, assembled.derivation))
278
+ return undefined;
279
+ const record = observation.journals.get(input.contractId);
280
+ const delivery = record?.entries.findLast((entry) => entry.kind === "deliver");
281
+ if (record === undefined || delivery === undefined)
282
+ throw new Error("current delivery is missing its journal fact");
283
+ input.progress?.recordAdmission({ kind: "accepted", facts: [], state, journal: record.entries });
284
+ return {
285
+ kind: "accepted",
286
+ facts: [],
287
+ state,
288
+ journal: record.entries,
289
+ value: {
290
+ ...state.delivery.data,
291
+ leading: { kind: "already-admitted", fact: delivery.entry },
292
+ },
293
+ };
205
294
  }
206
- async function decideAndAdmitDelivery(input, attempt, seat, observation, speculated) {
207
- const currentState = speculated.state;
208
- if (currentState !== null &&
209
- speculated.derivation !== undefined &&
210
- reusesCurrentCandidate(input, currentState, speculated.derivation)) {
211
- const record = observation.journals.get(input.contractId);
212
- const delivery = record?.entries.findLast((entry) => entry.kind === "deliver");
213
- if (record === undefined || delivery === undefined)
214
- throw new Error("current delivery is missing its journal fact");
215
- input.progress?.recordAdmission({ kind: "accepted", facts: [], state: currentState, journal: record.entries });
216
- return {
217
- kind: "accepted",
218
- facts: [],
219
- state: currentState,
220
- journal: record.entries,
221
- value: {
222
- ...currentState.delivery.data,
223
- leading: { kind: "already-admitted", fact: delivery.entry },
224
- },
225
- };
226
- }
227
- if (speculated.continuation === true) {
228
- const record = observation.journals.get(input.contractId);
229
- if (record === undefined ||
230
- record.state === null ||
231
- record.state.delivery === null ||
232
- speculated.derivation === undefined) {
233
- return { kind: "redecide" };
234
- }
235
- const state = record.state;
236
- input.progress?.recordAdmission({ kind: "accepted", facts: [], state, journal: record.entries });
237
- return {
238
- kind: "accepted",
239
- facts: [],
240
- state,
241
- journal: record.entries,
242
- value: record.state.delivery.data,
243
- };
295
+ /** Continue the admitted integration this worktree already carries, without a new offer. */
296
+ function continuationDeliveryDecision(input, observation, assembled) {
297
+ const record = observation.journals.get(input.contractId);
298
+ const state = record?.state ?? null;
299
+ if (record === undefined || state === null || state.delivery === null || assembled.derivation === undefined) {
300
+ return { kind: "redecide" };
244
301
  }
245
- const preparation = await resolveDeliveryPreparation(input, speculated);
302
+ input.progress?.recordAdmission({ kind: "accepted", facts: [], state, journal: record.entries });
303
+ return {
304
+ kind: "accepted",
305
+ facts: [],
306
+ state,
307
+ journal: record.entries,
308
+ value: state.delivery.data,
309
+ };
310
+ }
311
+ async function decideAndAdmitDelivery(input, attempt, seat, observation, assembled) {
312
+ const current = currentCandidateDeliveryDecision(input, observation, assembled);
313
+ if (current !== undefined)
314
+ return current;
315
+ if (assembled.continuation === true)
316
+ return continuationDeliveryDecision(input, observation, assembled);
317
+ const preparation = assembled.preparation ?? STALE_PRIVATE_STATE_PREPARATION;
318
+ if (preparation.kind === "stale")
319
+ return preparation;
246
320
  const decision = decideDeliver({
247
321
  input: {
248
322
  contractId: input.contractId,
@@ -274,22 +348,19 @@ async function decideAndAdmitDelivery(input, attempt, seat, observation, specula
274
348
  value: preparation.data,
275
349
  };
276
350
  }
277
- async function deliverAttemptInPrivateStateSeat(input, attempt, seat, speculated) {
278
- const observation = await matchingPrivateRootObservation(input.scope, input.channel, input.contractId, speculated.observation, async (fresh) => {
279
- if (speculated.worktree === undefined)
280
- return true;
281
- const state = contractState(fresh.decision, input.contractId);
282
- if (state === null)
283
- return false;
284
- return sameSpeculativeWorktreeInput(speculated.worktree, await recaptureDeliveryWorktree(input, state));
285
- });
286
- return "kind" in observation
287
- ? observation
288
- : await decideAndAdmitDelivery(input, attempt, seat, observation, speculated);
289
- }
351
+ /**
352
+ * One delivery attempt: the repeatable physical preparation happens outside custody, then a single
353
+ * in-custody observation, witness validation, assembly, decision, and atomic publication.
354
+ */
290
355
  async function deliverAttempt(input, attempt) {
291
- const speculated = await speculateDelivery(input);
292
- return await privateStateSeatAttempt(input.scope, async (seat) => await deliverAttemptInPrivateStateSeat(input, attempt, seat, speculated), attemptDecisionWithSeatClose);
356
+ const external = await prepareExternalDelivery(input);
357
+ return await privateStateSeatAttempt(input.scope, async (seat) => {
358
+ const observation = await observeContractsForAdmissionAt(input.scope, input.channel, [input.contractId]);
359
+ const assembled = await assembleDeliveryAttempt(input, observation, external);
360
+ if (assembled.kind === "stale")
361
+ return STALE_PRIVATE_STATE_PREPARATION;
362
+ return await decideAndAdmitDelivery(input, attempt, seat, observation, assembled);
363
+ }, attemptDecisionWithSeatClose);
293
364
  }
294
365
  function isIntegrationConflict(refusal) {
295
366
  return refusal.kind === "integration-failed" && refusal.reason === "conflict";
@@ -417,6 +488,8 @@ export async function admitDeliveryOperation(input) {
417
488
  return await finishDeliverRefusal(input, result.refusal);
418
489
  if (result.kind === "publication-failed")
419
490
  return { kind: "retry", reason: result };
491
+ if (result.kind === "stale" || result.kind === "redecide")
492
+ continue;
420
493
  if (result.kind === "collision" && index + 1 === attempts.length)
421
494
  return { kind: "retry", reason: result };
422
495
  }
@@ -128,12 +128,10 @@ declare const observationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
128
128
  phase: z.ZodEnum<{
129
129
  cleanup: "cleanup";
130
130
  materialize: "materialize";
131
- environment: "environment";
132
131
  setup: "setup";
133
132
  declaration: "declaration";
134
133
  }>;
135
134
  cwd: z.ZodOptional<z.ZodString>;
136
- source: z.ZodOptional<z.ZodString>;
137
135
  name: z.ZodOptional<z.ZodString>;
138
136
  command: z.ZodOptional<z.ZodString>;
139
137
  index: z.ZodOptional<z.ZodNumber>;
@@ -148,12 +146,10 @@ declare const observationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
148
146
  phase: z.ZodEnum<{
149
147
  cleanup: "cleanup";
150
148
  materialize: "materialize";
151
- environment: "environment";
152
149
  setup: "setup";
153
150
  declaration: "declaration";
154
151
  }>;
155
152
  cwd: z.ZodOptional<z.ZodString>;
156
- source: z.ZodOptional<z.ZodString>;
157
153
  name: z.ZodOptional<z.ZodString>;
158
154
  command: z.ZodOptional<z.ZodString>;
159
155
  index: z.ZodOptional<z.ZodNumber>;
@@ -2,7 +2,6 @@ import type { ExecutionProgress } from "./progress.js";
2
2
  import type { GitDecisionObservation } from "../git/observe.js";
3
3
  import type { GitDecodeChannel, GitTreeSelection } from "../git/read-observation.js";
4
4
  import type { GitRepository } from "../git/process.js";
5
- import type { GitRefAssertion } from "../git/repository.js";
6
5
  import { type WorktreeLeak } from "../git/scratch.js";
7
6
  import type { HookFailure } from "../git/hooks.js";
8
7
  import type { DecideInput, OfferDecision } from "../core/decide.js";
@@ -10,36 +9,32 @@ import type { ActorId, ContractId, ContractState, EntryUlid, SnapshotId } from "
10
9
  import { type AttestationRefusal } from "../core/verbs/attestation.js";
11
10
  import { type CapturedOutput } from "../verification/execution.js";
12
11
  import { type VerificationDefinition } from "../verification/declaration.js";
13
- import { type CompanionDecorator, type ProtocolResult } from "./run.js";
14
- type IntentAdmissionOptions<Input, Refusal, Seed> = Readonly<{
12
+ import { type CompanionDecorator, type ProtocolPreparation, type ProtocolResult } from "./run.js";
13
+ type CommonIntentAdmissionOptions<Refusal> = Readonly<{
15
14
  progress?: ExecutionProgress;
16
15
  observedContracts?: readonly ContractId[];
17
16
  observe?: (repository: GitRepository, channel: GitDecodeChannel, contracts: readonly ContractId[]) => Promise<GitDecisionObservation>;
18
17
  decorateOffer?: CompanionDecorator;
19
18
  validateAdmission?: (observation: GitDecisionObservation) => Refusal | undefined | Promise<Refusal | undefined>;
20
19
  observationSelection?: GitTreeSelection;
21
- prepareInput?: (observation: GitDecisionObservation, input: Seed) => Readonly<{
22
- kind: "prepared";
23
- input: Input;
24
- assertions?: readonly GitRefAssertion[];
25
- }> | Readonly<{
26
- kind: "refused";
27
- refusal: Refusal;
28
- }> | Promise<Readonly<{
29
- kind: "prepared";
30
- input: Input;
31
- assertions?: readonly GitRefAssertion[];
32
- }> | Readonly<{
33
- kind: "refused";
34
- refusal: Refusal;
35
- }>>;
36
20
  }>;
37
- /** Observe, decide, and atomically admit one intent with bounded Git retries. */
21
+ type IntentAdmissionOptions<Refusal = never> = CommonIntentAdmissionOptions<Refusal>;
22
+ type PreparedIntentAdmissionOptions<Input, Refusal, Seed, Prepared> = CommonIntentAdmissionOptions<Refusal> & Readonly<{
23
+ preparation: ProtocolPreparation<Input, Refusal, Seed, Prepared>;
24
+ }>;
25
+ /** Observe, decide, and atomically admit one intent whose invocation already is its decision input. */
38
26
  export declare function admitIntent<Input extends Readonly<{
39
27
  contractId: ContractId;
28
+ }>, Refusal>(channel: GitDecodeChannel, repository: GitRepository, input: Input, decide: (input: DecideInput<Input>) => OfferDecision<Refusal>, options?: IntentAdmissionOptions<Refusal>): Promise<ProtocolResult<Refusal>>;
29
+ /**
30
+ * Observe, decide, and atomically admit one intent whose repeatable preparation happens outside
31
+ * the publication seat and whose decision input is assembled from the fresh in-custody observation.
32
+ */
33
+ export declare function admitPreparedIntent<Input extends Readonly<{
34
+ contractId: ContractId;
40
35
  }>, Refusal, Seed extends Readonly<{
41
36
  contractId: ContractId;
42
- }> = Input>(channel: GitDecodeChannel, repository: GitRepository, input: Seed, decide: (input: DecideInput<Input>) => OfferDecision<Refusal>, options?: IntentAdmissionOptions<Input, Refusal, Seed>): Promise<ProtocolResult<Refusal>>;
37
+ }>, Prepared>(channel: GitDecodeChannel, repository: GitRepository, input: Seed, decide: (input: DecideInput<Input>) => OfferDecision<Refusal>, options: PreparedIntentAdmissionOptions<Input, Refusal, Seed, Prepared>): Promise<ProtocolResult<Refusal>>;
43
38
  type VerifyDeliveryInput = Readonly<{
44
39
  channel: GitDecodeChannel;
45
40
  repository: GitRepository;
@@ -1,6 +1,5 @@
1
1
  import { materializeScratchCandidate } from "../git/scratch.js";
2
2
  import { projectSettings } from "../settings.js";
3
- import { readManagedWorktreeAppointment } from "../workspace-place.js";
4
3
  import { dependencyKeySet } from "../core/subject.js";
5
4
  import { latestCurrentAttestations } from "../core/facts/gate.js";
6
5
  import { decideAttestation } from "../core/verbs/attestation.js";
@@ -8,22 +7,44 @@ import { executeVerification, capturedOutput, } from "../verification/execution.
8
7
  import { VERIFIED } from "../verification/declaration.js";
9
8
  import { runProtocol } from "./run.js";
10
9
  import { mintAttempts } from "./attempt.js";
11
- /** Observe, decide, and atomically admit one intent with bounded Git retries. */
10
+ function admissionOptions(options) {
11
+ return {
12
+ ...(options.progress === undefined ? {} : { progress: options.progress }),
13
+ ...(options.observedContracts === undefined ? {} : { observedContracts: options.observedContracts }),
14
+ ...(options.observe === undefined ? {} : { observe: options.observe }),
15
+ ...(options.decorateOffer === undefined ? {} : { decorateOffer: options.decorateOffer }),
16
+ ...(options.validateAdmission === undefined ? {} : { validateAdmission: options.validateAdmission }),
17
+ ...(options.observationSelection === undefined ? {} : { observationSelection: options.observationSelection }),
18
+ };
19
+ }
20
+ /** Observe, decide, and atomically admit one intent whose invocation already is its decision input. */
12
21
  export function admitIntent(channel, repository, input, decide, options = {}) {
13
22
  const contracts = options.observedContracts ?? [input.contractId];
14
23
  return runProtocol({
24
+ ...admissionOptions(options),
15
25
  input,
16
26
  channel,
17
27
  repository,
18
28
  contracts,
19
29
  attempts: mintAttempts({ entryCount: 2 }),
20
30
  decide,
21
- ...(options.progress === undefined ? {} : { progress: options.progress }),
22
- ...(options.observe === undefined ? {} : { observe: options.observe }),
23
- ...(options.decorateOffer === undefined ? {} : { decorateOffer: options.decorateOffer }),
24
- ...(options.validateAdmission === undefined ? {} : { validateAdmission: options.validateAdmission }),
25
- ...(options.observationSelection === undefined ? {} : { observationSelection: options.observationSelection }),
26
- ...(options.prepareInput === undefined ? {} : { prepareInput: options.prepareInput }),
31
+ });
32
+ }
33
+ /**
34
+ * Observe, decide, and atomically admit one intent whose repeatable preparation happens outside
35
+ * the publication seat and whose decision input is assembled from the fresh in-custody observation.
36
+ */
37
+ export function admitPreparedIntent(channel, repository, input, decide, options) {
38
+ const contracts = options.observedContracts ?? [input.contractId];
39
+ return runProtocol({
40
+ ...admissionOptions(options),
41
+ input,
42
+ preparation: options.preparation,
43
+ channel,
44
+ repository,
45
+ contracts,
46
+ attempts: mintAttempts({ entryCount: 2 }),
47
+ decide,
27
48
  });
28
49
  }
29
50
  function runtimeStop(outcome) {
@@ -98,21 +119,12 @@ export async function verifyDelivery(input) {
98
119
  { kind: "snapshot", value: snapshot },
99
120
  { kind: "segment", value: input.verification.segment },
100
121
  ]);
101
- const appointment = await readManagedWorktreeAppointment(input.repository, input.contractId);
102
- if (appointment.kind !== "appointed")
103
- return {
104
- step: {
105
- failure: "environment-failure",
106
- diagnostic: appointment.kind === "failed" ? appointment.diagnostic : "Verification environment source is not appointed",
107
- },
108
- };
109
122
  const execution = await executeVerification({
110
123
  repository: input.repository,
111
124
  candidate: snapshot,
112
125
  declarations: input.verification.declarations,
113
126
  materializeScratchCandidate,
114
127
  projectSettings,
115
- environmentSource: appointment.path,
116
128
  observe: (observation) => input.progress?.observe({ kind: "verification", contractId: input.contractId, snapshot, observation }),
117
129
  ...(input.signal === undefined ? {} : { signal: input.signal }),
118
130
  });
@@ -103,6 +103,8 @@ export type AttemptDecision<Value, Refusal = IntentRefusal> = (AcceptedAdmission
103
103
  refusal: Refusal;
104
104
  }> | Readonly<{
105
105
  kind: "redecide";
106
+ }> | Readonly<{
107
+ kind: "stale";
106
108
  }> | Readonly<{
107
109
  kind: "collision";
108
110
  }> | Extract<DecidedOfferResult, {
@@ -49,7 +49,7 @@ async function runFencedPlacement(repository, input, protocol) {
49
49
  const result = placementResultWithSeatClose(await withPrivateStatePublicationSeat(repository, async (seat) => {
50
50
  // The hint carries no acceptance authority. Form a fresh semantic offer under the seat.
51
51
  const prepared = await prepareProtocolAttempt(protocol, protocol.attempts[index]);
52
- if (prepared.kind === "refused")
52
+ if (prepared.kind !== "offered")
53
53
  return prepared;
54
54
  const state = contractState(prepared.observation.decision, input.contractId);
55
55
  if (state === null)
@@ -68,6 +68,8 @@ async function runFencedPlacement(repository, input, protocol) {
68
68
  observedTreeEqualsCandidate: await observedTreeEqualsCandidate(repository, observed, target.newOid),
69
69
  };
70
70
  if (changes?.predecessor !== target.expectedOid || changes.candidate !== target.newOid)
71
+ // A target preparation computed before custody is spent once the fresh offer names another
72
+ // movement. Re-derive it on the next attempt; never publish a preparation for stale bytes.
71
73
  return { kind: "changed-preparation", target };
72
74
  const physical = await prepareTargetPlacement(repository, state, target, changes);
73
75
  if (physical.kind === "refused")
@@ -92,6 +94,8 @@ async function runFencedPlacement(repository, input, protocol) {
92
94
  }
93
95
  if (result.kind === "redecide")
94
96
  continue;
97
+ if (result.kind === "stale")
98
+ continue;
95
99
  if (result.kind === "collision" && index + 1 < protocol.attempts.length)
96
100
  continue;
97
101
  if (result.kind !== "accepted")
@@ -19,6 +19,7 @@ export type ContractVerificationStatus = Readonly<{
19
19
  kind: "recorded";
20
20
  verdict: "satisfied" | "unsatisfied";
21
21
  at: string;
22
+ snapshot?: SnapshotId;
22
23
  }>;
23
24
  export type ContractTargetLag = GitContractTargetLag | Readonly<{
24
25
  kind: "counted";
@@ -1,5 +1,6 @@
1
1
  import { observeActiveContractWorld, observeContractsForAdmissionInObservationAt, observeDeliveryTargetAt, withContractReadObservationAt, } from "../../git/observe.js";
2
2
  import { decodeContractDocument, verificationDefinition } from "../../body/decode.js";
3
+ import { dependencyKeys } from "../../core/subject.js";
3
4
  import { observeTargetLag, observeWorkspace, conflictHandoffFor, conflictRecovery, worktreePath, } from "../../git/workspace.js";
4
5
  import { appointmentFor, readPlaceRegister } from "../../workspace-place.js";
5
6
  import { gateReports, latestCurrentAttestations } from "../../core/facts/gate.js";
@@ -36,8 +37,15 @@ function verificationFor(state, document) {
36
37
  return { kind: "undeclared" };
37
38
  const verifiedGate = gate("verified");
38
39
  const current = latestCurrentAttestations(state, new Set([verifiedGate])).get(verifiedGate);
39
- if (current !== undefined)
40
- return { kind: "recorded", verdict: current.data.verdict, at: current.at };
40
+ if (current !== undefined) {
41
+ const snapshot = dependencyKeys(current.data.subject).find((key) => key.kind === "snapshot")?.value;
42
+ return {
43
+ kind: "recorded",
44
+ verdict: current.data.verdict,
45
+ at: current.at,
46
+ ...(snapshot === undefined ? {} : { snapshot: snapshot }),
47
+ };
48
+ }
41
49
  return state.delivery === null ? undefined : { kind: "unrecorded" };
42
50
  }
43
51
  export function phaseAtFor(state, bindAt) {
@@ -5,7 +5,7 @@ import { type IntegrationPreparationRefusal } from "../git/integration.js";
5
5
  import type { GitRepository } from "../git/process.js";
6
6
  import type { GitDecodeChannel } from "../git/read-observation.js";
7
7
  import { type AcceptedAdmission } from "./attempt.js";
8
- import type { ProtocolTerminal } from "./run.js";
8
+ import { type ProtocolTerminal } from "./run.js";
9
9
  import { type PlacementExecutionFailure } from "./placement.js";
10
10
  type TargetMissing = Readonly<{
11
11
  kind: "target-missing";