@exaudeus/workrail 3.67.0 → 3.68.1
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/dist/application/services/compiler/template-registry.js +10 -1
- package/dist/cli/commands/worktrain-init.js +1 -1
- package/dist/console-ui/assets/{index-tOl8Vowf.js → index-DPdRJHMX.js} +1 -1
- package/dist/console-ui/index.html +1 -1
- package/dist/coordinators/modes/full-pipeline.js +4 -4
- package/dist/coordinators/modes/implement-shared.js +5 -5
- package/dist/coordinators/modes/implement.js +4 -4
- package/dist/coordinators/pr-review.js +4 -4
- package/dist/daemon/workflow-runner.d.ts +1 -0
- package/dist/daemon/workflow-runner.js +1 -0
- package/dist/manifest.json +31 -31
- package/dist/mcp/handlers/v2-context-budget.js +18 -0
- package/dist/mcp/handlers/v2-workflow.js +1 -1
- package/dist/mcp/workflow-protocol-contracts.js +2 -2
- package/dist/v2/durable-core/constants.d.ts +2 -0
- package/dist/v2/durable-core/constants.js +2 -1
- package/dist/v2/projections/session-metrics.js +1 -1
- package/docs/authoring-v2.md +4 -4
- package/docs/changelog-recent.md +3 -3
- package/docs/configuration.md +1 -1
- package/docs/design/adaptive-coordinator-context-candidates.md +1 -1
- package/docs/design/adaptive-coordinator-context.md +1 -1
- package/docs/design/adaptive-coordinator-routing-candidates.md +18 -18
- package/docs/design/adaptive-coordinator-routing-review.md +1 -1
- package/docs/design/adaptive-coordinator-routing.md +34 -34
- package/docs/design/agent-cascade-protocol.md +2 -2
- package/docs/design/console-daemon-separation-discovery.md +323 -0
- package/docs/design/context-assembly-design-candidates.md +1 -1
- package/docs/design/context-assembly-implementation-plan.md +1 -1
- package/docs/design/context-assembly-layer.md +2 -2
- package/docs/design/context-assembly-review-findings.md +1 -1
- package/docs/design/coordinator-access-audit.md +293 -0
- package/docs/design/coordinator-architecture-audit.md +62 -0
- package/docs/design/coordinator-error-handling-audit.md +240 -0
- package/docs/design/coordinator-testability-audit.md +426 -0
- package/docs/design/daemon-architecture-discovery.md +1 -1
- package/docs/design/daemon-console-separation-discovery.md +242 -0
- package/docs/design/daemon-memory-audit.md +203 -0
- package/docs/design/design-candidates-console-daemon-separation.md +256 -0
- package/docs/design/design-candidates-discovery-loop-fix.md +141 -0
- package/docs/design/design-review-findings-console-daemon-separation.md +106 -0
- package/docs/design/design-review-findings-discovery-loop-fix.md +81 -0
- package/docs/design/discovery-loop-fix-candidates.md +161 -0
- package/docs/design/discovery-loop-fix-design-review.md +106 -0
- package/docs/design/discovery-loop-fix-validation.md +258 -0
- package/docs/design/discovery-loop-investigation-A.md +188 -0
- package/docs/design/discovery-loop-investigation-B.md +287 -0
- package/docs/design/exploration-workflow-candidates.md +205 -0
- package/docs/design/exploration-workflow-design-review.md +166 -0
- package/docs/design/exploration-workflow-discovery.md +443 -0
- package/docs/design/ide-context-files-candidates.md +231 -0
- package/docs/design/ide-context-files-design-review.md +85 -0
- package/docs/design/ide-context-files.md +615 -0
- package/docs/design/implementation-plan-discovery-loop-fix.md +199 -0
- package/docs/design/implementation-plan-queue-poll-rotation.md +102 -0
- package/docs/design/in-process-http-audit.md +190 -0
- package/docs/design/layer3b-ghost-nodes-design-candidates.md +2 -2
- package/docs/design/loadSessionNotes-candidates.md +108 -0
- package/docs/design/loadSessionNotes-test-coverage-discovery.md +297 -0
- package/docs/design/loadSessionNotes-test-coverage-session4.md +209 -0
- package/docs/design/loadSessionNotes-test-coverage-v3.md +321 -0
- package/docs/design/probe-session-design-candidates.md +261 -0
- package/docs/design/probe-session-phase0.md +490 -0
- package/docs/design/routines-guide.md +7 -7
- package/docs/design/session-metrics-attribution-candidates.md +250 -0
- package/docs/design/session-metrics-attribution-design-review.md +115 -0
- package/docs/design/session-metrics-attribution-discovery.md +319 -0
- package/docs/design/session-metrics-candidates.md +227 -0
- package/docs/design/session-metrics-design-review.md +104 -0
- package/docs/design/session-metrics-discovery.md +454 -0
- package/docs/design/spawn-session-debug.md +202 -0
- package/docs/design/trigger-validator-candidates.md +214 -0
- package/docs/design/trigger-validator-review.md +109 -0
- package/docs/design/trigger-validator-shaping-phase0.md +239 -0
- package/docs/design/trigger-validator.md +454 -0
- package/docs/design/v2-core-design-locks.md +2 -2
- package/docs/design/workflow-extension-points.md +15 -15
- package/docs/design/workflow-id-validation-at-startup.md +1 -1
- package/docs/design/workflow-id-validation-implementation-plan.md +2 -2
- package/docs/design/workflow-trigger-lifecycle-audit.md +175 -0
- package/docs/design/worktrain-task-queue-candidates.md +5 -5
- package/docs/design/worktrain-task-queue.md +4 -4
- package/docs/discovery/coordinator-script-design.md +1 -1
- package/docs/discovery/coordinator-ux-discovery.md +3 -3
- package/docs/discovery/simulation-report.md +1 -1
- package/docs/discovery/workflow-modernization-discovery.md +326 -0
- package/docs/discovery/workflow-selection-for-discovery-tasks.md +33 -33
- package/docs/discovery/worktrain-status-briefing.md +1 -1
- package/docs/discovery/wr-discovery-goal-reframing.md +1 -1
- package/docs/docker.md +1 -1
- package/docs/ideas/backlog.md +227 -0
- package/docs/ideas/third-party-workflow-setup-design-thinking.md +1 -1
- package/docs/integrations/claude-code.md +5 -5
- package/docs/integrations/firebender.md +1 -1
- package/docs/plans/agentic-orchestration-roadmap.md +2 -2
- package/docs/plans/mr-review-workflow-redesign.md +9 -9
- package/docs/plans/ui-ux-workflow-design-candidates.md +4 -4
- package/docs/plans/ui-ux-workflow-discovery.md +2 -2
- package/docs/plans/workflow-categories-candidates.md +8 -8
- package/docs/plans/workflow-categories-discovery.md +4 -4
- package/docs/plans/workflow-modernization-design.md +430 -0
- package/docs/plans/workflow-staleness-detection-candidates.md +11 -11
- package/docs/plans/workflow-staleness-detection-review.md +4 -4
- package/docs/plans/workflow-staleness-detection.md +9 -9
- package/docs/plans/workrail-platform-vision.md +3 -3
- package/docs/reference/agent-context-cleaner-snippet.md +1 -1
- package/docs/reference/agent-context-guidance.md +4 -4
- package/docs/reference/context-optimization.md +2 -2
- package/docs/roadmap/now-next-later.md +2 -2
- package/docs/roadmap/open-work-inventory.md +16 -16
- package/docs/workflows.md +31 -31
- package/package.json +1 -1
- package/spec/workflow-tags.json +47 -47
- package/workflows/adaptive-ticket-creation.json +16 -16
- package/workflows/architecture-scalability-audit.json +22 -22
- package/workflows/bug-investigation.agentic.v2.json +3 -3
- package/workflows/classify-task-workflow.json +1 -1
- package/workflows/coding-task-workflow-agentic.json +6 -6
- package/workflows/cross-platform-code-conversion.v2.json +8 -8
- package/workflows/document-creation-workflow.json +8 -8
- package/workflows/documentation-update-workflow.json +8 -8
- package/workflows/intelligent-test-case-generation.json +2 -2
- package/workflows/learner-centered-course-workflow.json +2 -2
- package/workflows/mr-review-workflow.agentic.v2.json +4 -4
- package/workflows/personal-learning-materials-creation-branched.json +8 -8
- package/workflows/presentation-creation.json +5 -5
- package/workflows/production-readiness-audit.json +1 -1
- package/workflows/relocation-workflow-us.json +31 -31
- package/workflows/routines/context-gathering.json +1 -1
- package/workflows/routines/design-review.json +1 -1
- package/workflows/routines/execution-simulation.json +1 -1
- package/workflows/routines/feature-implementation.json +3 -3
- package/workflows/routines/final-verification.json +1 -1
- package/workflows/routines/hypothesis-challenge.json +1 -1
- package/workflows/routines/ideation.json +1 -1
- package/workflows/routines/parallel-work-partitioning.json +3 -3
- package/workflows/routines/philosophy-alignment.json +2 -2
- package/workflows/routines/plan-analysis.json +1 -1
- package/workflows/routines/plan-generation.json +1 -1
- package/workflows/routines/tension-driven-design.json +6 -6
- package/workflows/scoped-documentation-workflow.json +26 -26
- package/workflows/ui-ux-design-workflow.json +14 -14
- package/workflows/workflow-diagnose-environment.json +1 -1
- package/workflows/workflow-for-workflows.json +1 -1
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# Design: triggers.yml Validator for WorkTrain
|
|
2
|
+
|
|
3
|
+
**Status:** Draft
|
|
4
|
+
**Date:** 2026-04-19
|
|
5
|
+
**Author:** Etienne Beaulac (via wr.discovery workflow)
|
|
6
|
+
**Scope:** `src/trigger/trigger-store.ts`, `src/trigger/types.ts`, `src/cli-worktrain.ts` -- NOT `src/mcp/`
|
|
7
|
+
|
|
8
|
+
**Artifact strategy:** This document is a human-readable reference for the design decisions made during the `wr.discovery` workflow. It is NOT execution truth -- notes and context variables in the WorkRail session are the durable record. This document may be updated as decisions evolve but is not required for session recovery.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context / Ask
|
|
13
|
+
|
|
14
|
+
### Original Stated Goal (solution-framed)
|
|
15
|
+
|
|
16
|
+
> Design a triggers.yml validator that enforces explicit configuration of all consequential fields, so WorkTrain's behavior is fully readable from the config file without knowing source code defaults.
|
|
17
|
+
|
|
18
|
+
### Reframed Problem Statement
|
|
19
|
+
|
|
20
|
+
WorkTrain's runtime behavior cannot be determined from reading `triggers.yml` alone because consequential fields have silent defaults, so operators only discover misconfiguration through production failures rather than at startup.
|
|
21
|
+
|
|
22
|
+
### Background: Production Incidents
|
|
23
|
+
|
|
24
|
+
Three classes of misconfiguration have caused real production pain:
|
|
25
|
+
|
|
26
|
+
1. `branchStrategy` silently defaulted to `none` -- 3 parallel sessions wrote to the same checkout simultaneously (no worktree isolation)
|
|
27
|
+
2. `goalTemplate` silently defaulted to `{{$.goal}}` -- confusing startup warning with no guidance
|
|
28
|
+
3. `maxSessionMinutes` absent -- 30-minute hidden system default, no visibility in config
|
|
29
|
+
4. Same issue dispatched 3 times before idempotency kicked in -- concurrency cap as sole safety net
|
|
30
|
+
|
|
31
|
+
**Root cause:** implicit defaults + no startup validation = behavior that cannot be determined from reading the config.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Path Recommendation
|
|
36
|
+
|
|
37
|
+
**Chosen path: `design_first`**
|
|
38
|
+
|
|
39
|
+
Rationale: the goal is solution-framed (prescribes a validator). The design risk is solving the wrong problem or designing the wrong interface. Before writing any code, we need to resolve three key questions:
|
|
40
|
+
|
|
41
|
+
1. **Strict vs. lenient mode** -- should the validator be always-strict or configurable?
|
|
42
|
+
2. **Migration path** -- how do existing triggers.yml files that predate the validator get handled?
|
|
43
|
+
3. **Where validation runs** -- startup only, `worktrain trigger validate` only, or both?
|
|
44
|
+
|
|
45
|
+
`design_first` over `full_spectrum`: the landscape is already well-understood from code inspection. The trigger system is fully readable. The risk is not missing context -- it is committing to the wrong design contract.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Constraints / Anti-Goals
|
|
50
|
+
|
|
51
|
+
### Constraints
|
|
52
|
+
|
|
53
|
+
- **Scope:** Only `src/trigger/trigger-store.ts`, `src/trigger/types.ts`, `src/cli-worktrain.ts`
|
|
54
|
+
- **No `src/mcp/` changes**
|
|
55
|
+
- **No external dependencies** for the validator (no JSON Schema library, no ajv)
|
|
56
|
+
- **Backward-compatible parse API** -- `loadTriggerConfig()` public signature must not change (callers in trigger-listener.ts)
|
|
57
|
+
- **Result types, not exceptions** -- consistent with existing TriggerStoreError pattern
|
|
58
|
+
- **Deterministic** -- same triggers.yml produces same validation result always
|
|
59
|
+
|
|
60
|
+
### Anti-Goals
|
|
61
|
+
|
|
62
|
+
- Do not build a general-purpose YAML schema validator
|
|
63
|
+
- Do not add a `strict: true` flag to `~/.workrail/config.json` (introduces hidden behavior)
|
|
64
|
+
- Do not add API calls to `worktrain trigger validate` (it must be static analysis only)
|
|
65
|
+
- Do not auto-fix or auto-fill missing fields (that hides the problem)
|
|
66
|
+
- Do not break existing `triggers.yml` files that are already correctly configured
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Landscape Packet
|
|
71
|
+
|
|
72
|
+
### Current State: What trigger-store.ts Already Validates
|
|
73
|
+
|
|
74
|
+
`validateAndResolveTrigger()` (1354 lines in trigger-store.ts) already enforces:
|
|
75
|
+
|
|
76
|
+
| Check | Behavior |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `autoOpenPR: true` without `autoCommit: true` | **Warning** (soft, not error) |
|
|
79
|
+
| `github_queue_poll` without `source.repo` | **Hard error** (missing_field) |
|
|
80
|
+
| `github_queue_poll` without `source.token` | **Hard error** (missing_field) |
|
|
81
|
+
| `branchStrategy` invalid value | **Hard error** (invalid_field_value) |
|
|
82
|
+
| `concurrencyMode` invalid value | **Hard error** (invalid_field_value) |
|
|
83
|
+
| `dispatchCondition` missing payloadPath/equals | **Hard error** (missing_field) |
|
|
84
|
+
| `maxSessionMinutes` non-integer or <= 0 | **Hard error** (invalid_field_value) |
|
|
85
|
+
|
|
86
|
+
### Current State: What Is NOT Validated (Silent Defaults)
|
|
87
|
+
|
|
88
|
+
| Field | Current Behavior | Production Risk |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `branchStrategy` absent + `autoCommit: true` | Defaults to `none` silently | Parallel sessions corrupt main checkout |
|
|
91
|
+
| `goalTemplate` absent + `goal` absent | Defaults to `{{$.goal}}` with a console.log | Confusing startup warning |
|
|
92
|
+
| `maxSessionMinutes` absent | System default 30 min (hidden) | No visibility in config |
|
|
93
|
+
| `concurrencyMode` absent | Defaults to `serial` silently | OK, serial is safe -- but not visible |
|
|
94
|
+
| `branchPrefix`/`baseBranch` absent with worktree | Defaults to `worktrain/` and `main` | Acceptable defaults, but invisible |
|
|
95
|
+
|
|
96
|
+
### Existing Production triggers.yml Audit
|
|
97
|
+
|
|
98
|
+
| Trigger | maxSessionMinutes | branchStrategy | concurrencyMode | goalTemplate | Verdict |
|
|
99
|
+
|---|---|---|---|---|---|
|
|
100
|
+
| `test-task` | 60 (explicit) | worktree (explicit) | parallel (explicit) | explicit | **PASSES** |
|
|
101
|
+
| `mr-review` | 30 (explicit) | none (explicit) | parallel (explicit) | explicit | **PASSES** |
|
|
102
|
+
| `self-improvement` | 90 (explicit) | worktree (explicit) | absent (defaults serial) | absent (defaults {{$.goal}}) | **WARNINGS** |
|
|
103
|
+
|
|
104
|
+
The existing production `triggers.yml` is mostly compliant. Only `self-improvement` would generate warnings for `concurrencyMode` and `goalTemplate`.
|
|
105
|
+
|
|
106
|
+
### TriggerStoreError Taxonomy (Current)
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
type TriggerStoreError =
|
|
110
|
+
| { kind: 'parse_error'; message: string; lineNumber?: number }
|
|
111
|
+
| { kind: 'missing_secret'; envVarName: string; triggerId: string }
|
|
112
|
+
| { kind: 'missing_field'; field: string; triggerId: string }
|
|
113
|
+
| { kind: 'invalid_field_value'; field: string; triggerId: string }
|
|
114
|
+
| { kind: 'unknown_provider'; provider: string; triggerId: string }
|
|
115
|
+
| { kind: 'unknown_workspace'; workspaceName: string; triggerId: string }
|
|
116
|
+
| { kind: 'file_not_found'; filePath: string }
|
|
117
|
+
| { kind: 'io_error'; message: string }
|
|
118
|
+
| { kind: 'duplicate_id'; triggerId: string }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
No new error kinds are needed. The proposed hard errors all map to `missing_field` or `invalid_field_value`.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Problem Frame Packet
|
|
126
|
+
|
|
127
|
+
### Primary Users and Stakeholders
|
|
128
|
+
|
|
129
|
+
| Stakeholder | Job / Outcome | Pain / Tension |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| **Etienne (operator, solo)** | Configure WorkTrain to autonomously handle GitHub issues and PRs | Has to read source code to understand what fields matter; discovered branchStrategy gap only after 3 sessions corrupted the same checkout |
|
|
132
|
+
| **trigger-listener.ts** (startup path) | Start with a known-good config or fail fast with actionable errors | Currently: one bad trigger skips, daemon starts with valid subset. Stricter: any bad trigger blocks all triggers. |
|
|
133
|
+
| **loadTriggerConfig() callers** (trigger-listener.ts, trigger-store tests) | Parse triggers.yml reliably with stable API | A breaking API change (e.g. adding required params) would require updating all call sites |
|
|
134
|
+
| **Future WorkTrain operators** (non-Etienne) | Onboard to WorkTrain without reading source code | Need config to be self-documenting at read time |
|
|
135
|
+
|
|
136
|
+
### Core Tensions
|
|
137
|
+
|
|
138
|
+
**Tension 1: Fail-fast vs. partial degradation**
|
|
139
|
+
Current behavior: one bad trigger is skipped, rest run. Proposed: safety-violation triggers block startup entirely. Operators running 5+ triggers will be frustrated if one misconfiguration blocks all others. Partial degradation (skip the bad trigger, warn loudly) is more practical at scale.
|
|
140
|
+
|
|
141
|
+
**Tension 2: Explicit config vs. sensible defaults**
|
|
142
|
+
The design asks operators to explicitly set `maxSessionMinutes` on every trigger. But `maxSessionMinutes: 30` as a default is actually reasonable for most read-only triggers. Forcing explicit values adds config noise without preventing real incidents (the 30-min default is not what caused any of the production problems). The true danger fields are `branchStrategy` and `concurrencyMode`, not timeout.
|
|
143
|
+
|
|
144
|
+
**Tension 3: Startup validation vs. validate subcommand**
|
|
145
|
+
If hard errors block startup (trigger-listener.ts), operators must fix config before the daemon will run at all. If hard errors only surface via `worktrain trigger validate`, operators might not run it before starting the daemon. The cleanest UX: `worktrain trigger validate` is the single check; the daemon startup calls it automatically before loading triggers.
|
|
146
|
+
|
|
147
|
+
**Tension 4: Breaking change risk for autoOpenPR + no autoCommit**
|
|
148
|
+
The existing code warns on this combination but does not error. Upgrading to hard error is technically correct but breaks any existing trigger that has this config. Since the production `triggers.yml` does not have this combination, it is safe for Etienne. But it is a breaking change for the documented behavior.
|
|
149
|
+
|
|
150
|
+
### Success Criteria (Concrete)
|
|
151
|
+
|
|
152
|
+
1. After this design is implemented, an operator can add a new trigger to triggers.yml and `worktrain trigger validate` will tell them if they forgot any field that would cause a production incident -- without running the daemon.
|
|
153
|
+
2. The three production incidents (checkout corruption, goalTemplate warning, hidden timeout) each map to a specific named rule that fires for a config that would reproduce them.
|
|
154
|
+
3. `worktrain trigger validate` exits in <2 seconds on a 10-trigger file with no network calls.
|
|
155
|
+
4. The existing production `triggers.yml` (3 triggers) produces 0 errors and at most 3 warnings from `worktrain trigger validate`.
|
|
156
|
+
5. Adding `worktrain trigger validate` does not require any change to `trigger-listener.ts` or `src/mcp/`.
|
|
157
|
+
|
|
158
|
+
### Primary Framing Risk
|
|
159
|
+
|
|
160
|
+
**The single specific thing that would make the current framing wrong:**
|
|
161
|
+
|
|
162
|
+
If the root cause of the production incidents is NOT missing validation, but instead missing documentation or missing defaults in the `worktrain init` scaffolded triggers.yml template -- then validation at startup or via a CLI command addresses the symptom but not the root cause. If `worktrain init` generates a triggers.yml with all consequential fields pre-filled with safe explicit values, then new operators would never encounter the silent default problem in the first place. Validation would then only help operators who hand-edit their config outside of `worktrain init`.
|
|
163
|
+
|
|
164
|
+
**Evidence that would trigger a retriage:** discovering that the three production incidents all happened on configs originally generated by `worktrain init` (rather than manually written). In that case, fixing `worktrain init`'s template is the higher-leverage intervention.
|
|
165
|
+
|
|
166
|
+
### The Core Tension (Summary)
|
|
167
|
+
|
|
168
|
+
The problem has two distinct failure modes:
|
|
169
|
+
|
|
170
|
+
**Failure mode A: Dangerous silent default** -- `branchStrategy` absent + `autoCommit: true` = parallel sessions corrupting the main checkout. This is a safety violation. It warrants a hard error.
|
|
171
|
+
|
|
172
|
+
**Failure mode B: Confusing invisible default** -- `maxSessionMinutes` absent = hidden 30-min timeout. This is an observability problem, not a safety problem. A warning surfaces it; a hard error is disproportionate.
|
|
173
|
+
|
|
174
|
+
The proposed design conflates both into "hard errors block startup." The right design separates them:
|
|
175
|
+
- **Safety violations** (could corrupt data or cause infinite loops) = hard errors
|
|
176
|
+
- **Observability gaps** (hidden defaults that are still safe) = warnings that appear in `worktrain trigger validate` output
|
|
177
|
+
|
|
178
|
+
### Three Key Design Questions to Resolve
|
|
179
|
+
|
|
180
|
+
#### Q1: Strict vs. Lenient Mode
|
|
181
|
+
|
|
182
|
+
**Options:**
|
|
183
|
+
- A. Always strict (no config flag) -- simpler, no hidden behavior, breaks on upgrade
|
|
184
|
+
- B. Opt-in strict via `worktrain trigger validate --strict` (flag, not daemon config) -- clean separation between "works" and "passes audit"
|
|
185
|
+
- C. Always-on warnings at startup, hard errors only for safety violations
|
|
186
|
+
|
|
187
|
+
**Recommendation:** Option C. Safety violations (branchStrategy absent + autoCommit) become hard errors always. Observability gaps produce warnings always. No config flags. The `worktrain trigger validate` command surfaces all warnings and errors with formatting.
|
|
188
|
+
|
|
189
|
+
Rationale: a config flag `strict: true` in `config.json` introduces hidden behavior (triggers.yml behaves differently depending on config.json). A CLI `--strict` flag on `validate` is fine because it only affects the validate subcommand output, not daemon behavior.
|
|
190
|
+
|
|
191
|
+
#### Q2: Migration Path
|
|
192
|
+
|
|
193
|
+
**Observation:** existing production `triggers.yml` already passes most checks. Only `self-improvement` is missing `concurrencyMode` and `goalTemplate` explicit values, both of which are safe defaults (serial mode is safe; `{{$.goal}}` is functional).
|
|
194
|
+
|
|
195
|
+
**Recommendation:**
|
|
196
|
+
- Hard errors for safety violations are non-negotiable on new triggers
|
|
197
|
+
- Existing triggers that only have observability gaps (missing concurrencyMode, goalTemplate) get warnings, not errors
|
|
198
|
+
- `worktrain trigger validate` output shows a "migration diff" section: what fields to add for clean validation
|
|
199
|
+
|
|
200
|
+
#### Q3: Where Validation Runs
|
|
201
|
+
|
|
202
|
+
**Recommendation:** Both locations, with different severity:
|
|
203
|
+
- **Startup (daemon):** Hard errors only (safety violations). Daemon refuses to start a trigger that would corrupt data.
|
|
204
|
+
- **`worktrain trigger validate`:** Hard errors + all warnings + human-readable summary.
|
|
205
|
+
|
|
206
|
+
This means startup is not blocked by observability warnings -- only by safety violations.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Candidate Generation Expectations
|
|
211
|
+
|
|
212
|
+
*This section records what the candidate directions must cover for design_first rigor:*
|
|
213
|
+
|
|
214
|
+
- At least one direction must meaningfully reframe the problem rather than just packaging the obvious solution (a new validator component)
|
|
215
|
+
- At least one direction must be conservative/minimal (extend existing code, smallest surface area)
|
|
216
|
+
- At least one direction must be more ambitious (structural change that prevents the class of errors, not just catches them)
|
|
217
|
+
- All directions must satisfy the 5 decision criteria (safety violations = hard errors, observability = warnings, static CLI, no API break, scope constraint)
|
|
218
|
+
- The severity question (autoCommit+branchStrategy:none under serial = error or warning?) must be explicitly resolved in at least one direction
|
|
219
|
+
|
|
220
|
+
## Candidate Directions
|
|
221
|
+
|
|
222
|
+
### Direction 1: Extend validateAndResolveTrigger() with a strict-mode parameter (RECOMMENDED)
|
|
223
|
+
|
|
224
|
+
Add a `ValidationMode` type and a `mode` parameter to `validateAndResolveTrigger()`:
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
type ValidationMode = 'lenient' | 'strict';
|
|
228
|
+
|
|
229
|
+
// loadTriggerConfig() adds an optional mode parameter
|
|
230
|
+
export function loadTriggerConfig(
|
|
231
|
+
yamlContent: string,
|
|
232
|
+
env: Record<string, string | undefined>,
|
|
233
|
+
workspaces: Readonly<Record<string, WorkspaceConfig>>,
|
|
234
|
+
mode: ValidationMode = 'lenient',
|
|
235
|
+
): Result<TriggerConfig, TriggerStoreError>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
- `lenient` (default): current behavior. Safety violations still hard-error. Observability warnings logged but not blocking.
|
|
239
|
+
- `strict`: additionally blocks on observability gaps (missing maxSessionMinutes, missing explicit concurrencyMode for parallel triggers, etc.)
|
|
240
|
+
|
|
241
|
+
Startup uses `lenient`. `worktrain trigger validate` uses `strict` for its exit code but reports both.
|
|
242
|
+
|
|
243
|
+
**Pros:** No new files, extends existing error taxonomy, no API surface change for callers.
|
|
244
|
+
**Cons:** The `mode` parameter adds complexity to a function that is already 650+ lines.
|
|
245
|
+
|
|
246
|
+
### Direction 2: Separate `validateTriggerStrict()` function in trigger-store.ts
|
|
247
|
+
|
|
248
|
+
Keep `validateAndResolveTrigger()` as-is for parsing. Add a new pure function:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
export interface TriggerValidationIssue {
|
|
252
|
+
readonly severity: 'error' | 'warning';
|
|
253
|
+
readonly rule: string; // e.g. 'branch_strategy_required_with_auto_commit'
|
|
254
|
+
readonly triggerId: string;
|
|
255
|
+
readonly message: string;
|
|
256
|
+
readonly suggestedFix?: string;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function validateTriggerStrict(
|
|
260
|
+
trigger: TriggerDefinition,
|
|
261
|
+
): readonly TriggerValidationIssue[]
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
This takes an _already-parsed_ TriggerDefinition and applies semantic validation rules on top of structural parse validation.
|
|
265
|
+
|
|
266
|
+
**Pros:** Clean separation of concerns (parse vs. semantic validation). Pure function, easy to test. Composable with `worktrain trigger validate`.
|
|
267
|
+
**Cons:** Two-pass validation (parse then validate) means startup needs two calls.
|
|
268
|
+
|
|
269
|
+
### Direction 3: JSON Schema generation for triggers.yml
|
|
270
|
+
|
|
271
|
+
Generate a JSON Schema from the TypeScript types and validate triggers.yml at authoring time via VS Code or pre-commit hook.
|
|
272
|
+
|
|
273
|
+
**Pros:** Catches errors before the file is deployed. Works in editors with real-time feedback.
|
|
274
|
+
**Cons:** Out of scope (does not address the `src/cli-worktrain.ts` deliverable). The narrow custom YAML parser would need to be replaced or supplemented. Does not provide the human-readable `worktrain trigger validate` output.
|
|
275
|
+
|
|
276
|
+
**Verdict:** Complementary to Direction 1 or 2, not a replacement. Noted for future work.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Validator Rule Taxonomy
|
|
281
|
+
|
|
282
|
+
### Hard Errors (block startup and fail `worktrain trigger validate`)
|
|
283
|
+
|
|
284
|
+
| Rule ID | Condition | Error Kind |
|
|
285
|
+
|---|---|---|
|
|
286
|
+
| `auto_commit_requires_branch_strategy` | `autoCommit: true` AND `branchStrategy` absent or `'none'` | `missing_field` / `invalid_field_value` |
|
|
287
|
+
| `auto_open_pr_requires_auto_commit` | `autoOpenPR: true` AND `autoCommit` not `true` | `invalid_field_value` (upgrade from current warning) |
|
|
288
|
+
| `worktree_requires_base_branch` | `branchStrategy: worktree` AND `baseBranch` absent | `missing_field` |
|
|
289
|
+
| `worktree_requires_branch_prefix` | `branchStrategy: worktree` AND `branchPrefix` absent | `missing_field` |
|
|
290
|
+
| `queue_poll_requires_source_repo` | `github_queue_poll` AND `source.repo` absent | `missing_field` (already enforced) |
|
|
291
|
+
| `queue_poll_requires_source_token` | `github_queue_poll` AND `source.token` absent | `missing_field` (already enforced) |
|
|
292
|
+
|
|
293
|
+
### Warnings (logged at startup, surfaced by `worktrain trigger validate`)
|
|
294
|
+
|
|
295
|
+
| Rule ID | Condition | Message |
|
|
296
|
+
|---|---|---|
|
|
297
|
+
| `max_session_minutes_not_set` | `agentConfig.maxSessionMinutes` absent | "maxSessionMinutes not set; system default is 30 min -- add explicit value for observability" |
|
|
298
|
+
| `concurrent_without_worktree` | `concurrencyMode: parallel` AND `branchStrategy: none` | "parallel sessions share a checkout; if autoCommit is true this will corrupt files" |
|
|
299
|
+
| `goal_template_implicit` | `goalTemplate` absent AND `goal` absent | "goalTemplate will default to {{$.goal}}; explicit configuration recommended" |
|
|
300
|
+
| `max_turns_not_set` | `agentConfig.maxTurns` absent | "maxTurns not set; no turn limit will apply" |
|
|
301
|
+
| `auto_commit_without_secret_scan` | `autoCommit: true` AND `secretScan: false` | "secret scanning disabled on a committing trigger" |
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## `worktrain trigger validate` Output Format
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
$ worktrain trigger validate
|
|
309
|
+
|
|
310
|
+
WorkTrain Trigger Validation
|
|
311
|
+
Config: /Users/etienneb/git/personal/workrail
|
|
312
|
+
|
|
313
|
+
Trigger: test-task (generic)
|
|
314
|
+
Delivery: autoCommit=true autoOpenPR=true
|
|
315
|
+
Branch: worktree -> worktrain/<sessionId> off main
|
|
316
|
+
Concurrency: parallel
|
|
317
|
+
Limits: maxSessionMinutes=60 [maxTurns not set]
|
|
318
|
+
Goal: from payload (goalTemplate={{$.goal}})
|
|
319
|
+
Status: WARNING (1)
|
|
320
|
+
- [W] max_turns_not_set: maxTurns not set; no turn limit will apply
|
|
321
|
+
|
|
322
|
+
Trigger: mr-review (generic)
|
|
323
|
+
Delivery: autoCommit=false autoOpenPR=false
|
|
324
|
+
Branch: none (read-only)
|
|
325
|
+
Concurrency: parallel
|
|
326
|
+
Limits: maxSessionMinutes=30
|
|
327
|
+
Goal: from payload (goalTemplate=Review PR {{$.pull_request.number}}: {{$.pull_request.title}})
|
|
328
|
+
Status: OK
|
|
329
|
+
|
|
330
|
+
Trigger: self-improvement (github_queue_poll)
|
|
331
|
+
Queue: assignee=worktrain-etienneb repo=EtienneBBeaulac/workrail
|
|
332
|
+
Delivery: autoCommit=true autoOpenPR=true
|
|
333
|
+
Branch: worktree -> worktrain/<sessionId> off main
|
|
334
|
+
Concurrency: serial [WARNING: concurrencyMode not set, defaulting to serial]
|
|
335
|
+
Limits: maxSessionMinutes=90 maxTurns=60
|
|
336
|
+
Goal: implicit {{$.goal}} (no goalTemplate set)
|
|
337
|
+
Status: WARNING (2)
|
|
338
|
+
- [W] goal_template_implicit: goalTemplate will default to {{$.goal}}; explicit configuration recommended
|
|
339
|
+
- [W] concurrent_without_worktree: N/A (serial mode)
|
|
340
|
+
|
|
341
|
+
Summary: 3 triggers 0 errors 3 warnings
|
|
342
|
+
Exit code: 0 (no errors)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Implementation Plan
|
|
348
|
+
|
|
349
|
+
### Phase 1: Hard error upgrades + startup hint (no new files)
|
|
350
|
+
|
|
351
|
+
**File:** `src/trigger/trigger-store.ts`
|
|
352
|
+
|
|
353
|
+
1. Upgrade `autoOpenPR: true` without `autoCommit: true` from warning to hard error (`invalid_field_value`) -- **BREAKING CHANGE**, document in PR
|
|
354
|
+
2. Add hard error: `autoCommit: true` with `branchStrategy` absent or `'none'` (new check in `validateAndResolveTrigger`) -- hard error regardless of `concurrencyMode` (latent danger)
|
|
355
|
+
3. Add hard error: `branchStrategy: worktree` without `baseBranch` -- only if chosen to require explicit (design question Y3 in review; recommendation: yes, require it)
|
|
356
|
+
4. Add `console.log` hint in `loadTriggerConfig()` on successful parse: `"Loaded ${N} trigger(s). Run 'worktrain trigger validate' for a full config health check."`
|
|
357
|
+
|
|
358
|
+
**File:** `src/trigger/types.ts`
|
|
359
|
+
|
|
360
|
+
5. No type changes needed for Phase 1 (all TriggerStoreError kinds already exist)
|
|
361
|
+
|
|
362
|
+
### Phase 2: Semantic validator function (new export from trigger-store.ts)
|
|
363
|
+
|
|
364
|
+
**File:** `src/trigger/types.ts`
|
|
365
|
+
|
|
366
|
+
6. Add `TriggerValidationIssue` interface with `severity: 'error' | 'warning'` and closed `rule` union (9 named rules)
|
|
367
|
+
|
|
368
|
+
**File:** `src/trigger/trigger-store.ts`
|
|
369
|
+
|
|
370
|
+
7. Add `validateTriggerStrict(trigger: TriggerDefinition): readonly TriggerValidationIssue[]`
|
|
371
|
+
- **INVARIANT (document in code comment):** This function must reproduce ALL error-severity checks from `validateAndResolveTrigger()` as `TriggerValidationIssue` with `severity: 'error'`. The validate CLI must be a strict superset of what the daemon checks. Keep these in sync.
|
|
372
|
+
- Includes: hard error rules (safety violations) AND warning rules (observability gaps)
|
|
373
|
+
8. Add `validateAllTriggers(config: TriggerConfig): readonly TriggerValidationIssue[]`
|
|
374
|
+
|
|
375
|
+
### Phase 3: CLI subcommand + tests
|
|
376
|
+
|
|
377
|
+
**New file:** `src/cli/commands/worktrain-trigger-validate.ts`
|
|
378
|
+
|
|
379
|
+
9. `WorktrainTriggerValidateDeps` interface (following `WorktrainTriggerTestDeps` pattern -- all I/O injected)
|
|
380
|
+
10. `executeWorktrainTriggerValidateCommand()` function
|
|
381
|
+
- Calls `loadTriggerConfig()` then `validateAllTriggers()`
|
|
382
|
+
- Prints human-readable per-trigger summary
|
|
383
|
+
- Exit 0 if no errors (warnings OK), exit 1 if any errors
|
|
384
|
+
- No API calls, no network I/O
|
|
385
|
+
|
|
386
|
+
**File:** `src/cli-worktrain.ts`
|
|
387
|
+
|
|
388
|
+
11. Add `worktrain trigger validate` subcommand to existing `triggerCommand` group (line ~1539)
|
|
389
|
+
|
|
390
|
+
**Test requirement (Orange O2 from review):**
|
|
391
|
+
|
|
392
|
+
12. Unit test: construct a TriggerDefinition that would fail validateAndResolveTrigger (e.g., `autoCommit: true, branchStrategy: undefined`) and verify that `validateTriggerStrict()` produces a `severity: 'error'` issue for the same condition. This prevents the sync regression identified in failure mode FM2.
|
|
393
|
+
|
|
394
|
+
### Phase 4: Startup integration (deferred)
|
|
395
|
+
|
|
396
|
+
**File:** `src/trigger/trigger-listener.ts` (OUT OF SCOPE -- do not touch)
|
|
397
|
+
|
|
398
|
+
Note: Hard error upgrades in Phase 1 propagate automatically through the existing `loadTriggerConfigFromFile()` call chain in trigger-listener.ts. Semantic warnings from Phase 2 are NOT surfaced at daemon startup -- only via `worktrain trigger validate`. This is the accepted tradeoff.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Open Questions
|
|
403
|
+
|
|
404
|
+
1. **Should `branchStrategy: worktree` without explicit `baseBranch`/`branchPrefix` be a hard error or warning?** Defaults (`main`, `worktrain/`) are safe and well-documented. Recommendation: warning only.
|
|
405
|
+
|
|
406
|
+
2. **Should `autoCommit: true` + `branchStrategy: none` be a hard error or warning?** It's dangerous (corrupts checkout under parallel runs) but safe under `serial` concurrencyMode. Recommendation: hard error only when `concurrencyMode: parallel`, warning when `serial`.
|
|
407
|
+
|
|
408
|
+
3. **Should `worktrain trigger validate` read from a specific path or always use cwd?** Recommendation: default to `~/.workrail/triggers.yml` (same as daemon), with `--config <path>` override.
|
|
409
|
+
|
|
410
|
+
4. **Startup behavior change for `trigger-listener.ts`:** The design calls for startup validation, but `trigger-listener.ts` is out of scope. Phase 4 is deferred. The hard error upgrades in Phase 1 (which run inside `validateAndResolveTrigger`) apply at startup automatically via the existing `loadTriggerConfigFromFile()` call chain.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Decision Log
|
|
415
|
+
|
|
416
|
+
| Date | Decision | Rationale |
|
|
417
|
+
|---|---|---|
|
|
418
|
+
| 2026-04-19 | Use Candidate B (two-layer validation + CLI subcommand) | Best-fit scope, satisfies all 5 decision criteria, clean separation of structural parse from semantic validation. |
|
|
419
|
+
| 2026-04-19 | Hard errors for safety violations, warnings for observability gaps | Proportionate. Avoids breaking startup on non-dangerous misconfigs. The three production incidents are safety-class. |
|
|
420
|
+
| 2026-04-19 | autoCommit:true + branchStrategy:none = hard error regardless of concurrencyMode | Latent danger: serial+none is safe today but becomes corrupt-checkout immediately when concurrencyMode changes to parallel. Fail-fast on the latent footgun. |
|
|
421
|
+
| 2026-04-19 | No strict mode config flag | Config flags introduce hidden behavior. CLI --strict on validate subcommand only. |
|
|
422
|
+
| 2026-04-19 | TriggerValidationIssue.rule is a closed string-literal union | Enables exhaustiveness in switch statements. Catches new rules at compile time when consuming code handles them. |
|
|
423
|
+
| 2026-04-19 | Phase 4 (startup integration) deferred -- trigger-listener.ts out of scope | Hard error upgrades in Phase 1 propagate automatically through existing loadTriggerConfigFromFile() call chain. No trigger-listener.ts changes needed. |
|
|
424
|
+
| 2026-04-19 | Candidate C (type-level discriminated union) deferred as follow-up | Too broad for current scope. The correct long-term fix but a separate task. |
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Final Summary
|
|
429
|
+
|
|
430
|
+
**Selected direction:** Candidate B -- Two-Layer Validation + CLI Subcommand.
|
|
431
|
+
|
|
432
|
+
**Why it won:** Satisfies all five decision criteria within the stated scope. Hard errors for safety violations (three production incidents prevented), warnings for observability gaps, static `worktrain trigger validate` CLI with no API calls, backward-compatible loadTriggerConfig() API, implementation confined to trigger-store.ts + types.ts + cli-worktrain.ts.
|
|
433
|
+
|
|
434
|
+
**Strongest alternative:** Candidate A (minimal safety patch). It solves the safety goal but provides no observability improvement or CLI subcommand. It is the correct Phase 1 implementation of Candidate B, not an alternative.
|
|
435
|
+
|
|
436
|
+
**Accepted tradeoffs:**
|
|
437
|
+
- Semantic warnings are only visible via `worktrain trigger validate` (not daemon startup logs). Operators must know to run it.
|
|
438
|
+
- Two validation layers means two places to add new rules. Mitigated by unit tests on validateTriggerStrict.
|
|
439
|
+
- autoOpenPR+no autoCommit is upgraded from warning to hard error (behavioral change for any config with this combination -- none exist in production).
|
|
440
|
+
|
|
441
|
+
**Identified failure modes:**
|
|
442
|
+
- An operator deploys a new trigger, never runs validate, and misses an observability warning (e.g., missing maxSessionMinutes). Mitigation: loadTriggerConfig() should log a hint to run validate on successful parse.
|
|
443
|
+
- A developer adds a new validation rule to validateAndResolveTrigger but forgets to add the corresponding semantic check to validateTriggerStrict. Mitigation: unit test coverage for validateTriggerStrict.
|
|
444
|
+
|
|
445
|
+
**Confidence band:** High. No red findings from the design review. Two Orange findings (sync invariant contract, unit test requirement) are incorporated into the implementation plan. Remaining uncertainty is implementation-level, not design-level.
|
|
446
|
+
|
|
447
|
+
**Residual risks:**
|
|
448
|
+
- Sync gap between validateAndResolveTrigger and validateTriggerStrict (Orange O1/O2) -- mitigated by contract comment and unit test in Phase 3.
|
|
449
|
+
- Operator never runs validate (Yellow Y1) -- mitigated by startup hint in Phase 1.
|
|
450
|
+
|
|
451
|
+
**Follow-up tasks (not blocking this implementation):**
|
|
452
|
+
1. **Candidate C:** Replace optional `branchStrategy` with a discriminated `AutoCommitConfig` type in `types.ts` for compile-time safety guarantee.
|
|
453
|
+
2. **worktrain init template:** Fix the scaffold to generate all consequential fields with explicit values so new configs pass strict mode from day one.
|
|
454
|
+
3. **self-improvement trigger:** Add `goalTemplate: "{{$.title}}"` and `concurrencyMode: serial` to the production `triggers.yml` to eliminate the 2 warnings from `worktrain trigger validate`.
|
|
@@ -2545,7 +2545,7 @@ Three architectural alternatives if agent friction becomes significant:
|
|
|
2545
2545
|
|
|
2546
2546
|
## 19. Agent Delegation Instructions (Workflow-Driven Subagent Execution)
|
|
2547
2547
|
|
|
2548
|
-
**Issue**: Workflows request subagent delegation (e.g., "Spawn 3 WorkRail Executors SIMULTANEOUSLY using routine-ideation") but agents frequently misinterpret these instructions, leading to:
|
|
2548
|
+
**Issue**: Workflows request subagent delegation (e.g., "Spawn 3 WorkRail Executors SIMULTANEOUSLY using wr.routine-ideation") but agents frequently misinterpret these instructions, leading to:
|
|
2549
2549
|
- Agents starting new workflow runs instead of spawning subagents via the Task tool
|
|
2550
2550
|
- Sequential execution when parallel delegation is requested
|
|
2551
2551
|
- Incorrect subagent type selection (using general-purpose instead of workrail-executor)
|
|
@@ -2589,7 +2589,7 @@ DO NOT call Task tools sequentially - make all {N} calls in one response block.
|
|
|
2589
2589
|
4. **Template consistency**: Standardized format across all workflows reduces learning overhead
|
|
2590
2590
|
|
|
2591
2591
|
**Implementation Requirement**:
|
|
2592
|
-
- Update all workflows that use delegation (coding-task
|
|
2592
|
+
- Update all workflows that use delegation (wr.coding-task, wr.mr-review, wr.bug-investigation, etc.) to use this explicit template
|
|
2593
2593
|
- Add this guidance to workflow authoring documentation
|
|
2594
2594
|
|
|
2595
2595
|
**Verification**:
|
|
@@ -175,12 +175,12 @@ The parent workflow declares extension points as a top-level field alongside `st
|
|
|
175
175
|
|
|
176
176
|
```json
|
|
177
177
|
{
|
|
178
|
-
"id": "coding-task
|
|
178
|
+
"id": "wr.coding-task",
|
|
179
179
|
"version": "2.2.0",
|
|
180
180
|
"extensionPoints": {
|
|
181
181
|
"design_review": {
|
|
182
182
|
"purpose": "Review a selected design for tradeoff quality, failure modes, simpler alternatives, and philosophy alignment.",
|
|
183
|
-
"defaultBinding": "routine-design-review",
|
|
183
|
+
"defaultBinding": "wr.routine-design-review",
|
|
184
184
|
"acceptedKinds": ["routine", "workflow"],
|
|
185
185
|
"inputContract": {
|
|
186
186
|
"requiredContext": ["selectedApproach", "acceptedTradeoffs", "identifiedFailureModes"],
|
|
@@ -192,7 +192,7 @@ The parent workflow declares extension points as a top-level field alongside `st
|
|
|
192
192
|
},
|
|
193
193
|
"plan_audit": {
|
|
194
194
|
"purpose": "Audit implementation plan for completeness, risk, and philosophy alignment.",
|
|
195
|
-
"defaultBinding": "routine-plan-analysis",
|
|
195
|
+
"defaultBinding": "wr.routine-plan-analysis",
|
|
196
196
|
"acceptedKinds": ["routine", "workflow"],
|
|
197
197
|
"inputContract": {
|
|
198
198
|
"requiredContext": ["implementationPlan", "slices", "invariants"],
|
|
@@ -204,7 +204,7 @@ The parent workflow declares extension points as a top-level field alongside `st
|
|
|
204
204
|
},
|
|
205
205
|
"final_verification": {
|
|
206
206
|
"purpose": "Verify implementation against acceptance criteria, invariants, and philosophy.",
|
|
207
|
-
"defaultBinding": "routine-final-verification",
|
|
207
|
+
"defaultBinding": "wr.routine-final-verification",
|
|
208
208
|
"acceptedKinds": ["routine", "workflow"],
|
|
209
209
|
"inputContract": {
|
|
210
210
|
"requiredContext": ["implementationPlan", "acceptanceCriteria", "invariants"],
|
|
@@ -293,7 +293,7 @@ Use extension points only when the seam is intentionally delegated and the deleg
|
|
|
293
293
|
|
|
294
294
|
### What is rebindable
|
|
295
295
|
|
|
296
|
-
Only routines/workflows listed in `extensionPoints` are rebindable. All other routine references (e.g., `routine-context-gathering`, `routine-execution-simulation`) remain hardcoded. The distinction between extension points and utility delegations must be explicit.
|
|
296
|
+
Only routines/workflows listed in `extensionPoints` are rebindable. All other routine references (e.g., `wr.routine-context-gathering`, `wr.routine-execution-simulation`) remain hardcoded. The distinction between extension points and utility delegations must be explicit.
|
|
297
297
|
|
|
298
298
|
## Implementation kinds
|
|
299
299
|
|
|
@@ -306,9 +306,9 @@ Best for:
|
|
|
306
306
|
|
|
307
307
|
Examples:
|
|
308
308
|
|
|
309
|
-
- `routine-design-review`
|
|
310
|
-
- `routine-final-verification`
|
|
311
|
-
- `routine-tension-driven-design`
|
|
309
|
+
- `wr.routine-design-review`
|
|
310
|
+
- `wr.routine-final-verification`
|
|
311
|
+
- `wr.routine-tension-driven-design`
|
|
312
312
|
|
|
313
313
|
### 2. Workflow implementation
|
|
314
314
|
|
|
@@ -414,7 +414,7 @@ The compiled workflow should include a **binding manifest**:
|
|
|
414
414
|
"hash": "sha256:abc123..."
|
|
415
415
|
},
|
|
416
416
|
"plan_audit": {
|
|
417
|
-
"resolvedTo": "routine-plan-analysis",
|
|
417
|
+
"resolvedTo": "wr.routine-plan-analysis",
|
|
418
418
|
"source": "default",
|
|
419
419
|
"kind": "routine",
|
|
420
420
|
"hash": "sha256:def456..."
|
|
@@ -450,7 +450,7 @@ Without this, debugging becomes too opaque.
|
|
|
450
450
|
|
|
451
451
|
The user experience should feel like:
|
|
452
452
|
|
|
453
|
-
- "Use `coding-task
|
|
453
|
+
- "Use `wr.coding-task`"
|
|
454
454
|
- "For `design_review`, use `my-team-security-review`"
|
|
455
455
|
|
|
456
456
|
Not:
|
|
@@ -470,7 +470,7 @@ Project-level overrides live in `.workrail/bindings.json`:
|
|
|
470
470
|
|
|
471
471
|
```json
|
|
472
472
|
{
|
|
473
|
-
"coding-task
|
|
473
|
+
"wr.coding-task": {
|
|
474
474
|
"design_review": "my-team-security-review",
|
|
475
475
|
"final_verification": "workflow-release-readiness-review"
|
|
476
476
|
}
|
|
@@ -480,7 +480,7 @@ Project-level overrides live in `.workrail/bindings.json`:
|
|
|
480
480
|
Per-run overrides via CLI:
|
|
481
481
|
|
|
482
482
|
```bash
|
|
483
|
-
workrail start coding-task
|
|
483
|
+
workrail start wr.coding-task \
|
|
484
484
|
--bind design_review=my-team-security-review
|
|
485
485
|
```
|
|
486
486
|
|
|
@@ -551,7 +551,7 @@ In the parent workflow JSON:
|
|
|
551
551
|
"extensionPoints": {
|
|
552
552
|
"final_verification": {
|
|
553
553
|
"purpose": "Verify implementation against acceptance criteria, invariants, and philosophy.",
|
|
554
|
-
"defaultBinding": "routine-final-verification",
|
|
554
|
+
"defaultBinding": "wr.routine-final-verification",
|
|
555
555
|
"acceptedKinds": ["routine", "workflow"],
|
|
556
556
|
"inputContract": {
|
|
557
557
|
"requiredContext": ["implementationPlan", "acceptanceCriteria", "invariants"]
|
|
@@ -591,7 +591,7 @@ In `.workrail/bindings.json`:
|
|
|
591
591
|
|
|
592
592
|
```json
|
|
593
593
|
{
|
|
594
|
-
"coding-task
|
|
594
|
+
"wr.coding-task": {
|
|
595
595
|
"final_verification": "workflow-release-readiness-review"
|
|
596
596
|
}
|
|
597
597
|
}
|
|
@@ -682,6 +682,6 @@ The bounded phase implementation framing leads to a better system design.
|
|
|
682
682
|
4. Add `.workrail/bindings.json` loading and resolution chain (CLI > project > default)
|
|
683
683
|
5. Include binding manifest in compiled workflow hash and session snapshot
|
|
684
684
|
6. Add `workrail inspect --extension-points` command
|
|
685
|
-
7. Convert `coding-task
|
|
685
|
+
7. Convert `wr.coding-task` prompt text to use `{{wr.bindings.*}}` refs for the initial 3 slots
|
|
686
686
|
8. Add slot compatibility metadata to routines/workflows
|
|
687
687
|
9. Implement contract validation (required inputs available, required outputs produced)
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
### The Bug
|
|
12
12
|
|
|
13
|
-
A user writes `workflowId: coding-task
|
|
13
|
+
A user writes `workflowId: wr.coding-task.lean.v2` (filename without extension) instead of `wr.coding-task` (the actual workflow ID). The daemon starts fine, accepts webhooks, but every dispatch silently fails with `workflow_not_found`. The error only surfaces in logs, not at startup. The operator has no way to know their trigger is broken until they watch logs during an actual webhook event.
|
|
14
14
|
|
|
15
15
|
### Core Tensions
|
|
16
16
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## 1. Problem Statement
|
|
10
10
|
|
|
11
|
-
When a user writes an incorrect `workflowId` in `triggers.yml` (e.g., `coding-task
|
|
11
|
+
When a user writes an incorrect `workflowId` in `triggers.yml` (e.g., `wr.coding-task.lean.v2` instead of `wr.coding-task`), the daemon starts successfully, accepts webhooks, but every dispatch silently fails with `workflow_not_found`. The error only appears in logs during actual webhook events -- not at startup. This is a silent-failure bug.
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -135,7 +135,7 @@ Production default (not on the option -- called inline): `async (id) => (await c
|
|
|
135
135
|
|
|
136
136
|
**Fixtures needed:**
|
|
137
137
|
- A minimal `triggers.yml` with two triggers: one with valid workflowId, one with invalid
|
|
138
|
-
- `getWorkflowByIdFn` stub: `vi.fn().mockImplementation(async (id: string) => id === 'coding-task
|
|
138
|
+
- `getWorkflowByIdFn` stub: `vi.fn().mockImplementation(async (id: string) => id === 'wr.coding-task')`
|
|
139
139
|
|
|
140
140
|
**Note:** Tests write real `triggers.yml` files to `tmpPath()` directories (pattern established in existing tests). Check how existing `startTriggerListener` tests set up workspace directories.
|
|
141
141
|
|