@dougharness/cli 1.0.2 → 1.1.0
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/bin.js +8 -0
- package/dist/bin.js.map +1 -1
- package/dist/board-serve.js +9 -3
- package/dist/board-serve.js.map +1 -1
- package/dist/board.js +10 -2
- package/dist/board.js.map +1 -1
- package/dist/detect/repo.js +14 -1
- package/dist/detect/repo.js.map +1 -1
- package/dist/detect/types.d.ts +2 -0
- package/dist/doctor.d.ts +46 -0
- package/dist/doctor.js +491 -0
- package/dist/doctor.js.map +1 -0
- package/dist/generate/agents.d.ts +7 -0
- package/dist/generate/agents.js +62 -12
- package/dist/generate/agents.js.map +1 -1
- package/dist/generate/claude-md.js +4 -0
- package/dist/generate/claude-md.js.map +1 -1
- package/dist/generate/config.d.ts +8 -0
- package/dist/generate/config.js +4 -1
- package/dist/generate/config.js.map +1 -1
- package/dist/generate/proposal.js +15 -6
- package/dist/generate/proposal.js.map +1 -1
- package/dist/generate/settings.d.ts +2 -0
- package/dist/generate/settings.js +17 -2
- package/dist/generate/settings.js.map +1 -1
- package/dist/init.d.ts +14 -0
- package/dist/init.js +94 -8
- package/dist/init.js.map +1 -1
- package/dist/memory-setup.d.ts +28 -0
- package/dist/memory-setup.js +323 -0
- package/dist/memory-setup.js.map +1 -0
- package/node_modules/@dougharness/flow/.claude-plugin/plugin.json +16 -4
- package/node_modules/@dougharness/flow/agents/planner.md +2 -2
- package/node_modules/@dougharness/flow/agents/researcher.md +2 -2
- package/node_modules/@dougharness/flow/hooks/hooks.json +16 -0
- package/node_modules/@dougharness/flow/lib/board.mjs +154 -12
- package/node_modules/@dougharness/flow/lib/code-index.mjs +18 -3
- package/node_modules/@dougharness/flow/lib/context.mjs +57 -0
- package/node_modules/@dougharness/flow/lib/cost.mjs +129 -4
- package/node_modules/@dougharness/flow/lib/embeddings.mjs +185 -23
- package/node_modules/@dougharness/flow/lib/land.mjs +69 -10
- package/node_modules/@dougharness/flow/lib/learn.mjs +4 -4
- package/node_modules/@dougharness/flow/lib/memory.mjs +326 -35
- package/node_modules/@dougharness/flow/lib/plan.mjs +9 -0
- package/node_modules/@dougharness/flow/package.json +2 -1
- package/node_modules/@dougharness/flow/scripts/board.mjs +60 -20
- package/node_modules/@dougharness/flow/scripts/context.mjs +48 -0
- package/node_modules/@dougharness/flow/scripts/cost.mjs +15 -3
- package/node_modules/@dougharness/flow/scripts/memory.mjs +190 -34
- package/node_modules/@dougharness/flow/scripts/plan.mjs +32 -64
- package/node_modules/@dougharness/flow/scripts/session-recall.mjs +132 -0
- package/node_modules/@dougharness/flow/skills/{core-next → doug-hand}/SKILL.md +31 -18
- package/node_modules/@dougharness/flow/skills/doug-learn/SKILL.md +1 -1
- package/node_modules/@dougharness/flow/skills/doug-next/SKILL.md +44 -10
- package/node_modules/@dougharness/flow/skills/doug-swarm/SKILL.md +5 -5
- package/node_modules/@dougharness/flow/skills/research/SKILL.md +4 -2
- package/node_modules/@dougharness/flow/skills/run-report/SKILL.md +8 -9
- package/node_modules/@dougharness/flow/skills/swarm-launch/SKILL.md +1 -1
- package/node_modules/@dougharness/flow/workflows/doug-implement.js +119 -72
- package/node_modules/@dougharness/gates/.claude-plugin/plugin.json +1 -1
- package/node_modules/@dougharness/gates/hooks/hooks.json +11 -0
- package/node_modules/@dougharness/gates/lib/baseline.mjs +166 -1
- package/node_modules/@dougharness/gates/lib/block-ledger.mjs +58 -1
- package/node_modules/@dougharness/gates/lib/checkpoint.mjs +1 -1
- package/node_modules/@dougharness/gates/lib/config.mjs +20 -0
- package/node_modules/@dougharness/gates/lib/docs-gate.mjs +95 -0
- package/node_modules/@dougharness/gates/lib/evidence.mjs +2 -0
- package/node_modules/@dougharness/gates/lib/run.mjs +4 -0
- package/node_modules/@dougharness/gates/lib/test-totals.mjs +40 -7
- package/node_modules/@dougharness/gates/lib/trace.mjs +24 -7
- package/node_modules/@dougharness/gates/lib/verified-tree.mjs +225 -0
- package/node_modules/@dougharness/gates/package.json +1 -1
- package/node_modules/@dougharness/gates/scripts/research-cap.mjs +133 -5
- package/node_modules/@dougharness/gates/scripts/stop-gate.mjs +551 -113
- package/node_modules/@dougharness/gates/scripts/trace.mjs +5 -1
- package/node_modules/@dougharness/gates/scripts/turn-start.mjs +17 -0
- package/node_modules/@dougharness/gates/scripts/verify.mjs +146 -0
- package/package.json +3 -3
- package/templates/board-app.js +2 -2
- package/node_modules/@dougharness/flow/lib/rehearse.mjs +0 -825
- package/node_modules/@dougharness/flow/scripts/rehearse.mjs +0 -129
- package/node_modules/@dougharness/flow/skills/harness-fix/SKILL.md +0 -85
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// On-demand live rehearsal of the flow, swarm, and hand tracks on a small real card (the ts-basic fixture's
|
|
3
|
-
// fix-hours), spawning the real `claude` binary. It is a script, not a test, and it never runs in the gate:
|
|
4
|
-
// evals/ already spends real money to measure arms and must not gain correctness assertions, and seam-contracts
|
|
5
|
-
// settles the deterministic side without a new top-level suite, so this lives here, next to cost.mjs and
|
|
6
|
-
// board.mjs, as a spend-and-record script of the flow plugin that reads the same skills it exercises.
|
|
7
|
-
//
|
|
8
|
-
// rehearse.mjs [flow|swarm|hand|all] --card <id> --spend [dir]
|
|
9
|
-
// no arguments print the estimate table and exit 2; nothing is spawned
|
|
10
|
-
// a scenario, no --spend print that scenario's per-stage estimate and exit 2; nothing is spawned
|
|
11
|
-
// --spend, no --card exit 2 ("--card <id> names the card this rehearsal records under"); nothing is spawned
|
|
12
|
-
// --spend and --card run it: [dir] is the real repository (default cwd) the outcome records under
|
|
13
|
-
// <the id> on its board; exit 0 when every run scenario is "passed", 1 otherwise
|
|
14
|
-
//
|
|
15
|
-
// Recording goes through the existing `board.mjs record` CLI only, never lib/board.mjs directly (that would
|
|
16
|
-
// bypass its research-note promotion and batch handling): the run form for flow/swarm (a synthetic, honest
|
|
17
|
-
// report when the workflow never wrote one, never invented task rows) and the hand form for hand, both carrying
|
|
18
|
-
// a rehearsal --note and --rehearsal <scenario> (the entry's heading and commit sha read as the fixture's, not
|
|
19
|
-
// this repository's landing); never memory.mjs (a fixture run has no run id the cost script can find, and the
|
|
20
|
-
// outcome log is for this repository's own runs). Every adversary block a real report carries is printed for the
|
|
21
|
-
// user to classify by hand.
|
|
22
|
-
//
|
|
23
|
-
// A passed scenario's fixture is removed after its stream logs and last report are archived into this
|
|
24
|
-
// repository's own .doug/.state/rehearsal/<scenario>-<timestamp>/ (a failed scenario keeps the whole fixture
|
|
25
|
-
// instead, as before). Every session this script spawns disallows the Artifact tool, since a gate or build stage
|
|
26
|
-
// that reaches the doug-board skill must never actually publish from a rehearsal.
|
|
27
|
-
//
|
|
28
|
-
// The `claude` binary name is overridable with $DOUG_REHEARSE_CLAUDE; a real user never sets it.
|
|
29
|
-
|
|
30
|
-
import { readFileSync, rmSync } from "node:fs";
|
|
31
|
-
import { resolve } from "node:path";
|
|
32
|
-
import { loadBoard, findCard, adversaryBlocks } from "../lib/board.mjs";
|
|
33
|
-
import { parseArgs, estimateLines, SCENARIOS, scenarioTotal, runScenario, recordRunOutcome, recordHandOutcome, rehearsalNote, extractGateLine, archiveEvidence } from "../lib/rehearse.mjs";
|
|
34
|
-
|
|
35
|
-
function fail(msg, code = 2) {
|
|
36
|
-
process.stderr.write(msg + "\n");
|
|
37
|
-
process.exit(code);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function printEstimates(scenario) {
|
|
41
|
-
process.stdout.write("Estimated cost (USD), from docs/live-runs.md measurements:\n");
|
|
42
|
-
for (const l of estimateLines(scenario)) process.stdout.write(l + "\n");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const opts = parseArgs(process.argv.slice(2));
|
|
46
|
-
|
|
47
|
-
if (!opts.scenario) {
|
|
48
|
-
printEstimates(null);
|
|
49
|
-
process.stdout.write("\nusage: rehearse.mjs [flow|swarm|hand|all] --card <id> --spend [dir]\n");
|
|
50
|
-
process.exit(2);
|
|
51
|
-
}
|
|
52
|
-
if (opts.scenario !== "all" && !SCENARIOS.includes(opts.scenario)) fail(`unknown scenario "${opts.scenario}"; scenarios are ${SCENARIOS.join(", ")}, all`, 2);
|
|
53
|
-
|
|
54
|
-
if (!opts.spend) {
|
|
55
|
-
printEstimates(opts.scenario === "all" ? null : opts.scenario);
|
|
56
|
-
process.stdout.write("\nAdd --spend to run it.\n");
|
|
57
|
-
process.exit(2);
|
|
58
|
-
}
|
|
59
|
-
if (!opts.card) fail("--card <id> names the card this rehearsal records under", 2);
|
|
60
|
-
|
|
61
|
-
const dir = resolve(opts.dir || process.cwd());
|
|
62
|
-
let board;
|
|
63
|
-
try {
|
|
64
|
-
board = loadBoard(dir);
|
|
65
|
-
} catch (err) {
|
|
66
|
-
fail(`cannot read the board at ${dir}: ${err.message}`, 2);
|
|
67
|
-
}
|
|
68
|
-
if (!findCard(board, opts.card)) fail(`no card "${opts.card}" on the board at ${dir}`, 2);
|
|
69
|
-
|
|
70
|
-
const scenarios = opts.scenario === "all" ? SCENARIOS : [opts.scenario];
|
|
71
|
-
process.stdout.write(`Estimated cost: $${scenarios.reduce((s, n) => s + scenarioTotal(n), 0).toFixed(2)}. Running ${scenarios.join(", ")} against ${opts.card} at ${dir}.\n`);
|
|
72
|
-
|
|
73
|
-
let allPassed = true;
|
|
74
|
-
for (const scenario of scenarios) {
|
|
75
|
-
const result = runScenario(scenario);
|
|
76
|
-
const passed = result.outcome === "passed";
|
|
77
|
-
allPassed = allPassed && passed;
|
|
78
|
-
|
|
79
|
-
const outcomeForNote = result.reportSynthesized ? `no report: the session ended at stage ${result.failedStage}: ${result.failedMessage}` : result.outcome;
|
|
80
|
-
const note = rehearsalNote({ scenario, outcome: outcomeForNote, stages: result.stages, cost: result.totalCost, agentNames: result.agentNames });
|
|
81
|
-
|
|
82
|
-
process.stdout.write(`\n${scenario}: ${result.outcome}\n`);
|
|
83
|
-
process.stdout.write(` wall clock: ${result.wallClock}\n`);
|
|
84
|
-
process.stdout.write(` measured cost: $${result.totalCost.toFixed(2)}\n`);
|
|
85
|
-
for (const s of result.stages) process.stdout.write(` stage ${s.name}: wall ${s.wallClock}${s.cost !== null ? `, cost $${s.cost.toFixed(2)}` : ""}${s.streamPath ? `, stream ${s.streamPath}` : ""}\n`);
|
|
86
|
-
|
|
87
|
-
// A passed fixture's evidence (its stream logs and last report) is archived into this repository before the
|
|
88
|
-
// fixture is removed. Archiving lives in the same defended path as recording, right below: a throw here (an
|
|
89
|
-
// unwritable .doug/.state, ENOSPC, ...) must not abort the loop before the outcome is recorded, and the evidence
|
|
90
|
-
// must survive somewhere, so an archive failure is reported on its own line and keeps the fixture instead of
|
|
91
|
-
// removing it, exactly like a failed scenario already does.
|
|
92
|
-
let evidencePath = null;
|
|
93
|
-
let keepFixture = !passed;
|
|
94
|
-
if (passed) {
|
|
95
|
-
try {
|
|
96
|
-
evidencePath = archiveEvidence({ fixtureDir: result.fixtureDir, dir, scenario });
|
|
97
|
-
process.stdout.write(` evidence archived: ${evidencePath}\n`);
|
|
98
|
-
} catch (err) {
|
|
99
|
-
keepFixture = true;
|
|
100
|
-
process.stdout.write(` evidence not archived: ${err.message}\n`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
process.stdout.write(` fixture: ${result.fixtureDir}${keepFixture ? " (kept for inspection)" : " (removed)"}\n`);
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
let recorded;
|
|
107
|
-
if (scenario === "hand") {
|
|
108
|
-
recorded = recordHandOutcome(dir, opts.card, { commit: result.commit, wallClock: result.wallClock, gate: extractGateLine(result.fixtureDir) || "not observed", note, rehearsal: scenario });
|
|
109
|
-
} else {
|
|
110
|
-
recorded = recordRunOutcome(dir, opts.card, { reportFile: result.reportFile, wallClock: result.wallClock, cost: result.totalCost, mergeCommit: result.commit, note, rehearsal: scenario });
|
|
111
|
-
if (!result.reportSynthesized) {
|
|
112
|
-
const report = JSON.parse(readFileSync(result.reportFile, "utf8"));
|
|
113
|
-
const blocks = adversaryBlocks(report);
|
|
114
|
-
if (blocks.length) {
|
|
115
|
-
process.stdout.write(" adversary blocks (classify by hand with board.mjs record --adversary):\n");
|
|
116
|
-
for (const b of blocks) process.stdout.write(` ${b.task}/${b.id}${b.pass !== null ? ` (pass ${b.pass})` : ""}: ${b.description}\n`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
process.stdout.write(` recorded: ${recorded}`);
|
|
121
|
-
} catch (err) {
|
|
122
|
-
process.stdout.write(` recording failed: ${err.message}\n`);
|
|
123
|
-
allPassed = false;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (!keepFixture) rmSync(result.fixtureDir, { recursive: true, force: true });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
process.exit(allPassed ? 0 : 1);
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: harness-fix
|
|
3
|
-
description: The by-hand procedure for changing Doug's own harness code (plugins/doug-flow, plugins/doug-gates, packages/doug-codex, packages/doug-cli, evals) without running it through the flow (decision 0005). Which test file covers which module, a single test file while iterating, the full gate before a commit, gate scripts copied into .doug/hooks/scripts, no attribution trailers, and a docs/live-runs.md line when a measurement changes. Use it for any edit under those directories, and from /core-next.
|
|
4
|
-
allowed-tools: Read, Edit, Write, Grep, Glob, Bash
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# harness-fix
|
|
8
|
-
|
|
9
|
-
Harness code is built directly in the checkout: tests first, the full gate, a plain commit. This is the procedure; `/core-next` follows it for every hand-track card, and it applies just as well to a one-line fix made outside a card.
|
|
10
|
-
|
|
11
|
-
## 0. Who does the work
|
|
12
|
-
|
|
13
|
-
The lead briefs and gates; it never implements, verifies, or reviews the change itself. Before the coder, the `tester` agent (`.claude/agents/tester.md`), spawned with the Agent tool on the `implement` row of the CLAUDE.md Models table, writes or extends the test file first, from the goal; the coder implements against it. A tester that leaves tests red by design ends with its tests_red_by_design claim, in its final plain-text message or its hand-back call; the SubagentStop gate reads both. The `coder` agent, on the same row, may not edit a test except with a stated reason in its report. The `reviewer` agent, on the `review` row, reviews, and checks that rule. Verification on the hand track is the gate itself (`pnpm typecheck` and `pnpm test:unit`), which the reviewer runs and the lead re-runs before the commit. This holds on both tracks, swarm or not; a hand-track lead is the session model. For a card whose acceptance is that a mechanism exists, the reviewer is expected to mutate the mechanism and rerun the test rather than only read the diff (rule 7), rerunning the brief's mutation list and adding its own; the flow track's `plugins/doug-flow/agents/reviewer.md` does not carry this instruction — it is read-only by tool policy, and its verifier and adversary stages run the code afterward instead. On a tests-only card (the goal says tests only, no production change) there is no coder: the tester runs the brief's mutation list itself in a scratch copy or git worktree under `.doug/.state`, never editing a production file in the live checkout, and reports each result.
|
|
14
|
-
|
|
15
|
-
## 1. Find the test that covers the module
|
|
16
|
-
|
|
17
|
-
Under a card, the tester writes or extends the test before the change, in the file that already covers the module, and the coder runs only that file while iterating: `pnpm exec vitest run <path/to/file.test>`. For a one-line fix outside a card there is no tester: its author writes the test first, in the same file, and runs only that file.
|
|
18
|
-
|
|
19
|
-
| Module | Test file |
|
|
20
|
-
|---|---|
|
|
21
|
-
| `plugins/doug-flow/workflows/doug-implement.js` (the loop, the ledger, the prompts), `agents/*.md`, `skills/*/SKILL.md`, the plugin manifest | `plugins/doug-flow/tests/template.test.mjs` |
|
|
22
|
-
| `plugins/doug-flow/lib/board.mjs`, `scripts/board.mjs` | `plugins/doug-flow/tests/board.test.mjs` |
|
|
23
|
-
| `plugins/doug-flow/lib/plan.mjs` validation, levels, rendering, `mergePlans` | `plugins/doug-flow/tests/plan.test.mjs` |
|
|
24
|
-
| `scripts/plan.mjs set`, `plan.mjs merge` (several cards in one plan) and `--file`, config defaults for install and adversary | `plugins/doug-flow/tests/plan-set.test.mjs` |
|
|
25
|
-
| `lib/plan.mjs` specHash, reusePlan, `plan.mjs replan` | `plugins/doug-flow/tests/replan.test.mjs` |
|
|
26
|
-
| `plugins/doug-flow/lib/land.mjs`, `plan.mjs land`, worktree pruning | `plugins/doug-flow/tests/land.test.mjs` |
|
|
27
|
-
| `plugins/doug-flow/lib/worktrees.mjs` (worktree removal, used by `land.mjs`; branch retirement, used by `scripts/plan.mjs`) | `plugins/doug-flow/tests/land.test.mjs` (removal), `plugins/doug-flow/tests/replan.test.mjs` (retirement) |
|
|
28
|
-
| `plugins/doug-flow/lib/models.mjs` (the CLAUDE.md Models table) | `plugins/doug-flow/tests/models.test.mjs` |
|
|
29
|
-
| `plugins/doug-flow/lib/cost.mjs`, `scripts/cost.mjs` (a run's cost from local transcripts; the price table) | `plugins/doug-flow/tests/cost.test.mjs` |
|
|
30
|
-
| `plugins/doug-flow/lib/embeddings.mjs` (the embedding provider layer: openai-compatible and voyage adapters, probeProvider, doctorReport) | `plugins/doug-flow/tests/embeddings.test.mjs` |
|
|
31
|
-
| `plugins/doug-flow/lib/code-index.mjs` (the opt-in semantic code index: file listing, chunking, incremental build, status, search) | `plugins/doug-flow/tests/code-index.test.mjs` |
|
|
32
|
-
| `plugins/doug-flow/lib/learn.mjs`, `scripts/learn.mjs` (deterministic proposals from outcomes/lessons signals and the run trace; card learn-signals) | `plugins/doug-flow/tests/learn.test.mjs` |
|
|
33
|
-
| `plugins/doug-flow/lib/decisions.mjs` (proposal diffs for docs/decisions/ ADRs and .claude/rules/ conventions; card memory-decisions), `scripts/memory.mjs`'s `decision`/`rule` cases | `plugins/doug-flow/tests/decisions.test.mjs` |
|
|
34
|
-
| `plugins/doug-flow/lib/memory.mjs`, `scripts/memory.mjs` (the outcome log and lesson store: recall, the outcome record, reflect, and the memory.mjs CLI's index dispatch; card memory-lib) | `plugins/doug-flow/tests/memory.test.mjs`, `plugins/doug-flow/tests/memory-cli.test.mjs` |
|
|
35
|
-
| `plugins/doug-flow/lib/memory-import.mjs` (the `memory.mjs import` command; card memory-import) | `plugins/doug-flow/tests/memory-import.test.mjs` |
|
|
36
|
-
| `plugins/doug-gates/scripts/*.mjs` end to end (protect-paths, guard-bash, format-on-edit, edit-loop, stop-gate, reanchor, checkpoint) | `plugins/doug-gates/tests/hooks.test.mjs` |
|
|
37
|
-
| `plugins/doug-gates/lib/bash-rules.mjs` | `plugins/doug-gates/tests/bash-rules.test.mjs` |
|
|
38
|
-
| `plugins/doug-gates/lib/scope.mjs` (plan scope) | `plugins/doug-gates/tests/scope.test.mjs` |
|
|
39
|
-
| `plugins/doug-gates/lib/secret-rules.mjs`, `scripts/secret-scan.mjs` | `plugins/doug-gates/tests/secret-scan.test.mjs` |
|
|
40
|
-
| `plugins/doug-gates/lib/checkpoint.mjs` | `plugins/doug-gates/tests/checkpoint.test.mjs` |
|
|
41
|
-
| `plugins/doug-gates/lib/config.mjs`, state and paths | `plugins/doug-gates/tests/config-state.test.mjs` |
|
|
42
|
-
| `plugins/doug-gates/lib/proposals.mjs` (the applied-proposal ledger reader; card memory-decisions) | `plugins/doug-gates/tests/hooks.test.mjs` (protect-paths/stop-gate proposal-path blocks) |
|
|
43
|
-
| `plugins/doug-gates/lib/glob.mjs` | `plugins/doug-gates/tests/glob.test.mjs` |
|
|
44
|
-
| `plugins/doug-gates/lib/anchor.mjs` (the PreCompact snapshot in the anchor) | `plugins/doug-gates/tests/hooks.test.mjs` (reanchor on PreCompact) |
|
|
45
|
-
| `plugins/doug-gates/lib/evidence.mjs` (verification evidence: which recorded commands count) | `plugins/doug-gates/tests/evidence.test.mjs`; the stop-gate and guard-bash sides in `hooks.test.mjs` |
|
|
46
|
-
| `plugins/doug-gates/lib/trace.mjs` (the run trace: line shape, transcript usage, replay, attribution) | `plugins/doug-gates/tests/trace.test.mjs`; the `trace` script end to end in `hooks.test.mjs` |
|
|
47
|
-
| `plugins/doug-gates/scripts/statusline.mjs` | `plugins/doug-gates/tests/statusline.test.mjs` |
|
|
48
|
-
| the checked-in pre-commit hook | `plugins/doug-gates/tests/git-hooks.test.mjs` |
|
|
49
|
-
| `packages/doug-cli/src/board.ts` (`doug board`) | `packages/doug-cli/tests/board.test.ts` |
|
|
50
|
-
| `packages/doug-cli/src/board-page.ts`, `board-serve.ts`, `templates/board-app.js` | `packages/doug-cli/tests/board-page.test.ts` (serve tests skip with a reason where a local listener is denied: `board-page-skip.test.ts`) |
|
|
51
|
-
| `packages/doug-cli/src/detect/*` | `packages/doug-cli/tests/detect.test.ts` |
|
|
52
|
-
| `packages/doug-cli/src/generate/*` (config, CLAUDE.md, settings, proposal, apply) | `packages/doug-cli/tests/proposal.test.ts` |
|
|
53
|
-
| `packages/doug-cli/src/diff.ts` | `packages/doug-cli/tests/diff.test.ts` |
|
|
54
|
-
| `packages/doug-cli/src/ablate.ts` (`doug ablate`: eval results per condition, the runner pass-through) | `packages/doug-cli/tests/ablate.test.ts` |
|
|
55
|
-
| `packages/doug-cli/src/trace.ts` (`doug trace`: replay and per-agent attribution of a run trace) | `packages/doug-cli/tests/trace.test.ts` |
|
|
56
|
-
| `packages/doug-codex/src/prompt.ts` | `packages/doug-codex/tests/prompt.test.ts` |
|
|
57
|
-
| `packages/doug-codex/src/parse.ts` (Codex JSONL, verdict, exit codes) | `packages/doug-codex/tests/parse.test.ts` |
|
|
58
|
-
| `packages/doug-codex/src/run.ts` (spawning codex, timeout, worktree check) | `packages/doug-codex/tests/run.test.ts` |
|
|
59
|
-
| `packages/doug-codex/src/contract.ts` and `docs/worker-contract.md` | `packages/doug-codex/tests/contract.test.ts` |
|
|
60
|
-
| `packages/doug-codex/src/bin.ts` (`codex-review`) | `packages/doug-codex/tests/cli.test.ts` |
|
|
61
|
-
| `evals/run.mjs` (the scorer: tool calls from stream-json, leaks, must-run commands) and `evals/tasks/*.json` | `evals/tests/run.test.mjs` |
|
|
62
|
-
| `plugins/doug-flow/scripts/rehearse.mjs`, `lib/rehearse.mjs` (the on-demand live rehearsal runner: estimates, fixture, stream assertions, recording) | `plugins/doug-flow/tests/rehearse.test.mjs` |
|
|
63
|
-
| the `reviewIssues` report key (doug-implement.js) round-tripping into `lib/memory.mjs`'s `review_issue_count`/`review_issues`, through `board.mjs record`, `board.mjs summary`, and `plan.mjs replan` (card seam-contracts) | `plugins/doug-flow/tests/seams.test.mjs` |
|
|
64
|
-
| every `board.mjs`/`plan.mjs`/`memory.mjs` subcommand a `skills/*/SKILL.md`, `CLAUDE.md`, or `docs/worker-contract.md` names being a real dispatch case (card seam-contracts) | `plugins/doug-flow/tests/seams.test.mjs` |
|
|
65
|
-
| `claude plugin validate` actually catching a broken plugin manifest (card seam-contracts) | `plugins/doug-flow/tests/seams.test.mjs` |
|
|
66
|
-
| `doug init`'s PreToolUse wiring firing for real (protect-paths.mjs deny/allow, not just a string comparison of the wiring) (card seam-contracts) | `packages/doug-cli/tests/init-hooks.test.ts` |
|
|
67
|
-
|
|
68
|
-
`packages/doug-codex/tests/codex-live.test.ts` spawns the real Codex and is excluded from the gate; leave it out of iteration.
|
|
69
|
-
|
|
70
|
-
## 2. Rules while changing harness code
|
|
71
|
-
|
|
72
|
-
1. The workflow file `doug-implement.js` may not import, call `Date.now` or `Math.random`, or name a model; its template tests assert that, and it must parse when wrapped the way the Workflow runtime wraps it. A top-level `return` in it is expected, so `node --check` fails on it by design.
|
|
73
|
-
2. The Workflow tool runs the plugin copy loaded at session start. An edited workflow is launched with `scriptPath` pointing at the file, or the session is restarted.
|
|
74
|
-
3. After editing a gate script under `plugins/doug-gates/scripts/`, copy it to `.doug/hooks/scripts/` too: this repository has Doug installed on itself and its hooks run from there.
|
|
75
|
-
4. A change to `plugins/doug-flow/lib/board.mjs` or `lib/plan.mjs` reaches `packages/doug-cli` through the `@dougharness/flow` workspace dependency; the CLI's `src/flow-board.d.ts` declares the shapes, so a new field or option is added there as well or `pnpm typecheck` fails.
|
|
76
|
-
5. Keep the change to what the card or fix asks. A defect found on the way becomes its own hand-track card.
|
|
77
|
-
6. If a hook blocks a step, report it; do not work around it.
|
|
78
|
-
7. When the card's acceptance is that a mechanism exists, prove it before reporting done: mutate or remove the mechanism, run the new test file, confirm it fails, then revert the mutation and report which assertion failed. That is the line: a card whose acceptance is that a mechanism exists needs it; a card that only changes prose, a message, or a docs line does not. To prove it, the brief lists one mutation per case the card's goal names, each with the test that must fail; the coder runs every listed mutation and reports each result; the reviewer reruns the list and adds its own. Apply each mutation in a scratch copy or git worktree under `.doug/.state`, run the one test file there, and remove the copy.
|
|
79
|
-
8. A card that changes a workflow's or a skill's user-visible behaviour runs the live scenario that covers it before landing: `node plugins/doug-flow/scripts/rehearse.mjs <flow|swarm|hand> --card <id> --spend`, and its landing note quotes the outcome. The swarm scenario is the one that proves plugin loading and agent-name resolution in the real runtime. `docs/rehearsals.md` says what each scenario proves, how to read a result, and how to add one.
|
|
80
|
-
|
|
81
|
-
## 3. The gate, the commit, the record
|
|
82
|
-
|
|
83
|
-
1. Before the commit run the full gate: `pnpm typecheck` and `pnpm test:unit`. Never `pnpm test`, which spawns Codex. Say what ran and the counts.
|
|
84
|
-
2. Commit without attribution trailers, one commit per coherent change, with a message that says what changed and why. Leave `.doug/plan.json` and `.doug/anchor.md` out unless the change is about them.
|
|
85
|
-
3. When the change alters a measurement (a run's cost, wall clock, pass count, or what a stage does), add a line to `docs/live-runs.md`; a change to the board record shows on the served page (`doug board serve`).
|