@astrosheep/keiyaku 2.9.11 → 2.9.13

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 (218) hide show
  1. package/README.md +79 -85
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/call-terms.js +1 -0
  4. package/build/agents/providers/claude-agent-sdk/adapter.js +17 -4
  5. package/build/cli/commands/akuma/akuma/handler.js +2 -1
  6. package/build/cli/commands/akuma/akuma/meta.js +4 -3
  7. package/build/cli/commands/akuma/catalog.js +2 -0
  8. package/build/cli/commands/akuma/list/handler.js +1 -1
  9. package/build/cli/commands/akuma/list/meta-list.js +12 -0
  10. package/build/cli/commands/akuma/list/meta-ls.js +2 -2
  11. package/build/cli/commands/akuma.js +5 -0
  12. package/build/cli/commands/contract/amend/meta.js +4 -3
  13. package/build/cli/commands/contract/arc/meta.js +2 -0
  14. package/build/cli/commands/contract/audit/handler.js +28 -2
  15. package/build/cli/commands/contract/audit/meta.js +4 -3
  16. package/build/cli/commands/contract/bind/meta.js +4 -4
  17. package/build/cli/commands/contract/petition/handler.js +2 -1
  18. package/build/cli/commands/contract/petition/meta.js +2 -2
  19. package/build/cli/commands/contract/renew/handler.js +44 -3
  20. package/build/cli/commands/contract/renew/meta.js +5 -4
  21. package/build/cli/commands/metadata.js +14 -10
  22. package/build/cli/commands/projection/call/handler.js +1 -1
  23. package/build/cli/commands/projection/call/meta.js +1 -1
  24. package/build/cli/commands/projection/catalog.js +2 -2
  25. package/build/cli/commands/projection/{revive → fork}/handler.js +10 -5
  26. package/build/cli/commands/projection/fork/meta.js +12 -0
  27. package/build/cli/commands/projection/history/handler.js +46 -2
  28. package/build/cli/commands/projection/history/meta.js +3 -3
  29. package/build/cli/commands/projection/kill/handler.js +4 -5
  30. package/build/cli/commands/projection/kill/meta.js +2 -2
  31. package/build/cli/commands/projection/status/handler.js +29 -13
  32. package/build/cli/commands/projection/status/meta.js +14 -3
  33. package/build/cli/commands/projection/tell/handler.js +8 -4
  34. package/build/cli/commands/projection/tell/meta.js +1 -1
  35. package/build/cli/commands/projection/wait/handler.js +45 -20
  36. package/build/cli/commands/projection/wait/meta.js +1 -1
  37. package/build/cli/commands/shared.js +2 -2
  38. package/build/cli/commands/system/catalog.js +2 -0
  39. package/build/cli/commands/task/add/handler.js +28 -12
  40. package/build/cli/commands/task/add/meta.js +18 -6
  41. package/build/cli/commands/task/catalog.js +4 -0
  42. package/build/cli/commands/task/compose/handler.js +18 -0
  43. package/build/cli/commands/task/compose/meta.js +10 -0
  44. package/build/cli/commands/task/doctor/handler.js +2 -3
  45. package/build/cli/commands/task/doctor/meta.js +2 -2
  46. package/build/cli/commands/task/done/meta.js +2 -2
  47. package/build/cli/commands/task/drop/handler.js +7 -2
  48. package/build/cli/commands/task/drop/meta.js +6 -3
  49. package/build/cli/commands/task/hold/meta.js +2 -2
  50. package/build/cli/commands/task/log/meta.js +2 -2
  51. package/build/cli/commands/task/ls/meta.js +2 -2
  52. package/build/cli/commands/task/note/handler.js +6 -0
  53. package/build/cli/commands/task/note/meta.js +11 -0
  54. package/build/cli/commands/task/resume/meta.js +2 -2
  55. package/build/cli/commands/task/shared.js +29 -15
  56. package/build/cli/commands/task/show/meta.js +2 -2
  57. package/build/cli/commands/task/start/meta.js +2 -2
  58. package/build/cli/commands/task/stop/meta.js +2 -2
  59. package/build/cli/commands/task/update/meta.js +3 -2
  60. package/build/cli/commands/verification/handler.js +43 -0
  61. package/build/cli/commands/verification/meta.js +13 -0
  62. package/build/cli/completion.js +16 -13
  63. package/build/cli/flags.js +48 -12
  64. package/build/cli/help.js +29 -30
  65. package/build/cli/index.js +14 -8
  66. package/build/cli/parse-flags.js +60 -21
  67. package/build/cli/parse-metadata.js +10 -4
  68. package/build/cli/parse-selectors.js +22 -4
  69. package/build/cli/parse.js +43 -30
  70. package/build/cli/projection-address.js +7 -7
  71. package/build/cli/render/arc.js +12 -3
  72. package/build/cli/render/audit.js +2 -2
  73. package/build/cli/render/call.js +4 -4
  74. package/build/cli/render/kanshi.js +122 -85
  75. package/build/cli/render/misc.js +2 -2
  76. package/build/cli/render/petition.js +16 -1
  77. package/build/cli/render/projection-history.js +17 -4
  78. package/build/cli/render/shared.js +5 -5
  79. package/build/cli/render/status-indicator.js +47 -0
  80. package/build/cli/render/status.js +106 -76
  81. package/build/cli/render/success-response.js +20 -5
  82. package/build/cli/render/task.js +33 -5
  83. package/build/cli/render/tell.js +10 -4
  84. package/build/cli/render/tool-command-normalization.js +137 -0
  85. package/build/cli/render/tool-presentation.js +2 -1
  86. package/build/cli/render/verification.js +23 -0
  87. package/build/cli/render/wait.js +101 -33
  88. package/build/cli/types.js +2 -1
  89. package/build/config/akuma-loader.js +21 -1
  90. package/build/config/settings/knobs.js +7 -1
  91. package/build/config/settings/schema.js +10 -5
  92. package/build/core/addressing.js +3 -3
  93. package/build/core/amend.js +102 -17
  94. package/build/core/arc.js +4 -4
  95. package/build/core/audit/candidate.js +10 -18
  96. package/build/core/audit/coordinates.js +12 -17
  97. package/build/core/audit/evidence.js +6 -4
  98. package/build/core/audit/facade.js +3 -3
  99. package/build/core/audit/report.js +1 -1
  100. package/build/core/bind-reconciliation.js +42 -23
  101. package/build/core/bind.js +182 -81
  102. package/build/core/call/call.js +6 -7
  103. package/build/core/call/context.js +46 -33
  104. package/build/core/call/execution.js +21 -6
  105. package/build/core/call/prompt.js +11 -42
  106. package/build/core/contract-carrier-runtime.js +209 -105
  107. package/build/core/contract-carrier.js +156 -73
  108. package/build/core/contract-view.js +43 -6
  109. package/build/core/contract.js +2 -1
  110. package/build/core/derived-replay.js +168 -35
  111. package/build/core/draft.js +60 -27
  112. package/build/core/forfeit.js +1 -1
  113. package/build/core/lifecycle-history.js +13 -0
  114. package/build/core/lifecycle-recovery.js +32 -27
  115. package/build/core/lifecycle-runner.js +14 -14
  116. package/build/core/log.js +1 -1
  117. package/build/core/outcome-base.js +2 -2
  118. package/build/core/projection/akuma-name.js +43 -0
  119. package/build/core/projection/generation/database.js +141 -79
  120. package/build/core/projection/generation/ledger.js +91 -0
  121. package/build/core/projection/generation/model.js +19 -14
  122. package/build/core/projection/generation/projection-generation-continuation.js +1 -1
  123. package/build/core/projection/generation/projection-generation-doorbell.js +88 -0
  124. package/build/core/projection/generation/projection-generation-execution.js +24 -0
  125. package/build/core/projection/generation/projection-generation-identity.js +4 -0
  126. package/build/core/projection/generation/projection-generation-launcher.js +72 -138
  127. package/build/core/projection/generation/projection-generation-process.js +16 -15
  128. package/build/core/projection/generation/projection-generation-runner.js +132 -76
  129. package/build/core/projection/generation/projection-generation-runtime.js +10 -61
  130. package/build/core/projection/generation/protocol.js +68 -0
  131. package/build/core/projection/generation/store.js +17 -7
  132. package/build/core/projection/generation/transitions.js +24 -14
  133. package/build/core/projection/index.js +5 -5
  134. package/build/core/projection/projection-core.js +6 -2
  135. package/build/core/projection/projection-execution-observer.js +1 -1
  136. package/build/core/projection/projection-history.js +8 -8
  137. package/build/core/projection/projection-kill.js +20 -10
  138. package/build/core/projection/projection-life-observer.js +8 -8
  139. package/build/core/projection/projection-mint.js +6 -8
  140. package/build/core/projection/projection-status-observation.js +77 -8
  141. package/build/core/projection/projection-status.js +151 -4
  142. package/build/core/projection/projection-wait.js +48 -29
  143. package/build/core/projection/projection-wake.js +28 -88
  144. package/build/core/projection/tell/launch-store.js +1 -1
  145. package/build/core/projection/tell/store.js +1 -1
  146. package/build/core/renew-build.js +204 -74
  147. package/build/core/renew-plan.js +34 -9
  148. package/build/core/renew-rewrite.js +56 -15
  149. package/build/core/renew.js +39 -35
  150. package/build/core/repository-ledger/accepted-fold-read.js +6 -3
  151. package/build/core/repository-ledger/claim-evidence.js +1 -1
  152. package/build/core/repository-ledger/codec.js +11 -5
  153. package/build/core/repository-ledger/current-state-store.js +464 -349
  154. package/build/core/repository-ledger/fold-repository.js +5 -6
  155. package/build/core/repository-ledger/identity.js +60 -0
  156. package/build/core/repository-ledger/inventory.js +3 -3
  157. package/build/core/repository-ledger/read-model.js +57 -9
  158. package/build/core/repository-ledger/write-transaction.js +24 -17
  159. package/build/core/run-control/connection-bound-close.js +41 -0
  160. package/build/core/run-control/detached-lease-bootstrap.js +208 -0
  161. package/build/core/run-control/detached-process.js +14 -0
  162. package/build/core/run-control/index.js +6 -0
  163. package/build/core/{process-group.js → run-control/process-tree.js} +1 -1
  164. package/build/core/run-control/runner-lease.js +172 -0
  165. package/build/core/run-control/sqlite-process-lifetime-lock.js +174 -0
  166. package/build/core/seal.js +44 -32
  167. package/build/core/settlement/claim-delivery.js +22 -9
  168. package/build/core/settlement/claim.js +8 -6
  169. package/build/core/settlement/petition-claim-gates.js +9 -8
  170. package/build/core/settlement/petition-head-guard.js +5 -6
  171. package/build/core/settlement/petition-preview.js +21 -5
  172. package/build/core/settlement/petition.js +51 -17
  173. package/build/core/settlement/settlement.js +20 -15
  174. package/build/core/settlement/verdict.js +2 -2
  175. package/build/core/settlement/verification.js +492 -364
  176. package/build/core/status/board.js +184 -75
  177. package/build/core/status/drift.js +8 -10
  178. package/build/core/task/board.js +1 -0
  179. package/build/core/task/commands.js +25 -0
  180. package/build/core/task/compose.js +328 -0
  181. package/build/core/task/document.js +102 -39
  182. package/build/core/task/index.js +4 -3
  183. package/build/core/task/settlement-git.js +70 -30
  184. package/build/core/task/settlement-policy.js +27 -14
  185. package/build/core/task/source-board.js +1 -0
  186. package/build/core/task/task-bind-preparation.js +59 -9
  187. package/build/core/task/task-contract.js +2 -2
  188. package/build/core/task/task-git-store.js +1 -0
  189. package/build/core/task/task-store-repository.js +2 -0
  190. package/build/core/task/task.js +2 -2
  191. package/build/core/transcripts.js +4 -4
  192. package/build/core/verification-declaration.js +95 -0
  193. package/build/core/worktree-bootstrap.js +1 -1
  194. package/build/core/worktree-path.js +7 -11
  195. package/build/flow-error.js +15 -2
  196. package/build/generated/version.js +2 -2
  197. package/build/git/branches.js +41 -70
  198. package/build/git/commits.js +92 -21
  199. package/build/git/core.js +9 -161
  200. package/build/git/diff/preview.js +4 -4
  201. package/build/git/diff/read.js +4 -4
  202. package/build/git/diff/structured.js +5 -5
  203. package/build/git/process.js +229 -0
  204. package/build/git/refs.js +30 -5
  205. package/build/git/staging.js +39 -115
  206. package/build/git/streaming-batch.js +9 -16
  207. package/build/git/worktree.js +104 -91
  208. package/build/index.js +7 -0
  209. package/package.json +2 -2
  210. package/skills/keiyaku-akuma/SKILL.md +27 -21
  211. package/skills/keiyaku-task/SKILL.md +61 -5
  212. package/skills/keiyaku-workflow/SKILL.md +81 -26
  213. package/build/cli/commands/projection/revive/meta.js +0 -12
  214. package/build/core/projection/projection-life-protocol.js +0 -115
  215. package/build/core/projection/projection-runner-lock.js +0 -382
  216. package/build/core/projection/tell/database.js +0 -127
  217. package/build/core/settlement/verification-coordination.js +0 -305
  218. package/build/core/settlement/verification-supervisor.js +0 -275
