Address PR review feedback (#1363)
Greptile + CodeRabbit findings across core/engine/dashboard. Stale findings (written against earlier commits) verified and skipped; valid ones fixed. Engine: - await-input: do not clear pausedReason in the /input route (the node's marker must survive unpause); the node clears it after consuming input. Embed a colon-free epoch watermark in the marker so only post-pause steering comments count as the reply (ISO timestamps collided with the colon separator and the dashboard question parser). - gate nodes without a registered runner now fail closed (throw) instead of silently passing. - a thrown interpreter error in maybeExecuteWorkflowGraph now falls back to the legacy pipeline instead of stranding the task in-progress. - approved-CLI path clears the stale awaiting-cli-approval status/marker. Core: - persist+cascade workflow selection: purge task_workflow_selection rows and compiled workflow_steps on physical task deletes; migration 105 cleans already-orphaned rows; catch-cleanup for materialized steps when the owner write fails; WF-id allocation now in a BEGIN IMMEDIATE transaction. - compiler validates the canonical execute->review->merge seam order (rejects duplicate/misordered seams). - disk-backed reopen round-trip + tightened updatedAt/list assertions. Dashboard: - WorkflowSelector clears stale default/options across project changes and on fetch failure; InlineCreateCard/NewTaskModal reset the workflow on all clear/discard paths and include it in dirty-state. - WorkflowNodeEditor: config-key deletion now persists; removed an invalid eslint-disable that was itself a hard lint error. - TaskCard: single status badge for awaiting-input (no duplicate). - WorkflowResultsTab: reset paused-action UI between pauses; surface resume/approve failures inline. - TaskDetailModal: treat awaiting-user-input/awaiting-cli-approval/paused as not-in-progress for the live-log subscription. - workflow-flow-mapping: don't write synthetic node names back into IR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -102,10 +102,36 @@ export function validateLinearity(ir: WorkflowIr): WorkflowCompileError | null {
|
||||
}
|
||||
|
||||
// Reachability: the single main path must reach end and cover every node.
|
||||
// While walking, enforce the canonical seam pipeline: each of execute/review/
|
||||
// merge may appear at most once and only in that order. The compiler treats
|
||||
// seams as a fixed execute → review → merge boundary (merge flips pre- to
|
||||
// post-merge), so out-of-order or duplicate seams would compile inconsistently
|
||||
// with the runtime contract.
|
||||
const expectedSeamOrder = ["execute", "review", "merge"] as const;
|
||||
const seenSeams = new Set<string>();
|
||||
let nextExpectedSeamIndex = 0;
|
||||
const visited = new Set<string>();
|
||||
let cursor: string | undefined = startNode.id;
|
||||
while (cursor && !visited.has(cursor)) {
|
||||
visited.add(cursor);
|
||||
const node = nodesById.get(cursor);
|
||||
const seam = node ? seamOf(node) : undefined;
|
||||
if (seam) {
|
||||
if (seenSeams.has(seam)) {
|
||||
return new WorkflowCompileError(`seam '${seam}' appears more than once`);
|
||||
}
|
||||
while (
|
||||
nextExpectedSeamIndex < expectedSeamOrder.length &&
|
||||
expectedSeamOrder[nextExpectedSeamIndex] !== seam
|
||||
) {
|
||||
nextExpectedSeamIndex += 1;
|
||||
}
|
||||
if (expectedSeamOrder[nextExpectedSeamIndex] !== seam) {
|
||||
return new WorkflowCompileError("seams must follow the execute -> review -> merge order");
|
||||
}
|
||||
seenSeams.add(seam);
|
||||
nextExpectedSeamIndex += 1;
|
||||
}
|
||||
if (cursor === endNode.id) break;
|
||||
cursor = mainEdge(outgoing.get(cursor) ?? [])?.to;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user