@exaudeus/workrail 3.70.1 → 3.70.2

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.
@@ -4,6 +4,55 @@ Workflow and feature ideas that are worth capturing but not yet planned or desig
4
4
 
5
5
  ---
6
6
 
7
+ ## `jumpIf`: conditional step jumps with per-target jump counter (Apr 23, 2026)
8
+
9
+ **Problem:** Workflows with investigation or iterative refinement patterns (bug-investigation, mr-review) can exhaust their hypothesis set and reach an `inconclusive_but_narrowed` state with no structural way to restart an earlier phase. The only current options are: (1) prose guidance inside loop decision steps telling the agent to "reopen the shortlist" (unreliable), or (2) nested loops (not yet supported by the schema). A `jumpIf` primitive would let any step conditionally restart execution from an earlier step when a context condition is met.
10
+
11
+ **Proposed design:**
12
+
13
+ A `jumpIf` field on any step declaration:
14
+
15
+ ```json
16
+ {
17
+ "id": "phase-4b-loop-decision",
18
+ "jumpIf": {
19
+ "condition": { "var": "diagnosisType", "equals": "inconclusive_but_narrowed" },
20
+ "target": "phase-2-hypothesis-generation-and-shortlist",
21
+ "maxJumps": 2
22
+ }
23
+ }
24
+ ```
25
+
26
+ **Engine behavior:**
27
+ - When a step completes and its `jumpIf.condition` is met, the engine checks the per-session jump counter for `target`
28
+ - Counter is derived from the event log: count `jump_recorded` events where `toStepId === target` -- fully append-only and replayable
29
+ - If `counter < maxJumps`: append `jump_recorded` event, create fresh nodeIds for `target` and all subsequent steps, mint a new continueToken pointing at the fresh target node
30
+ - If `counter >= maxJumps`: jump is blocked, execution falls through to the next step after the `jumpIf` step (safety cap, not an error)
31
+ - Fresh nodeIds mean no dedupeKey collisions and no DAG cycles -- the same step definition can appear multiple times in the session DAG as distinct nodes, same as loop iterations
32
+
33
+ **Why this is safe:**
34
+ - `maxJumps` is a required field -- no unbounded loops possible
35
+ - Counter is derivable from the append-only event log -- no mutable state
36
+ - The token system is unaffected -- each jump produces a fresh continueToken encoding a fresh nodeId
37
+ - Fall-through on limit reached is predictable and operator-visible
38
+
39
+ **Open design questions:**
40
+ - `maxJumps` default if omitted -- probably require it explicitly (same as `maxIterations` on loops, which is also required)
41
+ - DAG console rendering -- backward jumps create "re-entry" edges. Needs a distinct visual treatment (dashed edge? "JUMP x2" label?) -- tracked separately under console execution trace work
42
+ - Interaction with `runCondition` -- if a jumped-to step has a `runCondition` that evaluates false at re-entry time, does the engine skip it and advance? Probably yes, same as first-time evaluation.
43
+ - Whether `jumpIf` and loop `body` can coexist on the same step -- probably yes, they're independent control-flow mechanisms
44
+
45
+ **Scope when ready to implement:**
46
+ - `spec/workflow.schema.json`: add `jumpIf` to `standardStep`
47
+ - `spec/authoring-spec.json`: add authoring rule
48
+ - Compiler: validate `target` resolves to a reachable earlier step, `maxJumps >= 1`
49
+ - Engine (`src/v2/durable-core/`): new `jump_recorded` event kind, counter derivation, fresh nodeId creation on jump
50
+ - Console DAG: render jump edges distinctly
51
+
52
+ **Motivation workflow:** `wr.bug-investigation` -- when all hypotheses are eliminated and `diagnosisType === 'inconclusive_but_narrowed'`, jump back to phase 2 (hypothesis generation) with the eliminated theories in context, up to 2 times before falling through to validation/handoff.
53
+
54
+ ---
55
+
7
56
  ## Research Notes: Autonomous Platform Vision (Apr 14, 2026)
8
57
 
9
58
  ### Common-Ground relationship + cross-repo execution model
@@ -4542,22 +4591,22 @@ worktrain console --workspace ~/git/myproject # workspace-scoped view
4542
4591
  ### What shipped (Apr 17-18)
4543
4592
 
4544
4593
  **Daemon stabilization:**
4545
- - `report_issue` tool -- agents call this instead of dying silently; structured JSON written to `~/.workrail/issues/<sessionId>.jsonl`, event emitted to daemon stream, WORKTRAIN_STUCK marker in `WorkflowRunResult`
4546
- - Richer `BASE_SYSTEM_PROMPT` -- baked-in behavioral principles (oracle hierarchy, self-directed reasoning, workflow-as-contract, silent failure policy) rather than relying on soul file alone
4547
- - `/bin/bash` for Bash tool -- process substitution `<(...)` and other bash-specific syntax now works
4548
- - `DaemonEventEmitter` -- structured event stream at `~/.workrail/events/daemon/YYYY-MM-DD.jsonl`
4549
- - Self-configuration -- `triggers.yml`, upgraded `daemon-soul.md` (WorkRail-specific rules + coding philosophy), `AGENTS.md` WorkTrain section
4594
+ - `report_issue` tool -- agents call this instead of dying silently; structured JSON written to `~/.workrail/issues/<sessionId>.jsonl`, event emitted to daemon stream, WORKTRAIN_STUCK marker in `WorkflowRunResult`
4595
+ - Richer `BASE_SYSTEM_PROMPT` -- baked-in behavioral principles (oracle hierarchy, self-directed reasoning, workflow-as-contract, silent failure policy) rather than relying on soul file alone
4596
+ - `/bin/bash` for Bash tool -- process substitution `<(...)` and other bash-specific syntax now works
4597
+ - `DaemonEventEmitter` -- structured event stream at `~/.workrail/events/daemon/YYYY-MM-DD.jsonl`
4598
+ - Self-configuration -- `triggers.yml`, upgraded `daemon-soul.md` (WorkRail-specific rules + coding philosophy), `AGENTS.md` WorkTrain section
4550
4599
 