@@ -1,8 +1,9 @@
1
1
  import { createOathGate } from "./petition-claim-gates.js";
2
- import { assertFoldedPetitionable, } from "./petition.js";
2
+ import { assertFoldedPetitionable, precedingRenewSealResult, } from "./petition.js";
3
3
  import { captureFoldedSeal } from "../seal.js";
4
4
  import { withContractCarrierSession } from "../contract-carrier.js";
5
5
  import { FlowError } from "../../flow-error.js";
6
+ import { normalizeScopePattern } from "../scope.js";
6
7
  export const PETITION_PREVIEW_GATE_NAMES = [
7
8
  "contract",
8
9
  "freshness",
@@ -44,6 +45,7 @@ export async function previewPetition(input) {
44
45
  const base = session.lifecycle.pins.base;
45
46
  const target = { ref: session.lifecycle.pins.target.ref, branch: session.lifecycle.pins.target.ref.slice("refs/heads/".length) };
46
47
  const context = { lifecycle: session.lifecycle, deliveryCwd: session.target.root, base, target };
48
+ const appendScope = (input.appendScope ?? []).map(normalizeScopePattern);
47
49
  const gates = [{ name: "contract", result: "pass" }];
48
50
  const freshness = await gate("freshness", async () => {
49
51
  if (!session.pins.target.head || context.base !== session.pins.target.head) {
@@ -58,15 +60,28 @@ export async function previewPetition(input) {
58
60
  })
59
61
  : notEvaluated("arc");
60
62
  gates.push(arc);
61
- const state = await gate("state", () => {
62
- assertFoldedPetitionable(input.contractId, context.lifecycle);
63
+ const state = await gate("state", async () => {
64
+ await assertFoldedPetitionable(input.contractId, context.lifecycle, session.repository, session.stableRoot);
63
65
  });
64
66
  gates.push(state);
65
67
  let seal;
68
+ let scopeWarning = null;
66
69
  if (freshness.result === "pass" && arc.result === "pass" && state.result === "pass") {
67
70
  try {
68
- const capture = await captureFoldedSeal(context.deliveryCwd, context.lifecycle, "HEAD");
69
- seal = { name: "seal", result: "pass", detail: sealFileDetail(capture?.diffstat.files ?? 0) };
71
+ const precedingRenewSeal = appendScope.length === 0
72
+ ? await precedingRenewSealResult(context.deliveryCwd, context.lifecycle)
73
+ : null;
74
+ const capture = precedingRenewSeal
75
+ ? null
76
+ : await captureFoldedSeal(context.deliveryCwd, context.lifecycle, "HEAD", appendScope, "warn");
77
+ const scope = precedingRenewSeal ?? capture;
78
+ if (scope?.scopeAudit.violations.length) {
79
+ scopeWarning = {
80
+ violations: [...scope.scopeAudit.violations],
81
+ evidence: [...scope.scopeViolationEvidence],
82
+ };
83
+ }
84
+ seal = { name: "seal", result: "pass", detail: sealFileDetail(scope?.diffstat.files ?? 0) };
70
85
  }
71
86
  catch (error) {
72
87
  seal = { name: "seal", result: "failed", detail: failureDetail(error) };
@@ -102,6 +117,7 @@ export async function previewPetition(input) {
102
117
  contract: input.contractId,
103
118
  target: context.target.ref,
104
119
  arc: { source: { arc: context.lifecycle.phase === "active" ? context.lifecycle.intent.arc : null, fence: context.lifecycle.pins.delivery } },
120
+ scopeWarning,
105
121
  gates,
106
122
  verdict: gates.some((item) => item.result === "failed") ? "would_fail" : "would_succeed",
107
123
  };
@@ -3,14 +3,44 @@ import { parseCommandMarkdown } from "../command-markdown.js";
3
3
  import { runLifecycle } from "../lifecycle-runner.js";
4
4
  import { queueMembership, readQueueReadModel } from "./queue.js";
5
5
  import { captureFoldedSeal } from "../seal.js";
6
- import { currentLifecycleState } from "../repository-ledger/read-model.js";
6
+ import { currentLifecycleState, lookupCurrentContract } from "../repository-ledger/read-model.js";
7
7
  import { assertCleanTrackedWorkingTree } from "../../git/worktree.js";
8
- import { normalizeScopePattern } from "../scope.js";
9
- export function assertFoldedPetitionable(contractId, model) {
8
+ import { normalizeScopePattern, scopePathEvidence } from "../scope.js";
9
+ import { readRemainingTaskNeedsForSettlement } from "../task/settlement-policy.js";
10
+ export async function assertFoldedPetitionable(contractId, model, repository, stableRoot) {
10
11
  const state = currentLifecycleState(model);
11
12
  if (state.state !== "active" && state.state !== "bound") {
12
13
  throw new FlowError("INTERNAL_STATE", `contract ${contractId} cannot petition from state ${state.state}`);
13
14
  }
15
+ const unavailable = model.causal.after.filter((dependency) => {
16
+ const prerequisite = lookupCurrentContract(repository, dependency);
17
+ return prerequisite.status !== "healthy" ||
18
+ (prerequisite.model.phase !== "claimed" && prerequisite.model.phase !== "forfeited");
19
+ });
20
+ if (unavailable.length > 0) {
21
+ throw new FlowError("INTERNAL_STATE", `contract ${contractId} cannot petition before after dependencies settle: ${unavailable.join(", ")}`);
22
+ }
23
+ const pendingNeeds = (await readRemainingTaskNeedsForSettlement(stableRoot, model.causal.needs))
24
+ .filter((need) => !need.satisfied);
25
+ if (pendingNeeds.length > 0) {
26
+ throw new FlowError("INTERNAL_STATE", `contract ${contractId} cannot petition before task needs settle: ${pendingNeeds.map((need) => need.id).join(", ")}`);
27
+ }
28
+ }
29
+ /** Rehydrate the seal consumed by an immediately preceding renew without auditing a new segment. */
30
+ export async function precedingRenewSealResult(cwd, lifecycle, renewIndex = lifecycle.history.length - 1) {
31
+ const renew = lifecycle.history[renewIndex]?.entry;
32
+ const seal = lifecycle.history[renewIndex - 1];
33
+ if (renew?.kind !== "renew" || seal?.entry.kind !== "seal" || seal.entry.data.sealedBy !== "renew")
34
+ return null;
35
+ return {
36
+ ...seal.entry.data,
37
+ receipts: [...seal.entry.data.receipts],
38
+ diffstat: { ...seal.entry.data.diffstat },
39
+ scopeAudit: { violations: [...seal.entry.data.scopeAudit.violations] },
40
+ scopeViolationEvidence: await scopePathEvidence(cwd, lifecycle.effectiveScope, seal.entry.data.scopeAudit.violations),
41
+ sealedBy: "renew",
42
+ ledgerHead: seal.objectId,
43
+ };
14
44
  }
15
45
  function nextSettlementSeat(read, target) {
16
46
  let floor = 0;
@@ -68,7 +98,7 @@ export async function petitionContract(input) {
68
98
  const branch = target.slice("refs/heads/".length);
69
99
  throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} must renew onto ${branch} before petition`, { facts: { kind: "needs_renew", contractId: input.contractId } });
70
100
  }
71
- assertFoldedPetitionable(input.contractId, session.lifecycle);
101
+ await assertFoldedPetitionable(input.contractId, session.lifecycle, session.repository, session.stableRoot);
72
102
  return { lifecycle: session.lifecycle, deliveryCwd };
73
103
  },
74
104
  prepare: async (admission) => {
@@ -88,7 +118,7 @@ export async function petitionContract(input) {
88
118
  receipts: [...acceptedSeal.data.receipts],
89
119
  diffstat: { ...acceptedSeal.data.diffstat },
90
120
  scopeAudit: { violations: [...acceptedSeal.data.scopeAudit.violations] },
91
- scopeViolationEvidence: [],
121
+ scopeViolationEvidence: await scopePathEvidence(input.cwd, admission.business.lifecycle.effectiveScope, acceptedSeal.data.scopeAudit.violations),
92
122
  };
93
123
  prefixIndex -= 1;
94
124
  }
@@ -101,13 +131,14 @@ export async function petitionContract(input) {
101
131
  return {
102
132
  additions: [],
103
133
  capture,
134
+ precedingRenewSeal: await precedingRenewSealResult(input.cwd, admission.business.lifecycle, admission.business.lifecycle.history.findIndex(({ objectId }) => objectId === transaction.entryObjectIds.at(-1)) - 1),
104
135
  seat: accepted.data.seat,
105
136
  targetHead: accepted.data.intent === "claim" ? accepted.data.targetHead : admission.pins.target.head ?? "",
106
137
  existing: { transactionObjectId: transaction.transactionObjectId },
107
138
  };
108
139
  }
109
140
  const scopeEntry = patterns.length === 0 ? null : {
110
- v: 1,
141
+ v: 2,
111
142
  kind: "amend",
112
143
  contract: input.contractId,
113
144
  at,
@@ -118,12 +149,12 @@ export async function petitionContract(input) {
118
149
  if (!deliveryCwd)
119
150
  throw new FlowError("INTERNAL_STATE", `petition ${input.contractId} is missing its delivery worktree`);
120
151
  const lifecycle = admission.business.lifecycle;
121
- const followsRenewWithoutInterveningFact = lifecycle.phase === "active"
122
- && lifecycle.seal === null
123
- && lifecycle.history.at(-1)?.entry.kind === "renew";
124
- const capture = followsRenewWithoutInterveningFact
152
+ const precedingRenewSeal = patterns.length === 0
153
+ ? await precedingRenewSealResult(input.cwd, lifecycle)
154
+ : null;
155
+ const capture = precedingRenewSeal
125
156
  ? null
126
- : await captureFoldedSeal(deliveryCwd, lifecycle, "HEAD", patterns);
157
+ : await captureFoldedSeal(deliveryCwd, lifecycle, "HEAD", patterns, "warn");
127
158
  let sealEntry = null;
128
159
  if (capture) {
129
160
  const { scopeViolationEvidence: _evidence, ...durableCapture } = capture;
@@ -145,6 +176,7 @@ export async function petitionContract(input) {
145
176
  return {
146
177
  additions,
147
178
  capture,
179
+ precedingRenewSeal,
148
180
  seat: nextSettlementSeat(admission.repository, admission.pins.target.ref),
149
181
  targetHead,
150
182
  };
@@ -169,7 +201,7 @@ export async function petitionContract(input) {
169
201
  const base = session.lifecycle.pins.base;
170
202
  if (base !== session.pins.target.head)
171
203
  return { code: "PETITION_TARGET_CHANGED", message: "petition target/base facts changed during preparation" };
172
- assertFoldedPetitionable(input.contractId, session.lifecycle);
204
+ await assertFoldedPetitionable(input.contractId, session.lifecycle, session.repository, session.stableRoot);
173
205
  return undefined;
174
206
  },
175
207
  effect: async ({ context, prepared }) => {
@@ -208,15 +240,15 @@ export async function petitionContract(input) {
208
240
  ? await context.replayCommitted({ transactionObjectId: prepared.existing.transactionObjectId })
209
241
  : await context.publishAuthoritative({
210
242
  verb: "petition",
211
- admittedLedgerHead: context.session.lifecycle.observedLedgerHead,
212
- acceptedLifecycleTail: context.session.lifecycle.history.at(-1).objectId,
243
+ admittedLedgerHead: context.session.pins.repositoryLedgerHead,
244
+ acceptedLifecycleTail: context.session.lifecycle.contractHead,
213
245
  entries: additions,
214
246
  });
215
247
  if (result.status === "indeterminate") {
216
- return { kind: "precommit-effects-only", authoritativeHead: result.currentHead ?? context.session.lifecycle.observedLedgerHead };
248
+ return { kind: "precommit-effects-only", authoritativeHead: result.currentHead ?? context.session.pins.repositoryLedgerHead };
217
249
  }
218
250
  if (result.status !== "committed") {
219
- const authoritativeHead = result.currentHead ?? context.session.lifecycle.observedLedgerHead;
251
+ const authoritativeHead = result.currentHead ?? context.session.pins.repositoryLedgerHead;
220
252
  return { kind: "refused-before-effects", authoritativeHead, refusal: { code: "LEDGER_CAS_CONFLICT", message: `contract ${input.contractId} changed during petition` } };
221
253
  }
222
254
  if (input.reviewPersistence) {
@@ -254,7 +286,9 @@ export async function petitionContract(input) {
254
286
  position,
255
287
  seat: prepared.seat,
256
288
  reviewHistoryPath,
257
- sealed: prepared.capture ? { ...prepared.capture, sealedBy: "petition", ledgerHead: result.transaction.entryObjectIds[result.transaction.entries.findIndex((entry) => entry.kind === "seal")] } : undefined,
289
+ sealed: prepared.capture
290
+ ? { ...prepared.capture, sealedBy: "petition", ledgerHead: result.transaction.entryObjectIds[result.transaction.entries.findIndex((entry) => entry.kind === "seal")] }
291
+ : prepared.precedingRenewSeal ?? undefined,
258
292
  },
259
293
  };
260
294
  },
@@ -1,9 +1,8 @@
1
1
  import { FlowError } from "../../flow-error.js";
2
2
  import { readCurrentContractContext } from "../context.js";
3
3
  import { convergeContractCarrier, withContractCarrierSession } from "../contract-carrier.js";
4
- import { createGit } from "../../git/core.js";
4
+ import { requireCommitCoordinate } from "../../git/commits.js";
5
5
  import { getCurrentBranch, requireGitRepository } from "../../git/branches.js";
6
- import { getLatestCommitHash } from "../../git/staging.js";
7
6
  import { readContractLog } from "../log.js";
8
7
  import { scopePathEvidence } from "../scope.js";
9
8
  import { nextReviewResponseNumber } from "../transcripts.js";
@@ -45,15 +44,17 @@ async function pinnedCloseCandidate(cwd, contractId, signal) {
45
44
  if (session.target.status !== "available" || !session.pins.delivery.head) {
46
45
  throw new FlowError("INTERNAL_STATE", session.target.status === "available" ? `contract ${contractId} delivery ref does not resolve` : session.target.reason);
47
46
  }
48
- const git = createGit(session.target.root);
49
- const [head, tree] = await Promise.all([
50
- git.raw(["rev-parse", "--verify", "HEAD^{commit}"]),
51
- git.raw(["rev-parse", "--verify", "HEAD^{tree}"]),
52
- ]);
53
- if (head.trim() !== session.pins.delivery.head) {
47
+ const coordinate = await requireCommitCoordinate(session.target.root, "HEAD");
48
+ if (coordinate.commit !== session.pins.delivery.head) {
54
49
  throw new FlowError("INTERNAL_STATE", `contract ${contractId} delivery head changed while petition was being prepared`);
55
50
  }
56
- return { deliveryCwd: session.target.root, candidate: { head: head.trim(), tree: tree.trim() }, contractVerification: contractVerificationDeclarations(session.lifecycle) };
51
+ const bind = session.lifecycle.history.find(({ entry }) => entry.kind === "bind")?.entry;
52
+ return {
53
+ deliveryCwd: session.target.root,
54
+ candidate: { head: coordinate.commit, tree: coordinate.tree },
55
+ contractVerification: contractVerificationDeclarations(session.lifecycle),
56
+ preparation: bind?.kind === "bind" && bind.data.workspace === "worktree" ? bind.data.bootstrap ?? null : null,
57
+ };
57
58
  });
58
59
  }
59
60
  async function loadCloseContext(cwd, requestedContractId, signal) {
@@ -66,6 +67,7 @@ async function loadCloseContext(cwd, requestedContractId, signal) {
66
67
  deliveryCwd: pinned.deliveryCwd,
67
68
  verificationCandidate: pinned.candidate,
68
69
  contractVerification: pinned.contractVerification,
70
+ verificationPreparation: pinned.preparation,
69
71
  keiyakuBranch: `keiyaku/${requestedContractId}`,
70
72
  baseBranch: lifecycle.pins.target.ref.slice("refs/heads/".length),
71
73
  contractId: requestedContractId,
@@ -88,6 +90,7 @@ async function loadCloseContext(cwd, requestedContractId, signal) {
88
90
  deliveryCwd: pinned.deliveryCwd,
89
91
  verificationCandidate: pinned.candidate,
90
92
  contractVerification: pinned.contractVerification,
93
+ verificationPreparation: pinned.preparation,
91
94
  keiyakuBranch,
92
95
  baseBranch: contractContext.baseBranch,
93
96
  contractId: contractContext.contractId,
@@ -107,14 +110,15 @@ async function throwClaimGateFailure(failure, _input, context, _dependencies) {
107
110
  }
108
111
  async function runClaimGatePipelineOrThrow(input, context, dependencies) {
109
112
  const deliveryCwd = context.deliveryCwd ?? context.cwd;
110
- const verificationCandidate = context.verificationCandidate ?? {
111
- head: await getLatestCommitHash(deliveryCwd),
112
- tree: (await createGit(deliveryCwd).raw(["rev-parse", "--verify", "HEAD^{tree}"])).trim(),
113
- };
113
+ const verificationCandidate = context.verificationCandidate ?? await (async () => {
114
+ const coordinate = await requireCommitCoordinate(deliveryCwd, "HEAD");
115
+ return { head: coordinate.commit, tree: coordinate.tree };
116
+ })();
117
+ const verificationPreparation = context.verificationPreparation ?? null;
114
118
  const gateConfig = await dependencies.resolveClaimGateConfig(context.cwd);
115
119
  const repositoryGates = gateConfig.repositoryGates ?? gateConfig.verificationCommands ?? [];
116
120
  const verificationPlan = composeVerificationPlan({ contract: context.contractVerification ?? [], repositoryGates, timeoutMs: gateConfig.verificationTimeoutMs });
117
- const coordinationRoot = await stableRepoRoot(context.cwd);
121
+ const repositoryRoot = await stableRepoRoot(context.cwd);
118
122
  let review;
119
123
  let reviewHeadBeforeWrite;
120
124
  let reviewerActor;
@@ -123,11 +127,12 @@ async function runClaimGatePipelineOrThrow(input, context, dependencies) {
123
127
  for (const gate of buildClaimGatePipeline()) {
124
128
  const result = await gate.evaluate({
125
129
  cwd: deliveryCwd,
126
- coordinationRoot,
130
+ repositoryRoot,
127
131
  contractId: context.contractId,
128
132
  input,
129
133
  verificationPlan,
130
134
  verificationCandidate,
135
+ verificationPreparation,
131
136
  baseBranch: dependencies.baseBranch,
132
137
  reviewNumber: dependencies.reviewNumber,
133
138
  });
@@ -103,12 +103,12 @@ export async function verdictContract(input) {
103
103
  value: { result: admission.business.existing.result, summary: admission.business.existing.summary },
104
104
  };
105
105
  }
106
- const committed = await context.publishAuthoritative({ verb: "verdict", admittedLedgerHead: admission.ledgerHead, acceptedLifecycleTail: context.session.lifecycle.history.at(-1).objectId, entries: [prepared.entry] });
106
+ const committed = await context.publishAuthoritative({ verb: "verdict", admittedLedgerHead: admission.ledgerHead, acceptedLifecycleTail: context.session.lifecycle.contractHead, entries: [prepared.entry] });
107
107
  if (committed.status === "indeterminate") {
108
108
  return { kind: "precommit-effects-only", authoritativeHead: committed.currentHead ?? admission.ledgerHead };
109
109
  }
110
110
  if (committed.status !== "committed") {
111
- return { kind: "refused-before-effects", authoritativeHead: committed.currentHead ?? context.session.lifecycle.observedLedgerHead, refusal: { code: "LEDGER_CAS_CONFLICT", message: `contract ${input.contractId} changed during verdict` } };
111
+ return { kind: "refused-before-effects", authoritativeHead: committed.currentHead ?? context.session.pins.repositoryLedgerHead, refusal: { code: "LEDGER_CAS_CONFLICT", message: `contract ${input.contractId} changed during verdict` } };
112
112
  }
113
113
  return {
114
114
  kind: "committed",