ai-foreman 1.7.13 → 1.7.14

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 (47) hide show
  1. package/README.md +33 -3
  2. package/dist/adapters/claude.d.ts +5 -0
  3. package/dist/adapters/claude.js +122 -16
  4. package/dist/adapters/codex.d.ts +2 -0
  5. package/dist/adapters/codex.js +30 -8
  6. package/dist/adapters/recovering.d.ts +2 -0
  7. package/dist/adapters/recovering.js +6 -0
  8. package/dist/adapters/types.d.ts +22 -0
  9. package/dist/agentRun.js +21 -3
  10. package/dist/branch/currentGuard.d.ts +2 -0
  11. package/dist/branch/currentGuard.js +9 -0
  12. package/dist/branch/finalization.d.ts +22 -0
  13. package/dist/branch/finalization.js +120 -0
  14. package/dist/branch/git.js +7 -2
  15. package/dist/branch/runner.d.ts +3 -2
  16. package/dist/branch/runner.js +277 -75
  17. package/dist/buildRuns.d.ts +1 -0
  18. package/dist/buildRuns.js +33 -3
  19. package/dist/cli/start.js +314 -86
  20. package/dist/cli/state.d.ts +4 -0
  21. package/dist/cli/state.js +69 -0
  22. package/dist/continuity.d.ts +4 -0
  23. package/dist/continuity.js +26 -3
  24. package/dist/foreman.d.ts +22 -4
  25. package/dist/foreman.js +105 -19
  26. package/dist/handoffs.d.ts +5 -2
  27. package/dist/handoffs.js +93 -12
  28. package/dist/index.js +2 -0
  29. package/dist/qaFailureDelivery.d.ts +100 -0
  30. package/dist/qaFailureDelivery.js +570 -0
  31. package/dist/qaProtocolV2.d.ts +233 -0
  32. package/dist/qaProtocolV2.js +114 -0
  33. package/dist/qaRecovery.d.ts +15 -3
  34. package/dist/qaRecovery.js +477 -83
  35. package/dist/qaReview.d.ts +42 -17
  36. package/dist/qaReview.js +1216 -457
  37. package/dist/qaRuntime.d.ts +14 -0
  38. package/dist/qaRuntime.js +44 -0
  39. package/dist/qaSnapshot.d.ts +34 -0
  40. package/dist/qaSnapshot.js +302 -34
  41. package/dist/stateTransfer.d.ts +57 -0
  42. package/dist/stateTransfer.js +644 -0
  43. package/dist/statusReporter.d.ts +2 -0
  44. package/dist/statusReporter.js +6 -0
  45. package/dist/workflowDb.d.ts +245 -2
  46. package/dist/workflowDb.js +647 -6
  47. package/package.json +15 -3
@@ -1,5 +1,6 @@
1
- import type { BuildRecoveryDecisionReceipt, ContextSample, ContinuityCheckpoint, ContinuityDelta, ContinuityEvent, ContinuityHead, ContinuityHeadState, HandoffLineage, HandoffManifestV1, LiveSettingsAcknowledgment, OperationLifecycle, PendingHumanDecision, ProviderSessionRefV1, RecoveryAttemptOutcome, RecoveryAttemptReceipt, ResolvedAutonomyPolicy, ResolvedAgentSettings, SessionUsageSample, StructuredInterruption, SupervisorState, WorkflowIssue } from "rafi-spec";
1
+ 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
2
  import type { BranchResumeSession } from "./branch/resume.js";
3
+ import { type BuilderRemediationReceiptV2, type FrozenQaSourceStateV2, type HandoffAcceptanceReceiptV2, type QaPassCertificateV2, type QaReducerEventV2, type QaReducerStateV2, type QaReportDisposition, type QaReviewBasisV2, type QaTurnIntentV2, type QaTurnReceiptV2 } from "./qaProtocolV2.js";
3
4
  export declare const WORKFLOW_DB_FILE = ".rafi/recovery.sqlite3";