4551
4600
  **Workflow library:**
4552
- - mr-review v2.6 -- `philosophy_alignment` reviewer family; scoped philosophy extraction in fact packet; 7th coverage domain; "is this the right design?" framing
4553
- - wfw v2.5 -- phases 2 and 3 split into dedicated prep-step design steps (2a/2b, 3a/3b); principle: assessments need dedicated prep steps, not on-the-fly evidence gathering
4554
- - Clean workflow display names across library (removed `v2 •`, `Lean •`, etc.)
4555
- - `philosophy.mdc` created at `~/.firebender/commands/philosophy.mdc` -- MR review subagents now evaluate findings against coding philosophy
4601
+ - mr-review v2.6 -- `philosophy_alignment` reviewer family; scoped philosophy extraction in fact packet; 7th coverage domain; "is this the right design?" framing
4602
+ - wfw v2.5 -- phases 2 and 3 split into dedicated prep-step design steps (2a/2b, 3a/3b); principle: assessments need dedicated prep steps, not on-the-fly evidence gathering
4603
+ - Clean workflow display names across library (removed `v2 •`, `Lean •`, etc.)
4604
+ - `philosophy.mdc` created at `~/.firebender/commands/philosophy.mdc` -- MR review subagents now evaluate findings against coding philosophy
4556
4605
 
4557
4606
  **Integrations and infrastructure:**
