ai-foreman 1.7.19 → 1.7.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 (205) hide show
  1. package/README.md +29 -5
  2. package/dist/activity.d.ts +3 -0
  3. package/dist/activity.js +18 -6
  4. package/dist/adapters/claude.d.ts +16 -0
  5. package/dist/adapters/claude.js +28 -3
  6. package/dist/adapters/codex.d.ts +20 -0
  7. package/dist/adapters/codex.js +99 -5
  8. package/dist/adapters/recovering.d.ts +9 -0
  9. package/dist/adapters/recovering.js +10 -0
  10. package/dist/adapters/types.d.ts +15 -0
  11. package/dist/agentRun.d.ts +7 -0
  12. package/dist/agentRun.js +24 -13
  13. package/dist/branch/currentGuard.d.ts +1 -0
  14. package/dist/branch/currentGuard.js +1 -0
  15. package/dist/branch/finalization.js +6 -1
  16. package/dist/branch/git.d.ts +1 -0
  17. package/dist/branch/git.js +15 -1
  18. package/dist/branch/runner.d.ts +2 -0
  19. package/dist/branch/runner.js +92 -5
  20. package/dist/buildAdmission.d.ts +61 -0
  21. package/dist/buildAdmission.js +286 -0
  22. package/dist/buildApproval.d.ts +2 -0
  23. package/dist/buildApproval.js +17 -0
  24. package/dist/buildAssignment.d.ts +33 -0
  25. package/dist/buildAssignment.js +215 -0
  26. package/dist/buildInterventions.d.ts +90 -0
  27. package/dist/buildInterventions.js +334 -0
  28. package/dist/buildLaunchGate.d.ts +1 -0
  29. package/dist/buildLaunchGate.js +36 -0
  30. package/dist/buildOwnershipReconciliation.d.ts +19 -0
  31. package/dist/buildOwnershipReconciliation.js +41 -0
  32. package/dist/buildOwnershipRepair.d.ts +33 -0
  33. package/dist/buildOwnershipRepair.js +111 -0
  34. package/dist/buildRuns.d.ts +24 -1
  35. package/dist/buildRuns.js +216 -70
  36. package/dist/buildSyntheticWork.d.ts +2 -0
  37. package/dist/buildSyntheticWork.js +30 -0
  38. package/dist/buildWorkAdmission.d.ts +17 -0
  39. package/dist/buildWorkAdmission.js +57 -0
  40. package/dist/buildWorkAuthorization.d.ts +2 -0
  41. package/dist/buildWorkAuthorization.js +23 -0
  42. package/dist/buildWorkContext.d.ts +3 -0
  43. package/dist/buildWorkContext.js +6 -0
  44. package/dist/buildWorkMigration.d.ts +9 -0
  45. package/dist/buildWorkMigration.js +206 -0
  46. package/dist/buildWorkReconciliation.d.ts +12 -0
  47. package/dist/buildWorkReconciliation.js +70 -0
  48. package/dist/builderGuidanceFollowup.d.ts +15 -0
  49. package/dist/builderGuidanceFollowup.js +34 -0
  50. package/dist/cli/doctor.js +3 -2
  51. package/dist/cli/graph.d.ts +2 -0
  52. package/dist/cli/graph.js +75 -0
  53. package/dist/cli/manager.d.ts +8 -0
  54. package/dist/cli/manager.js +234 -12
  55. package/dist/cli/recovery.js +3 -2
  56. package/dist/cli/runtimeAuthPrompt.d.ts +5 -0
  57. package/dist/cli/runtimeAuthPrompt.js +41 -7
  58. package/dist/cli/start.d.ts +8 -0
  59. package/dist/cli/start.js +2091 -1849
  60. package/dist/cli/status.js +20 -5
  61. package/dist/cli/tickets.js +9 -7
  62. package/dist/continuity.d.ts +16 -1
  63. package/dist/continuity.js +68 -12
  64. package/dist/foreman.d.ts +12 -4
  65. package/dist/foreman.js +397 -60
  66. package/dist/graph/boundary.d.ts +15 -0
  67. package/dist/graph/boundary.js +50 -0
  68. package/dist/graph/bridge.d.ts +9 -0
  69. package/dist/graph/bridge.js +146 -0
  70. package/dist/graph/bridge.py +205 -0
  71. package/dist/graph/config.d.ts +11 -0
  72. package/dist/graph/config.js +40 -0
  73. package/dist/graph/corpus.d.ts +16 -0
  74. package/dist/graph/corpus.js +188 -0
  75. package/dist/graph/derived.d.ts +17 -0
  76. package/dist/graph/derived.js +73 -0
  77. package/dist/graph/host.d.ts +4 -0
  78. package/dist/graph/host.js +160 -0
  79. package/dist/graph/install.d.ts +3 -0
  80. package/dist/graph/install.js +50 -0
  81. package/dist/graph/lifecycle.d.ts +11 -0
  82. package/dist/graph/lifecycle.js +124 -0
  83. package/dist/graph/maintenance.d.ts +43 -0
  84. package/dist/graph/maintenance.js +301 -0
  85. package/dist/graph/manager.d.ts +9 -0
  86. package/dist/graph/manager.js +92 -0
  87. package/dist/graph/preparation.d.ts +41 -0
  88. package/dist/graph/preparation.js +43 -0
  89. package/dist/graph/read.d.ts +27 -0
  90. package/dist/graph/read.js +152 -0
  91. package/dist/graph/semantic.d.ts +17 -0
  92. package/dist/graph/semantic.js +27 -0
  93. package/dist/graph/session.d.ts +8 -0
  94. package/dist/graph/session.js +92 -0
  95. package/dist/graph/sources.d.ts +4 -0
  96. package/dist/graph/sources.js +11 -0
  97. package/dist/graph/storage.d.ts +38 -0
  98. package/dist/graph/storage.js +159 -0
  99. package/dist/graph/turn.d.ts +17 -0
  100. package/dist/graph/turn.js +360 -0
  101. package/dist/graph/util.d.ts +5 -0
  102. package/dist/graph/util.js +51 -0
  103. package/dist/handoffs.d.ts +1 -0
  104. package/dist/handoffs.js +5 -1
  105. package/dist/humanDecision.d.ts +21 -2
  106. package/dist/humanDecision.js +169 -10
  107. package/dist/index.js +4 -1
  108. package/dist/installOwnership.d.ts +46 -0
  109. package/dist/installOwnership.js +440 -0
  110. package/dist/linuxProbeInventory.d.ts +12 -0
  111. package/dist/linuxProbeInventory.js +48 -0
  112. package/dist/log.d.ts +1 -1
  113. package/dist/log.js +7 -1
  114. package/dist/managerEvidence.d.ts +25 -0
  115. package/dist/managerEvidence.js +326 -0
  116. package/dist/managerEvidenceArtifacts.d.ts +38 -0
  117. package/dist/managerEvidenceArtifacts.js +118 -0
  118. package/dist/managerPacket.d.ts +2 -0
  119. package/dist/managerPacket.js +23 -0
  120. package/dist/markers.d.ts +1 -1
  121. package/dist/markers.js +2 -2
  122. package/dist/observability.js +1 -1
  123. package/dist/processIdentity.d.ts +21 -1
  124. package/dist/processIdentity.js +87 -5
  125. package/dist/providerPhase.d.ts +13 -0
  126. package/dist/providerPhase.js +26 -0
  127. package/dist/qaAuthorizedDisposition.d.ts +24 -0
  128. package/dist/qaAuthorizedDisposition.js +26 -0
  129. package/dist/qaBuildGate.d.ts +4 -0
  130. package/dist/qaBuildGate.js +216 -0
  131. package/dist/qaBuilderCoverage.d.ts +5 -0
  132. package/dist/qaBuilderCoverage.js +78 -0
  133. package/dist/qaContractCoverage.d.ts +10 -0
  134. package/dist/qaContractCoverage.js +55 -0
  135. package/dist/qaContractDelivery.d.ts +23 -0
  136. package/dist/qaContractDelivery.js +145 -0
  137. package/dist/qaContractFreshness.d.ts +15 -0
  138. package/dist/qaContractFreshness.js +36 -0
  139. package/dist/qaDeliveryJournal.d.ts +10 -0
  140. package/dist/qaDeliveryJournal.js +16 -1
  141. package/dist/qaEffectiveConfig.d.ts +20 -0
  142. package/dist/qaEffectiveConfig.js +40 -0
  143. package/dist/qaEvidenceReader.d.ts +14 -0
  144. package/dist/qaEvidenceReader.js +176 -0
  145. package/dist/qaFailureDelivery.d.ts +2 -0
  146. package/dist/qaFailureDelivery.js +107 -10
  147. package/dist/qaHandbackMigration.d.ts +1 -1
  148. package/dist/qaHandbackMigration.js +3 -3
  149. package/dist/qaPreparation.d.ts +26 -0
  150. package/dist/qaPreparation.js +150 -0
  151. package/dist/qaPreparationInputs.d.ts +8 -0
  152. package/dist/qaPreparationInputs.js +47 -0
  153. package/dist/qaPreparationMetrics.d.ts +145 -0
  154. package/dist/qaPreparationMetrics.js +120 -0
  155. package/dist/qaPreparationPolicy.d.ts +5 -0
  156. package/dist/qaPreparationPolicy.js +51 -0
  157. package/dist/qaPreparationStore.d.ts +157 -0
  158. package/dist/qaPreparationStore.js +412 -0
  159. package/dist/qaProtocolV2.d.ts +28 -0
  160. package/dist/qaProtocolV2.js +12 -0
  161. package/dist/qaReview.d.ts +6 -0
  162. package/dist/qaReview.js +293 -41
  163. package/dist/qaTimeline.d.ts +18 -0
  164. package/dist/qaTimeline.js +123 -0
  165. package/dist/qaVerificationContract.d.ts +17 -0
  166. package/dist/qaVerificationContract.js +236 -0
  167. package/dist/readinessCleanup.d.ts +19 -0
  168. package/dist/readinessCleanup.js +122 -0
  169. package/dist/readinessGate.d.ts +1 -0
  170. package/dist/readinessGate.js +82 -0
  171. package/dist/recoveryGuidance.d.ts +17 -0
  172. package/dist/recoveryGuidance.js +38 -0
  173. package/dist/runtimeAuth.d.ts +1 -0
  174. package/dist/runtimeAuth.js +5 -1
  175. package/dist/runtimeReadiness.d.ts +13 -0
  176. package/dist/runtimeReadiness.js +206 -10
  177. package/dist/sessionIdentity.d.ts +2 -0
  178. package/dist/sessionIdentity.js +14 -0
  179. package/dist/sessionLifecycle.js +3 -3
  180. package/dist/sources/sourceRegistry.js +7 -0
  181. package/dist/stateTransfer.js +85 -8
  182. package/dist/statusReporter.d.ts +1 -0
  183. package/dist/statusReporter.js +1 -0
  184. package/dist/supervisedStart.d.ts +6 -0
  185. package/dist/supervisedStart.js +178 -62
  186. package/dist/supervisor.d.ts +2 -0
  187. package/dist/supervisor.js +26 -2
  188. package/dist/terminalStyle.d.ts +21 -0
  189. package/dist/terminalStyle.js +50 -0
  190. package/dist/ticketPopulation.d.ts +1 -0
  191. package/dist/ticketPopulation.js +5 -1
  192. package/dist/tickets/commands.js +2 -2
  193. package/dist/tickets/queue.js +1 -1
  194. package/dist/tickets/ticketSchema.d.ts +198 -0
  195. package/dist/tickets/ticketSchema.js +2 -0
  196. package/dist/windowsProbeJob.d.ts +12 -0
  197. package/dist/windowsProbeJob.js +144 -0
  198. package/dist/workflowDb.d.ts +121 -6
  199. package/dist/workflowDb.js +874 -30
  200. package/dist/workflowReader.d.ts +116 -2
  201. package/dist/workflowReader.js +131 -4
  202. package/package.json +89 -8
  203. package/scripts/copy-graph-assets.mjs +3 -0
  204. package/scripts/graph-benchmark.mjs +20 -0
  205. package/scripts/graph-evaluation.mjs +85 -0
