feat(FN-4368): add workflow step gateMode schema and types
Fusion-Task-Id: FN-4368 Fusion-Task-Lineage: ac9b12e6-2101-4b51-89a0-6422fd7850ed
This commit is contained in:
@@ -688,4 +688,37 @@ describe("schema migration", () => {
|
||||
|
||||
db.close();
|
||||
});
|
||||
|
||||
it("adds workflow_steps.gateMode and backfills prompt rows to advisory", () => {
|
||||
const db = new Database(fusionDir);
|
||||
db.exec("CREATE TABLE IF NOT EXISTS __meta (key TEXT PRIMARY KEY, value TEXT)");
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS workflow_steps (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
mode TEXT NOT NULL DEFAULT 'prompt',
|
||||
phase TEXT NOT NULL DEFAULT 'pre-merge',
|
||||
prompt TEXT NOT NULL DEFAULT '',
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
createdAt TEXT NOT NULL,
|
||||
updatedAt TEXT NOT NULL
|
||||
)
|
||||
`);
|
||||
db.exec("INSERT INTO __meta (key, value) VALUES ('schemaVersion', '75')");
|
||||
db.exec("INSERT INTO __meta (key, value) VALUES ('lastModified', '1000')");
|
||||
db.exec("INSERT INTO workflow_steps (id, name, description, mode, phase, prompt, enabled, createdAt, updatedAt) VALUES ('WS-001', 'Prompt', 'Prompt step', 'prompt', 'pre-merge', 'p', 1, '2025-01-01T00:00:00.000Z', '2025-01-01T00:00:00.000Z')");
|
||||
db.exec("INSERT INTO workflow_steps (id, name, description, mode, phase, prompt, enabled, createdAt, updatedAt) VALUES ('WS-002', 'Script', 'Script step', 'script', 'pre-merge', '', 1, '2025-01-01T00:00:00.000Z', '2025-01-01T00:00:00.000Z')");
|
||||
|
||||
db.init();
|
||||
|
||||
const rows = db.prepare("SELECT id, mode, gateMode FROM workflow_steps ORDER BY id ASC").all() as Array<{ id: string; mode: string; gateMode: string }>;
|
||||
expect(rows).toEqual([
|
||||
{ id: "WS-001", mode: "prompt", gateMode: "advisory" },
|
||||
{ id: "WS-002", mode: "script", gateMode: "gate" },
|
||||
]);
|
||||
expect(db.getSchemaVersion()).toBe(76);
|
||||
|
||||
db.close();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -323,6 +323,7 @@ CREATE TABLE IF NOT EXISTS workflow_steps (
|
||||
description TEXT NOT NULL,
|
||||
mode TEXT NOT NULL DEFAULT 'prompt',
|
||||
phase TEXT NOT NULL DEFAULT 'pre-merge',
|
||||
gateMode TEXT NOT NULL DEFAULT 'gate',
|
||||
prompt TEXT NOT NULL DEFAULT '',
|
||||
gateMode TEXT NOT NULL DEFAULT 'advisory',
|
||||
toolMode TEXT,
|
||||
@@ -1769,6 +1770,7 @@ export class Database {
|
||||
description TEXT NOT NULL,
|
||||
mode TEXT NOT NULL DEFAULT 'prompt',
|
||||
phase TEXT NOT NULL DEFAULT 'pre-merge',
|
||||
gateMode TEXT NOT NULL DEFAULT 'gate',
|
||||
prompt TEXT NOT NULL DEFAULT '',
|
||||
gateMode TEXT NOT NULL DEFAULT 'advisory',
|
||||
toolMode TEXT,
|
||||
@@ -1799,6 +1801,7 @@ export class Database {
|
||||
description,
|
||||
mode,
|
||||
phase,
|
||||
gateMode,
|
||||
prompt,
|
||||
gateMode,
|
||||
toolMode,
|
||||
@@ -1823,6 +1826,7 @@ export class Database {
|
||||
|
||||
const mode = step.mode === "script" ? "script" : "prompt";
|
||||
const phase = step.phase === "post-merge" ? "post-merge" : "pre-merge";
|
||||
const gateMode = step.mode === "script" ? "gate" : "advisory";
|
||||
const createdAt =
|
||||
typeof step.createdAt === "string" && step.createdAt
|
||||
? step.createdAt
|
||||
@@ -1839,6 +1843,7 @@ export class Database {
|
||||
description,
|
||||
mode,
|
||||
phase,
|
||||
gateMode,
|
||||
typeof step.prompt === "string" ? step.prompt : "",
|
||||
step.gateMode === "gate" || step.gateMode === "advisory"
|
||||
? step.gateMode
|
||||
|
||||
@@ -238,6 +238,7 @@ export interface ModelPreset {
|
||||
/** Execution mode for a workflow step. */
|
||||
export type WorkflowStepMode = "prompt" | "script";
|
||||
export type WorkflowStepToolMode = "readonly" | "coding";
|
||||
export type WorkflowStepGateMode = "gate" | "advisory";
|
||||
|
||||
/** Lifecycle phase for workflow step execution. */
|
||||
export type WorkflowStepPhase = "pre-merge" | "post-merge";
|
||||
@@ -256,6 +257,8 @@ export interface WorkflowStep {
|
||||
mode: WorkflowStepMode;
|
||||
/** Lifecycle phase — "pre-merge" runs before merge (default), "post-merge" runs after merge success */
|
||||
phase?: WorkflowStepPhase;
|
||||
/** Gate behavior — gate blocks merge/auto-revive on failure, advisory records non-blocking findings. */
|
||||
gateMode: WorkflowStepGateMode;
|
||||
/** Full agent prompt to execute when this step runs (used when mode is "prompt") */
|
||||
prompt: string;
|
||||
/** Whether failures should block merge (`gate`) or be informational (`advisory`). */
|
||||
@@ -354,6 +357,8 @@ export interface WorkflowStepInput {
|
||||
mode?: WorkflowStepMode;
|
||||
/** Lifecycle phase — defaults to "pre-merge" if not specified */
|
||||
phase?: WorkflowStepPhase;
|
||||
/** Gate behavior — defaults by mode (prompt: advisory, script: gate) when omitted. */
|
||||
gateMode?: WorkflowStepGateMode;
|
||||
/** Agent prompt (used when mode is "prompt"). Optional — can be AI-generated later via refinement. */
|
||||
prompt?: string;
|
||||
/** Failure behavior. Defaults to advisory for prompt mode and gate for script mode. */
|
||||
@@ -386,6 +391,8 @@ export interface WorkflowStepResult {
|
||||
status: "passed" | "failed" | "advisory_failure" | "skipped" | "pending";
|
||||
/** Output from the workflow step agent (findings, errors, etc.) */
|
||||
output?: string;
|
||||
/** Optional non-blocking notes for advisory findings surfaced in task detail UI. */
|
||||
notes?: string;
|
||||
/** ISO-8601 timestamp when the step started */
|
||||
startedAt?: string;
|
||||
/** ISO-8601 timestamp when the step completed */
|
||||
|
||||
Reference in New Issue
Block a user