4558
- - GitLab polling triggers fully merged (#404) -- zero-webhook MR polling
4559
- - TS6 forward-compat tsconfig fixes (#401) -- unblocks TypeScript 6 dep bumps
4560
- - Standalone console spec -- `worktrain console` as independent file-reading binary, zero coupling to daemon or MCP server
4607
+ - GitLab polling triggers fully merged (#404) -- zero-webhook MR polling
4608
+ - TS6 forward-compat tsconfig fixes (#401) -- unblocks TypeScript 6 dep bumps
4609
+ - Standalone console spec -- `worktrain console` as independent file-reading binary, zero coupling to daemon or MCP server
4561
4610
 
4562
4611
  ---
4563
4612
 
@@ -5309,19 +5358,19 @@ Long-term (when mobile exists):
5309
5358
 
5310
5359
  ### What works at this commit
5311
5360
 
5312
- - Daemon accepts webhooks, starts sessions, runs workflows end-to-end
5313
- - Sessions advance through all workflow phases autonomously
5314
- - `mr-review-workflow-agentic` v2.6 runs fully -- context gathering, review phases, synthesis loop, validation, handoff
5315
- - `wr.discovery` v3.2.0 runs fully -- with new phase-0-reframe (goal reframing before research)
5316
- - Console shows live sessions via event log (no daemon connection required)
5317
- - MCP server is stable (bridge removed, EPIPE fixed, v3.34.1 published)
5318
- - GitHub + GitLab polling triggers (no webhooks needed)
5319
- - `worktrain init`, `tell`, `inbox`, `spawn`, `await` CLI commands
5320
- - Stuck detection + visibility (`worktrain status`, `worktrain logs --follow`)
5321
- - `complete_step` tool -- daemon manages continueToken, LLM never handles it
5322
- - Assessment gate circuit breaker (stops at 3 blocked attempts, shows artifact format)
5323
- - `worktrain daemon --install` creates launchd service (daemon survives MCP reconnects)
5324
- - Self-configuration (`triggers.yml`, `daemon-soul.md`, `AGENTS.md` for workrail repo)
5361
+ - Daemon accepts webhooks, starts sessions, runs workflows end-to-end
5362
+ - Sessions advance through all workflow phases autonomously
5363
+ - `mr-review-workflow-agentic` v2.6 runs fully -- context gathering, review phases, synthesis loop, validation, handoff
5364
+ - `wr.discovery` v3.2.0 runs fully -- with new phase-0-reframe (goal reframing before research)
5365
+ - Console shows live sessions via event log (no daemon connection required)
5366
+ - MCP server is stable (bridge removed, EPIPE fixed, v3.34.1 published)
5367
+ - GitHub + GitLab polling triggers (no webhooks needed)
5368
+ - `worktrain init`, `tell`, `inbox`, `spawn`, `await` CLI commands
5369
+ - Stuck detection + visibility (`worktrain status`, `worktrain logs --follow`)
5370
+ - `complete_step` tool -- daemon manages continueToken, LLM never handles it
5371
+ - Assessment gate circuit breaker (stops at 3 blocked attempts, shows artifact format)
5372
+ - `worktrain daemon --install` creates launchd service (daemon survives MCP reconnects)
5373
+ - Self-configuration (`triggers.yml`, `daemon-soul.md`, `AGENTS.md` for workrail repo)
5325
5374
 
5326
5375
  ### Current limitations at this commit
5327
5376
 
@@ -5508,10 +5557,10 @@ Artifact: design-candidates-stdio-simplification-2026-04-18.md
5508
5557
 
5509
5558
  ### What additionally shipped since the milestone (commit 473f4bd0)
5510
5559
 
5511
- - **`complete_step` tool** (#569) -- daemon manages continueToken internally, LLM never handles it. Notes required (min 50 chars). `continue_workflow` deprecated.
5512
- - **`spawn_agent` tool** (#573) -- native in-process child session spawning. parentSessionId in session_created event. Depth enforcement. Semaphore bypass. All 4 WorkflowRunResult variants handled.
5513
- - **`complete_step` description fix** (#575) -- removed token-seeking language from deprecated continue_workflow description that would have triggered the LLM to seek a token.
5514
- - **Discovery ran before both implementations** -- wr.discovery validated complete_step approach (found 1 merge blocker fixed), designed spawn_agent architecture (found semaphore deadlock risk avoided).
5560
+ - **`complete_step` tool** (#569) -- daemon manages continueToken internally, LLM never handles it. Notes required (min 50 chars). `continue_workflow` deprecated.
5561
+ - **`spawn_agent` tool** (#573) -- native in-process child session spawning. parentSessionId in session_created event. Depth enforcement. Semaphore bypass. All 4 WorkflowRunResult variants handled.
5562
+ - **`complete_step` description fix** (#575) -- removed token-seeking language from deprecated continue_workflow description that would have triggered the LLM to seek a token.
5563
+ - **Discovery ran before both implementations** -- wr.discovery validated complete_step approach (found 1 merge blocker fixed), designed spawn_agent architecture (found semaphore deadlock risk avoided).
5515
5564
 
5516
5565
  ### Updated limitations
5517
5566
 
@@ -6051,24 +6100,24 @@ Also consolidated from three workflow variants to one canonical file.
6051
6100
 
6052
6101
  ### What shipped since v3.36.0 (Apr 18 -- Apr 19)
6053
6102
 
6054
- - **`wr.shaping`** -- faithful Shape Up shaping workflow (9 steps, two human gates with autonomous fallback)
6055
- - **`coding-task-workflow-agentic` Phase 0.5** -- upstream context detection; skips design phases when solution is pre-specified. Three-workflow pipeline: shaping → discovery → coding.
6056
- - **Coding workflow consolidated** -- from three variants (lean, full, lean.v2) to one canonical file.
6057
- - **HttpServer removed from MCP server** (#601) -- pure stdio. MCP server can no longer accidentally start an HTTP server.
6058
- - **Late-bound goals** (#604) -- `goalTemplate: "{{$.goal}}"` defaults for webhook-driven sessions. Goals can come from the payload, not just the static trigger definition.
6059
- - **Coordinator message queue drain** (#606) -- `pr-review` coordinator reads `~/.workrail/message-queue.jsonl` before each spawn cycle. `worktrain tell stop`, `skip-pr <n>`, `add-pr <n>` work.
6060
- - **Notifications shipped** -- `NotificationService` implemented, wired into `TriggerRouter` via `trigger-listener.ts`. `WORKTRAIN_NOTIFY_MACOS=true` and `WORKTRAIN_NOTIFY_WEBHOOK=<url>` in `~/.workrail/config.json`.
6061
- - **`worktrain run pr-review`** -- fully wired coordinator command. `spawnSession` → `awaitSessions` → `getAgentResult` (session-wide artifact aggregation) → `parseFindingsFromNotes` → route by severity.
6062
- - **`wr.review_verdict` artifact path** -- end-to-end wired: `mr-review-workflow.agentic.v2.json` phase-6 emits it, `artifact-contract-validator.ts` validates it at `continue_workflow` time, coordinator reads it with keyword-scan fallback.
6063
- - **`worktrain logs` / `worktrain health`** -- structured daemon log tailing and per-session health summary. `worktrain status <id>` deprecated in favor of `worktrain health <id>`.
6064
- - **`signal_coordinator` tool** -- agent can emit structured mid-session signals (`progress`, `finding`, `data_needed`, `approval_needed`, `blocked`) without advancing the step.
6065
- - **`ChildWorkflowRunResult` + `assertNever`** -- spawn_agent delivery_failed bug fixed. `delivery_failed` impossible state is compile-time excluded.
6066
- - **`lastStepArtifacts` on `WorkflowRunSuccess`** -- `onComplete` callback forwards artifacts alongside notes. Coordinator can read typed artifacts from result without a separate HTTP call.
6067
- - **`steerRegistry` + POST `/sessions/:id/steer`** -- coordinator injection endpoint wired in daemon console. Running sessions register a steer callback; coordinators can inject mid-session messages via HTTP.
6068
- - **GitHub polling adapters** -- `github_issues_poll` and `github_prs_poll` providers fully implemented alongside existing `gitlab_poll`.
6069
- - **Knowledge graph spike** -- `src/knowledge-graph/` module: DuckDB in-memory + ts-morph indexer + two validation queries. NOT yet wired to an MCP tool (ts-morph in devDependencies).
6070
- - **`worktrain daemon --install`** -- launchd plist creation, load, verify. Daemon survives MCP server reconnects.
6071
- - **Performance sweep** -- April 2026 sweep identified 10 highest-leverage fixes, filed as issues #248-257. Not yet merged.
6103
+ - **`wr.shaping`** -- faithful Shape Up shaping workflow (9 steps, two human gates with autonomous fallback)
6104
+ - **`coding-task-workflow-agentic` Phase 0.5** -- upstream context detection; skips design phases when solution is pre-specified. Three-workflow pipeline: shaping → discovery → coding.
6105
+ - **Coding workflow consolidated** -- from three variants (lean, full, lean.v2) to one canonical file.
6106
+ - **HttpServer removed from MCP server** (#601) -- pure stdio. MCP server can no longer accidentally start an HTTP server.
6107
+ - **Late-bound goals** (#604) -- `goalTemplate: "{{$.goal}}"` defaults for webhook-driven sessions. Goals can come from the payload, not just the static trigger definition.
6108
+ - **Coordinator message queue drain** (#606) -- `pr-review` coordinator reads `~/.workrail/message-queue.jsonl` before each spawn cycle. `worktrain tell stop`, `skip-pr <n>`, `add-pr <n>` work.
6109
+ - **Notifications shipped** -- `NotificationService` implemented, wired into `TriggerRouter` via `trigger-listener.ts`. `WORKTRAIN_NOTIFY_MACOS=true` and `WORKTRAIN_NOTIFY_WEBHOOK=<url>` in `~/.workrail/config.json`.
6110
+ - **`worktrain run pr-review`** -- fully wired coordinator command. `spawnSession` → `awaitSessions` → `getAgentResult` (session-wide artifact aggregation) → `parseFindingsFromNotes` → route by severity.
6111
+ - **`wr.review_verdict` artifact path** -- end-to-end wired: `mr-review-workflow.agentic.v2.json` phase-6 emits it, `artifact-contract-validator.ts` validates it at `continue_workflow` time, coordinator reads it with keyword-scan fallback.
6112
+ - **`worktrain logs` / `worktrain health`** -- structured daemon log tailing and per-session health summary. `worktrain status <id>` deprecated in favor of `worktrain health <id>`.
6113
+ - **`signal_coordinator` tool** -- agent can emit structured mid-session signals (`progress`, `finding`, `data_needed`, `approval_needed`, `blocked`) without advancing the step.
6114
+ - **`ChildWorkflowRunResult` + `assertNever`** -- spawn_agent delivery_failed bug fixed. `delivery_failed` impossible state is compile-time excluded.
6115
+ - **`lastStepArtifacts` on `WorkflowRunSuccess`** -- `onComplete` callback forwards artifacts alongside notes. Coordinator can read typed artifacts from result without a separate HTTP call.
6116
+ - **`steerRegistry` + POST `/sessions/:id/steer`** -- coordinator injection endpoint wired in daemon console. Running sessions register a steer callback; coordinators can inject mid-session messages via HTTP.
6117
+ - **GitHub polling adapters** -- `github_issues_poll` and `github_prs_poll` providers fully implemented alongside existing `gitlab_poll`.
6118
+ - **Knowledge graph spike** -- `src/knowledge-graph/` module: DuckDB in-memory + ts-morph indexer + two validation queries. NOT yet wired to an MCP tool (ts-morph in devDependencies).
6119
+ - **`worktrain daemon --install`** -- launchd plist creation, load, verify. Daemon survives MCP server reconnects.
6120
+ - **Performance sweep** -- April 2026 sweep identified 10 highest-leverage fixes, filed as issues #248-257. Not yet merged.
6072
6121
 
6073
6122
  ### Accurate limitations (as of v3.40.0)
6074
6123
 
@@ -6406,27 +6455,27 @@ Design this as part of the adaptive coordinator (#3). The `touchesUI` flag belon
6406
6455
 
6407
6456
  All five top-priority autonomous pipeline items shipped:
6408
6457
 
6409
- - **#1 -- Worktree isolation + auto-commit** (PR #630) -- Each WorkTrain coding session now runs in an isolated git worktree (`~/.workrail/worktrees/<sessionId>`). `trigger.workspacePath` is never mutated; all tool factories receive `sessionWorkspacePath`. Crash recovery sidecar persists `worktreePath` for orphan cleanup. `delivery-action.ts` asserts HEAD branch before push. `test-task` trigger: `branchStrategy: worktree`, `autoCommit: true`, `autoOpenPR: true`.
6458
+ - **#1 -- Worktree isolation + auto-commit** (PR #630) -- Each WorkTrain coding session now runs in an isolated git worktree (`~/.workrail/worktrees/<sessionId>`). `trigger.workspacePath` is never mutated; all tool factories receive `sessionWorkspacePath`. Crash recovery sidecar persists `worktreePath` for orphan cleanup. `delivery-action.ts` asserts HEAD branch before push. `test-task` trigger: `branchStrategy: worktree`, `autoCommit: true`, `autoOpenPR: true`.
6410
6459
 
6411
- - **#2 -- Stuck detection escalation** (PR #636) -- New `WorkflowRunResult._tag: 'stuck'` discriminant. When `repeated_tool_call` heuristic fires and `stuckAbortPolicy !== 'notify_only'` (default: `'abort'`), daemon aborts the session immediately instead of burning the 30-min wall clock. Writes structured entry to `~/.workrail/outbox.jsonl`. `stuckAbortPolicy` and `noProgressAbortEnabled` configurable per trigger in `agentConfig`. `ChildWorkflowRunResult` updated atomically.
6460
+ - **#2 -- Stuck detection escalation** (PR #636) -- New `WorkflowRunResult._tag: 'stuck'` discriminant. When `repeated_tool_call` heuristic fires and `stuckAbortPolicy !== 'notify_only'` (default: `'abort'`), daemon aborts the session immediately instead of burning the 30-min wall clock. Writes structured entry to `~/.workrail/outbox.jsonl`. `stuckAbortPolicy` and `noProgressAbortEnabled` configurable per trigger in `agentConfig`. `ChildWorkflowRunResult` updated atomically.
6412
6461
 
6413
- - **#3 -- Adaptive pipeline coordinator** (PR #639) -- `worktrain run pipeline --issue N --workspace path` routes tasks to the right pipeline via pure static routing:
6462
+ - **#3 -- Adaptive pipeline coordinator** (PR #639) -- `worktrain run pipeline --issue N --workspace path` routes tasks to the right pipeline via pure static routing:
6414
6463
  - dep-bump + PR number → QUICK_REVIEW (delegates to `runPrReviewCoordinator`)
6415
6464
  - PR/MR number → REVIEW_ONLY
6416
6465
  - `current-pitch.md` exists → IMPLEMENT (coding + PR + review + merge)
6417
6466
  - Default → FULL (discovery → shaping → coding → PR → review → merge)
6418
6467
  - Fix loop cap: 2 iterations max. Escalating audit chain for Critical findings. UX gate for UI-touching tasks. 6 hardcoded timeout constants. Pitch archived after IMPLEMENT/FULL completes.
6419
6468
 
6420
- - **#4 -- GitHub issue queue poll trigger** (PR #637) -- New `github_queue_poll` trigger provider. Polls GitHub issues matching `GitHubQueueConfig` (assignee-based MVP, `label`/`mention`/`query` typed but `not_implemented`). Maturity inference from 3 deterministic heuristics. Idempotency check (conservative: parse errors = active). JSONL decision log at `~/.workrail/queue-poll.jsonl`. `maxTotalConcurrentSessions` cap. Bot identity config (`botName`, `botEmail`).
6469
+ - **#4 -- GitHub issue queue poll trigger** (PR #637) -- New `github_queue_poll` trigger provider. Polls GitHub issues matching `GitHubQueueConfig` (assignee-based MVP, `label`/`mention`/`query` typed but `not_implemented`). Maturity inference from 3 deterministic heuristics. Idempotency check (conservative: parse errors = active). JSONL decision log at `~/.workrail/queue-poll.jsonl`. `maxTotalConcurrentSessions` cap. Bot identity config (`botName`, `botEmail`).
6421
6470
 
6422
- - **#5 -- Context assembly layer** (PR #624, shipped earlier) -- `ContextAssembler` injects git diff summary + prior session notes before turn 1. Feeds into coordinator pre-dispatch.
6471
+ - **#5 -- Context assembly layer** (PR #624, shipped earlier) -- `ContextAssembler` injects git diff summary + prior session notes before turn 1. Feeds into coordinator pre-dispatch.
6423
6472
 
6424
- - **Performance sweep** (all 10 issues #248-257 -- already confirmed complete)
6425
- - **Console session tree** (PR #607 -- parentSessionId rendered in UI)
6426
- - **Daemon file-nav tools** (PR #619) -- Glob, Grep, Edit + upgraded Read/Write with staleness guard
6427
- - **`spawn_agent` artifacts** (PR #613) -- `lastStepArtifacts` surfaced through spawn_agent return
6428
- - **`wr.shaping` workflow** (PR #610) -- faithful Shape Up shaping, 9 steps
6429
- - **Coding workflow Phase 0.5** (PR #610) -- upstream context detection, three-workflow pipeline
6473
+ - **Performance sweep** (all 10 issues #248-257 -- already confirmed complete)
6474
+ - **Console session tree** (PR #607 -- parentSessionId rendered in UI)
6475
+ - **Daemon file-nav tools** (PR #619) -- Glob, Grep, Edit + upgraded Read/Write with staleness guard
6476
+ - **`spawn_agent` artifacts** (PR #613) -- `lastStepArtifacts` surfaced through spawn_agent return
6477
+ - **`wr.shaping` workflow** (PR #610) -- faithful Shape Up shaping, 9 steps
6478
+ - **Coding workflow Phase 0.5** (PR #610) -- upstream context detection, three-workflow pipeline
6430
6479
 
6431
6480
  ### WorkTrain current capabilities (v3.45.0)
6432
6481
 
@@ -7497,22 +7546,22 @@ Medium for the cleanup command (quality of life, stops log noise). High for star
7497
7546
 
7498
7547
  **All five autonomous pipeline items (previously recorded) plus:**
7499
7548
 
7500
- - **Discovery loop fix** (#748) -- three coupled fixes: thread `maxSessionMinutes` through `spawnSession` (sessions now get 55/35/65 min instead of 30 min default), inspect `PipelineOutcome` in polling-scheduler and apply `worktrain:in-progress` label on escalation, write issue-ownership sidecar for cross-restart idempotency
7501
- - **In-process `awaitSessions` and `getAgentResult`** (#741) -- replaced HTTP calls to the daemon's own console with direct `ConsoleService` access
7502
- - **Try/catch on all coordinator I/O** (#740) -- `getAgentResult`, `pollForPR`, `postToOutbox` all wrapped; coordinator no longer crashes on I/O failure
7503
- - **Dispatch dedup prealloc bypass** (#744) -- `dispatch()` now bypasses dedup for pre-allocated sessions, fixing the zombie session bug that prevented discovery from starting
7504
- - **Promise.race crash fix** (#733) -- worktrees scan timeout no longer crashes the daemon via unhandled rejection
7505
- - **Trigger validator** (#690) -- `worktrain trigger validate` command, `validateTriggerStrict()` pure function
7506
- - **`worktrain trigger poll`** (#697) -- force immediate poll cycle on any queue trigger
7507
- - **`worktrain trigger test`** (#656) -- dry-run showing what would dispatch
7508
- - **Auto-load ~/.workrail/.env** (#673) -- daemon reads secrets from .env automatically
7509
- - **Daemon lifecycle events** (#674) -- `session_aborted` on SIGTERM, `daemon_heartbeat` every 30s
7510
- - **Attribution signals** (#658) -- `[WT]` PR title prefix, `Co-authored-by: WorkTrain` commit trailers, `worktrain:generated` label
7511
- - **Secret scan before push** (#660) -- pattern-based scan blocks commits with leaked credentials
7512
- - **Unified logs stream** (#680) -- `worktrain logs` now merges daemon events, queue-poll.jsonl, and filtered stderr
7513
- - **Stale lock file handling** (#705) -- validates lock file PID before trusting port discovery
7514
- - **5 architectural audits** (docs/design/) -- coordinator access, error handling, testability, type bloat, memory management
7515
- - **Stale user workflow cleanup** -- removed old copies from `~/.workrail/workflows/` that were causing ValidationError noise
7549
+ - **Discovery loop fix** (#748) -- three coupled fixes: thread `maxSessionMinutes` through `spawnSession` (sessions now get 55/35/65 min instead of 30 min default), inspect `PipelineOutcome` in polling-scheduler and apply `worktrain:in-progress` label on escalation, write issue-ownership sidecar for cross-restart idempotency
7550
+ - **In-process `awaitSessions` and `getAgentResult`** (#741) -- replaced HTTP calls to the daemon's own console with direct `ConsoleService` access
7551
+ - **Try/catch on all coordinator I/O** (#740) -- `getAgentResult`, `pollForPR`, `postToOutbox` all wrapped; coordinator no longer crashes on I/O failure
7552
+ - **Dispatch dedup prealloc bypass** (#744) -- `dispatch()` now bypasses dedup for pre-allocated sessions, fixing the zombie session bug that prevented discovery from starting
7553
+ - **Promise.race crash fix** (#733) -- worktrees scan timeout no longer crashes the daemon via unhandled rejection
7554
+ - **Trigger validator** (#690) -- `worktrain trigger validate` command, `validateTriggerStrict()` pure function
7555
+ - **`worktrain trigger poll`** (#697) -- force immediate poll cycle on any queue trigger
7556
+ - **`worktrain trigger test`** (#656) -- dry-run showing what would dispatch
7557
+ - **Auto-load ~/.workrail/.env** (#673) -- daemon reads secrets from .env automatically
7558
+ - **Daemon lifecycle events** (#674) -- `session_aborted` on SIGTERM, `daemon_heartbeat` every 30s
7559
+ - **Attribution signals** (#658) -- `[WT]` PR title prefix, `Co-authored-by: WorkTrain` commit trailers, `worktrain:generated` label
7560
+ - **Secret scan before push** (#660) -- pattern-based scan blocks commits with leaked credentials
7561
+ - **Unified logs stream** (#680) -- `worktrain logs` now merges daemon events, queue-poll.jsonl, and filtered stderr
7562
+ - **Stale lock file handling** (#705) -- validates lock file PID before trusting port discovery
7563
+ - **5 architectural audits** (docs/design/) -- coordinator access, error handling, testability, type bloat, memory management
7564
+ - **Stale user workflow cleanup** -- removed old copies from `~/.workrail/workflows/` that were causing ValidationError noise
7516
7565
 
7517
7566
  ### Current pipeline state (live)
7518
7567
 
@@ -7591,30 +7640,30 @@ Discovery session `ecf359d7` running: 77 turns, 11 step advances (active, making
7591
7640
  This was a major session covering daemon/console separation, metrics infrastructure, and workflow stability fixes.
7592
7641
 
7593
7642
  **Architecture -- daemon/console/MCP separation:**
7594
- - **Delete daemon-console.ts** (#753) -- daemon no longer bundles an embedded console; `worktrain console` is now the sole console entry point
7595
- - **Remove dead steer/poll endpoints** (#755) -- deleted `worktrain trigger poll` CLI and the steer/poll HTTP endpoints that were only used by the deleted daemon-console
7596
- - **Wire workflow catalog into standalone console** (#783, open) -- `worktrain console` Workflows tab now works without the MCP server running; `EnhancedMultiSourceWorkflowStorage` constructed directly in `standalone-console.ts`
7643
+ - **Delete daemon-console.ts** (#753) -- daemon no longer bundles an embedded console; `worktrain console` is now the sole console entry point
7644
+ - **Remove dead steer/poll endpoints** (#755) -- deleted `worktrain trigger poll` CLI and the steer/poll HTTP endpoints that were only used by the deleted daemon-console
7645
+ - **Wire workflow catalog into standalone console** (#783, open) -- `worktrain console` Workflows tab now works without the MCP server running; `EnhancedMultiSourceWorkflowStorage` constructed directly in `standalone-console.ts`
7597
7646
 
7598
7647
  **Metrics infrastructure (6-step sequence, all merged):**
7599
- - **timestampMs on events** (#768, #772) -- `DomainEventEnvelopeV1Schema` now has required `timestampMs`; backfill script at `scripts/backfill-timestamps.ts`
7600
- - **`run_completed` event** (#773) -- emitted on successful session completion with `startGitSha`, `endGitSha`, `agentCommitShas`, `captureConfidence`, `durationMs`
7601
- - **Authoring docs: metrics_* keys** (#767) -- `metricsProfile` field and SHA accumulation convention documented in `docs/authoring-v2.md`
7602
- - **`projectSessionMetricsV2` projection** (#771) -- pure projection reading `run_completed` + `context_set metrics_*` keys, wired into `ConsoleSessionSummary`
7603
- - **Console metrics display** (#777) -- `SessionMetricsSection` in session detail view; `GET /api/v2/sessions/:id/diff-summary` endpoint
7604
- - **`stats-summary.json` writer** (#769) -- `~/.workrail/data/stats-summary.json` aggregated from `execution-stats.jsonl`, written post-session and every 30s heartbeat
7648
+ - **timestampMs on events** (#768, #772) -- `DomainEventEnvelopeV1Schema` now has required `timestampMs`; backfill script at `scripts/backfill-timestamps.ts`
7649
+ - **`run_completed` event** (#773) -- emitted on successful session completion with `startGitSha`, `endGitSha`, `agentCommitShas`, `captureConfidence`, `durationMs`
7650
+ - **Authoring docs: metrics_* keys** (#767) -- `metricsProfile` field and SHA accumulation convention documented in `docs/authoring-v2.md`
7651
+ - **`projectSessionMetricsV2` projection** (#771) -- pure projection reading `run_completed` + `context_set metrics_*` keys, wired into `ConsoleSessionSummary`
7652
+ - **Console metrics display** (#777) -- `SessionMetricsSection` in session detail view; `GET /api/v2/sessions/:id/diff-summary` endpoint
7653
+ - **`stats-summary.json` writer** (#769) -- `~/.workrail/data/stats-summary.json` aggregated from `execution-stats.jsonl`, written post-session and every 30s heartbeat
7605
7654
 
7606
7655
  **Engine improvements:**
7607
- - **Execution time tracking** (#756) -- `execution-stats.jsonl` per session in finally block
7608
- - **Worktree orphan leak fix** (#756) -- sidecar deletion deferred to `maybeRunDelivery()` for worktree sessions
7609
- - **assertNever for ReviewSeverity** (#756)
7610
- - **Crash recovery phase A** (#759) -- `clearQueueIssueSidecars()` fixes 56-min re-dispatch block; sidecar preservation for sessions with progress
7611
- - **Conversation history persistence** (#762) -- `<sessionId>-conversation.jsonl` per daemon session, append-only delta flush at each turn
7612
- - **queue-poll.jsonl rotation** (#761) -- 10 MB size cap with `.1` backup
7613
- - **Remove WorkTrain-owned label writes** (#765) -- `worktrain:in-progress`, `worktrain:generated` labels removed; deduplication now purely internal (sidecar + dispatchingIssues + session scan)
7614
- - **metricsProfile footer injection** (#779) -- engine injects `metrics_*` accumulation footers based on `metricsProfile` workflow field; all 35 bundled workflows assigned profiles
7656
+ - **Execution time tracking** (#756) -- `execution-stats.jsonl` per session in finally block
7657
+ - **Worktree orphan leak fix** (#756) -- sidecar deletion deferred to `maybeRunDelivery()` for worktree sessions
7658
+ - **assertNever for ReviewSeverity** (#756)
7659
+ - **Crash recovery phase A** (#759) -- `clearQueueIssueSidecars()` fixes 56-min re-dispatch block; sidecar preservation for sessions with progress
7660
+ - **Conversation history persistence** (#762) -- `<sessionId>-conversation.jsonl` per daemon session, append-only delta flush at each turn
7661
+ - **queue-poll.jsonl rotation** (#761) -- 10 MB size cap with `.1` backup
7662
+ - **Remove WorkTrain-owned label writes** (#765) -- `worktrain:in-progress`, `worktrain:generated` labels removed; deduplication now purely internal (sidecar + dispatchingIssues + session scan)
7663
+ - **metricsProfile footer injection** (#779) -- engine injects `metrics_*` accumulation footers based on `metricsProfile` workflow field; all 35 bundled workflows assigned profiles
7615
7664
 
7616
7665
  **Workflow namespace:**
7617
- - **Rename all bundled workflows to `wr.*`** (#782, open) -- `coding-task-workflow-agentic` → `wr.coding-task`, `mr-review-workflow-agentic` → `wr.mr-review`, etc. Prevents local project source from shadowing bundled workflows on version mismatch.
7666
+ - **Rename all bundled workflows to `wr.*`** (#782, open) -- `coding-task-workflow-agentic` → `wr.coding-task`, `mr-review-workflow-agentic` → `wr.mr-review`, etc. Prevents local project source from shadowing bundled workflows on version mismatch.
7618
7667
 
7619
7668
  ---
7620
7669
 
@@ -7648,22 +7697,43 @@ This was a major session covering daemon/console separation, metrics infrastruct
7648
7697
 
7649
7698
  ---
7650
7699
 
7651
- ### Current system state (for next engineer picking this up)
7700
+ ### Current system state (Apr 23, 2026 -- end of session)
7701
+
7702
+ **npm version: v3.68.1** | Daemon: stopped | MCP: connected on 3.68.1
7703
+
7704
+ **What shipped this session (Apr 23):**
7705
+ - **`wr.*` workflow namespace rename** (#782) -- all 31 bundled workflows renamed; `legacy_project` source can no longer shadow bundled ones
7706
+ - **`triggers.yml` updated** (#785) -- `wr.coding-task`, `wr.mr-review`
7707
+ - **Standalone console Workflows tab** (#783) -- works without MCP server
7708
+ - **Validation regression test** (#784) -- `additionalProperties: false` confirmed enforced
7709
+ - **Session metrics refactor** (#786) -- defensive cast removed, types clean
7710
+ - **Validation warnings in `list_workflows`** (#787) -- users now see why their workflow disappeared
7711
+ - **`loadSessionNotes` export fix** (#790) -- 14 pre-existing test failures now pass
7712
+ - **`metrics_outcome` validation** (#793) -- agents get `VALIDATION_ERROR` immediately if they pass invalid values; tested and confirmed working
7652
7713
 
7653
- **Daemon:** Stopped intentionally. Unload: `launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/io.worktrain.daemon.plist`
7654
- **To restart daemon:** `launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/io.worktrain.daemon.plist`
7655
- **MCP server:** Reconnecting -- run `/mcp` in Claude Code to get fresh 3.66.0 process
7656
- **Global npm:** Updated to 3.66.0 (`npm update -g @exaudeus/workrail`)
7657
- **Local build:** Built from main at 3.66.0 (`npm run build` done)
7658
- **triggers.yml:** Must update `workflowId` values to new `wr.*` IDs after #782 merges (e.g. `coding-task-workflow-agentic` → `wr.coding-task`)
7714
+ **Active bugs / gaps:**
7715
+ - GitHub admin bypass removed from ruleset -- `gh pr merge --admin` will fail
7716
+ - `metrics_pr_numbers` still 0% (review workflows not picking up footer) -- expected, no sessions have completed `wr.mr-review` with new IDs yet
7717
+ - Only 20% of sessions have `run_completed` -- most daemon sessions don't complete due to crashes/timeouts; normal
7659
7718
 
7660
- **Immediate next actions:**
7661
- 1. Reconnect MCP (`/mcp` in Claude Code)
7662
- 2. Run `wr.mr-review` on PR #782 (rename) and PR #783 (console fix)
7663
- 3. Merge both PRs
7664
- 4. Wait for validation fix shaping to complete, then code and ship it
7665
- 5. Update `triggers.yml` with new `wr.*` workflow IDs
7666
- 6. Restart daemon and monitor first pipeline run with new IDs
7719
+ **Known gaps (not yet started):**
7720
+ - **Phase B crash recovery** -- actual agent loop restart after crash
7721
+ - **`workrail cleanup` command** -- dead managed sources, old sessions
7722
+ - **Versioned workflow schema validation** -- see backlog entry above
7723
+ - **console-routes.ts dispatch coupling** -- `POST /api/v2/auto/dispatch` imports from `src/daemon/`
7724
+ - **Daemon agent loop stall detection** -- 120s liveness check for frozen loops
7725
+
7726
+ **System state:**
7727
+ - **WorkRail MCP server:** Connected at 3.68.1 (global npm `npx -y @exaudeus/workrail`). All `wr.*` IDs working.
7728
+ - **WorkTrain daemon:** Stopped. Start: `launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/io.worktrain.daemon.plist`. Points at local dist (`/Users/etienneb/git/personal/workrail/dist/cli-worktrain.js`).
7729
+ - **WorkRail console:** Not running. Start: `worktrain console`. Reads session files directly, no daemon required.
7730
+ - **Global npm:** 3.68.1 (`npm update -g @exaudeus/workrail` done)
7731
+ - **Local build:** Built from main at 3.68.1 (`npm run build` done)
7732
+
7733
+ **Next up:**
7734
+ 1. Restart daemon and watch first pipeline run with `wr.*` IDs
7735
+ 2. Versioned schema validation (design ready in backlog, audit confirmed v1 = current schema)
7736
+ 3. Daemon agent loop stall detection (medium priority)
7667
7737
 
7668
7738
  ---
7669
7739
 
@@ -7804,3 +7874,49 @@ Convention drift is a recurring tax. Migration is a one-time cost. In a codebase
7804
7874
  This is not urgent -- the current codebase is working well. But if autonomous agent usage grows and human review per-PR decreases further, the compiler enforcement gap becomes more important, not less.
7805
7875
 
7806
7876
  **Priority:** Low / long-term. Worth revisiting when the agent is writing the majority of new code. Requires a concrete spike: rewrite one module (e.g. `src/v2/durable-core/domain/`) in Kotlin and measure the real friction before committing to a full migration.
7877
+
7878
+ ---
7879
+
7880
+ ## Task re-dispatch loop protection (Apr 23, 2026) -- HIGH PRIORITY
7881
+
7882
+ **The problem:** When a pipeline session fails (stuck, crash, timeout), the idempotency sidecar (`queue-issue-<N>.json`) expires after its TTL and the queue re-selects the same issue on the next poll cycle. There is no memory of how many times an issue has been attempted. A task that consistently fails (bad workflow, broken code, unsolvable problem) gets retried indefinitely, burning API credits and producing no forward progress.
7883
+
7884
+ **Concrete incident:** Issue #393 ("test(daemon): add coverage for loadSessionNotes failure paths") was dispatched in a loop -- discovery + shaping + coding sessions repeatedly started, failed stuck, and were re-dispatched. The issue had already been resolved by human intervention but the daemon didn't know.
7885
+
7886
+ **What we need:** Per-issue attempt tracking with a max-attempts cap and escalation on exhaustion.
7887
+
7888
+ **Design sketch:**
7889
+
7890
+ 1. **Attempt counter in the sidecar:** Extend `queue-issue-<N>.json` to include `attemptCount: number`. On each new dispatch for the same issue, increment the counter. When `attemptCount >= maxAttempts` (default 3), do not dispatch -- instead emit an outbox notification and apply a `worktrain:needs-human` label (or equivalent internal signal) so the issue is skipped until a human resets it.
7891
+
7892
+ 2. **Sidecar persistence across TTL expiry:** Today the sidecar is deleted when the TTL expires. To count attempts across expiry, either: (a) use a longer-lived separate tracking file per issue, or (b) check the daemon event log for previous `session_started` events with the same `issueNumber` goal within a lookback window (e.g. last 24h).
7893
+
7894
+ 3. **Human reset mechanism:** A human should be able to say "try again" by closing and reopening the issue, or by removing a `worktrain:stuck` label, or via a `worktrain retry <issueNumber>` CLI command.
7895
+
7896
+ 4. **Escalation signal:** When max attempts is hit, post a comment on the GitHub issue: "WorkTrain attempted this task 3 times and was unable to complete it. Manual intervention required." This closes the invisible failure loop.
7897
+
7898
+ **Files to change:**
7899
+ - `src/trigger/adapters/github-queue-poller.ts` -- track attempt count when writing sidecar
7900
+ - `src/trigger/polling-scheduler.ts` -- check attempt count before dispatch
7901
+ - `~/.workrail/daemon-sessions/queue-issue-<N>.json` schema -- add `attemptCount`
7902
+
7903
+ **Priority:** High. This is a production correctness issue -- the daemon will burn unlimited credits on a broken task without this.
7904
+
7905
+ ---
7906
+
7907
+ ## Auto-start mechanism inventory (Apr 23, 2026)
7908
+
7909
+ **Current auto-start mechanisms for WorkTrain daemon:**
7910
+
7911
+ 1. **launchd plist** (`~/Library/LaunchAgents/io.worktrain.daemon.plist`) with `KeepAlive: true` -- daemon restarts automatically on crash or manual kill. Only `launchctl bootout` stops it permanently.
7912
+
7913
+ No other auto-start mechanisms exist (no login items, no cron, no systemd).
7914
+
7915
+ **Operational notes:**
7916
+ - To stop temporarily: `launchctl stop io.worktrain.daemon` -- daemon stops but restarts on next launchd check
7917
+ - To stop permanently: `launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/io.worktrain.daemon.plist`
7918
+ - To restart after bootout: `launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/io.worktrain.daemon.plist`
7919
+
7920
+ **Known risk:** When working on daemon code, always `bootout` first. A `stop` will just respawn the old binary. This has caused confusion multiple times in this session.
7921
+
7922
+ **Improvement idea:** Add a `worktrain daemon stop --permanent` command that does the bootout automatically, and `worktrain daemon start` that does the bootstrap. Makes the distinction between temporary stop and permanent stop explicit without requiring operators to know launchd internals.