@exaudeus/workrail 3.33.0 → 3.34.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/cli-worktrain.js +167 -8
- package/dist/console-ui/assets/{index-BuJFLLfY.js → index-BVU9OSOb.js} +1 -1
- package/dist/console-ui/index.html +1 -1
- package/dist/daemon/agent-loop.d.ts +1 -0
- package/dist/daemon/agent-loop.js +1 -1
- package/dist/daemon/daemon-events.d.ts +17 -1
- package/dist/daemon/workflow-runner.d.ts +1 -1
- package/dist/daemon/workflow-runner.js +96 -21
- package/dist/manifest.json +45 -69
- package/dist/mcp/handlers/v2-error-mapping.d.ts +3 -0
- package/dist/mcp/handlers/v2-error-mapping.js +2 -0
- package/dist/mcp/handlers/v2-execution/advance.js +25 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.js +7 -0
- package/dist/mcp/transports/http-entry.js +0 -7
- package/dist/mcp/transports/stdio-entry.js +0 -8
- package/dist/mcp-server.d.ts +0 -2
- package/dist/mcp-server.js +1 -42
- package/dist/trigger/polled-event-store.js +8 -6
- package/dist/v2/durable-core/domain/observation-builder.d.ts +3 -0
- package/dist/v2/durable-core/domain/observation-builder.js +2 -2
- package/dist/v2/durable-core/domain/prompt-renderer.d.ts +2 -1
- package/dist/v2/durable-core/domain/prompt-renderer.js +10 -0
- package/dist/v2/usecases/console-service.js +65 -14
- package/dist/v2/usecases/console-types.d.ts +1 -0
- package/docs/design/bridge-removal-pr-a-candidates.md +115 -0
- package/docs/design/bridge-removal-pr-a-design-review.md +79 -0
- package/docs/design/bridge-removal-pr-a-implementation-plan.md +203 -0
- package/docs/discovery/design-candidates.md +180 -0
- package/docs/discovery/design-review-findings.md +110 -0
- package/docs/discovery/wr-discovery-goal-reframing.md +303 -0
- package/docs/ideas/backlog.md +361 -0
- package/package.json +1 -1
- package/workflows/wr.discovery.json +58 -7
- package/dist/mcp/transports/bridge-entry.d.ts +0 -102
- package/dist/mcp/transports/bridge-entry.js +0 -454
- package/dist/mcp/transports/bridge-events.d.ts +0 -55
- package/dist/mcp/transports/bridge-events.js +0 -24
- package/dist/mcp/transports/primary-tombstone.d.ts +0 -21
- package/dist/mcp/transports/primary-tombstone.js +0 -51
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# PR-A Bridge Removal -- Implementation Plan
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-04-17
|
|
4
|
+
**Branch:** `feat/mcp-simplify-remove-bridge`
|
|
5
|
+
**Confidence:** High
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem Statement
|
|
10
|
+
|
|
11
|
+
The WorkRail MCP server contains a bridge mechanism (bridge-entry.ts, primary-tombstone.ts, bridge-events.ts) that was built to solve port contention between multiple Claude Code windows. PR #512 (merged) introduced `worktrain console` as a standalone process that owns the dashboard UI independently of the MCP server. The bridge mechanism's reason for existence is gone. It adds ~1127 lines of reconnect state machine, spawn coordination, and tombstone logic that make startup non-deterministic (150ms probe delay) and increase operational complexity.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Acceptance Criteria
|
|
16
|
+
|
|
17
|
+
1. `src/mcp/transports/bridge-entry.ts` does not exist
|
|
18
|
+
2. `src/mcp/transports/primary-tombstone.ts` does not exist
|
|
19
|
+
3. `src/mcp/transports/bridge-events.ts` does not exist
|
|
20
|
+
4. `src/mcp-server.ts` no longer imports or re-exports `startBridgeServer`, `detectHealthyPrimary`, or `waitForStdinReadable`
|
|
21
|
+
5. `src/mcp-server.ts` no longer contains the auto-bridge detection block (lines 89-118 in current file)
|
|
22
|
+
6. `src/mcp/transports/stdio-entry.ts` no longer imports from `primary-tombstone.ts` or `bridge-events.ts`
|
|
23
|
+
7. `src/mcp/transports/http-entry.ts` no longer imports from `primary-tombstone.ts` or `bridge-events.ts`
|
|
24
|
+
8. `npm run build` exits 0 with 0 TypeScript errors
|
|
25
|
+
9. `npm test` exits 0
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Non-Goals
|
|
30
|
+
|
|
31
|
+
- HttpServer removal (PR-B)
|
|
32
|
+
- ToolContext changes
|
|
33
|
+
- DI token cleanup
|
|
34
|
+
- Any change to http-entry.ts transport logic (MCP-over-HTTP for bot services)
|
|
35
|
+
- Modifying http-listener.ts or http-listener.test.ts
|
|
36
|
+
- Removing `ctx.httpServer?.stop()` from shutdown hooks (HttpServer still starts in PR-A state)
|
|
37
|
+
- Cleaning up `worktrain-spawn.ts` / `worktrain-await.ts` dashboard.lock fallback (chore PR later)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Philosophy-Driven Constraints
|
|
42
|
+
|
|
43
|
+
- **Architectural fixes over patches:** Delete root cause, not add flags
|
|
44
|
+
- **YAGNI:** Delete all three modules with no callers
|
|
45
|
+
- **Determinism:** Startup path must be a single unconditional call to `startStdioServer()` for stdio mode
|
|
46
|
+
- **Commit type:** `chore(mcp)` -- internal cleanup, no user-visible behavior change, no tool contract change
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Invariants
|
|
51
|
+
|
|
52
|
+
1. `WORKRAIL_TRANSPORT=http` path must still work -- `startHttpServer()` is called unconditionally for http mode
|
|
53
|
+
2. `WORKRAIL_TRANSPORT=stdio` must call `startStdioServer()` directly after removal -- no probe, no bridge detection
|
|
54
|
+
3. `mcp/index.ts` exports must be unchanged (confirmed: no bridge symbols were re-exported)
|
|
55
|
+
4. `tests/integration/mcp-http-transport.test.ts` must pass -- MCP-over-HTTP transport is untouched
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Selected Approach
|
|
60
|
+
|
|
61
|
+
**Direct deletion with targeted import removal.** Delete 3 source files and 3 test files. Remove their imports and call sites from 3 modified source files. TypeScript compiler verifies completeness at the import boundary.
|
|
62
|
+
|
|
63
|
+
**Runner-up:** None. All alternatives were anti-patterns.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Vertical Slices
|
|
68
|
+
|
|
69
|
+
### Slice 1: Create branch and verify baseline
|
|
70
|
+
|
|
71
|
+
- Create git branch `feat/mcp-simplify-remove-bridge` from current HEAD
|
|
72
|
+
- Run `npm run build` to confirm baseline is green
|
|
73
|
+
- Run `npm test` to confirm baseline test suite is green
|
|
74
|
+
- **Done when:** Both commands exit 0
|
|
75
|
+
|
|
76
|
+
### Slice 2: Delete source files
|
|
77
|
+
|
|
78
|
+
- Delete `src/mcp/transports/bridge-entry.ts`
|
|
79
|
+
- Delete `src/mcp/transports/primary-tombstone.ts`
|
|
80
|
+
- Delete `src/mcp/transports/bridge-events.ts`
|
|
81
|
+
- **Done when:** Files do not exist on disk
|
|
82
|
+
|
|
83
|
+
### Slice 3: Delete test files
|
|
84
|
+
|
|
85
|
+
- Delete `tests/unit/mcp/transports/bridge-entry.test.ts`
|
|
86
|
+
- Delete `tests/unit/mcp/transports/primary-tombstone.test.ts`
|
|
87
|
+
- Delete `tests/unit/mcp/stdin-probe.test.ts`
|
|
88
|
+
- **Done when:** Files do not exist on disk
|
|
89
|
+
|
|
90
|
+
### Slice 4: Modify mcp-server.ts
|
|
91
|
+
|
|
92
|
+
Remove the following from `src/mcp-server.ts`:
|
|
93
|
+
- Import of `startBridgeServer`, `detectHealthyPrimary` from `./mcp/transports/bridge-entry.js`
|
|
94
|
+
- Re-export of `startBridgeServer`, `detectHealthyPrimary` from `./mcp/transports/bridge-entry.js`
|
|
95
|
+
- `STDIO_CLIENT_PROBE_MS` constant (line 49)
|
|
96
|
+
- `waitForStdinReadable` function (lines 62-82)
|
|
97
|
+
- Auto-bridge detection block inside `main()` (lines 88-118)
|
|
98
|
+
- Top JSDoc comment block (lines 11-24) describing auto-bridge -- replace with simplified description
|
|
99
|
+
- **Done when:** File compiles with no errors referencing bridge-entry; `main()` calls `startStdioServer()` unconditionally for stdio mode
|
|
100
|
+
|
|
101
|
+
### Slice 5: Modify stdio-entry.ts
|
|
102
|
+
|
|
103
|
+
Remove from `src/mcp/transports/stdio-entry.ts`:
|
|
104
|
+
- Import: `import { writeTombstone, clearTombstone } from './primary-tombstone.js'`
|
|
105
|
+
- Import: `import { logBridgeEvent } from './bridge-events.js'`
|
|
106
|
+
- Call: `logBridgeEvent({ kind: 'primary_started', transport: 'stdio' })` (line 39)
|
|
107
|
+
- Call: `clearTombstone()` (line 44)
|
|
108
|
+
- In `onBeforeTerminate`: remove the tombstone write block (lines 124-127: `const port = ctx.httpServer?.getPort(); if (port != null) { writeTombstone(port, process.pid); }`)
|
|
109
|
+
- **Done when:** File compiles with no imports or references to deleted modules; `onBeforeTerminate` only calls `await ctx.httpServer?.stop()`
|
|
110
|
+
|
|
111
|
+
### Slice 6: Modify http-entry.ts
|
|
112
|
+
|
|
113
|
+
Remove from `src/mcp/transports/http-entry.ts` (tombstone/bridge-events call sites ONLY):
|
|
114
|
+
- Import: `import { clearTombstone, writeTombstone } from './primary-tombstone.js'`
|
|
115
|
+
- Import: `import { logBridgeEvent } from './bridge-events.js'`
|
|
116
|
+
- Call: `logBridgeEvent({ kind: 'primary_started', transport: 'http', port })` (line 32)
|
|
117
|
+
- Call: `clearTombstone()` (line 35)
|
|
118
|
+
- In `onBeforeTerminate`: remove `if (boundPort != null) { writeTombstone(boundPort, process.pid); }` (lines 111-113)
|
|
119
|
+
- **Done when:** File compiles with no imports or references to deleted modules; ALL transport logic (bindWithPortFallback, MCP endpoint registration, health endpoint) is unchanged
|
|
120
|
+
|
|
121
|
+
### Slice 7: Build and test verification
|
|
122
|
+
|
|
123
|
+
- Run `npm run build` -- must exit 0 with 0 errors
|
|
124
|
+
- Run `npm test` -- must exit 0
|
|
125
|
+
- **Done when:** Both commands succeed
|
|
126
|
+
|
|
127
|
+
### Slice 8: Commit and push PR
|
|
128
|
+
|
|
129
|
+
- `git add` the 6 deleted files and 3 modified source files
|
|
130
|
+
- Commit with message: `chore(mcp): remove bridge, tombstone, and bridge-events from MCP server`
|
|
131
|
+
- Push branch and create PR against main
|
|
132
|
+
- **Done when:** PR is open
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Test Design
|
|
137
|
+
|
|
138
|
+
**Tests to delete:**
|
|
139
|
+
- `tests/unit/mcp/transports/bridge-entry.test.ts` -- imports deleted module
|
|
140
|
+
- `tests/unit/mcp/transports/primary-tombstone.test.ts` -- imports deleted module
|
|
141
|
+
- `tests/unit/mcp/stdin-probe.test.ts` -- imports `waitForStdinReadable` from mcp-server.ts (also deleted)
|
|
142
|
+
|
|
143
|
+
**Tests that must stay green:**
|
|
144
|
+
- `tests/unit/mcp-server.test.ts` -- reads mcp-server.ts as string; no assertion for bridge exports
|
|
145
|
+
- `tests/unit/mcp/http-listener.test.ts` -- tests createHttpListener lifecycle; no bridge dependency
|
|
146
|
+
- `tests/integration/mcp-http-transport.test.ts` -- tests MCP-over-HTTP; no bridge dependency
|
|
147
|
+
- All other tests (no bridge imports in non-deleted test files)
|
|
148
|
+
|
|
149
|
+
**No new tests required.** The change is a deletion; the verification is `npm run build` (0 errors) + `npm test`.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Risk Register
|
|
154
|
+
|
|
155
|
+
| Risk | Likelihood | Impact | Mitigation |
|
|
156
|
+
|---|---|---|---|
|
|
157
|
+
| Missed import in unexpected file | Low | Build failure | Grep sweep confirmed before implementation: only 7 files (5 src, 2 tests) import from deleted modules |
|
|
158
|
+
| http-entry.ts transport logic broken | Low | Runtime failure | Tombstone call sites are isolated lines; transport logic verified as non-overlapping |
|
|
159
|
+
| mcp-server.test.ts string assertions fail | Low | Test failure | Test file read in full; no assertion for bridge exports |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## PR Packaging Strategy
|
|
164
|
+
|
|
165
|
+
Single PR. Branch: `feat/mcp-simplify-remove-bridge`. All 8 slices in one commit.
|
|
166
|
+
|
|
167
|
+
Commit message: `chore(mcp): remove bridge, tombstone, and bridge-events from MCP server`
|
|
168
|
+
|
|
169
|
+
PR description must include:
|
|
170
|
+
- What was deleted and why (bridge mechanism superseded by standalone worktrain console)
|
|
171
|
+
- What was NOT changed (http-entry.ts transport logic, http-listener.ts, ToolContext)
|
|
172
|
+
- Link to design doc: `docs/design/stdio-simplification-design-candidates.md` PR-A section
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Philosophy Alignment Per Slice
|
|
177
|
+
|
|
178
|
+
| Slice | Principle | Status |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| All slices | Architectural fixes over patches | Satisfied -- root cause deleted, no shim |
|
|
181
|
+
| Slice 2-3 | YAGNI with discipline | Satisfied -- all 3 modules have zero callers post-removal |
|
|
182
|
+
| Slice 4 | Determinism over cleverness | Satisfied -- startup becomes single unconditional call |
|
|
183
|
+
| Slice 4 | Make illegal states unrepresentable | Satisfied -- waitForStdinReadable deleted |
|
|
184
|
+
| Slice 4 | Document why, not what | Satisfied -- JSDoc updated to reflect simplified behavior |
|
|
185
|
+
| Slice 5-6 | Type safety as first line | Satisfied -- compiler verifies no remaining references |
|
|
186
|
+
| Slice 6 | Keep interfaces small | Satisfied -- http-entry.ts shrinks, transport logic unchanged |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Follow-Up Tickets
|
|
191
|
+
|
|
192
|
+
- `worktrain-spawn.ts` and `worktrain-await.ts` `dashboard.lock` fallback is now permanently dead code. Remove in a separate chore PR.
|
|
193
|
+
- PR-B: Remove HttpServer from MCP server startup entirely.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Unresolved Unknown Count
|
|
198
|
+
|
|
199
|
+
**0.** All import surfaces verified, failure modes addressed, acceptance criteria measurable.
|
|
200
|
+
|
|
201
|
+
## Plan Confidence Band
|
|
202
|
+
|
|
203
|
+
**High.**
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Design Candidates: wr.discovery Goal Reframing
|
|
2
|
+
|
|
3
|
+
**Status:** Candidate generation complete -- for main agent review
|
|
4
|
+
**Date:** 2026-04-18
|
|
5
|
+
**Session:** wr.discovery (improving goal reframing)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem Understanding
|
|
10
|
+
|
|
11
|
+
### Core tensions
|
|
12
|
+
|
|
13
|
+
**T1: Early interrogation vs late-discovered context**
|
|
14
|
+
Goal interrogation in Phase 0 happens before any landscape work. Some hidden assumptions only become visible after reading the codebase. An early interrogation catches structural goal-type issues (solution-framed vs problem-framed) but misses context-dependent assumptions. Phase 1g retriage catches these later -- but only if the agent explicitly sets `retriageNeeded = true`.
|
|
15
|
+
|
|
16
|
+
**T2: Non-interactive constraint vs interrogation quality**
|
|
17
|
+
The best reframing comes from dialogue. Daemon sessions have no human. Non-interactive interrogation means the agent interrogates itself, which risks circular reasoning (surfacing expected assumptions rather than genuinely hidden ones).
|
|
18
|
+
|
|
19
|
+
**T3: Overhead for well-framed goals**
|
|
20
|
+
Any mandatory goal-challenge step adds overhead to every session, including correctly-framed ones. The mechanism must be lightweight for good goals, substantial for misframed ones.
|
|
21
|
+
|
|
22
|
+
**T4: Workflow enforcement vs agent judgment**
|
|
23
|
+
The workflow can instruct the agent to classify a goal, but the classification itself is still LLM output. A `runCondition` on `goalType = solution_framed` is structural, but the `goalType` value is agent judgment. There is no escape from this.
|
|
24
|
+
|
|
25
|
+
### Likely seam
|
|
26
|
+
|
|
27
|
+
Phase 0's `procedure` block -- specifically the `Capture` step that lists context variables and the path selection logic. This is where goal misframing has the highest downstream impact (wrong `pathRecommendation` propagates through all subsequent steps).
|
|
28
|
+
|
|
29
|
+
### What makes this hard
|
|
30
|
+
|
|
31
|
+
1. The agent interrogates itself -- self-adversarial reasoning is weaker than adversarial reasoning against a well-defined artifact
|
|
32
|
+
2. Solution-framed goals can look like problem-framed goals ('improve discovery' looks like a problem frame but contains hidden assumptions)
|
|
33
|
+
3. Adding required output fields to Phase 0 means sessions starting mid-workflow (without Phase 0 context) need graceful fallback
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Philosophy Constraints
|
|
38
|
+
|
|
39
|
+
| Principle | Constraint |
|
|
40
|
+
|---|---|
|
|
41
|
+
| Validate at boundaries, trust inside | Phase 0 is the input boundary; it must validate goal framing |
|
|
42
|
+
| Make illegal states unrepresentable | Solution-framed goal processed without interrogation should not be a valid state |
|
|
43
|
+
| YAGNI with discipline | The mechanism must add near-zero cost for well-framed goals |
|
|
44
|
+
| Architectural fixes over patches | The fix should change structural invariants, not add 'be careful' reminders |
|
|
45
|
+
| Determinism over cleverness | Same goalType -> same downstream path bias |
|
|
46
|
+
|
|
47
|
+
**Philosophy conflict:** 'Make illegal states unrepresentable' conflicts with 'YAGNI with discipline' when it comes to adding a mandatory interrogation step. A mandatory step is more enforceable but adds overhead for every session.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Impact Surface
|
|
52
|
+
|
|
53
|
+
| Surface | Must stay consistent |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `pathRecommendation` context variable | Set by Phase 0; used by all phase-1 `runCondition` gates |
|
|
56
|
+
| `problemStatement` context variable | Should reflect the actual problem, not the stated solution |
|
|
57
|
+
| `designDocPath` content | Problem framing section becomes misleading if it reflects a solution-framed goal verbatim |
|
|
58
|
+
| Phase 1g `retriageNeeded` trigger | If retriage condition changes, existing sessions may behave differently |
|
|
59
|
+
| Daemon sessions | Cannot be blocked on interactive responses |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Candidates
|
|
64
|
+
|
|
65
|
+
### Candidate 1: Minimal -- Extend Phase 0 `Capture` with `goalType` and `impliedProblem`
|
|
66
|
+
|
|
67
|
+
**Summary:** Add `goalType` (4-value closed enum: `solution_framed | problem_framed | opportunity_framed | decision_framed`) and `impliedProblem` to the Phase 0 `Capture` step. Add a procedure instruction: classify first, derive `impliedProblem` when `solution_framed`, then select path with `goalType` awareness.
|
|
68
|
+
|
|
69
|
+
**Tensions resolved:** T3 (near-zero overhead for well-framed goals -- classification is lightweight), T4 partially (structural variable exists)
|
|
70
|
+
**Tensions accepted:** T1 (pre-context), T2 (self-interrogation), T4 fully (goalType is still agent judgment)
|
|
71
|
+
|
|
72
|
+
**Boundary:** Phase 0 `Capture` list and `procedure` text
|
|
73
|
+
|
|
74
|
+
**Why best fit:** Phase 0 already captures 12+ context variables. Adding `goalType` and `impliedProblem` follows the established pattern. No new step IDs, no new `runCondition` chains, fully backward compatible.
|
|
75
|
+
|
|
76
|
+
**Failure mode:** Agent classifies a solution-framed goal as `opportunity_framed`, skipping `impliedProblem` derivation. No structural enforcement prevents this.
|
|
77
|
+
|
|
78
|
+
**Repo pattern:** Follows the existing 'Phase 0 captures context variables for downstream use' pattern.
|
|
79
|
+
|
|
80
|
+
**Gains:** Zero new steps. Backward compatible. `goalType` available for all downstream phases.
|
|
81
|
+
**Gives up:** No enforcement that classification happens before path selection. Still relies on procedure text instructions, not structural ordering.
|
|
82
|
+
|
|
83
|
+
**Scope judgment: best-fit as a minimal change.** Not too narrow (introduces the structural signal). Not too broad (no new steps).
|
|
84
|
+
|
|
85
|
+
**Philosophy:** Honors 'YAGNI', 'Determinism'. Conflicts with 'Make illegal states unrepresentable' (misframings are still structurally possible).
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### Candidate 2: Structural -- New mandatory Phase 0a before current Phase 0
|
|
90
|
+
|
|
91
|
+
**Summary:** Add a new step `phase-0a-goal-interrogation` that runs before the current Phase 0. Always runs. Required outputs: `goalType` (4-value enum), `impliedProblem` (string, required when `solution_framed`), `hiddenAssumptions` (array, min 1 when `goalType != problem_framed`), `alternativeFraming` (string, optional). Phase 0 then reads `goalType` from context rather than deriving it.
|
|
92
|
+
|
|
93
|
+
**Tensions resolved:** T3 partially (well-framed goals produce trivial Phase 0a output fast), T4 (structural enforcement -- path selection cannot happen without Phase 0a having run)
|
|
94
|
+
**Tensions accepted:** T1 (still pre-landscape), T2 (self-interrogation)
|
|
95
|
+
|
|
96
|
+
**Boundary:** A new step with ID `phase-0a-goal-interrogation`, inserted as the first step of the workflow. Phase 0 becomes a consumer of `goalType` rather than its producer.
|
|
97
|
+
|
|
98
|
+
**Why best fit:** True structural enforcement. Phase 0a is a required step. The interrogation runs before path selection by design, not by instruction. Mirrors the existing `phase-0b-capability-setup` pattern (a pre-phase setup step before the main classification phase).
|
|
99
|
+
|
|
100
|
+
**Failure mode:** For well-framed goals, Phase 0a adds overhead. More importantly: Phase 0a and Phase 0 can produce contradictory conclusions if the agent reconsiders its interpretation between steps.
|
|
101
|
+
|
|
102
|
+
**Repo pattern:** Adapts the `phase-0b-capability-setup` pattern. Departs in that Phase 0a runs before Phase 0 (changes existing step order).
|
|
103
|
+
|
|
104
|
+
**Gains:** True enforcement. `hiddenAssumptions` and `alternativeFraming` become required outputs with engine validation. Sets a seam for a future reusable `routine-goal-interrogation`.
|
|
105
|
+
**Gives up:** Adds a step to every session (overhead for well-framed goals). Changes step order (Phase 0 is no longer the first step).
|
|
106
|
+
|
|
107
|
+
**Scope judgment: best-fit for structural correctness, slightly overbroad for immediate need.** The structural separation is the correct long-term architecture.
|
|
108
|
+
|
|
109
|
+
**Philosophy:** Honors 'Architectural fixes over patches', 'Make illegal states unrepresentable', 'Validate at boundaries'. Conflicts with 'YAGNI with discipline'.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### Candidate 3: Distributed -- Three targeted strengthening changes to existing steps
|
|
114
|
+
|
|
115
|
+
**Summary:** No new steps. Three changes: (1) add `goalType` classification + `impliedProblem` to Phase 0 procedure (same as C1). (2) Make `problemFrameTemplate`'s 'What would make this framing wrong' field a required non-empty output contract in Phase 1e/1f steps. (3) Change Phase 1g `runCondition` from `retriageNeeded = true` to `pathRecommendation == design_first || pathRecommendation == full_spectrum` (retriage always runs for these paths).
|
|
116
|
+
|
|
117
|
+
**Tensions resolved:** T1 (distributed checkpoints catch both pre-context issues at Phase 0 and post-landscape issues at Phase 1g), T3 (no new steps)
|
|
118
|
+
**Tensions accepted:** T2 (self-interrogation at all checkpoints), T4 partially
|
|
119
|
+
|
|
120
|
+
**Boundary:** Three existing steps: Phase 0 (procedure text), Phase 1e/1f (output contract), Phase 1g (runCondition).
|
|
121
|
+
|
|
122
|
+
**Why best fit:** Fixes the three specific weak points in the existing design without adding new steps. Distributed checkpoints catch more than a single-point interrogation.
|
|
123
|
+
|
|
124
|
+
**Failure mode:** An agent anchored to the original framing can produce weak 'what would make this wrong' answers -- required non-empty output enforces form but not quality. Phase 1g always-on for `design_first` runs a (potentially unnecessary) retriage step for sessions where the path was correct from the start.
|
|
125
|
+
|
|
126
|
+
**Repo pattern:** Adapts existing `outputRequired` contract pattern. Adapts `runCondition` pattern. Follows (not departs from) established mechanisms.
|
|
127
|
+
|
|
128
|
+
**Gains:** No new steps. Reinforces three existing weak mechanisms. Catches both early and late misframings.
|
|
129
|
+
**Gives up:** No single strong enforcement point. Effect is diffuse. Does not fix path-selection bias (wrong path can still be chosen in Phase 0 before Phase 1g runs).
|
|
130
|
+
|
|
131
|
+
**Scope judgment: too narrow as standalone, best-fit as complement to C1 or C2.**
|
|
132
|
+
|
|
133
|
+
**Philosophy:** Honors 'YAGNI with discipline', 'Architectural fixes over patches'. Conflicts with 'Make illegal states unrepresentable' (path selection still uses raw stated goal).
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Comparison and Recommendation
|
|
138
|
+
|
|
139
|
+
### Tension resolution matrix
|
|
140
|
+
|
|
141
|
+
| Tension | C1 (Phase 0 extension) | C2 (new Phase 0a) | C3 (distributed) |
|
|
142
|
+
|---|---|---|---|
|
|
143
|
+
| T1: pre-context interrogation | Accepts | Accepts | Resolves (Phase 1g post-landscape) |
|
|
144
|
+
| T2: self-interrogation quality | Accepts (same for all) | Accepts | Accepts |
|
|
145
|
+
| T3: overhead for well-framed goals | **Resolves** (lightweight) | Accepts (adds step) | **Resolves** (absorbed) |
|
|
146
|
+
| T4: structural enforcement | Partial | **Resolves** (mandatory step) | Partial |
|
|
147
|
+
|
|
148
|
+
### Recommendation: C1 + C3 hybrid, with C2 as future evolution
|
|
149
|
+
|
|
150
|
+
**Primary (immediate):** C1 extended with procedural strength: add `goalType`, `impliedProblem`, `hiddenAssumptions` to Phase 0 Capture as required context variables. Add explicit procedure: classify goal type first, derive implied problem before path selection, let goalType influence path bias toward `design_first` for `solution_framed` goals.
|
|
151
|
+
|
|
152
|
+
**Secondary (no new steps):** Three C3 changes: (a) `goalType` in Phase 0 (same as C1), (b) make 'What would make this framing wrong' a required non-empty output in Phase 1e/1f, (c) change Phase 1g `runCondition` to always run for `design_first` and `full_spectrum` paths.
|
|
153
|
+
|
|
154
|
+
**Future evolution:** If the C1+C3 hybrid proves insufficient for daemon sessions, extract Phase 0a as a mandatory pre-step (C2).
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Self-Critique
|
|
159
|
+
|
|
160
|
+
**Strongest argument against this recommendation:** C1's enforcement is procedural (instructions), not structural (step ordering). A capable LLM running in QUICK mode or under context pressure can skip the classification step and proceed to path selection. C2's mandatory separate step is the only way to structurally guarantee the interrogation happened.
|
|
161
|
+
|
|
162
|
+
**Counter:** Both approaches ultimately rely on the LLM following instructions. The difference is in how much structural scaffolding supports following those instructions. C2 enforces 'the step ran' not 'the step ran well.'
|
|
163
|
+
|
|
164
|
+
**Narrower option:** Just add `goalType` to the Capture list with no procedure change. Too narrow -- introduces the variable without the interrogation mechanism.
|
|
165
|
+
|
|
166
|
+
**Broader option:** Extract a reusable `routine-goal-interrogation` callable from any workflow. Justified if pattern proves valuable in other workflows. Not warranted now.
|
|
167
|
+
|
|
168
|
+
**Assumption that would invalidate this:** Claude Sonnet already implicitly reframes solution-framed goals. Counter-evidence: two real examples (MCP simplification, structured output session) show this is not reliably true.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Open Questions for the Main Agent
|
|
173
|
+
|
|
174
|
+
1. **Should `goalType` influence path selection automatically** (e.g., `solution_framed` -> force `design_first`) or **only as a soft bias**? Automatic enforcement is stronger but may override user intent for cases where the solution IS the right framing.
|
|
175
|
+
|
|
176
|
+
2. **How should `impliedProblem` flow to the design doc?** Should Phase 0 write it as the `problemStatement` in the design doc (replacing the stated goal), or record it as a separate field ('stated goal' vs 'implied problem')?
|
|
177
|
+
|
|
178
|
+
3. **Phase 1g runCondition change:** Making Phase 1g always run for `design_first` and `full_spectrum` is a behavior change for existing sessions. Is this backward compatible enough?
|
|
179
|
+
|
|
180
|
+
4. **`hiddenAssumptions` format:** Should this be a free-text field or a structured array? Free-text is easier to author; structured allows downstream steps to reference specific assumptions.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Design Review Findings: wr.discovery Goal Reframing
|
|
2
|
+
|
|
3
|
+
*Concise, actionable findings for main-agent synthesis. Not a final decision.*
|
|
4
|
+
**Date:** 2026-04-18
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Tradeoff Review
|
|
9
|
+
|
|
10
|
+
**Tradeoff 1: goalType classification remains agent judgment**
|
|
11
|
+
|
|
12
|
+
- Acceptable: this pattern is established in the workflow (rigorMode, pathRecommendation are all agent-derived)
|
|
13
|
+
- Classification examples in the procedure reduce misclassification probability
|
|
14
|
+
- **Finding: YELLOW.** Add goalType classification examples to procedure text to reduce ambiguity at the problem_framed / opportunity_framed boundary.
|
|
15
|
+
|
|
16
|
+
**Tradeoff 2: overhead for well-framed goals is nonzero**
|
|
17
|
+
|
|
18
|
+
- A few additional context variable captures and procedure lines in Phase 0
|
|
19
|
+
- Well-framed goals produce minimal output ('goalType = problem_framed, no impliedProblem needed')
|
|
20
|
+
- **Finding: NON-ISSUE.** Overhead is trivial.
|
|
21
|
+
|
|
22
|
+
**Tradeoff 3: Phase 1g always-on for design_first/full_spectrum**
|
|
23
|
+
|
|
24
|
+
- One additional advance per session for these paths
|
|
25
|
+
- Produces trivially short output for well-framed sessions ('pathChangedAfterContext = false')
|
|
26
|
+
- **CRITICAL CORRECTION NEEDED:** Phase 1g runCondition must be an OR (`retriageNeeded = true OR pathRecommendation in [design_first, full_spectrum]`) not a replacement. Otherwise landscape_first sessions that explicitly need retriage will not trigger it.
|
|
27
|
+
- **Finding: YELLOW.** Runnable as-designed if the OR condition is used correctly.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Failure Mode Review
|
|
32
|
+
|
|
33
|
+
**Failure mode 1: Agent misclassifies solution-framed goal as opportunity_framed**
|
|
34
|
+
- Status: **Partially mitigated.** C3's Phase 1e/1f required 'what would make this framing wrong' output provides a downstream catch. Classification examples in Phase 0 reduce probability.
|
|
35
|
+
- Missing mitigation: examples in procedure (address in revisions)
|
|
36
|
+
- **Finding: MEDIUM risk, mitigated.**
|
|
37
|
+
|
|
38
|
+
**Failure mode 2: 'What would make this framing wrong' output is formulaic**
|
|
39
|
+
- Status: **Partially mitigated.** Making it required non-empty enforces form but not quality.
|
|
40
|
+
- Missing mitigation: specificity instruction ('name ONE concrete condition, not a general caveat')
|
|
41
|
+
- **Finding: LOW-MEDIUM risk.**
|
|
42
|
+
|
|
43
|
+
**Failure mode 3: Phase 1g doesn't surface new insights for well-framed sessions**
|
|
44
|
+
- Status: **Non-issue by design.** For well-framed sessions, Phase 1g is a graceful no-op that confirms the path is still correct. One advance wasted, nothing more.
|
|
45
|
+
- **Finding: LOW risk, acceptable.**
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Runner-Up / Simpler Alternative Review
|
|
50
|
+
|
|
51
|
+
**C2 (mandatory Phase 0a):** The structural enforcement advantage is real but comes at the cost of a mandatory overhead step for all sessions. The C1+C3 hybrid achieves most of C2's value via procedure-level enforcement plus structural runCondition changes. C2 is the right escalation if the hybrid proves insufficient.
|
|
52
|
+
|
|
53
|
+
**Simpler variant:** Just one sentence added to Phase 0: 'If the goal is solution-framed, derive the underlying problem.' Too narrow -- no context variables means no downstream reference to the reframing.
|
|
54
|
+
|
|
55
|
+
**`alternativeFraming` addition from C2:** Borrowing C2's `alternativeFraming` requirement (one reframe even when the original goal seems correct) is high-value, low-cost. Add to Phase 0 design doc entry, not as a context variable.
|
|
56
|
+
|
|
57
|
+
**Finding: C1+C3 hybrid with two refinements (examples, alternativeFraming) stands. No direction change needed.**
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Philosophy Alignment
|
|
62
|
+
|
|
63
|
+
| Principle | Status |
|
|
64
|
+
|---|---|
|
|
65
|
+
| Validate at boundaries, trust inside | SATISFIED -- Phase 0 becomes an active validator |
|
|
66
|
+
| Make illegal states unrepresentable | PARTIALLY SATISFIED -- C3 structural changes help; C2 would fully satisfy |
|
|
67
|
+
| YAGNI with discipline | SATISFIED -- no new steps, minimal additions |
|
|
68
|
+
| Architectural fixes over patches | SATISFIED -- runCondition changes and required output contracts are structural |
|
|
69
|
+
| Determinism over cleverness | SATISFIED -- same goalType input produces same path behavior |
|
|
70
|
+
|
|
71
|
+
**One explicit philosophy tension:** 'Make illegal states unrepresentable' vs 'YAGNI with discipline' -- deliberately accepted, C2 is escalation path.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Findings
|
|
76
|
+
|
|
77
|
+
### Yellow findings
|
|
78
|
+
|
|
79
|
+
**Y1: goalType classification boundary ambiguity**
|
|
80
|
+
The boundary between `problem_framed` and `opportunity_framed` is unclear without examples. Add classification examples to Phase 0 procedure to reduce misclassification at this boundary.
|
|
81
|
+
|
|
82
|
+
**Y2: Phase 1g runCondition must be OR, not replacement**
|
|
83
|
+
The retriage step runCondition must be: `retriageNeeded = true OR pathRecommendation == design_first OR pathRecommendation == full_spectrum`. A straight replacement would break landscape_first sessions that legitimately need retriage.
|
|
84
|
+
|
|
85
|
+
**Y3: 'What would make this framing wrong' needs specificity instruction**
|
|
86
|
+
The required output field should specify 'name ONE concrete falsification condition, not a general caveat.' Without this, the field can be satisfied by formulaic responses.
|
|
87
|
+
|
|
88
|
+
### No Red or Orange findings
|
|
89
|
+
|
|
90
|
+
The selected C1+C3 direction has no material structural weaknesses.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Recommended Revisions
|
|
95
|
+
|
|
96
|
+
1. **Add goalType classification examples** to Phase 0 procedure (solution_framed: 'add X', 'implement Y', 'build X'; problem_framed: 'reduce X', 'fix Y'; opportunity_framed: 'explore X', 'decide whether Y'; decision_framed: 'choose between A and B')
|
|
97
|
+
|
|
98
|
+
2. **Add `alternativeFraming`** as a required design doc entry in Phase 0: 'Before selecting a path, generate one alternative framing -- if the stated goal is wrong, what would a better goal be?'
|
|
99
|
+
|
|
100
|
+
3. **Use OR condition for Phase 1g runCondition:** `retriageNeeded = true OR pathRecommendation in [design_first, full_spectrum]`
|
|
101
|
+
|
|
102
|
+
4. **Add specificity instruction** to Phase 1e/1f 'what would make this framing wrong' field: require naming one concrete falsification condition.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Residual Concerns
|
|
107
|
+
|
|
108
|
+
1. The goalType classification is LLM-dependent. Without empirical testing on real sessions, we cannot confirm the classification is reliable. This is an inherent limitation of the approach.
|
|
109
|
+
|
|
110
|
+
2. The C1+C3 hybrid does not prevent path-selection bias for the window between Phase 0 path selection and Phase 1g retriage. A session that selects the wrong path in Phase 0 runs several steps in the wrong direction before Phase 1g can correct it. Acceptable for STANDARD rigor; C2 is the correct escalation if this proves problematic.
|