4
5
  export type WorkflowKind = "plan" | "ticket-plan" | "ticket-populate" | "uninstall" | "build" | "qa-remediation" | "recovery" | "legacy";
5
6
  export type WorkflowRunStatus = "running" | "paused" | "blocked" | "completed" | "failed" | "cancelled" | "superseded";
@@ -74,6 +75,121 @@ export interface RoleMutationLease {
74
75
  sessionKey?: string;
75
76
  movedAt: string;
76
77
  }
78
+ export interface QaRecoveryHeadRecord {
79
+ runId: string;
80
+ ticketId: string;
81
+ packetId: string;
82
+ packetPath: string;
83
+ packetDigest: string;
84
+ reviewedStateDigest: string;
85
+ revision: number;
86
+ correctionTurns: number;
87
+ pendingAction: string;
88
+ updatedAt: string;
89
+ }
90
+ export interface QaPacketProjectionRecord {
91
+ runId: string;
92
+ ticketId: string;
93
+ packetRevision: number;
94
+ packetDigest: string;
95
+ path: string;
96
+ /** Exact canonical manifest bytes needed to finish an interrupted filesystem publication. */
97
+ manifestJson?: string;
98
+ status: "intended" | "published";
99
+ createdAt: string;
100
+ }
101
+ export interface QaFinalizationStepRecord {
102
+ operationId: string;
103
+ runId: string;
104
+ ticketId: string;
105
+ certificateId: string;
106
+ kind: string;
107
+ status: "intended" | "completed" | "invalidated";
108
+ intent: {
109
+ expectedSourceStateDigest: string;
110
+ expectedGitTree: string;
111
+ allowedProjectionPaths: string[];
112
+ reducerRevision: number;
113
+ };
114
+ receipt?: unknown;
115
+ }
116
+ export interface QaReviewAttemptRecord {
117
+ attemptId: string;
118
+ runId: string;
119
+ ticketId: string;
120
+ reviewNumber: number;
121
+ cycle: number;
122
+ remediationGeneration: number;
123
+ sourceDigest: string;
124
+ status: "started" | "passed" | "failed" | "interrupted";
125
+ reportDigest?: string;
126
+ findingIds?: string[];
127
+ namespacedFindingIds?: string[];
128
+ detail?: string;
129
+ createdAt: string;
130
+ updatedAt: string;
131
+ }
132
+ export interface QaRemediationAttemptRecord {
133
+ attemptId: string;
134
+ runId: string;
135
+ ticketId: string;
136
+ reviewAttemptId: string;
137
+ generation: number;
138
+ mode: "validated-report" | "planner-remediation";
139
+ status: "intended" | "started" | "succeeded" | "failed" | "uncertain";
140
+ requestDigest: string;
141
+ responseDigest?: string;
142
+ summaryDigest?: string;
143
+ detail?: string;
144
+ createdAt: string;
145
+ updatedAt: string;
146
+ }
147
+ export type QaFailureHandoffState = "prepared" | "delivery-intended" | "delivery-uncertain" | "response-invalid" | "builder-blocked" | "remediation-reported" | "recheck-required" | "source-drift";
148
+ export interface QaFailureHandoffRecord {
149
+ handoffId: string;
150
+ operationId: string;
151
+ runId: string;
152
+ ticketId: string;
153
+ reviewAttemptId: string;
154
+ reportDigest: string;
155
+ generation: number;
156
+ reviewedContentDigest: string;
157
+ reviewBasisDigest: string;
158
+ state: QaFailureHandoffState;
159
+ handoffDigest: string;
160
+ hostInstructionDigest: string;
161
+ builderSession?: ProviderSessionRefV1;
162
+ providerTurnId?: string;
163
+ receiptDigest?: string;
164
+ responseDigest?: string;
165
+ parsedResponseDigest?: string;
166
+ postSourceDigest?: string;
167
+ detail?: string;
168
+ createdAt: string;
169
+ updatedAt: string;
170
+ }
171
+ export interface QaTransitionRecordV2 {
172
+ sequence: number;
173
+ runId: string;
174
+ ticketId: string;
175
+ fromRevision: number;
176
+ toRevision: number;
177
+ event: QaReducerEventV2;
178
+ state: QaReducerStateV2;
179
+ createdAt: string;
180
+ }
181
+ export interface QaReportRecordV2 {
182
+ reportDigest: string;
183
+ runId: string;
184
+ ticketId: string;
185
+ reviewNumber: number;
186
+ sourceStateDigest: string;
187
+ reviewBasisDigest: string;
188
+ disposition: QaReportDisposition;
189
+ report: unknown;
190
+ createdAt: string;
191
+ updatedAt: string;
192
+ }
77
193
  /** Authoritative persistence for every resumable workflow in a project. */
