deepflow 0.1.110 → 0.1.111
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/bin/wave-runner.js +11 -3
- package/bin/worktree-deps.js +28 -22
- package/package.json +1 -1
- package/src/commands/df/execute.md +62 -25
- package/src/commands/df/plan.md +8 -2
- package/src/commands/df/verify.md +2 -0
package/bin/wave-runner.js
CHANGED
|
@@ -83,9 +83,11 @@ function parsePlan(text) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// Match pending task header: - [ ] **T{N}**...
|
|
86
|
-
|
|
86
|
+
// Captures optional [TAG] as group 2 (e.g. INTEGRATION, SPIKE, OPTIMIZE)
|
|
87
|
+
const taskMatch = line.match(/^\s*-\s+\[\s+\]\s+\*\*T(\d+)\*\*(?:\s+\[([^\]]*)\])?[:\s]*(.*)/);
|
|
87
88
|
if (taskMatch) {
|
|
88
|
-
const
|
|
89
|
+
const rawTag = taskMatch[2] ? taskMatch[2].trim().toUpperCase() : null;
|
|
90
|
+
const rest = taskMatch[3].trim();
|
|
89
91
|
|
|
90
92
|
// Extract inline blocked-by (from " | Blocked by: T1, T2")
|
|
91
93
|
let inlineBlockedBy = [];
|
|
@@ -118,6 +120,7 @@ function parsePlan(text) {
|
|
|
118
120
|
files: null,
|
|
119
121
|
effort: inlineEffort,
|
|
120
122
|
spec: currentSpec,
|
|
123
|
+
tag: rawTag,
|
|
121
124
|
};
|
|
122
125
|
tasks.push(current);
|
|
123
126
|
continue;
|
|
@@ -275,13 +278,14 @@ function buildWaves(tasks, stuckIds) {
|
|
|
275
278
|
|
|
276
279
|
/**
|
|
277
280
|
* Format waves as a JSON array of task objects, each with a `wave` field.
|
|
278
|
-
* Fields: id, description, model, files, effort, blockedBy, spec, wave
|
|
281
|
+
* Fields: id, description, model, files, effort, blockedBy, spec, tag, isIntegration, isSpike, isOptimize, wave
|
|
279
282
|
*/
|
|
280
283
|
function formatWavesJson(waves) {
|
|
281
284
|
const result = [];
|
|
282
285
|
for (let i = 0; i < waves.length; i++) {
|
|
283
286
|
const waveNum = i + 1;
|
|
284
287
|
for (const t of waves[i]) {
|
|
288
|
+
const tag = t.tag || null;
|
|
285
289
|
result.push({
|
|
286
290
|
id: t.id,
|
|
287
291
|
description: t.description || null,
|
|
@@ -290,6 +294,10 @@ function formatWavesJson(waves) {
|
|
|
290
294
|
effort: t.effort || null,
|
|
291
295
|
blockedBy: t.blockedBy,
|
|
292
296
|
spec: t.spec || null,
|
|
297
|
+
tag: tag,
|
|
298
|
+
isIntegration: tag === 'INTEGRATION',
|
|
299
|
+
isSpike: tag === 'SPIKE',
|
|
300
|
+
isOptimize: tag === 'OPTIMIZE',
|
|
293
301
|
wave: waveNum,
|
|
294
302
|
});
|
|
295
303
|
}
|
package/bin/worktree-deps.js
CHANGED
|
@@ -41,38 +41,44 @@ function parseArgs() {
|
|
|
41
41
|
|
|
42
42
|
function findNodeModules(root) {
|
|
43
43
|
const results = [];
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
|
|
46
|
+
function addIfNM(relDir) {
|
|
47
|
+
if (seen.has(relDir)) return;
|
|
48
|
+
const abs = path.join(root, relDir, 'node_modules');
|
|
49
|
+
if (fs.existsSync(abs)) {
|
|
50
|
+
seen.add(relDir);
|
|
51
|
+
results.push(relDir === '.' ? 'node_modules' : path.join(relDir, 'node_modules'));
|
|
52
|
+
}
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
// Root node_modules
|
|
56
|
+
addIfNM('.');
|
|
57
|
+
|
|
58
|
+
// Walk every top-level directory up to 2 levels deep looking for node_modules.
|
|
59
|
+
// This covers both flat layouts (go/frontend, web/admin) and monorepo layouts
|
|
60
|
+
// (packages/foo, apps/bar) without hardcoding directory names.
|
|
61
|
+
function walk(relDir, depth) {
|
|
62
|
+
if (depth > 2) return;
|
|
63
|
+
const abs = path.join(root, relDir);
|
|
58
64
|
let entries;
|
|
59
65
|
try {
|
|
60
|
-
entries = fs.readdirSync(
|
|
66
|
+
entries = fs.readdirSync(abs, { withFileTypes: true });
|
|
61
67
|
} catch (_) {
|
|
62
|
-
|
|
68
|
+
return;
|
|
63
69
|
}
|
|
64
|
-
|
|
65
70
|
for (const entry of entries) {
|
|
66
|
-
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
71
|
+
if (!entry.isDirectory()) continue;
|
|
72
|
+
if (entry.name.startsWith('.')) continue;
|
|
73
|
+
if (entry.name === 'node_modules') continue;
|
|
74
|
+
const childRel = relDir === '.' ? entry.name : path.join(relDir, entry.name);
|
|
75
|
+
addIfNM(childRel);
|
|
76
|
+
walk(childRel, depth + 1);
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
walk('.', 1);
|
|
81
|
+
|
|
76
82
|
return results;
|
|
77
83
|
}
|
|
78
84
|
|
package/package.json
CHANGED
|
@@ -40,44 +40,55 @@ Each task = one background agent. **NEVER use TaskOutput** (100KB+ transcripts e
|
|
|
40
40
|
`--continue` → load `.deepflow/checkpoint.json`, verify worktree exists (else error "Use --fresh"), skip completed. `--fresh` → delete checkpoint. Checkpoint exists → prompt "Resume? (y/n)".
|
|
41
41
|
Shell: `` !`cat .deepflow/checkpoint.json 2>/dev/null || echo 'NOT_FOUND'` `` / `` !`git diff --quiet && echo 'CLEAN' || echo 'DIRTY'` ``
|
|
42
42
|
|
|
43
|
-
### 1.5. CREATE
|
|
43
|
+
### 1.5. CREATE WORKTREES (per spec)
|
|
44
44
|
|
|
45
|
-
Require clean HEAD.
|
|
45
|
+
Require clean HEAD. Discover **all** specs in execution scope:
|
|
46
|
+
```
|
|
47
|
+
DOING_SPECS=!`ls specs/doing-*.md 2>/dev/null | sed 's|specs/doing-||;s|\.md$||' | tr '\n' ' ' || echo 'NOT_FOUND'`
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For **each** `{spec}` in `DOING_SPECS`, create `.deepflow/worktrees/{spec}` on branch `df/{spec}`. Reuse if exists; `--fresh` deletes first. If `worktree.sparse_paths` non-empty: `git worktree add --no-checkout`, `sparse-checkout set {paths}`, checkout.
|
|
51
|
+
|
|
52
|
+
Build an in-memory map `SPEC_WORKTREES = {spec → {path, branch}}`. This map drives per-task routing in §5 and §5.5 and is persisted in `.deepflow/checkpoint.json` under `spec_worktrees`. Tasks from spec A run in worktree A; tasks from spec B run in worktree B. No cross-spec commits share a branch.
|
|
46
53
|
|
|
47
|
-
|
|
54
|
+
Then run §1.5.1, §1.6, and §1.7 **per worktree** before any wave spawns.
|
|
48
55
|
|
|
49
|
-
|
|
56
|
+
### 1.5.1. SYMLINK DEPENDENCIES (per worktree)
|
|
57
|
+
|
|
58
|
+
After each worktree is created, symlink `node_modules` from the main repo so TypeScript/LSP/build can resolve dependencies without a full install:
|
|
50
59
|
```bash
|
|
51
|
-
node "${HOME}/.claude/bin/worktree-deps.js" --source "$(git rev-parse --show-toplevel)" --worktree "${
|
|
60
|
+
node "${HOME}/.claude/bin/worktree-deps.js" --source "$(git rev-parse --show-toplevel)" --worktree "${SPEC_WORKTREES[spec].path}"
|
|
52
61
|
```
|
|
53
62
|
The script finds `node_modules` at root and inside monorepo directories (`packages/`, `apps/`, etc.) and creates symlinks in the worktree. Outputs JSON: `{"linked": N, "total": M}`. Errors are non-fatal — log and continue.
|
|
54
63
|
|
|
55
|
-
### 1.6. RATCHET SNAPSHOT
|
|
64
|
+
### 1.6. RATCHET SNAPSHOT (per worktree)
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
For each spec worktree, snapshot pre-existing test files — only these count for ratchet (agent-created excluded):
|
|
58
67
|
```bash
|
|
59
|
-
git -C ${
|
|
68
|
+
git -C ${SPEC_WORKTREES[spec].path} ls-files | grep -E '\.(test|spec)\.[^/]+$|^test_|_test\.[^/]+$|^tests/|__tests__/' > .deepflow/auto-snapshot-{spec}.txt
|
|
60
69
|
```
|
|
61
70
|
|
|
71
|
+
Each spec has its own snapshot file. Ratchet checks in §5.5 pass the snapshot file matching the task's spec.
|
|
72
|
+
|
|
62
73
|
### 1.7. NO-TESTS BOOTSTRAP
|
|
63
74
|
|
|
64
75
|
<!-- AC-1: zero test files triggers bootstrap before wave 1 -->
|
|
65
76
|
<!-- AC-2: bootstrap success re-snapshots auto-snapshot.txt; subsequent tasks use updated snapshot -->
|
|
66
77
|
<!-- AC-3: bootstrap failure with default model retries with Opus; double failure halts with specific message -->
|
|
67
78
|
|
|
68
|
-
**Gate:** After §1.6 snapshot, check
|
|
79
|
+
**Gate (per spec):** After §1.6 snapshot, check each spec's snapshot file independently:
|
|
69
80
|
```bash
|
|
70
|
-
SNAPSHOT_COUNT=$(wc -l < .deepflow/auto-snapshot.txt | tr -d ' ')
|
|
81
|
+
SNAPSHOT_COUNT=$(wc -l < .deepflow/auto-snapshot-{spec}.txt | tr -d ' ')
|
|
71
82
|
```
|
|
72
|
-
If `SNAPSHOT_COUNT` is `0` (zero test files found), MUST spawn bootstrap agent
|
|
83
|
+
If `SNAPSHOT_COUNT` is `0` for a given spec (zero test files found), MUST spawn a bootstrap agent for **that spec** before any implementation task from that spec runs. Other specs with non-empty snapshots proceed normally.
|
|
73
84
|
|
|
74
|
-
**Bootstrap flow:**
|
|
75
|
-
1. Spawn `Agent(model="{default_model}", ...)` with Bootstrap prompt (§6). End turn, wait for notification.
|
|
76
|
-
2. **On success (TASK_STATUS:pass):** Re-snapshot immediately:
|
|
85
|
+
**Bootstrap flow (per empty-snapshot spec):**
|
|
86
|
+
1. Spawn `Agent(model="{default_model}", ...)` with Bootstrap prompt (§6), `Working directory: ${SPEC_WORKTREES[spec].path}`. End turn, wait for notification.
|
|
87
|
+
2. **On success (TASK_STATUS:pass):** Re-snapshot immediately for that spec:
|
|
77
88
|
```bash
|
|
78
|
-
git -C ${
|
|
89
|
+
git -C ${SPEC_WORKTREES[spec].path} ls-files | grep -E '\.(test|spec)\.[^/]+$|^test_|_test\.[^/]+$|^tests/|__tests__/' > .deepflow/auto-snapshot-{spec}.txt
|
|
79
90
|
```
|
|
80
|
-
All subsequent tasks use this updated snapshot as their ratchet baseline. Proceed to wave 1.
|
|
91
|
+
All subsequent tasks for that spec use this updated snapshot as their ratchet baseline. Proceed to wave 1.
|
|
81
92
|
3. **On failure (TASK_STATUS:fail) with default model:** Retry ONCE with `Agent(model="opus", ...)` using the same Bootstrap prompt.
|
|
82
93
|
- Opus success → re-snapshot (same command above) → proceed to wave 1.
|
|
83
94
|
- Opus failure → halt with message: `"Bootstrap failed with both default and Opus — manual intervention required"`. Do not proceed.
|
|
@@ -137,17 +148,19 @@ Context ≥50% → checkpoint and exit. Before spawning: `TaskUpdate(status: "in
|
|
|
137
148
|
|
|
138
149
|
**Token tracking start:** Store `start_percentage` (from context.json) and `start_timestamp` (ISO 8601) keyed by task_id. Omit if unavailable.
|
|
139
150
|
|
|
140
|
-
**NEVER use `isolation: "worktree"`.** Deepflow manages
|
|
151
|
+
**NEVER use `isolation: "worktree"`.** Deepflow manages one worktree **per spec** (§1.5). Tasks from the same spec commit to the same branch so wave 2 sees wave 1 commits; tasks from different specs commit to different branches and never interleave. **Spawn ALL ready tasks in ONE message** except file conflicts.
|
|
141
152
|
|
|
142
|
-
**
|
|
153
|
+
**Per-spec routing (CRITICAL):** Each task in `WAVE_JSON` carries a `spec` field (from `bin/wave-runner.js`). When building the agent prompt (§6), you MUST set `Working directory: ${SPEC_WORKTREES[task.spec].path}` — the worktree for that task's spec, NOT the first spec in the map. Cross-spec contamination (spawning a task from spec B into spec A's worktree) corrupts branch history and breaks `/df:verify`. If `task.spec` is absent from the JSON, fall back to deriving it from the task's mini-plan file `.deepflow/plans/doing-{specName}.md`; if still unresolvable, defer the task and log `"⚠ T{N} deferred — cannot resolve spec"`.
|
|
143
154
|
|
|
144
|
-
|
|
155
|
+
**File conflicts (1 file = 1 writer):** Check `Files:` from wave-runner JSON output or from mini-plan detail files (`.deepflow/plans/doing-{specName}.md`). File-conflict rule applies **only within the same spec** — two tasks from different specs touching files with identical paths are actually in different worktrees and cannot collide. Overlap within a spec → spawn lowest-numbered only; rest stay pending. Log: `"⏳ T{N} deferred — file conflict with T{M} on {filename}"`
|
|
156
|
+
|
|
157
|
+
**≥2 [SPIKE] tasks same problem →** Parallel Spike Probes (§5.7). **[OPTIMIZE] tasks →** Optimize Cycle (§5.9), one at a time. **[INTEGRATION] tasks** (`task.isIntegration === true` in WAVE_JSON) **→** use the Integration Task prompt template (§6 Integration Task), not the Standard Task template. Integration tasks always land in the final wave via `Blocked by:` — wave-runner guarantees this, so they execute after all producer/consumer implementation tasks have committed. Route them to the **consumer spec's** worktree via `SPEC_WORKTREES[task.spec].path` (plan.md §4.8.2 places the integration task under the consumer's section header, so `task.spec` is already the consumer).
|
|
145
158
|
|
|
146
159
|
### 5.5. RATCHET CHECK
|
|
147
160
|
|
|
148
|
-
Run `node "${HOME}/.claude/bin/ratchet.js"` in the worktree
|
|
161
|
+
Run `node "${HOME}/.claude/bin/ratchet.js"` in the **task's spec worktree** after each agent completes, using that spec's snapshot file:
|
|
149
162
|
```bash
|
|
150
|
-
node "${HOME}/.claude/bin/ratchet.js" --worktree ${
|
|
163
|
+
node "${HOME}/.claude/bin/ratchet.js" --worktree ${SPEC_WORKTREES[task.spec].path} --snapshot .deepflow/auto-snapshot-{task.spec}.txt --task T{N}
|
|
151
164
|
```
|
|
152
165
|
|
|
153
166
|
The script handles all health checks internally and outputs structured JSON:
|
|
@@ -205,7 +218,7 @@ If no `DECISIONS:` line in agent output → skip silently (mechanical tasks don'
|
|
|
205
218
|
**Edit scope validation:** `git diff HEAD~1 --name-only` vs allowed globs. Violation → revert, report.
|
|
206
219
|
**Impact completeness:** diff vs Impact callers/duplicates. Gap → advisory warning (no revert).
|
|
207
220
|
|
|
208
|
-
**Metric gate (Optimize only):** Run `eval "${metric_command}"` with cwd=`${
|
|
221
|
+
**Metric gate (Optimize only):** Run `eval "${metric_command}"` with cwd=`${SPEC_WORKTREES[task.spec].path}` (never `cd && eval`). Parse float (non-numeric → revert). Compare using `direction`+`min_improvement_threshold`. Both ratchet AND metric must pass → keep. Ratchet pass + metric stagnant → revert. Secondary metrics: regression > `regression_threshold` (5%) → WARNING in auto-report.md (no revert).
|
|
209
222
|
|
|
210
223
|
**Token tracking result (on pass):** Read `end_percentage`. Sum token fields from `.deepflow/token-history.jsonl` between start/end timestamps (awk ISO 8601 compare). Write to `.deepflow/results/T{N}.yaml`:
|
|
211
224
|
```yaml
|
|
@@ -255,7 +268,7 @@ Git operations that produce large output (diff, stash, cherry-pick conflict outp
|
|
|
255
268
|
**Pattern:**
|
|
256
269
|
```
|
|
257
270
|
Spawn Agent(model="haiku", run_in_background=false):
|
|
258
|
-
Working directory: {
|
|
271
|
+
Working directory: ${SPEC_WORKTREES[task.spec].path}
|
|
259
272
|
Run: {git command}
|
|
260
273
|
Return exactly ONE line: "{operation}: {N lines changed / N files / outcome}"
|
|
261
274
|
Do NOT output the raw diff or full command output.
|
|
@@ -330,7 +343,9 @@ REPEAT:
|
|
|
330
343
|
|
|
331
344
|
### 6. PER-TASK (agent prompt)
|
|
332
345
|
|
|
333
|
-
**Common preamble (all):** `Working directory: {
|
|
346
|
+
**Common preamble (all):** `Working directory: ${SPEC_WORKTREES[task.spec].path}. All file ops use this path. Commit format: {type}({spec}): {desc}`
|
|
347
|
+
|
|
348
|
+
Resolve `task.spec` from the `WAVE_JSON` entry for this task (fallback: scan `.deepflow/plans/doing-*.md` for the task's block). Never hand an agent a worktree path that belongs to a different spec.
|
|
334
349
|
|
|
335
350
|
**Task detail loading (before building agent prompt):** Check for `.deepflow/plans/doing-{task_id}.md` (shell injection):
|
|
336
351
|
```
|
|
@@ -357,6 +372,17 @@ Steps (only when `Files:` list is non-empty):
|
|
|
357
372
|
|
|
358
373
|
<!-- AC-6: Backward-compatible no-op — when neither Domain Model section exists in the spec nor Existing Types extraction yields content (EXISTING_TYPES is empty string), the Standard Task prompt contains no extra context blocks and is identical to the pre-injection baseline. Zero prompt overhead, zero tool calls for tasks that lack these context sources. -->
|
|
359
374
|
|
|
375
|
+
**Template selection (deterministic, from WAVE_JSON):**
|
|
376
|
+
|
|
377
|
+
| Flag | Template |
|
|
378
|
+
|-----------------------|------------------------------------|
|
|
379
|
+
| `isIntegration: true` | Integration Task (below) |
|
|
380
|
+
| `isSpike: true` | Spike |
|
|
381
|
+
| `isOptimize: true` | Optimize Task |
|
|
382
|
+
| (none) | Standard Task |
|
|
383
|
+
|
|
384
|
+
Read these fields from `WAVE_JSON` entries. Do NOT re-parse the task description for tags — the flags are authoritative. If `isIntegration` is true, skip Standard Task entirely and jump to Integration Task (below).
|
|
385
|
+
|
|
360
386
|
**Standard Task** (`Agent(model="{Model}", ...)`):
|
|
361
387
|
```
|
|
362
388
|
--- START ---
|
|
@@ -498,7 +524,18 @@ Skills: `atomic-commits`, `browse-fetch`. Agents: Implementation (`general-purpo
|
|
|
498
524
|
| sonnet/medium | `Agent(model="sonnet")` | `Direct and efficient. Explain only non-obvious logic.` |
|
|
499
525
|
| opus/high | `Agent(model="opus")` | _(none)_ |
|
|
500
526
|
|
|
501
|
-
**Checkpoint:** `.deepflow/checkpoint.json`:
|
|
527
|
+
**Checkpoint:** `.deepflow/checkpoint.json`:
|
|
528
|
+
```json
|
|
529
|
+
{
|
|
530
|
+
"completed_tasks": ["T1"],
|
|
531
|
+
"current_wave": 2,
|
|
532
|
+
"spec_worktrees": {
|
|
533
|
+
"upload": {"path": ".deepflow/worktrees/upload", "branch": "df/upload"},
|
|
534
|
+
"auth": {"path": ".deepflow/worktrees/auth", "branch": "df/auth"}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
One entry per `doing-*` spec in scope. `--continue` rehydrates this map before wave scheduling.
|
|
502
539
|
|
|
503
540
|
## Failure Handling
|
|
504
541
|
|
package/src/commands/df/plan.md
CHANGED
|
@@ -349,11 +349,17 @@ If no shared interfaces found, return:
|
|
|
349
349
|
|
|
350
350
|
**Skip if:** Interface Map returns "(none detected — specs are independent)".
|
|
351
351
|
|
|
352
|
-
For each group of specs sharing interfaces, generate ONE integration task
|
|
352
|
+
For each group of specs sharing interfaces, generate ONE integration task per interface cluster.
|
|
353
|
+
|
|
354
|
+
**Placement (CRITICAL for worktree routing):** Integration tasks must be placed under the **consumer spec's** `### {consumer-spec-name}` section in the consolidated PLAN.md, NOT at the end of the file and NOT under their own header. `bin/wave-runner.js` assigns `task.spec` from the nearest preceding `### ` header, and `/df:execute` uses that field to route the task to the correct per-spec worktree (`SPEC_WORKTREES[task.spec].path`). If an integration task lands under a header that is not a real spec (e.g. `### Integration`), execute will fail to resolve a worktree and defer the task.
|
|
355
|
+
|
|
356
|
+
**Consumer selection:** The "consumer" is the spec that reads/calls the interface (e.g. frontend consumes API produced by backend → frontend is consumer). The fix-the-consumer rule in execute.md §6 Integration Task template means the integration agent will modify consumer-side code, which matches the consumer's worktree. If a cluster has multiple consumers, emit one integration task per consumer under each consumer's section.
|
|
357
|
+
|
|
358
|
+
The `[INTEGRATION]` tag is parsed deterministically by `bin/wave-runner.js` and surfaced as `isIntegration: true` in its JSON output; execute.md §6 uses that flag (not the task description) to pick the Integration Task prompt.
|
|
353
359
|
|
|
354
360
|
**Integration task format:**
|
|
355
361
|
```markdown
|
|
356
|
-
- [ ] **T{N}** [INTEGRATION]: Verify {
|
|
362
|
+
- [ ] **T{N}** [INTEGRATION]: Verify {producer_spec} ↔ {consumer_spec} contracts
|
|
357
363
|
- Files: {files at integration boundaries — API handlers, adapters, shared types, migrations}
|
|
358
364
|
- Integration ACs:
|
|
359
365
|
- End-to-end flow: {producer} → {consumer} works with real data
|
|
@@ -221,6 +221,8 @@ Objective: ... | Approach: ... | Why it worked: ... | Files: ...
|
|
|
221
221
|
- Don't auto-fix — add fix tasks to PLAN.md, then `/df:execute --continue`
|
|
222
222
|
- Capture learnings for significant approaches
|
|
223
223
|
- **Terse output** — Output ONLY the compact report format (section 3)
|
|
224
|
+
- **No LSP diagnostics** — Use ONLY build/test command exit codes and output for L0/L4. Do NOT use the LSP tool to collect TypeScript diagnostics — worktree environments have incomplete `node_modules` symlinks that produce false-positive module-resolution errors (2307, 2875). If the build command exits 0, L0 passes — do not second-guess it with LSP.
|
|
225
|
+
- **No narration of false positives** — Never output diagnostics and then explain they are false positives. If you know they are false positives, suppress them entirely. Wasted output tokens cost money.
|
|
224
226
|
|
|
225
227
|
## Post-Verification: Worktree Merge & Cleanup
|
|
226
228
|
|