@@ -1,3 +1,4 @@
1
+ import { type QaPreparationDepthDecisionV1 } from "rafi-spec";
1
2
  export type TicketPriority = "P0" | "P1" | "P2" | "P3";
2
3
  export type TicketSize = "XS" | "S" | "M" | "L" | "XL";
3
4
  export type TicketRisk = "Low" | "Medium" | "High";
@@ -22,6 +23,7 @@ export interface TicketPlanRef {
22
23
  slice_ref: string;
23
24
  }
24
25
  export interface TicketDef {
26
+ qa_preparation?: QaPreparationDepthDecisionV1;
25
27
  id: string;
26
28
  order: number;
27
29
  title: string;
@@ -47,6 +49,104 @@ export declare const TICKET_JSON_SCHEMA: {
47
49
  readonly required: readonly ["id", "order", "title", "area", "priority", "size", "risk", "depends_on", "summary", "acceptance", "required_tests", "likely_files"];
48
50
  readonly additionalProperties: true;
49
51
  readonly properties: {
52
+ readonly qa_preparation: {
53
+ readonly type: "object";
54
+ readonly additionalProperties: false;
55
+ readonly required: readonly ["version", "decisionId", "level", "rationale", "riskFactors", "policyVersion", "plannerOperationId", "plannerIdentity", "timestamp", "minimumLevel", "minimumReasons"];
56
+ readonly properties: {
57
+ readonly version: {
58
+ readonly const: 1;
59
+ };
60
+ readonly decisionId: {
61
+ readonly type: "string";
62
+ readonly minLength: 1;
63
+ };
64
+ readonly level: {
65
+ readonly type: "integer";
66
+ readonly minimum: 1;
67
+ readonly maximum: 5;
68
+ };
69
+ readonly rationale: {
70
+ readonly type: "string";
71
+ readonly minLength: 1;
72
+ };
73
+ readonly policyVersion: {
74
+ readonly const: "qa-preparation-v1";
75
+ };
76
+ readonly plannerOperationId: {
77
+ readonly type: "string";
78
+ readonly minLength: 1;
79
+ };
80
+ readonly plannerIdentity: {
81
+ readonly type: "string";
82
+ readonly minLength: 1;
83
+ };
84
+ readonly timestamp: {
85
+ readonly type: "string";
86
+ readonly pattern: "^\\d{4}-\\d{2}-\\d{2}T";
87
+ };
88
+ readonly minimumLevel: {
89
+ readonly type: "integer";
90
+ readonly minimum: 1;
91
+ readonly maximum: 5;
92
+ };
93
+ readonly minimumReasons: {
94
+ readonly type: "array";
95
+ readonly items: {
96
+ readonly type: "string";
97
+ readonly minLength: 1;
98
+ };
99
+ };
100
+ readonly predecessorDecisionId: {
101
+ readonly type: "string";
102
+ readonly minLength: 1;
103
+ };
104
+ readonly lowRisk: {
105
+ readonly type: "object";
106
+ readonly additionalProperties: false;
107
+ readonly required: readonly ["narrowBehavior", "understoodDependencies", "adequateVerification"];
108
+ readonly properties: {
109
+ readonly narrowBehavior: {
110
+ readonly type: "string";
111
+ readonly minLength: 1;
112
+ };
113
+ readonly understoodDependencies: {
114
+ readonly type: "string";
115
+ readonly minLength: 1;
116
+ };
117
+ readonly adequateVerification: {
118
+ readonly type: "string";
119
+ readonly minLength: 1;
120
+ };
121
+ };
122
+ };
123
+ readonly riskFactors: {
124
+ readonly type: "array";
125
+ readonly items: {
126
+ readonly type: "object";
127
+ readonly additionalProperties: false;
128
+ readonly required: readonly ["category", "rationale", "references"];
129
+ readonly properties: {
130
+ readonly category: {
131
+ readonly enum: string[];
132
+ };
133
+ readonly rationale: {
134
+ readonly type: "string";
135
+ readonly minLength: 1;
136
+ };
137
+ readonly references: {
138
+ readonly type: "array";
139
+ readonly minItems: 1;
140
+ readonly items: {
141
+ readonly type: "string";
142
+ readonly minLength: 1;
143
+ };
144
+ };
145
+ };
146
+ };
147
+ };
148
+ };
149
+ };
50
150
  readonly id: {
51
151
  readonly type: "string";
52
152
  readonly pattern: "^[A-Za-z][A-Za-z0-9-_]*$";
@@ -212,6 +312,104 @@ export declare const TICKETS_FILE_SCHEMA: {
212
312
  readonly required: readonly ["id", "order", "title", "area", "priority", "size", "risk", "depends_on", "summary", "acceptance", "required_tests", "likely_files"];
213
313
  readonly additionalProperties: true;
214
314
  readonly properties: {
315
+ readonly qa_preparation: {
316
+ readonly type: "object";
317
+ readonly additionalProperties: false;
318
+ readonly required: readonly ["version", "decisionId", "level", "rationale", "riskFactors", "policyVersion", "plannerOperationId", "plannerIdentity", "timestamp", "minimumLevel", "minimumReasons"];
319
+ readonly properties: {
320
+ readonly version: {
321
+ readonly const: 1;
322
+ };
323
+ readonly decisionId: {
324
+ readonly type: "string";
325
+ readonly minLength: 1;
326
+ };
327
+ readonly level: {
328
+ readonly type: "integer";
329
+ readonly minimum: 1;
330
+ readonly maximum: 5;
331
+ };
332
+ readonly rationale: {
333
+ readonly type: "string";
334
+ readonly minLength: 1;
335
+ };
336
+ readonly policyVersion: {
337
+ readonly const: "qa-preparation-v1";
338
+ };
339
+ readonly plannerOperationId: {
340
+ readonly type: "string";
341
+ readonly minLength: 1;
342
+ };
343
+ readonly plannerIdentity: {
344
+ readonly type: "string";
345
+ readonly minLength: 1;
346
+ };
347
+ readonly timestamp: {
348
+ readonly type: "string";
349
+ readonly pattern: "^\\d{4}-\\d{2}-\\d{2}T";
350
+ };
351
+ readonly minimumLevel: {
352
+ readonly type: "integer";
353
+ readonly minimum: 1;
354
+ readonly maximum: 5;
355
+ };
356
+ readonly minimumReasons: {
357
+ readonly type: "array";
358
+ readonly items: {
359
+ readonly type: "string";
360
+ readonly minLength: 1;
361
+ };
362
+ };
363
+ readonly predecessorDecisionId: {
364
+ readonly type: "string";
365
+ readonly minLength: 1;
366
+ };
367
+ readonly lowRisk: {
368
+ readonly type: "object";
369
+ readonly additionalProperties: false;
370
+ readonly required: readonly ["narrowBehavior", "understoodDependencies", "adequateVerification"];
371
+ readonly properties: {
372
+ readonly narrowBehavior: {
373
+ readonly type: "string";
374
+ readonly minLength: 1;
375
+ };
376
+ readonly understoodDependencies: {
377
+ readonly type: "string";
378
+ readonly minLength: 1;
379
+ };
380
+ readonly adequateVerification: {
381
+ readonly type: "string";
382
+ readonly minLength: 1;
383
+ };
384
+ };
385
+ };
386
+ readonly riskFactors: {
387
+ readonly type: "array";
388
+ readonly items: {
389
+ readonly type: "object";
390
+ readonly additionalProperties: false;
391
+ readonly required: readonly ["category", "rationale", "references"];
392
+ readonly properties: {
393
+ readonly category: {
394
+ readonly enum: string[];
395
+ };
396
+ readonly rationale: {
397
+ readonly type: "string";
398
+ readonly minLength: 1;
399
+ };
400
+ readonly references: {
401
+ readonly type: "array";
402
+ readonly minItems: 1;
403
+ readonly items: {
404
+ readonly type: "string";
405
+ readonly minLength: 1;
406
+ };
407
+ };
408
+ };
409
+ };
410
+ };
411
+ };
412
+ };
215
413
  readonly id: {
216
414
  readonly type: "string";
217
415
  readonly pattern: "^[A-Za-z][A-Za-z0-9-_]*$";
@@ -1,3 +1,4 @@
1
+ import { qaPreparationDepthDecisionV1Schema } from "rafi-spec";
1
2
  export const TICKET_JSON_SCHEMA = {
2
3
  type: "object",
3
4
  required: [
@@ -6,6 +7,7 @@ export const TICKET_JSON_SCHEMA = {
6
7
  ],
7
8
  additionalProperties: true,
8
9
  properties: {
10
+ qa_preparation: qaPreparationDepthDecisionV1Schema,
9
11
  id: { type: "string", pattern: "^[A-Za-z][A-Za-z0-9-_]*$" },
10
12
  order: { type: "number", minimum: 0 },
11
13
  title: { type: "string", minLength: 1 },
@@ -0,0 +1,12 @@
1
+ export declare const WINDOWS_JOB_SOURCE: string;
2
+ /** Standard npm shims are invoked as Node argv, never interpreted as shell text. */
3
+ export declare function windowsRuntimeInvocation(executable: string, args: string[]): {
4
+ executable: string;
5
+ args: string[];
6
+ };
7
+ export declare function windowsProbeCommand(tag: string, executable: string, args: string[], cwd: string, ownerStart: string, gated?: boolean): {
8
+ executable: string;
9
+ args: string[];
10
+ config: string;
11
+ };
12
+ export declare function windowsProbeJobState(tag: string, timeoutMs?: number): "absent" | "empty" | "active" | "unknown";
@@ -0,0 +1,144 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ // Keep this host program separate from all provider/user input. The provider is
5
+ // created suspended, assigned to a non-breakaway Job Object, then resumed.
6
+ // https://learn.microsoft.com/en-us/windows/win32/procthread/job-objects
7
+ export const WINDOWS_JOB_SOURCE = String.raw `
8
+ using System;
9
+ using System.Text;
10
+ using System.Threading;
11
+ using System.ComponentModel;
12
+ using System.Runtime.InteropServices;
13
+ public static class RafiProbeJob {
14
+ [StructLayout(LayoutKind.Sequential)] struct Limits {
15
+ public long ProcessTime, JobTime; public uint Flags;
16
+ public UIntPtr MinWorking, MaxWorking; public uint ActiveLimit;
17
+ public UIntPtr Affinity; public uint Priority, Scheduling;
18
+ }
19
+ [StructLayout(LayoutKind.Sequential)] struct Io { public ulong ReadOps, WriteOps, OtherOps, ReadBytes, WriteBytes, OtherBytes; }
20
+ [StructLayout(LayoutKind.Sequential)] struct Extended { public Limits Basic; public Io Io; public UIntPtr ProcessMemory, JobMemory, PeakProcess, PeakJob; }
21
+ [StructLayout(LayoutKind.Sequential)] struct Accounting { public long User, Kernel, PeriodUser, PeriodKernel; public uint Faults, Total, Active, Terminated; }
22
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] struct Startup {
23
+ public int Size; public string Reserved, Desktop, Title;
24
+ public uint X,Y,XSize,YSize,XChars,YChars,Fill,Flags;
25
+ public ushort Show,ReservedSize; public IntPtr ReservedBytes,Input,Output,Error;
26
+ }
27
+ [StructLayout(LayoutKind.Sequential)] struct StartupEx { public Startup Basic; public IntPtr Attributes; }
28
+ [StructLayout(LayoutKind.Sequential)] struct ProcessInfo { public IntPtr Process,Thread; public uint Pid,Tid; }
29
+ [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] static extern IntPtr CreateJobObject(IntPtr security,string name);
30
+ [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] static extern IntPtr OpenJobObject(uint access,bool inherit,string name);
31
+ [DllImport("kernel32.dll", SetLastError=true)] static extern bool SetInformationJobObject(IntPtr job,int kind,ref Extended value,uint size);
32
+ [DllImport("kernel32.dll", SetLastError=true)] static extern bool QueryInformationJobObject(IntPtr job,int kind,out Accounting value,uint size,IntPtr returned);
33
+ [DllImport("kernel32.dll", SetLastError=true)] static extern bool InitializeProcThreadAttributeList(IntPtr list,int count,int flags,ref UIntPtr size);
34
+ [DllImport("kernel32.dll", SetLastError=true)] static extern bool UpdateProcThreadAttribute(IntPtr list,uint flags,UIntPtr attribute,IntPtr value,UIntPtr size,IntPtr previous,IntPtr returned);
35
+ [DllImport("kernel32.dll")] static extern void DeleteProcThreadAttributeList(IntPtr list);
36
+ [DllImport("kernel32.dll", SetLastError=true)] static extern bool TerminateJobObject(IntPtr job,uint code);
37
+ [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] static extern bool CreateProcess(string app,StringBuilder command,IntPtr processSecurity,IntPtr threadSecurity,bool inherit,uint flags,IntPtr env,string cwd,ref StartupEx startup,out ProcessInfo process);
38
+ [DllImport("kernel32.dll", SetLastError=true)] static extern uint ResumeThread(IntPtr thread);
39
+ [DllImport("kernel32.dll", SetLastError=true)] static extern uint WaitForSingleObject(IntPtr handle,uint timeout);
40
+ [DllImport("kernel32.dll", SetLastError=true)] static extern bool GetExitCodeProcess(IntPtr handle,out uint code);
41
+ [DllImport("kernel32.dll")] static extern IntPtr GetStdHandle(int which);
42
+ [DllImport("kernel32.dll")] static extern bool CloseHandle(IntPtr handle);
43
+ static void Check(bool okay) { if (!okay) throw new Win32Exception(Marshal.GetLastWin32Error()); }
44
+ static string Name(string tag) { return "Global\\RafiProbe-" + Guid.Parse(tag).ToString(); }
45
+ public static string Quote(string value) {
46
+ StringBuilder result=new StringBuilder("\""); int slashes=0;
47
+ foreach(char c in value) {
48
+ if(c=='\\') { slashes++; continue; }
49
+ if(c=='\"') { result.Append('\\',slashes*2+1); result.Append(c); }
50
+ else { result.Append('\\',slashes); result.Append(c); }
51
+ slashes=0;
52
+ }
53
+ result.Append('\\',slashes*2); result.Append('"'); return result.ToString();
54
+ }
55
+ static uint Active(IntPtr job) { Accounting value; Check(QueryInformationJobObject(job,1,out value,(uint)Marshal.SizeOf(typeof(Accounting)),IntPtr.Zero)); return value.Active; }
56
+ public static string Query(string tag) {
57
+ IntPtr job=OpenJobObject(4,false,Name(tag));
58
+ if(job==IntPtr.Zero) { if(Marshal.GetLastWin32Error()==2) return "absent"; return "unknown"; }
59
+ try { return Active(job)==0 ? "empty" : "active"; } finally { CloseHandle(job); }
60
+ }
61
+ static bool OwnerAlive(int pid,long start) {
62
+ try { using(var owner=System.Diagnostics.Process.GetProcessById(pid)) return !owner.HasExited && owner.StartTime.ToUniversalTime().ToFileTimeUtc()==start; } catch { return false; }
63
+ }
64
+ public static int Run(string tag,string executable,string[] args,string cwd,int ownerPid,long ownerStart) {
65
+ IntPtr job=CreateJobObject(IntPtr.Zero,Name(tag));
66
+ if(job==IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error());
67
+ if(Marshal.GetLastWin32Error()==183) { CloseHandle(job); throw new Exception("Job name already exists"); }
68
+ ProcessInfo child=new ProcessInfo(); IntPtr attributes=IntPtr.Zero, jobs=IntPtr.Zero; bool initialized=false;
69
+ try {
70
+ Extended limits=new Extended(); limits.Basic.Flags=0x2000; // KILL_ON_JOB_CLOSE; never allow breakaway.
71
+ Check(SetInformationJobObject(job,9,ref limits,(uint)Marshal.SizeOf(typeof(Extended))));
72
+ UIntPtr bytes=UIntPtr.Zero; InitializeProcThreadAttributeList(IntPtr.Zero,1,0,ref bytes);
73
+ Check(bytes.ToUInt64()>0); attributes=Marshal.AllocHGlobal((IntPtr)(long)bytes.ToUInt64());
74
+ Check(InitializeProcThreadAttributeList(attributes,1,0,ref bytes)); initialized=true;
75
+ jobs=Marshal.AllocHGlobal(IntPtr.Size); Marshal.WriteIntPtr(jobs,job);
76
+ // PROC_THREAD_ATTRIBUTE_JOB_LIST assigns containment atomically with creation.
77
+ Check(UpdateProcThreadAttribute(attributes,0,new UIntPtr(0x2000du),jobs,new UIntPtr((uint)IntPtr.Size),IntPtr.Zero,IntPtr.Zero));
78
+ StartupEx startup=new StartupEx(); startup.Basic.Size=Marshal.SizeOf(typeof(StartupEx)); startup.Basic.Flags=0x100; startup.Attributes=attributes;
79
+ startup.Basic.Input=GetStdHandle(-10); startup.Basic.Output=GetStdHandle(-11); startup.Basic.Error=GetStdHandle(-12);
80
+ StringBuilder command=new StringBuilder(Quote(executable)); foreach(string arg in args) command.Append(" ").Append(Quote(arg));
81
+ Check(CreateProcess(executable,command,IntPtr.Zero,IntPtr.Zero,true,0x80004,IntPtr.Zero,cwd,ref startup,out child));
82
+ if(!OwnerAlive(ownerPid,ownerStart)) throw new Exception("Probe owner exited before startup");
83
+ Check(ResumeThread(child.Thread)!=0xffffffff);
84
+ while(true) {
85
+ uint waited=WaitForSingleObject(child.Process,100);
86
+ if(waited==0) break;
87
+ Check(waited==258); // WAIT_TIMEOUT
88
+ if(!OwnerAlive(ownerPid,ownerStart)) { TerminateJobObject(job,125); throw new Exception("Probe owner exited"); }
89
+ }
90
+ uint code; Check(GetExitCodeProcess(child.Process,out code));
91
+ Check(TerminateJobObject(job,0));
92
+ DateTime deadline=DateTime.UtcNow.AddSeconds(5);
93
+ while(Active(job)!=0 && DateTime.UtcNow<deadline) Thread.Sleep(25);
94
+ if(Active(job)!=0) throw new Exception("Job cleanup could not be verified");
95
+ return unchecked((int)code);
96
+ } finally {
97
+ if(initialized) DeleteProcThreadAttributeList(attributes);
98
+ if(attributes!=IntPtr.Zero) Marshal.FreeHGlobal(attributes);
99
+ if(jobs!=IntPtr.Zero) Marshal.FreeHGlobal(jobs);
100
+ if(child.Thread!=IntPtr.Zero) CloseHandle(child.Thread);
101
+ if(child.Process!=IntPtr.Zero) CloseHandle(child.Process);
102
+ CloseHandle(job);
103
+ }
104
+ }
105
+ }`;
106
+ function encoded(script) { return ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")]; }
107
+ const declaration = `$ErrorActionPreference='Stop'; Add-Type -TypeDefinition @'\n${WINDOWS_JOB_SOURCE}\n'@;`;
108
+ /** Standard npm shims are invoked as Node argv, never interpreted as shell text. */
109
+ export function windowsRuntimeInvocation(executable, args) {
110
+ if (!/\.(cmd|bat)$/i.test(executable))
111
+ return { executable, args };
112
+ const shim = readFileSync(executable, "utf8");
113
+ const match = /"%(?:dp0%|~dp0)[\\/]*([^"\r\n]+\.[cm]?js)"/i.exec(shim);
114
+ if (!match)
115
+ throw new Error("Unsupported Windows runtime shim; install the provider's standard npm shim or native executable");
116
+ const script = join(dirname(executable), match[1]);
117
+ if (!existsSync(script))
118
+ throw new Error("Windows runtime shim target is missing");
119
+ return { executable: process.execPath, args: [script, ...args] };
120
+ }
121
+ export function windowsProbeCommand(tag, executable, args, cwd, ownerStart, gated = false) {
122
+ if (!/^[a-f0-9-]{36}$/.test(tag))
123
+ throw new Error("Invalid Windows job identity");
124
+ if (!/^win:\d+$/.test(ownerStart))
125
+ throw new Error("Windows probe owner identity is unavailable");
126
+ const target = windowsRuntimeInvocation(executable, args);
127
+ return {
128
+ executable: join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe"),
129
+ args: encoded(`${gated ? "if ([Console]::In.ReadLine() -ne 'rafi-create-job') { exit 125 };" : ""}${declaration}\n$c=ConvertFrom-Json $env:RAFI_WINDOWS_PROBE_CONFIG; Remove-Item Env:RAFI_WINDOWS_PROBE_CONFIG; $code=[RafiProbeJob]::Run([string]$c.tag,[string]$c.executable,[string[]]$c.args,[string]$c.cwd,[int]$c.ownerPid,[long]$c.ownerStart); exit $code`),
130
+ config: JSON.stringify({ tag, ...target, cwd, ownerPid: process.pid, ownerStart: ownerStart.slice(4) }),
131
+ };
132
+ }
133
+ export function windowsProbeJobState(tag, timeoutMs = 10_000) {
134
+ if (!/^[a-f0-9-]{36}$/.test(tag))
135
+ return "unknown";
136
+ try {
137
+ const powershell = join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
138
+ const output = execFileSync(powershell, encoded(`${declaration}\n[RafiProbeJob]::Query('${tag}')`), { encoding: "utf8", timeout: Math.max(1, timeoutMs), stdio: ["ignore", "pipe", "ignore"] }).trim();
139
+ return output === "absent" || output === "empty" || output === "active" ? output : "unknown";
140
+ }
141
+ catch {
142
+ return "unknown";
143
+ }
144
+ }
@@ -1,5 +1,13 @@
1
+ import { type GraphDerivedAccess } from "./graph/derived.js";
2
+ import { QaPreparationStore } from "./qaPreparationStore.js";
3
+ import { GraphStore } from "./graph/storage.js";
4
+ import { reconcileWork, type BuildOwnershipRepairV1 } from "./buildWorkReconciliation.js";
5
+ import { verifyGuidance, verifyBuilderGuidance, finishGuidance, type InstructionRecipient } from "./buildInterventions.js";
6
+ import { type AdmitWorkInput } from "./buildWorkAdmission.js";
7
+ import { type ReadinessProcess } from "./readinessCleanup.js";
8
+ import { type BuildAdmission, type BuildLaunch } from "./buildAdmission.js";
1
9
  import type { BuildRecoveryDecisionReceipt, ContextSample, ContinuityCheckpoint, ContinuityDelta, ContinuityEvent, ContinuityHead, ContinuityHeadState, HandoffLineage, HandoffAcceptanceReceiptV1, HandoffManifestV1, LiveSettingsAcknowledgment, OperationLifecycle, PendingHumanDecision, ProviderSessionRefV1, RecoveryAttemptOutcome, RecoveryAttemptReceipt, ResolvedAutonomyPolicy, ResolvedAgentSettings, SessionUsageSample, StructuredInterruption, SupervisorState, WorkflowIssue } from "rafi-spec";
2
- import type { QaDeliveryTurnV3, QaDeliveryOutcome, QaDeliveryInvocationV3 } from "./qaDeliveryJournal.js";
10
+ import type { QaDeliveryTurn, QaDeliveryOutcome, QaDeliveryInvocationV3 } from "./qaDeliveryJournal.js";
3
11
  import type { BranchResumeSession } from "./branch/resume.js";
4
12
  import { type BuilderRemediationReceiptV2, type BuilderRemediationReceiptV3, type FrozenQaSourceStateV2, type HandoffAcceptanceReceiptV2, type QaPassCertificateV2, type QaReducerEventV2, type QaReducerStateV2, type QaReportDisposition, type QaReviewBasisV2, type QaTurnIntentV2, type QaTurnReceiptV2 } from "./qaProtocolV2.js";
5
13
  export declare const WORKFLOW_DB_FILE = ".rafi/recovery.sqlite3";
@@ -196,12 +204,101 @@ export interface QaReportRecordV2 {
196
204
  /** Authoritative persistence for every resumable workflow in a project. */
197
205
  export declare class WorkflowDb {
198
206
  readonly projectDir: string;
207
+ private readonly readinessAccess?;
199
208
  readonly path: string;
200
209
  private readonly db;
201
- constructor(projectDir: string, path?: string);
210
+ private writerAuthority?;
211
+ private writerLease?;
212
+ private coordinatorTransition;
213
+ private lineageTransition;
214
+ private workAuthority;
215
+ constructor(projectDir: string, path?: string, readinessAccess?: {
216
+ probeId: string;
217
+ } | {
218
+ runId: string;
219
+ } | undefined);
220
+ /** Connection-local SQL fences: helper/reconciler cannot gain general writer rights. */
221
+ private restrictReadinessConnection;
202
222
  close(): void;
223
+ qaPreparationStore(): QaPreparationStore;
224
+ graphStore(): GraphStore;
225
+ admitWork(input: AdmitWorkInput): import("rafi-spec").BuildWorkAdmissionV1;
226
+ private assertInstructionOwner;
227
+ reserveGuidance(runId: string, workId: string, recipient: InstructionRecipient, operationId: string, sourceDigest: string, text: string, reserve?: boolean): {
228
+ text: string;
229
+ ids: string[];
230
+ };
231
+ reconcileInstructionDeliveries(runId: string, workId: string): void;
232
+ decisionWorkId(decision: PendingHumanDecision): string | undefined;
233
+ finishGuidance(ids: string[], recipient: InstructionRecipient, result: Parameters<typeof finishGuidance>[3]): void;
234
+ builderVerificationContext(runId: string, workId: string, sourceDigest: string): {
235
+ text: string;
236
+ ids: string[];
237
+ };
238
+ verifyBuilderGuidance(ids: string[], certificate: Parameters<typeof verifyBuilderGuidance>[2], response: string, receiptDigest: string): void;
239
+ verifyGuidance(ids: string[], certificate: Parameters<typeof verifyGuidance>[2], response: string): void;
240
+ hasQueuedBuilderGuidance(runId: string, workId: string): boolean;
241
+ instruction(id: string): import("./buildInterventions.js").BuildInstruction | undefined;
242
+ assertFinalizationControls(runId: string, workId: string): void;
243
+ consumeInstructionControls(runId: string, workId: string, kind?: "questions" | "attempts"): string | undefined;
244
+ reconcileWork(request: BuildOwnershipRepairV1, input: Parameters<typeof reconcileWork>[2]): Record<string, unknown>;
245
+ reconciliation(id: string): Record<string, unknown> | undefined;
246
+ workDefinitions(runId: string): Array<{
247
+ workId: string;
248
+ kind: string;
249
+ definition: unknown;
250
+ }>;
251
+ recordWorkAssignment(runId: string, workId: string, operationId: string, record: unknown): void;
252
+ admittedWork(runId: string, workId: string): import("rafi-spec").BuildWorkAdmissionV1 | undefined;
253
+ assertAdmittedWork(runId: string, workId: string): import("rafi-spec").BuildWorkAdmissionV1;
203
254
  /** Atomic local changes only; never await provider or filesystem work here. */
204
255
  atomic<T>(work: () => T): T;
256
+ buildAdmission(): BuildAdmission | undefined;
257
+ private assertNoLegacyBuildOwner;
258
+ private assertExecutionProtocol;
259
+ acquireBuildAdmission(runId: string, phase: BuildAdmission["phase"]): BuildAdmission;
260
+ acquireBuildRecoveryAdmission(runId: string): BuildAdmission;
261
+ admitLeasedBuild(lease: ProjectLease): BuildAdmission;
262
+ reacquireBuildCoordinator(runId: string): BuildAdmission;
263
+ assertBuildAdmission(authority: BuildAdmission): void;
264
+ releaseBuildAdmission(authority: BuildAdmission): void;
265
+ reserveBuildLaunch(authority: BuildAdmission, role: BuildAdmission["phase"], digest: string, protocol?: BuildLaunch["protocol"]): BuildLaunch;
266
+ dispatchBuildLaunch(authority: BuildAdmission, token: string): void;
267
+ failBuildLaunch(authority: BuildAdmission, token: string): void;
268
+ claimBuildLaunch(runId: string, token: string, role: BuildAdmission["phase"], digest: string): BuildAdmission;
269
+ registerBuildLaunchChild(token: string): void;
270
+ acknowledgeBuildLaunchChild(authority: BuildAdmission, token: string, pid: number): void;
271
+ reconcileBuildLaunches(runId: string, original?: BuildAdmission): "retired" | "claimed" | "unknown";
272
+ buildLaunch(token: string): BuildLaunch | undefined;
273
+ preparationSuccessor(runId: string): string;
274
+ reservePreparationRetry(predecessor: string, args: string[], expectedStartArgs?: string): {
275
+ runId: string;
276
+ launch: BuildLaunch;
277
+ authority: BuildAdmission;
278
+ };
279
+ beginOwnedPreparationProcess(authority: BuildAdmission, tag?: string, gated?: boolean): string;
280
+ recordOwnedPreparationProcess(authority: BuildAdmission, id: string, pid: number): void;
281
+ finishOwnedPreparationProcess(authority: BuildAdmission, id: string, noChild?: boolean, outcome?: {
282
+ ready: boolean;
283
+ exitCode: number | null;
284
+ timedOut: boolean;
285
+ cancelled: boolean;
286
+ }): void;
287
+ readinessProcesses(runId?: string): ReadinessProcess[];
288
+ unresolvedPreparationProcesses(runId: string): string[];
289
+ registerReadinessHelper(id: string): void;
290
+ authorizeReadinessHelper(authority: BuildAdmission, id: string, pid: number): void;
291
+ assertReadinessHelper(id: string): ReadinessProcess;
292
+ recordReadinessCreator(id: string, pid: number): void;
293
+ private assertReadinessRelationships;
294
+ readinessCleanupDetails(runId: string): string[];
295
+ private assertReadinessCleanupOwner;
296
+ revokeReadinessHelper(id: string, original?: BuildAdmission): void;
297
+ reconcileReadiness(runId: string, original?: BuildAdmission, deadline?: number): Promise<string[]>;
298
+ preparationEligibility(runId: string): {
299
+ eligible: boolean;
300
+ reasons: string[];
301
+ };
205
302
  /** Ensure non-workflow build records can use the same durable event store. */
206
303
  ensureRun(runId: string, kind?: WorkflowKind, now?: Date): WorkflowRunSnapshot;
207
304
  createRun(input: {
@@ -219,6 +316,13 @@ export declare class WorkflowDb {
219
316
  completedPlanApprovals(): Array<Record<string, unknown>>;
220
317
  activeRuns(): WorkflowRunSnapshot[];
221
318
  resumableRuns(kind?: WorkflowKind): WorkflowRunSnapshot[];
319
+ /** Supervisors may pause a worker generation; they cannot publish worker state. */
320
+ transitionSupervisor(runId: string, workerGeneration: number, update: {
321
+ status?: WorkflowRunStatus;
322
+ checkpoint: string;
323
+ event?: string;
324
+ payload?: unknown;
325
+ }): WorkflowRunSnapshot;
222
326
  transition(runId: string, update: {
223
327
  status?: WorkflowRunStatus;
224
328
  checkpoint: string;
@@ -264,6 +368,7 @@ export declare class WorkflowDb {
264
368
  }, now?: Date): ContinuityCheckpoint;
265
369
  continuityCheckpoints(runId: string, role?: "builder" | "qa"): ContinuityCheckpoint[];
266
370
  latestContinuityCheckpoint(runId: string, role: "builder" | "qa"): ContinuityCheckpoint | undefined;
371
+ private assertGraphContinuityAccess;
267
372
  continuityHead(runId: string, role: "builder" | "qa" | "run"): ContinuityHead | undefined;
268
373
  setContinuityHeadState(runId: string, role: "builder" | "qa", state: ContinuityHeadState, now?: Date): ContinuityHead | undefined;
269
374
  recordSession(runId: string, role: string, stream: string, session: string | ProviderSessionRefV1 | undefined, transition: string, settings: ResolvedAgentSettings, now?: Date): void;
@@ -289,9 +394,16 @@ export declare class WorkflowDb {
289
394
  choices: PendingHumanDecision["choices"];
290
395
  evidence?: PendingHumanDecision["evidence"];
291
396
  }, now?: Date): PendingHumanDecision;
397
+ cancelPendingHumanDecisions(runId: string, reason: string, now?: Date): void;
398
+ humanDecisionKey(decisionId: string): string | undefined;
292
399
  humanDecision(decisionId: string): PendingHumanDecision | undefined;
293
400
  pendingHumanDecisions(runId: string): PendingHumanDecision[];
401
+ decisionContinuationAvailable(runId: string, decisionId: string): boolean;
402
+ nextDecisionContinuationKey(runId: string, decisionId: string): string;
294
403
  answeredTicketDecisions(runId: string, scopeRevision: string): PendingHumanDecision[];
404
+ /** Unconsumed answers to an older definition must not silently reopen a ticket. */
405
+ staleTicketDecisions(runId: string, scopeRevision: string): PendingHumanDecision[];
406
+ refreshStaleTicketDecisions(runId: string, scopeRevision: string, tickets?: readonly string[]): void;
295
407
  answerHumanDecision(runId: string, decisionId: string, choiceId: string, now?: Date, answer?: string): PendingHumanDecision;
296
408
  putSupervisorState(runId: string, state: SupervisorState, now?: Date): SupervisorState;
297
409
  runningSupervisors(): Array<{
@@ -315,6 +427,7 @@ export declare class WorkflowDb {
315
427
  operation(idempotencyKey: string): OperationRecord | undefined;
316
428
  operations(runId: string): OperationRecord[];
317
429
  putEvidence(kind: "handoff" | "diff" | "test" | "qa", value: string | Buffer, now?: Date): string;
430
+ registerGraphEvidence(value: string | Buffer, access: GraphDerivedAccess | GraphDerivedAccess[]): void;
318
431
  getEvidence(digest: string): Buffer | undefined;
319
432
  putQaRecoveryHead(input: Omit<QaRecoveryHeadRecord, "updatedAt">, now?: Date): QaRecoveryHeadRecord;
320
433
  qaRecoveryHead(runId: string, ticketId?: string): QaRecoveryHeadRecord | undefined;
@@ -329,8 +442,8 @@ export declare class WorkflowDb {
329
442
  qaRemediationAttempts(runId: string, ticketId: string): QaRemediationAttemptRecord[];
330
443
  qaRemediationAttempt(attemptId: string): QaRemediationAttemptRecord | undefined;
331
444
  recordQaDeliveryInvocation(record: QaDeliveryInvocationV3): void;
332
- recordQaDeliveryTurn(turn: QaDeliveryTurnV3): void;
333
- qaDeliveryTurns(operationId: string): QaDeliveryTurnV3[];
445
+ recordQaDeliveryTurn(turn: QaDeliveryTurn): void;
446
+ qaDeliveryTurns(operationId: string): QaDeliveryTurn[];
334
447
  /** Attempts, including ambiguous intents, are the common legacy/production ledger. */
335
448
  qaAutomaticRemediationCount(runId: string, ticketId: string): number;
336
449
  authorizeQaRemediation(runId: string, ticketId: string, reviewAttemptId: string, reason: string): string;
@@ -405,7 +518,8 @@ export declare class WorkflowDb {
405
518
  setQaReportDisposition(reportDigest: string, disposition: QaReportDisposition, reason: string, now?: Date): void;
406
519
  markQaReportsRecheckRequired(runId: string, ticketId: string, reason: string, now?: Date): void;
407
520
  resolveQaReportsAfterPass(runId: string, ticketId: string, now?: Date): void;
408
- commitQaWaiver(runId: string, ticketId: string, expectedRevision: number, reason: string, now?: Date): QaReducerStateV2;
521
+ authorizeContractQaWaiver(runId: string, workId: string, decisionId: string): string;
522
+ commitQaWaiver(runId: string, ticketId: string, expectedRevision: number, reason: string, now?: Date, authorizationRef?: string): QaReducerStateV2;
409
523
  builderRemediationReceipt(operationId: string): BuilderRemediationReceiptV2 | BuilderRemediationReceiptV3 | undefined;
410
524
  recordBuilderRemediationReceipt(receipt: BuilderRemediationReceiptV2 | BuilderRemediationReceiptV3): void;
411
525
  commitBuilderRemediationSuccess(receipt: BuilderRemediationReceiptV2 | BuilderRemediationReceiptV3, expectedRevision: number, now?: Date): QaReducerStateV2;
@@ -419,12 +533,13 @@ export declare class WorkflowDb {
419
533
  receipt?: BuilderRemediationReceiptV2 | BuilderRemediationReceiptV3;
420
534
  expectedRevision: number;
421
535
  }, now?: Date): QaReducerStateV2;
536
+ private assertContractCertificate;
422
537
  issueQaPassCertificate(input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, now?: Date): QaPassCertificateV2;
423
538
  commitQaPass(input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, expectedRevision: number, now?: Date): QaPassCertificateV2;
424
539
  /** Accept a passing verdict, its review-attempt outcome, report resolution, certificate, and reducer edge atomically. */
425
540
  commitQaPassAttempt(attemptId: string, input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, detail: string, expectedRevision: number, now?: Date): QaPassCertificateV2;
426
541
  consumeQaPassCertificate(runId: string, ticketId: string, certificateId: string, consumer: string, now?: Date): QaPassCertificateV2;
427
- invalidateUnconsumedQaPassCertificates(runId: string, ticketId: string, reason: string, now?: Date): void;
542
+ invalidateUnconsumedQaPassCertificates(runId: string, ticketId: string, reason: string, now?: Date, issuedBefore?: string): void;
428
543
  invalidateQaPassBeforeFinalization(input: {
429
544
  runId: string;
430
545
  ticketId: string;