78
194
  export declare class WorkflowDb {
79
195
  readonly projectDir: string;
@@ -185,8 +301,135 @@ export declare class WorkflowDb {
185
301
  operations(runId: string): OperationRecord[];
186
302
  putEvidence(kind: "handoff" | "diff" | "test" | "qa", value: string | Buffer, now?: Date): string;
187
303
  getEvidence(digest: string): Buffer | undefined;
304
+ putQaRecoveryHead(input: Omit<QaRecoveryHeadRecord, "updatedAt">, now?: Date): QaRecoveryHeadRecord;
305
+ qaRecoveryHead(runId: string, ticketId?: string): QaRecoveryHeadRecord | undefined;
306
+ pendingQaRecoveryHeads(runId: string): QaRecoveryHeadRecord[];
307
+ beginQaReviewAttempt(input: Omit<QaReviewAttemptRecord, "status" | "createdAt" | "updatedAt">, now?: Date): QaReviewAttemptRecord;
308
+ finishQaReviewAttempt(attemptId: string, patch: Pick<QaReviewAttemptRecord, "status"> & Partial<Pick<QaReviewAttemptRecord, "reportDigest" | "findingIds" | "namespacedFindingIds" | "detail">>, now?: Date): QaReviewAttemptRecord;
309
+ qaReviewAttempts(runId: string, ticketId: string): QaReviewAttemptRecord[];
310
+ qaReviewAttempt(attemptId: string): QaReviewAttemptRecord | undefined;
311
+ beginQaRemediationAttempt(input: Omit<QaRemediationAttemptRecord, "status" | "createdAt" | "updatedAt">, now?: Date): QaRemediationAttemptRecord;
312
+ commitQaRemediationIntent(expectedRevision: number, recovery: RecoveryAttemptReceipt, remediation: Omit<QaRemediationAttemptRecord, "status" | "createdAt" | "updatedAt">, now?: Date): QaReducerStateV2;
313
+ updateQaRemediationAttempt(attemptId: string, status: QaRemediationAttemptRecord["status"], patch?: Partial<Pick<QaRemediationAttemptRecord, "responseDigest" | "summaryDigest" | "detail">>, now?: Date): QaRemediationAttemptRecord;
314
+ qaRemediationAttempts(runId: string, ticketId: string): QaRemediationAttemptRecord[];
315
+ qaRemediationAttempt(attemptId: string): QaRemediationAttemptRecord | undefined;
316
+ recordQaFailureHandoffPrepared(input: {
317
+ handoffId: string;
318
+ operationId: string;
319
+ runId: string;
320
+ ticketId: string;
321
+ reviewAttemptId: string;
322
+ reportDigest: string;
323
+ generation: number;
324
+ reviewedContentDigest: string;
325
+ reviewBasisDigest: string;
326
+ handoffDigest: string;
327
+ hostInstructionDigest: string;
328
+ }, now?: Date): QaFailureHandoffRecord;
329
+ markQaFailureHandoffDeliveryIntended(handoffId: string, builderSession: ProviderSessionRefV1, now?: Date): QaFailureHandoffRecord;
330
+ transitionQaFailureHandoff(handoffId: string, state: QaFailureHandoffState, patch?: Partial<Pick<QaFailureHandoffRecord, "builderSession" | "providerTurnId" | "receiptDigest" | "responseDigest" | "parsedResponseDigest" | "postSourceDigest" | "detail">>, now?: Date): QaFailureHandoffRecord;
331
+ qaFailureHandoff(handoffId: string): QaFailureHandoffRecord | undefined;
332
+ qaFailureHandoffs(runId: string, ticketId: string): QaFailureHandoffRecord[];
333
+ qaTicketHead(runId: string, ticketId: string): QaReducerStateV2;
334
+ pendingQaTicketHeads(runId: string): QaReducerStateV2[];
335
+ /** Compare-and-swap the authoritative QA reducer head and append its event atomically. */
336
+ transitionQa(runId: string, ticketId: string, expectedRevision: number, event: QaReducerEventV2, now?: Date): QaReducerStateV2;
337
+ qaTransitions(runId: string, ticketId: string): QaTransitionRecordV2[];
338
+ assertQaRunFinalizable(runId: string): void;
339
+ putQaSourceState(state: FrozenQaSourceStateV2): void;
340
+ putQaReviewBasis(runId: string, ticketId: string, basis: QaReviewBasisV2, now?: Date): void;
341
+ commitQaReviewReady(source: FrozenQaSourceStateV2, basis: QaReviewBasisV2, session: ProviderSessionRefV1, confinement: {
342
+ digest: string;
343
+ }, attempt: {
344
+ attemptId: string;
345
+ cycle: number;
346
+ remediationGeneration: number;
347
+ }, expectedRevision: number, now?: Date): QaReducerStateV2;
348
+ recordQaHandoffReceipt(receipt: HandoffAcceptanceReceiptV2): void;
349
+ qaHandoffReceipt(operationId: string): HandoffAcceptanceReceiptV2 | undefined;
350
+ beginQaTurn(intent: QaTurnIntentV2): void;
351
+ commitQaTurnIntent(intent: QaTurnIntentV2, expectedRevision: number): QaReducerStateV2;
352
+ finishQaTurn(receipt: QaTurnReceiptV2): void;
353
+ recordQaReport(input: Omit<QaReportRecordV2, "disposition" | "createdAt" | "updatedAt">, findingIds: string[], now?: Date): QaReportRecordV2;
354
+ commitQaFailure(input: Omit<QaReportRecordV2, "disposition" | "createdAt" | "updatedAt">, findingIds: string[], expectedRevision: number, now?: Date): QaReducerStateV2;
355
+ /** Accept a failed verdict, its exact attempt outcome, report, findings, and reducer edge atomically. */
356
+ commitQaFailureAttempt(attemptId: string, input: Omit<QaReportRecordV2, "disposition" | "createdAt" | "updatedAt">, rawFindingIds: string[], namespacedFindingIds: string[], detail: string, expectedRevision: number, now?: Date): QaReducerStateV2;
357
+ qaReportChains(reportDigest: string): Array<{
358
+ predecessorReportDigest: string;
359
+ successorReportDigest: string;
360
+ relation: string;
361
+ createdAt: string;
362
+ }>;
363
+ qaReport(reportDigest: string): QaReportRecordV2 | undefined;
364
+ unresolvedQaReports(runId: string, ticketId: string): QaReportRecordV2[];
365
+ setQaReportDisposition(reportDigest: string, disposition: QaReportDisposition, reason: string, now?: Date): void;
366
+ markQaReportsRecheckRequired(runId: string, ticketId: string, reason: string, now?: Date): void;
367
+ resolveQaReportsAfterPass(runId: string, ticketId: string, now?: Date): void;
368
+ commitQaWaiver(runId: string, ticketId: string, expectedRevision: number, reason: string, now?: Date): QaReducerStateV2;
369
+ recordBuilderRemediationReceipt(receipt: BuilderRemediationReceiptV2): void;
370
+ commitBuilderRemediationSuccess(receipt: BuilderRemediationReceiptV2, expectedRevision: number, now?: Date): QaReducerStateV2;
371
+ commitQaRemediationOutcome(input: {
372
+ recoveryAttemptId: string;
373
+ remediationAttemptId: string;
374
+ outcome: "succeeded" | "failed" | "uncertain";
375
+ detail?: string;
376
+ responseDigest?: string;
377
+ summaryDigest?: string;
378
+ receipt?: BuilderRemediationReceiptV2;
379
+ expectedRevision: number;
380
+ }, now?: Date): QaReducerStateV2;
381
+ issueQaPassCertificate(input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, now?: Date): QaPassCertificateV2;
382
+ commitQaPass(input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, expectedRevision: number, now?: Date): QaPassCertificateV2;
383
+ /** Accept a passing verdict, its review-attempt outcome, report resolution, certificate, and reducer edge atomically. */
384
+ commitQaPassAttempt(attemptId: string, input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, detail: string, expectedRevision: number, now?: Date): QaPassCertificateV2;
385
+ consumeQaPassCertificate(runId: string, ticketId: string, certificateId: string, consumer: string, now?: Date): QaPassCertificateV2;
386
+ invalidateUnconsumedQaPassCertificates(runId: string, ticketId: string, reason: string, now?: Date): void;
387
+ invalidateQaPassBeforeFinalization(input: {
388
+ runId: string;
389
+ ticketId: string;
390
+ certificateId: string;
391
+ expectedSourceStateDigest: string;
392
+ expectedRevision: number;
393
+ reason: string;
394
+ }, now?: Date): QaReducerStateV2;
395
+ beginQaFinalization(input: {
396
+ runId: string;
397
+ ticketId: string;
398
+ certificateId: string;
399
+ consumer: string;
400
+ expectedSourceStateDigest: string;
401
+ expectedGitTree: string;
402
+ allowedProjectionPaths: string[];
403
+ expectedRevision: number;
404
+ operationId: string;
405
+ }, now?: Date): QaReducerStateV2;
406
+ planQaFinalizationStep(input: {
407
+ operationId: string;
408
+ runId: string;
409
+ ticketId: string;
410
+ certificateId: string;
411
+ kind: string;
412
+ intent: unknown;
413
+ }, now?: Date): void;
414
+ finishQaFinalizationStep(operationId: string, receipt: unknown, now?: Date): void;
415
+ finishPendingQaFinalizationSteps(runId: string, ticketId: string, receipt: unknown, now?: Date): void;
416
+ qaFinalizationSteps(runId: string, ticketId: string): QaFinalizationStepRecord[];
417
+ invalidateQaFinalization(runId: string, ticketId: string, expectedRevision: number, reason: string, branch?: string, now?: Date): QaReducerStateV2;
418
+ completeQaFinalization(runId: string, ticketId: string, expectedRevision: number, receipt: unknown, now?: Date): QaReducerStateV2;
419
+ planQaPacketProjection(input: {
420
+ runId: string;
421
+ ticketId: string;
422
+ qaRevision: number;
423
+ packetDigest: string;
424
+ path: string;
425
+ manifestJson: string;
426
+ }, now?: Date): void;
427
+ finishQaPacketProjection(runId: string, ticketId: string, packetDigest: string): void;
428
+ qaPacketProjection(packetDigest: string): QaPacketProjectionRecord | undefined;
429
+ qaPacketProjectionsAtPath(path: string): QaPacketProjectionRecord[];
430
+ pendingQaPacketProjections(runId: string): QaPacketProjectionRecord[];
188
431
  stageHandoff(manifest: HandoffManifestV1, markdown: string): HandoffLineage;
189
- acceptHandoff(runId: string, generation: number, successor: string | ProviderSessionRefV1, now?: Date): HandoffLineage;
432
+ acceptHandoff(runId: string, generation: number, successor: string | ProviderSessionRefV1, now?: Date, receipt?: HandoffAcceptanceReceiptV1): HandoffLineage;
190
433
  /** Fence the initial role owner without overwriting a lease already moved by a handoff. */
191
434
  claimInitialRoleLease(runId: string, role: "builder" | "qa", providerSession: string | ProviderSessionRefV1, now?: Date): RoleMutationLease;
192
435
  roleMutationLease(runId: string, role: "builder" | "qa"): RoleMutationLease | undefined;