ai-foreman 1.7.20 → 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.
- package/README.md +12 -2
- package/dist/activity.d.ts +3 -0
- package/dist/activity.js +18 -6
- package/dist/adapters/claude.d.ts +16 -0
- package/dist/adapters/claude.js +28 -3
- package/dist/adapters/codex.d.ts +20 -0
- package/dist/adapters/codex.js +99 -5
- package/dist/adapters/recovering.d.ts +9 -0
- package/dist/adapters/recovering.js +10 -0
- package/dist/adapters/types.d.ts +15 -0
- package/dist/agentRun.d.ts +7 -0
- package/dist/agentRun.js +24 -13
- package/dist/branch/currentGuard.d.ts +1 -0
- package/dist/branch/currentGuard.js +1 -0
- package/dist/branch/finalization.js +6 -1
- package/dist/branch/git.d.ts +1 -0
- package/dist/branch/git.js +15 -1
- package/dist/branch/runner.d.ts +2 -0
- package/dist/branch/runner.js +90 -4
- package/dist/buildAdmission.js +2 -0
- package/dist/buildAssignment.d.ts +33 -0
- package/dist/buildAssignment.js +215 -0
- package/dist/buildInterventions.d.ts +90 -0
- package/dist/buildInterventions.js +334 -0
- package/dist/buildOwnershipReconciliation.d.ts +19 -0
- package/dist/buildOwnershipReconciliation.js +41 -0
- package/dist/buildOwnershipRepair.d.ts +33 -0
- package/dist/buildOwnershipRepair.js +111 -0
- package/dist/buildRuns.d.ts +6 -0
- package/dist/buildRuns.js +23 -17
- package/dist/buildSyntheticWork.d.ts +2 -0
- package/dist/buildSyntheticWork.js +30 -0
- package/dist/buildWorkAdmission.d.ts +17 -0
- package/dist/buildWorkAdmission.js +57 -0
- package/dist/buildWorkAuthorization.d.ts +2 -0
- package/dist/buildWorkAuthorization.js +23 -0
- package/dist/buildWorkContext.d.ts +3 -0
- package/dist/buildWorkContext.js +6 -0
- package/dist/buildWorkMigration.d.ts +9 -0
- package/dist/buildWorkMigration.js +206 -0
- package/dist/buildWorkReconciliation.d.ts +12 -0
- package/dist/buildWorkReconciliation.js +70 -0
- package/dist/builderGuidanceFollowup.d.ts +15 -0
- package/dist/builderGuidanceFollowup.js +34 -0
- package/dist/cli/doctor.js +3 -2
- package/dist/cli/graph.d.ts +2 -0
- package/dist/cli/graph.js +75 -0
- package/dist/cli/manager.d.ts +8 -0
- package/dist/cli/manager.js +234 -12
- package/dist/cli/recovery.js +3 -2
- package/dist/cli/runtimeAuthPrompt.js +28 -8
- package/dist/cli/start.js +152 -48
- package/dist/cli/status.js +20 -5
- package/dist/cli/tickets.js +9 -7
- package/dist/continuity.d.ts +11 -0
- package/dist/continuity.js +22 -6
- package/dist/foreman.d.ts +10 -2
- package/dist/foreman.js +330 -39
- package/dist/graph/boundary.d.ts +15 -0
- package/dist/graph/boundary.js +50 -0
- package/dist/graph/bridge.d.ts +9 -0
- package/dist/graph/bridge.js +146 -0
- package/dist/graph/bridge.py +205 -0
- package/dist/graph/config.d.ts +11 -0
- package/dist/graph/config.js +40 -0
- package/dist/graph/corpus.d.ts +16 -0
- package/dist/graph/corpus.js +188 -0
- package/dist/graph/derived.d.ts +17 -0
- package/dist/graph/derived.js +73 -0
- package/dist/graph/host.d.ts +4 -0
- package/dist/graph/host.js +160 -0
- package/dist/graph/install.d.ts +3 -0
- package/dist/graph/install.js +50 -0
- package/dist/graph/lifecycle.d.ts +11 -0
- package/dist/graph/lifecycle.js +124 -0
- package/dist/graph/maintenance.d.ts +43 -0
- package/dist/graph/maintenance.js +301 -0
- package/dist/graph/manager.d.ts +9 -0
- package/dist/graph/manager.js +92 -0
- package/dist/graph/preparation.d.ts +41 -0
- package/dist/graph/preparation.js +43 -0
- package/dist/graph/read.d.ts +27 -0
- package/dist/graph/read.js +152 -0
- package/dist/graph/semantic.d.ts +17 -0
- package/dist/graph/semantic.js +27 -0
- package/dist/graph/session.d.ts +8 -0
- package/dist/graph/session.js +92 -0
- package/dist/graph/sources.d.ts +4 -0
- package/dist/graph/sources.js +11 -0
- package/dist/graph/storage.d.ts +38 -0
- package/dist/graph/storage.js +159 -0
- package/dist/graph/turn.d.ts +17 -0
- package/dist/graph/turn.js +360 -0
- package/dist/graph/util.d.ts +5 -0
- package/dist/graph/util.js +51 -0
- package/dist/handoffs.d.ts +1 -0
- package/dist/handoffs.js +5 -1
- package/dist/humanDecision.d.ts +21 -2
- package/dist/humanDecision.js +169 -11
- package/dist/index.js +2 -0
- package/dist/installOwnership.d.ts +46 -0
- package/dist/installOwnership.js +440 -0
- package/dist/linuxProbeInventory.d.ts +12 -0
- package/dist/linuxProbeInventory.js +48 -0
- package/dist/log.d.ts +1 -1
- package/dist/log.js +7 -1
- package/dist/managerEvidence.d.ts +25 -0
- package/dist/managerEvidence.js +326 -0
- package/dist/managerEvidenceArtifacts.d.ts +38 -0
- package/dist/managerEvidenceArtifacts.js +118 -0
- package/dist/managerPacket.d.ts +2 -0
- package/dist/managerPacket.js +23 -0
- package/dist/markers.d.ts +1 -1
- package/dist/markers.js +2 -2
- package/dist/observability.js +1 -1
- package/dist/processIdentity.js +7 -0
- package/dist/providerPhase.d.ts +13 -0
- package/dist/providerPhase.js +26 -0
- package/dist/qaAuthorizedDisposition.d.ts +24 -0
- package/dist/qaAuthorizedDisposition.js +26 -0
- package/dist/qaBuildGate.d.ts +4 -0
- package/dist/qaBuildGate.js +216 -0
- package/dist/qaBuilderCoverage.d.ts +5 -0
- package/dist/qaBuilderCoverage.js +78 -0
- package/dist/qaContractCoverage.d.ts +10 -0
- package/dist/qaContractCoverage.js +55 -0
- package/dist/qaContractDelivery.d.ts +23 -0
- package/dist/qaContractDelivery.js +145 -0
- package/dist/qaContractFreshness.d.ts +15 -0
- package/dist/qaContractFreshness.js +36 -0
- package/dist/qaDeliveryJournal.d.ts +10 -0
- package/dist/qaDeliveryJournal.js +16 -1
- package/dist/qaEffectiveConfig.d.ts +20 -0
- package/dist/qaEffectiveConfig.js +40 -0
- package/dist/qaEvidenceReader.d.ts +14 -0
- package/dist/qaEvidenceReader.js +176 -0
- package/dist/qaFailureDelivery.d.ts +2 -0
- package/dist/qaFailureDelivery.js +107 -10
- package/dist/qaHandbackMigration.d.ts +1 -1
- package/dist/qaHandbackMigration.js +3 -3
- package/dist/qaPreparation.d.ts +26 -0
- package/dist/qaPreparation.js +150 -0
- package/dist/qaPreparationInputs.d.ts +8 -0
- package/dist/qaPreparationInputs.js +47 -0
- package/dist/qaPreparationMetrics.d.ts +145 -0
- package/dist/qaPreparationMetrics.js +120 -0
- package/dist/qaPreparationPolicy.d.ts +5 -0
- package/dist/qaPreparationPolicy.js +51 -0
- package/dist/qaPreparationStore.d.ts +157 -0
- package/dist/qaPreparationStore.js +412 -0
- package/dist/qaProtocolV2.d.ts +28 -0
- package/dist/qaProtocolV2.js +12 -0
- package/dist/qaReview.d.ts +6 -0
- package/dist/qaReview.js +234 -24
- package/dist/qaTimeline.d.ts +18 -0
- package/dist/qaTimeline.js +123 -0
- package/dist/qaVerificationContract.d.ts +17 -0
- package/dist/qaVerificationContract.js +236 -0
- package/dist/readinessCleanup.js +12 -5
- package/dist/recoveryGuidance.d.ts +9 -0
- package/dist/recoveryGuidance.js +13 -0
- package/dist/runtimeAuth.d.ts +1 -0
- package/dist/runtimeAuth.js +5 -1
- package/dist/runtimeReadiness.d.ts +1 -0
- package/dist/runtimeReadiness.js +13 -1
- package/dist/sessionIdentity.d.ts +2 -0
- package/dist/sessionIdentity.js +14 -0
- package/dist/sessionLifecycle.js +3 -3
- package/dist/sources/sourceRegistry.js +7 -0
- package/dist/stateTransfer.js +50 -1
- package/dist/statusReporter.d.ts +1 -0
- package/dist/statusReporter.js +1 -0
- package/dist/supervisedStart.js +18 -8
- package/dist/terminalStyle.d.ts +21 -0
- package/dist/terminalStyle.js +50 -0
- package/dist/ticketPopulation.d.ts +1 -0
- package/dist/ticketPopulation.js +5 -1
- package/dist/tickets/commands.js +2 -2
- package/dist/tickets/queue.js +1 -1
- package/dist/tickets/ticketSchema.d.ts +198 -0
- package/dist/tickets/ticketSchema.js +2 -0
- package/dist/workflowDb.d.ts +51 -5
- package/dist/workflowDb.js +338 -7
- package/dist/workflowReader.d.ts +109 -2
- package/dist/workflowReader.js +48 -4
- package/package.json +84 -7
- package/scripts/copy-graph-assets.mjs +3 -0
- package/scripts/graph-benchmark.mjs +20 -0
- package/scripts/graph-evaluation.mjs +85 -0
package/dist/supervisedStart.js
CHANGED
|
@@ -154,6 +154,7 @@ export async function superviseStart(projectDir, runId, policy, selection) {
|
|
|
154
154
|
db.ensureRun(runId, "build");
|
|
155
155
|
db.freezeAutonomyPolicy(runId, policy);
|
|
156
156
|
let exitCode = 2;
|
|
157
|
+
let stopRequestSource;
|
|
157
158
|
const supervisor = new DurableSupervisor({ projectDir, runId, policy, admission: localBuildAuthority(projectDir),
|
|
158
159
|
checkpoint: () => db.getRun(runId)?.checkpoint ?? "preparing",
|
|
159
160
|
spawnWorker: generation => {
|
|
@@ -201,8 +202,10 @@ export async function superviseStart(projectDir, runId, policy, selection) {
|
|
|
201
202
|
}
|
|
202
203
|
catch { /* exited */ }
|
|
203
204
|
};
|
|
204
|
-
const watchdog = setInterval(() => { if (Date.now() - lastHeartbeat > 120_000)
|
|
205
|
-
|
|
205
|
+
const watchdog = setInterval(() => { if (Date.now() - lastHeartbeat > 120_000) {
|
|
206
|
+
stopRequestSource = "heartbeat-timeout";
|
|
207
|
+
stop();
|
|
208
|
+
} }, 5_000);
|
|
206
209
|
watchdog.unref();
|
|
207
210
|
child.on("message", message => { if (message && typeof message === "object" && "kind" in message && message.kind === "rafi-worker-heartbeat")
|
|
208
211
|
lastHeartbeat = Date.now(); });
|
|
@@ -237,6 +240,9 @@ export async function superviseStart(projectDir, runId, policy, selection) {
|
|
|
237
240
|
clearTimeout(killTimer);
|
|
238
241
|
exitCode = code ?? 2;
|
|
239
242
|
try {
|
|
243
|
+
const exitState = db.getRun(runId);
|
|
244
|
+
if (exitState)
|
|
245
|
+
db.transitionSupervisor(runId, generation, { checkpoint: exitState.checkpoint, event: "worker_exit", payload: { code, signal, stopRequested: stopping, source: stopRequestSource ?? "unknown", at: new Date().toISOString(), generation } });
|
|
240
246
|
// Durable records are authoritative even when the worker never sent IPC.
|
|
241
247
|
const deadline = Date.now() + 5000;
|
|
242
248
|
const owned = db.readinessProcesses(runId).filter(row => {
|
|
@@ -277,7 +283,10 @@ export async function superviseStart(projectDir, runId, policy, selection) {
|
|
|
277
283
|
}
|
|
278
284
|
else {
|
|
279
285
|
const state = db.getRun(runId);
|
|
280
|
-
if (code === 0 && state?.status
|
|
286
|
+
if (code === 0 && state?.status === "cancelled") {
|
|
287
|
+
resolve({ kind: "completed" });
|
|
288
|
+
}
|
|
289
|
+
else if (code === 0 && state?.status !== "completed") {
|
|
281
290
|
exitCode = 2;
|
|
282
291
|
resolve({ kind: "waiting_for_human" });
|
|
283
292
|
}
|
|
@@ -294,15 +303,16 @@ export async function superviseStart(projectDir, runId, policy, selection) {
|
|
|
294
303
|
return { pid: child.pid, result, stop };
|
|
295
304
|
},
|
|
296
305
|
});
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
process.once("
|
|
306
|
+
const stopInt = () => { stopRequestSource = "parent-SIGINT"; supervisor.requestStop(); };
|
|
307
|
+
const stopTerm = () => { stopRequestSource = "parent-SIGTERM"; supervisor.requestStop(); };
|
|
308
|
+
process.once("SIGINT", stopInt);
|
|
309
|
+
process.once("SIGTERM", stopTerm);
|
|
300
310
|
try {
|
|
301
311
|
await supervisor.run();
|
|
302
312
|
}
|
|
303
313
|
finally {
|
|
304
|
-
process.off("SIGINT",
|
|
305
|
-
process.off("SIGTERM",
|
|
314
|
+
process.off("SIGINT", stopInt);
|
|
315
|
+
process.off("SIGTERM", stopTerm);
|
|
306
316
|
db.close();
|
|
307
317
|
}
|
|
308
318
|
process.exitCode = exitCode;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Small, dependency-free terminal styling and display sanitization helpers. */
|
|
2
|
+
export type TerminalColorRole = "accent" | "success" | "warning" | "error" | "info";
|
|
3
|
+
export interface TerminalStyleStream {
|
|
4
|
+
readonly isTTY?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface TerminalStyleContext {
|
|
7
|
+
readonly stream?: TerminalStyleStream;
|
|
8
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
9
|
+
readonly platform?: NodeJS.Platform;
|
|
10
|
+
/** Declared data output is always plain, including FORCE_COLOR sessions. */
|
|
11
|
+
readonly machineReadable?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function terminalColorEnabled(context?: TerminalStyleContext): boolean;
|
|
14
|
+
export declare function styleTerminalText(role: TerminalColorRole, text: string, context?: TerminalStyleContext): string;
|
|
15
|
+
export declare function accent(text: string, context?: TerminalStyleContext): string;
|
|
16
|
+
export declare function success(text: string, context?: TerminalStyleContext): string;
|
|
17
|
+
export declare function warning(text: string, context?: TerminalStyleContext): string;
|
|
18
|
+
export declare function error(text: string, context?: TerminalStyleContext): string;
|
|
19
|
+
export declare function info(text: string, context?: TerminalStyleContext): string;
|
|
20
|
+
/** Remove terminal control sequences while retaining intended line breaks. */
|
|
21
|
+
export declare function sanitizeTerminalText(value: string): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Small, dependency-free terminal styling and display sanitization helpers. */
|
|
2
|
+
const ANSI = {
|
|
3
|
+
accent: "\x1b[36m",
|
|
4
|
+
success: "\x1b[32m",
|
|
5
|
+
warning: "\x1b[33m",
|
|
6
|
+
error: "\x1b[31m",
|
|
7
|
+
info: "\x1b[34m",
|
|
8
|
+
};
|
|
9
|
+
const RESET = "\x1b[39m";
|
|
10
|
+
export function terminalColorEnabled(context = {}) {
|
|
11
|
+
if (context.machineReadable)
|
|
12
|
+
return false;
|
|
13
|
+
const env = context.env ?? process.env;
|
|
14
|
+
const stream = context.stream ?? process.stdout;
|
|
15
|
+
if (Object.hasOwn(env, "NO_COLOR"))
|
|
16
|
+
return false;
|
|
17
|
+
if (env.TERM?.toLowerCase() === "dumb")
|
|
18
|
+
return false;
|
|
19
|
+
if (env.FORCE_COLOR === "0")
|
|
20
|
+
return false;
|
|
21
|
+
if (["1", "2", "3"].includes(env.FORCE_COLOR ?? ""))
|
|
22
|
+
return true;
|
|
23
|
+
if (!stream.isTTY)
|
|
24
|
+
return false;
|
|
25
|
+
// Modern Windows terminals advertise ANSI support. A bare legacy console TTY
|
|
26
|
+
// is not enough evidence, so leave it readable and unstyled.
|
|
27
|
+
if ((context.platform ?? process.platform) === "win32") {
|
|
28
|
+
return Boolean(env.WT_SESSION || env.ANSICON || env.ConEmuANSI === "ON" || env.TERM);
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
export function styleTerminalText(role, text, context = {}) {
|
|
33
|
+
const safeText = sanitizeTerminalText(text);
|
|
34
|
+
return terminalColorEnabled(context) ? `${ANSI[role]}${safeText}${RESET}` : safeText;
|
|
35
|
+
}
|
|
36
|
+
export function accent(text, context) { return styleTerminalText("accent", text, context); }
|
|
37
|
+
export function success(text, context) { return styleTerminalText("success", text, context); }
|
|
38
|
+
export function warning(text, context) { return styleTerminalText("warning", text, context); }
|
|
39
|
+
export function error(text, context) { return styleTerminalText("error", text, context); }
|
|
40
|
+
export function info(text, context) { return styleTerminalText("info", text, context); }
|
|
41
|
+
/** Remove terminal control sequences while retaining intended line breaks. */
|
|
42
|
+
export function sanitizeTerminalText(value) {
|
|
43
|
+
return value
|
|
44
|
+
// CSI, OSC, DCS/SOS/PM/APC, and two-byte ESC controls.
|
|
45
|
+
.replace(/\x1b\](?:[^\x07\x1b]|\x1b(?!\\))*(?:\x07|\x1b\\)?/gs, "")
|
|
46
|
+
.replace(/\x1b(?:[PX^_](?:.|\n)*?\x1b\\|\[[0-?]*[ -/]*[@-~]|[@-_])/g, "")
|
|
47
|
+
.replace(/\x9d[^\x07]*(?:\x07)?/g, "")
|
|
48
|
+
.replace(/\x9b[0-?]*[ -/]*[@-~]/g, "")
|
|
49
|
+
.replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g, "");
|
|
50
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { StructuredPlanV1 } from "rafi-spec";
|
|
|
2
2
|
import type { TicketDef } from "./tickets/ticketSchema.js";
|
|
3
3
|
import { type DeliveryConfig } from "./tickets/delivery.js";
|
|
4
4
|
export interface TicketSliceProposal {
|
|
5
|
+
qa_preparation?: TicketDef["qa_preparation"];
|
|
5
6
|
slice_ref: string;
|
|
6
7
|
title: string;
|
|
7
8
|
area: string;
|
package/dist/ticketPopulation.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { canonicalContractJson } from "./qaVerificationContract.js";
|
|
1
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
3
|
import { closeSync, copyFileSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -30,6 +31,9 @@ export function validateTicketPopulationProposal(proposal, plan, existing) {
|
|
|
30
31
|
const planned = new Set(plan.slices.map((slice) => slice.slice_ref));
|
|
31
32
|
const mapped = new Set();
|
|
32
33
|
for (const ticket of proposal.tickets) {
|
|
34
|
+
const depth = plan.slices.find(slice => slice.slice_ref === ticket.slice_ref)?.qa_preparation;
|
|
35
|
+
if (ticket.qa_preparation && (!depth || canonicalContractJson(ticket.qa_preparation) !== canonicalContractJson(depth)))
|
|
36
|
+
issues.push(`ticket-maker cannot override planner QA depth for ${ticket.slice_ref}`);
|
|
33
37
|
if (!planned.has(ticket.slice_ref))
|
|
34
38
|
issues.push(`unknown slice mapping ${ticket.slice_ref}`);
|
|
35
39
|
if (mapped.has(ticket.slice_ref))
|
|
@@ -64,7 +68,7 @@ export function materializeTicketPopulation(proposal, plan, existing) {
|
|
|
64
68
|
const materialized = proposal.tickets.map((slice, index) => {
|
|
65
69
|
const retained = byPlanSlice.get(`${plan.plan_id}:${slice.slice_ref}`);
|
|
66
70
|
return {
|
|
67
|
-
...(retained ?? {}), id: sliceToTicket.get(slice.slice_ref), order: retained?.order ?? nextOrder(existing, index),
|
|
71
|
+
...(retained ?? {}), qa_preparation: structuredClone(plan.slices.find(item => item.slice_ref === slice.slice_ref)?.qa_preparation), id: sliceToTicket.get(slice.slice_ref), order: retained?.order ?? nextOrder(existing, index),
|
|
68
72
|
title: slice.title, area: slice.area, priority: slice.priority, size: slice.size, risk: slice.risk,
|
|
69
73
|
depends_on: slice.depends_on.map((ref) => sliceToTicket.get(ref)), summary: slice.summary,
|
|
70
74
|
acceptance: [...slice.acceptance], required_tests: [...slice.required_tests], likely_files: [...slice.likely_files],
|
package/dist/tickets/commands.js
CHANGED
|
@@ -259,8 +259,8 @@ export function cmdBlock(projectDir, ticketId, opts) {
|
|
|
259
259
|
ctx.db.upsertState(ticketId, {
|
|
260
260
|
status: "blocked",
|
|
261
261
|
blocked_by_json: JSON.stringify(merged),
|
|
262
|
-
blocker_type: opts.blockerType ?? "dependency",
|
|
263
|
-
blocker_notes: opts.unblockCriteria ??
|
|
262
|
+
blocker_type: opts.blockerType ?? (merged.length ? "dependency" : "external"),
|
|
263
|
+
blocker_notes: opts.unblockCriteria ?? opts.summary ?? "Resolve the external prerequisite before continuing",
|
|
264
264
|
first_blocked_at: state?.first_blocked_at ?? now,
|
|
265
265
|
last_checked_at: now,
|
|
266
266
|
last_worked_at: now,
|
package/dist/tickets/queue.js
CHANGED
|
@@ -31,7 +31,7 @@ export function buildNextQueue(ticketDefs, states, queueLimit) {
|
|
|
31
31
|
blockedBy: blockedBy.length ? blockedBy.join(", ") : "None",
|
|
32
32
|
size: ticket.size,
|
|
33
33
|
risk: ticket.risk,
|
|
34
|
-
nextAction: state?.next_action ?? defaultNextAction(ticket, displayStatus, blockedBy),
|
|
34
|
+
nextAction: state?.next_action ?? (displayStatus === "blocked" && !blockedBy.length ? `Resolve blocker: ${state?.blocker_notes ?? "external prerequisite requires recovery"}` : defaultNextAction(ticket, displayStatus, blockedBy)),
|
|
35
35
|
requiredTests: ticket.required_tests.join("; "),
|
|
36
36
|
evidence: state?.evidence ?? "N/A until implemented.",
|
|
37
37
|
likelyFiles: ticket.likely_files.length ? ticket.likely_files.join(", ") : "unknown",
|
|
@@ -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 },
|
package/dist/workflowDb.d.ts
CHANGED
|
@@ -1,7 +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";
|
|
1
7
|
import { type ReadinessProcess } from "./readinessCleanup.js";
|
|
2
8
|
import { type BuildAdmission, type BuildLaunch } from "./buildAdmission.js";
|
|
3
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";
|
|
4
|
-
import type {
|
|
10
|
+
import type { QaDeliveryTurn, QaDeliveryOutcome, QaDeliveryInvocationV3 } from "./qaDeliveryJournal.js";
|
|
5
11
|
import type { BranchResumeSession } from "./branch/resume.js";
|
|
6
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";
|
|
7
13
|
export declare const WORKFLOW_DB_FILE = ".rafi/recovery.sqlite3";
|
|
@@ -205,6 +211,7 @@ export declare class WorkflowDb {
|
|
|
205
211
|
private writerLease?;
|
|
206
212
|
private coordinatorTransition;
|
|
207
213
|
private lineageTransition;
|
|
214
|
+
private workAuthority;
|
|
208
215
|
constructor(projectDir: string, path?: string, readinessAccess?: {
|
|
209
216
|
probeId: string;
|
|
210
217
|
} | {
|
|
@@ -213,6 +220,37 @@ export declare class WorkflowDb {
|
|
|
213
220
|
/** Connection-local SQL fences: helper/reconciler cannot gain general writer rights. */
|
|
214
221
|
private restrictReadinessConnection;
|
|
215
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;
|
|
216
254
|
/** Atomic local changes only; never await provider or filesystem work here. */
|
|
217
255
|
atomic<T>(work: () => T): T;
|
|
218
256
|
buildAdmission(): BuildAdmission | undefined;
|
|
@@ -330,6 +368,7 @@ export declare class WorkflowDb {
|
|
|
330
368
|
}, now?: Date): ContinuityCheckpoint;
|
|
331
369
|
continuityCheckpoints(runId: string, role?: "builder" | "qa"): ContinuityCheckpoint[];
|
|
332
370
|
latestContinuityCheckpoint(runId: string, role: "builder" | "qa"): ContinuityCheckpoint | undefined;
|
|
371
|
+
private assertGraphContinuityAccess;
|
|
333
372
|
continuityHead(runId: string, role: "builder" | "qa" | "run"): ContinuityHead | undefined;
|
|
334
373
|
setContinuityHeadState(runId: string, role: "builder" | "qa", state: ContinuityHeadState, now?: Date): ContinuityHead | undefined;
|
|
335
374
|
recordSession(runId: string, role: string, stream: string, session: string | ProviderSessionRefV1 | undefined, transition: string, settings: ResolvedAgentSettings, now?: Date): void;
|
|
@@ -355,8 +394,12 @@ export declare class WorkflowDb {
|
|
|
355
394
|
choices: PendingHumanDecision["choices"];
|
|
356
395
|
evidence?: PendingHumanDecision["evidence"];
|
|
357
396
|
}, now?: Date): PendingHumanDecision;
|
|
397
|
+
cancelPendingHumanDecisions(runId: string, reason: string, now?: Date): void;
|
|
398
|
+
humanDecisionKey(decisionId: string): string | undefined;
|
|
358
399
|
humanDecision(decisionId: string): PendingHumanDecision | undefined;
|
|
359
400
|
pendingHumanDecisions(runId: string): PendingHumanDecision[];
|
|
401
|
+
decisionContinuationAvailable(runId: string, decisionId: string): boolean;
|
|
402
|
+
nextDecisionContinuationKey(runId: string, decisionId: string): string;
|
|
360
403
|
answeredTicketDecisions(runId: string, scopeRevision: string): PendingHumanDecision[];
|
|
361
404
|
/** Unconsumed answers to an older definition must not silently reopen a ticket. */
|
|
362
405
|
staleTicketDecisions(runId: string, scopeRevision: string): PendingHumanDecision[];
|
|
@@ -384,6 +427,7 @@ export declare class WorkflowDb {
|
|
|
384
427
|
operation(idempotencyKey: string): OperationRecord | undefined;
|
|
385
428
|
operations(runId: string): OperationRecord[];
|
|
386
429
|
putEvidence(kind: "handoff" | "diff" | "test" | "qa", value: string | Buffer, now?: Date): string;
|
|
430
|
+
registerGraphEvidence(value: string | Buffer, access: GraphDerivedAccess | GraphDerivedAccess[]): void;
|
|
387
431
|
getEvidence(digest: string): Buffer | undefined;
|
|
388
432
|
putQaRecoveryHead(input: Omit<QaRecoveryHeadRecord, "updatedAt">, now?: Date): QaRecoveryHeadRecord;
|
|
389
433
|
qaRecoveryHead(runId: string, ticketId?: string): QaRecoveryHeadRecord | undefined;
|
|
@@ -398,8 +442,8 @@ export declare class WorkflowDb {
|
|
|
398
442
|
qaRemediationAttempts(runId: string, ticketId: string): QaRemediationAttemptRecord[];
|
|
399
443
|
qaRemediationAttempt(attemptId: string): QaRemediationAttemptRecord | undefined;
|
|
400
444
|
recordQaDeliveryInvocation(record: QaDeliveryInvocationV3): void;
|
|
401
|
-
recordQaDeliveryTurn(turn:
|
|
402
|
-
qaDeliveryTurns(operationId: string):
|
|
445
|
+
recordQaDeliveryTurn(turn: QaDeliveryTurn): void;
|
|
446
|
+
qaDeliveryTurns(operationId: string): QaDeliveryTurn[];
|
|
403
447
|
/** Attempts, including ambiguous intents, are the common legacy/production ledger. */
|
|
404
448
|
qaAutomaticRemediationCount(runId: string, ticketId: string): number;
|
|
405
449
|
authorizeQaRemediation(runId: string, ticketId: string, reviewAttemptId: string, reason: string): string;
|
|
@@ -474,7 +518,8 @@ export declare class WorkflowDb {
|
|
|
474
518
|
setQaReportDisposition(reportDigest: string, disposition: QaReportDisposition, reason: string, now?: Date): void;
|
|
475
519
|
markQaReportsRecheckRequired(runId: string, ticketId: string, reason: string, now?: Date): void;
|
|
476
520
|
resolveQaReportsAfterPass(runId: string, ticketId: string, now?: Date): void;
|
|
477
|
-
|
|
521
|
+
authorizeContractQaWaiver(runId: string, workId: string, decisionId: string): string;
|
|
522
|
+
commitQaWaiver(runId: string, ticketId: string, expectedRevision: number, reason: string, now?: Date, authorizationRef?: string): QaReducerStateV2;
|
|
478
523
|
builderRemediationReceipt(operationId: string): BuilderRemediationReceiptV2 | BuilderRemediationReceiptV3 | undefined;
|
|
479
524
|
recordBuilderRemediationReceipt(receipt: BuilderRemediationReceiptV2 | BuilderRemediationReceiptV3): void;
|
|
480
525
|
commitBuilderRemediationSuccess(receipt: BuilderRemediationReceiptV2 | BuilderRemediationReceiptV3, expectedRevision: number, now?: Date): QaReducerStateV2;
|
|
@@ -488,12 +533,13 @@ export declare class WorkflowDb {
|
|
|
488
533
|
receipt?: BuilderRemediationReceiptV2 | BuilderRemediationReceiptV3;
|
|
489
534
|
expectedRevision: number;
|
|
490
535
|
}, now?: Date): QaReducerStateV2;
|
|
536
|
+
private assertContractCertificate;
|
|
491
537
|
issueQaPassCertificate(input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, now?: Date): QaPassCertificateV2;
|
|
492
538
|
commitQaPass(input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, expectedRevision: number, now?: Date): QaPassCertificateV2;
|
|
493
539
|
/** Accept a passing verdict, its review-attempt outcome, report resolution, certificate, and reducer edge atomically. */
|
|
494
540
|
commitQaPassAttempt(attemptId: string, input: Omit<QaPassCertificateV2, "version" | "certificateId" | "unresolvedReportCount" | "issuedAt">, detail: string, expectedRevision: number, now?: Date): QaPassCertificateV2;
|
|
495
541
|
consumeQaPassCertificate(runId: string, ticketId: string, certificateId: string, consumer: string, now?: Date): QaPassCertificateV2;
|
|
496
|
-
invalidateUnconsumedQaPassCertificates(runId: string, ticketId: string, reason: string, now?: Date): void;
|
|
542
|
+
invalidateUnconsumedQaPassCertificates(runId: string, ticketId: string, reason: string, now?: Date, issuedBefore?: string): void;
|
|
497
543
|
invalidateQaPassBeforeFinalization(input: {
|
|
498
544
|
runId: string;
|
|
499
545
|
ticketId: string;
|