- restore customFields on unarchive; reconcile all occupants on field-schema edits (store.ts)
- serialize per-field saves + controlled inputs in TaskFieldsSection (race fixes)
- fn_workflow_get includes layout; Array.isArray guards in validateCodeNodeSources
- per-instance graphStepActiveContext keying; rebase in instance worktree; clear run-once memo on RETHINK
- GET /api/step-parsers + registry-backed parser select (plugin parsers reachable from editor)
- translate new workflowNodes/workflowFields strings across all 5 non-en locales
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migration 102 defers the destructive agentLogEntries drop until TaskStore
copies legacy rows to JSONL and writes the __meta guard, then relies on a
second init() pass gated on schemaVersion < SCHEMA_VERSION. Migrations
103-105 bump the version to 105 on the first pass, so the second pass never
fired and the legacy table survived forever. Make the drop version-independent
in migrate() and trigger the re-init whenever the legacy table remains.
Also pin secrets-schema.test.ts to String(SCHEMA_VERSION) instead of the
hardcoded "102" string the schema bump invalidated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Settings → Experimental gains a 'Workflow Graph Engine — dual-observe parity
(diagnostic)' toggle for the workflowInterpreterDualObserve flag.
- store.getWorkflowParitySummary() aggregates the workflow:parity-observed /
workflow:parity-drift run-audit events into the graduation signal: agree-rate,
per-field drift counts, and recent drift samples. Covered by
workflow-parity-summary.test.ts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve the two needs-human findings from PR #1363 review, plus surface the flag.
Merge seam (project-engine.ts):
- manualMergeResolvers is now a per-task LIST of waiters. Both the dashboard
"merge now" path and the interpreter merge seam call onMerge, so a single
resolver per task let the second caller overwrite (and strand) the first.
All resolve/reject/requeue/late-resolver/shutdown sites drain the whole list.
- New requestInterpreterMerge() honors auto-merge eligibility: when autoMerge
is off (or the task isn't merge-ready) it returns merged:false instead of
forcing the merge, so a graph merge node can't override an autoMerge-off
project — it parks the task in review for a human. setMergeRequester now wires
the interpreter to this gate rather than the human bypass.
Selection race (store.ts):
- selectTaskWorkflow/clearTaskWorkflowSelection now hold one withTaskLock across
their whole mutate sequence. Extracted updateTaskUnlocked() (the per-task lock
is non-reentrant, so they couldn't wrap the public updateTask without
deadlocking) and call that inside the lock.
Settings:
- Add "Workflow Graph Engine (run custom workflows)" to the Experimental
Features list so the workflowGraphExecutor flag is a labeled toggle in
Settings → Experimental, not just a raw key.
Tests: interpreter-merge-seam.test.ts (multi-waiter resolve/reject + autoMerge
eligibility gate); existing merge lifecycle/bypass/selection suites still pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
Main independently landed the same pausedReason persistence fix (column in
the task INSERT/upsert, TaskRow type, rowToTask mapping) with the column
ordered between paused and userPaused; adopt main's ordering and drop this
branch's duplicate entries so the values array stays aligned. Union the
dashboard package.json deps (main's compound-engineering plugin alongside
this branch's sorted pi-coding-agent/cli-printing-press/cursor-runtime).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both sides bootstrapped CONCEPTS.md — kept main's broader structure (Missions,
Merge lifecycle, CE sessions) and folded the branch-group vocabulary into its
Merge-lifecycle cluster (enriched Shared branch group + Self-healing sweep;
added Branch assignment mode, Landed, Group promotion). Union-merged core
index/store imports; took main's AGENTS.md discoverability wording. Also adds
execFile to the two child_process test mocks that only stubbed exec (the
coordinator's argv-based git calls now require it).
- syncGroupPrCallback forwards owner/repo to updatePr (multi-project daemons
could 404 or edit an unrelated same-numbered PR via process-cwd fallback)
- merger background reconcile re-reads the group before persisting and skips
the write when the PR snapshot changed (stale-write race vs newer open PR)
- branchContext.groupId trimmed on metadata emit/parse round-trip
- triageSlice non-shared invariant assertions (no groupId, no group row)
Address PR #1363 review findings:
- core: pausedReason was written in-memory and read by SELECT but never
persisted by the task upsert (missing column/value) nor mapped back in
rowToTask — so it was lost on every reload. Add it to both. This is the
root cause behind the workflow CLI-approval / await-input pause cycle and
also fixes token-budget / worktrunk pause reasons silently vanishing.
- dashboard: approve-cli now derives the approved command exclusively from
the task's pausedReason; a caller-supplied body.command is ignored, closing
a trust-on-first-use bypass.
- engine: await-input nodes resume only when THIS node paused the task (its
marker on pausedReason), not on any pre-existing steering comment.
- engine: write-capable custom nodes (coding/script/CLI) are refused until a
task worktree exists, so they never mutate the shared repo root before the
execute seam.
- engine: document cliSkipApproval as an intentional workflow-author-only
escape hatch; scriptName is now const (ESLint).
- tests: pausedReason round-trip coverage in store-persistence; approve-cli
body-command-ignored + no-pending-command coverage; built-in-aware list
assertion in workflow-routes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ship read-only built-in workflows surfaced in the workflow list and selectable
like any workflow: 'Coding' (the existing execute->review->merge pipeline as a
graph), 'Quick fix' (no review), 'Review-heavy' (extra security gate), and
'Compound engineering' (plan -> implement -> review -> code-review gate ->
merge -> document, invoking ce-plan/ce-code-review/ce-compound skills). Built-ins
lead the list, resolve by id for selection, and reject edit/delete.
CLI prompt nodes now accept a raw cliCommand (any command + args), not just
named scripts. A raw command must be explicitly approved by the user before it
runs: an unapproved command pauses the task (status awaiting-cli-approval) with
the command shown; the user approves via POST /tasks/:id/workflow/approve-cli,
which records the exact command string in settings.approvedWorkflowCliCommands
and resumes. Named scripts (settings.scripts) still never require approval.
Adds POST /tasks/:id/workflow/input to answer await-input nodes (records a
steering comment + resumes).