@shahboura/harness 3.0.4
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/.opencode/agents/developer.md +60 -0
- package/.opencode/agents/planner.md +51 -0
- package/.opencode/agents/reviewer.md +53 -0
- package/.opencode/commands/add-repo.md +26 -0
- package/.opencode/commands/dev-workflow.md +40 -0
- package/.opencode/commands/init-workspace.md +22 -0
- package/.opencode/commands/migrate-workspace.md +28 -0
- package/.opencode/commands/repo-map-refresh.md +23 -0
- package/.opencode/commands/story-workflow.md +24 -0
- package/.opencode/commands/workflow-status.md +23 -0
- package/.opencode/commands/workspace-config.md +27 -0
- package/.opencode/package.json +9 -0
- package/.opencode/plugins/harness-guards.ts +290 -0
- package/.opencode/skills/add-repo/SKILL.md +96 -0
- package/.opencode/skills/dev-workflow/SKILL.md +105 -0
- package/.opencode/skills/dev-workflow/shared/diagram-styling.md +65 -0
- package/.opencode/skills/dev-workflow/shared/engineering.md +14 -0
- package/.opencode/skills/dev-workflow/shared/status-block.md +29 -0
- package/.opencode/skills/dev-workflow/steps/analyze-comments.md +32 -0
- package/.opencode/skills/dev-workflow/steps/apply-fixes.md +24 -0
- package/.opencode/skills/dev-workflow/steps/comment-analysis.md +11 -0
- package/.opencode/skills/dev-workflow/steps/create-pr.md +39 -0
- package/.opencode/skills/dev-workflow/steps/develop-task.md +54 -0
- package/.opencode/skills/dev-workflow/steps/develop.md +60 -0
- package/.opencode/skills/dev-workflow/steps/fetch.md +34 -0
- package/.opencode/skills/dev-workflow/steps/fixup-task.md +12 -0
- package/.opencode/skills/dev-workflow/steps/gate.md +53 -0
- package/.opencode/skills/dev-workflow/steps/harden-task.md +12 -0
- package/.opencode/skills/dev-workflow/steps/harden.md +30 -0
- package/.opencode/skills/dev-workflow/steps/intake.md +52 -0
- package/.opencode/skills/dev-workflow/steps/metrics.md +21 -0
- package/.opencode/skills/dev-workflow/steps/plan-task.md +108 -0
- package/.opencode/skills/dev-workflow/steps/plan.md +80 -0
- package/.opencode/skills/dev-workflow/steps/pre-pr-fixes.md +16 -0
- package/.opencode/skills/dev-workflow/steps/pre-pr-review.md +14 -0
- package/.opencode/skills/dev-workflow/steps/pre-pr.md +14 -0
- package/.opencode/skills/dev-workflow/steps/preflight.md +32 -0
- package/.opencode/skills/dev-workflow/steps/quick-recheck.md +14 -0
- package/.opencode/skills/dev-workflow/steps/reconcile.md +27 -0
- package/.opencode/skills/dev-workflow/steps/review-task.md +32 -0
- package/.opencode/skills/dev-workflow/steps/security.md +18 -0
- package/.opencode/skills/dev-workflow/steps/triage-request.md +15 -0
- package/.opencode/skills/init-workspace/SKILL.md +155 -0
- package/.opencode/skills/migrate-workspace/SKILL.md +122 -0
- package/.opencode/skills/repo-map-refresh/SKILL.md +43 -0
- package/.opencode/skills/story-workflow/SKILL.md +78 -0
- package/.opencode/skills/story-workflow/commands/analyze.md +40 -0
- package/.opencode/skills/story-workflow/commands/groom.md +58 -0
- package/.opencode/skills/story-workflow/commands/improve.md +47 -0
- package/.opencode/skills/story-workflow/commands/refine.md +44 -0
- package/.opencode/skills/story-workflow/shared/context.md +22 -0
- package/.opencode/skills/story-workflow/shared/provider-io.md +73 -0
- package/.opencode/skills/story-workflow/templates/readiness-report.md +57 -0
- package/.opencode/skills/story-workflow/templates/story-template.md +51 -0
- package/.opencode/skills/story-workflow/templates/technical-notes.md +48 -0
- package/.opencode/skills/workflow-status/SKILL.md +30 -0
- package/.opencode/skills/workspace-config/SKILL.md +97 -0
- package/.opencode/tsconfig.json +11 -0
- package/CHANGELOG.md +396 -0
- package/LICENSE +21 -0
- package/README.md +351 -0
- package/package.json +32 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Instruction: hardening tests (developer shape, mode `harden`)
|
|
2
|
+
|
|
3
|
+
You are topping up coverage on code that already exists — tests must be
|
|
4
|
+
meaningful, not gaming:
|
|
5
|
+
|
|
6
|
+
- **Assertion depth (review-policy `assertion-depth`):** assert the full
|
|
7
|
+
observable contract — response body shape, error envelope, side effects.
|
|
8
|
+
Status-code-only or not-throws-only assertions are incomplete.
|
|
9
|
+
- Target the diff-coverage gaps you were given, not incidental old code.
|
|
10
|
+
- Never modify implementation code in this mode — tests only.
|
|
11
|
+
- Commit via `bin/harness commit --commit-class working`; report via the status
|
|
12
|
+
block with the coverage delta you achieved.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Step: harden (developer shape, mode `harden`)
|
|
2
|
+
|
|
3
|
+
Coverage top-up after ⟨approve-impl⟩ — tests here are green-from-birth
|
|
4
|
+
(they cover code that already exists), so NO red-proof machinery applies.
|
|
5
|
+
|
|
6
|
+
1. Resolve the coverage command: `bin/harness
|
|
7
|
+
resolve-coverage-cmd --repo <repo>` (per repo, `language.repos.<repo-
|
|
8
|
+
name>.coverage_cmd` — `discover` proposes one at `/init-workspace` time
|
|
9
|
+
where repo evidence supports it: python/go conventions, a node
|
|
10
|
+
`coverage` script or jest/vitest+provider, jacoco in a java pom). Null
|
|
11
|
+
means unconfigured — ask the user, never improvise a command. Their
|
|
12
|
+
answer is either a command (write it to
|
|
13
|
+
`language.repos.<name>.coverage_cmd` the `/workspace-config` way, then
|
|
14
|
+
re-resolve) or an explicit skip — record that with
|
|
15
|
+
`bin/harness log-event --json '{"kind":
|
|
16
|
+
"coverage-skipped", "repo": "<name>", "reason": "<their words>"}'` and
|
|
17
|
+
harden that repo from the tasks' own test gaps instead. Run the resolved command to find diff-coverage gaps against
|
|
18
|
+
the tasks' touched files.
|
|
19
|
+
2. Spawn `developer` with `harness-mode: harden` (+ run/repo/test-cmd
|
|
20
|
+
headers — test-cmd is per repo, same `language.repos.<repo-name>.test_cmd`
|
|
21
|
+
convention as `develop`) and the gap list. It follows `steps/harden-task.md`.
|
|
22
|
+
3. Spawn `reviewer` (`harness-mode: review`) on the new tests.
|
|
23
|
+
4. The DEVELOPER already committed its tests (harden-task.md's own
|
|
24
|
+
commit step — do not commit again from here; a second commit in
|
|
25
|
+
the same repo either fails on "nothing to commit" or sweeps unrelated
|
|
26
|
+
files via `git add -A`). Produce `<run>/reports/coverage.md`
|
|
27
|
+
summarizing before/after coverage and record the declared artifact:
|
|
28
|
+
`bin/harness artifact --name coverage-report
|
|
29
|
+
--value reports/coverage.md --run <run>`.
|
|
30
|
+
5. Advance: `bin/harness cursor --to security --run <run>`.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Step: intake (planner shape)
|
|
2
|
+
|
|
3
|
+
Spawn the planner to turn the normalized work item into a requirements
|
|
4
|
+
summary. It reads `<run>/work-item.json` — it has no provider access.
|
|
5
|
+
|
|
6
|
+
Spawn `planner` with prompt headers:
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
harness-mode: intake
|
|
10
|
+
harness-run: <run>
|
|
11
|
+
harness-repo: <primary-repo-path>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
…plus the ask: read `work-item.json` (+ the repo-map at
|
|
15
|
+
`.claude/context/repo-map/<repo-name>/` if present — index first, then
|
|
16
|
+
only the area files the work item touches), produce
|
|
17
|
+
`<run>/requirements.md` — restated requirements, acceptance criteria,
|
|
18
|
+
ambiguities/clarifying questions for the human.
|
|
19
|
+
|
|
20
|
+
The repo-map is generated at `/init-workspace` and its freshness is
|
|
21
|
+
(re)checked and stamped at **plan step 0** (the single owner). Here, just
|
|
22
|
+
READ what's present — do NOT generate it, run `repo-map-check`, or stamp
|
|
23
|
+
`.meta.json`; a missing or stale map is plan's job to refresh, not
|
|
24
|
+
intake's. (If it's absent, intake still proceeds on `work-item.json`
|
|
25
|
+
alone.) Don't investigate its status — plan handles it.
|
|
26
|
+
|
|
27
|
+
If the status block reports clarifying questions, surface them to the user
|
|
28
|
+
and relay answers (append to `requirements.md` via a re-spawn if substantial).
|
|
29
|
+
When surfacing them, **separate the two kinds** rather than presenting one
|
|
30
|
+
undifferentiated list:
|
|
31
|
+
|
|
32
|
+
- **confirm-a-default** — a question with a safe, stated default (you can
|
|
33
|
+
proceed if the human doesn't object). Batch these together and present the
|
|
34
|
+
default you'll take; a non-answer resolves cleanly.
|
|
35
|
+
- **resolve-a-real-fork** — a genuine either/or with no grounded default
|
|
36
|
+
(both branches are live). Present each on its own and wait for an explicit
|
|
37
|
+
pick; never bundle one of these behind a default, and never imply a fork is
|
|
38
|
+
settled when it isn't.
|
|
39
|
+
|
|
40
|
+
Mixing the two produces partial-answer states (the human ratifies the easy
|
|
41
|
+
defaults and the real fork silently rides along unanswered).
|
|
42
|
+
|
|
43
|
+
Note the run's seeded task list (`T1`) is a **provisional placeholder** —
|
|
44
|
+
fetch's positional default (`repos[0]`), flagged `provisional: true` in
|
|
45
|
+
state, not a scope decision. Do not present it to the human as one; the real
|
|
46
|
+
task list is set at plan-register and replaces it wholesale.
|
|
47
|
+
|
|
48
|
+
Record the declared artifact once requirements.md is final:
|
|
49
|
+
`bin/harness artifact --name requirements-summary
|
|
50
|
+
--value requirements.md --run <run>`.
|
|
51
|
+
|
|
52
|
+
Then advance: `bin/harness cursor --to plan --run <run>`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Step: metrics (orchestrator-owned, fully mechanical)
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
bin/harness metrics --run <run>
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Deterministic aggregation — timings from state, tokens from the ledger,
|
|
8
|
+
flagged events — into `<run>/reports/metrics.md`. No agent reasoning. Show
|
|
9
|
+
the user the summary. Final mirror **once per preflighted repo** (SKILL.md's
|
|
10
|
+
Publish rule — never the workspace), `--push` required so this closing
|
|
11
|
+
snapshot (metrics report included) actually reaches each PR's remote
|
|
12
|
+
branch instead of stranding locally:
|
|
13
|
+
`bin/harness publish-mirror --repo <preflighted-repo-path> --push --run <run>`.
|
|
14
|
+
Then declare the run finished — the successful sibling of abort, terminal
|
|
15
|
+
by declaration (mutations refuse from here on; the audit trail stays):
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
bin/harness complete --run <run>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The run is done.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Instruction: produce the plan (planner shape, mode `plan`)
|
|
2
|
+
|
|
3
|
+
Produce `<run>/plan.md`: the human-facing design for this story. Both
|
|
4
|
+
altitudes of approach decision below are approved at the single
|
|
5
|
+
`approve-plan` gate (design.md:495 — one gate, two altitudes).
|
|
6
|
+
|
|
7
|
+
## 0. Ground in the repo map
|
|
8
|
+
|
|
9
|
+
Before decomposing, read the auto-generated map at
|
|
10
|
+
`.claude/context/repo-map/<repo-name>/` for each repo the story touches —
|
|
11
|
+
the index first, then only the area detail files this story is likely to
|
|
12
|
+
touch (each is loadable standalone; never load the whole map). This is
|
|
13
|
+
where "the team uses <pattern>" comes from — cite it instead of
|
|
14
|
+
re-deriving the codebase. Two boundaries: the map speeds targeting, it
|
|
15
|
+
never replaces reading the real code for areas you plan to change; and its
|
|
16
|
+
freshness was already settled by the orchestrator before your spawn — READ
|
|
17
|
+
what's there, never run `repo-map-check`/`repo-map-stamp` or write
|
|
18
|
+
`.meta.json`. A missing map is not a blocker: proceed on code reading
|
|
19
|
+
alone and note the absence in your self-adversarial pass.
|
|
20
|
+
|
|
21
|
+
## 1. Decomposition
|
|
22
|
+
|
|
23
|
+
Tasks keyed by id (`T1`, `T2`…), each with: description, repo, edge-case
|
|
24
|
+
enumeration, risk tier, dependencies. One task = one reviewable unit.
|
|
25
|
+
|
|
26
|
+
**`depends_on` is HARD technical blockers ONLY — it is mechanically
|
|
27
|
+
enforced and gates cross-repo parallelism.** A task can't start until every
|
|
28
|
+
task it `depends_on` is done (the `dependencies-done` guard refuses), and
|
|
29
|
+
you can't loosen the graph past the plan gate (registration is plan-step-
|
|
30
|
+
only) — so an over-declared edge permanently *serializes work that could
|
|
31
|
+
run concurrently*. Declare an edge only when B literally cannot begin until
|
|
32
|
+
A completes (B compiles against a symbol A introduces, B's tests need code
|
|
33
|
+
A writes first, B mutates state A sets up). Do NOT encode as `depends_on`:
|
|
34
|
+
a cross-repo consumer whose contract is already ratified in
|
|
35
|
+
`requirements.md` (it doesn't depend on the producer's *implementation* —
|
|
36
|
+
build it in parallel against the fixed contract, stub the response; the
|
|
37
|
+
**ratified contract is the sync point, model it as a Cross-repo contract
|
|
38
|
+
below, not an edge** — e.g. a frontend task consuming a ratified backend
|
|
39
|
+
API is `depends_on: []`, not `[<backend tasks>]`); or mere merge/read order.
|
|
40
|
+
If your self-adversarial pass flags an edge as "soft / for clarity / not a
|
|
41
|
+
hard blocker," **remove it** (note sequencing in prose if useful) — the
|
|
42
|
+
enforced graph doesn't read your annotation. Keep the dependency diagram
|
|
43
|
+
faithful to the hard edges only: the graph the human approves is the one
|
|
44
|
+
that runs.
|
|
45
|
+
|
|
46
|
+
## 2. Solution Approaches (top-level altitude — only when a fork exists)
|
|
47
|
+
|
|
48
|
+
When a genuine architectural fork exists for the **whole story** (not a
|
|
49
|
+
per-task implementation detail), write a `## Solution Approaches` section:
|
|
50
|
+
2–3 whole-solution options (name, summary, trade-offs) + a recommendation.
|
|
51
|
+
**Skip this section when no real fork exists** — a single obvious approach
|
|
52
|
+
forces no filler comparison; over-triggering is worse than omitting it. Skip
|
|
53
|
+
silently, though, and the human at the gate can't tell "no fork" from
|
|
54
|
+
"missed one" — so when you skip it, add one line instead: `No architectural
|
|
55
|
+
fork identified: <why>` under the task table, visible either way.
|
|
56
|
+
|
|
57
|
+
## 3. Per-task detail
|
|
58
|
+
|
|
59
|
+
- **Test-intents**: named tests + one-line intent each, per task, as a
|
|
60
|
+
literal block under that task's section:
|
|
61
|
+
```
|
|
62
|
+
Test-intents:
|
|
63
|
+
- test_name_one — one-line intent
|
|
64
|
+
- test_name_two — one-line intent
|
|
65
|
+
```
|
|
66
|
+
Name each test exactly as the developer should write it (function/method
|
|
67
|
+
name) — `verify-red` mechanically checks these literal names appear in
|
|
68
|
+
the actual test files (coverage B1); the orchestrator carries the name
|
|
69
|
+
list, not the intent prose, into `plan-register`'s `test_intents` field.
|
|
70
|
+
- **`[API: <lib> v<X>]`** annotations where a task prescribes a library API
|
|
71
|
+
— the developer verifies the real signature before writing call sites.
|
|
72
|
+
- **≤2 pattern hints** per task: existing test files via bounded globbing
|
|
73
|
+
(≤5 globs), ranked by mtime, filename match only (no reading contents).
|
|
74
|
+
"No match" is a valid answer — don't widen the search.
|
|
75
|
+
- **Per-task approach options** where a single task (not the whole story)
|
|
76
|
+
has more than one reasonable implementation — distinct from the
|
|
77
|
+
story-level altitude in step 2.
|
|
78
|
+
- **Cross-repo contracts**, multi-repo stories only: name the producer repo,
|
|
79
|
+
consumer repo(s), and signature fragment(s) for anything one repo's task
|
|
80
|
+
emits and another's depends on — the enriched shape in `steps/plan.md`'s
|
|
81
|
+
registration example.
|
|
82
|
+
|
|
83
|
+
## 4. Diagrams
|
|
84
|
+
|
|
85
|
+
Four Mermaid diagrams, styled per `shared/diagram-styling.md`:
|
|
86
|
+
|
|
87
|
+
1. **Class/type diagram** (`classDiagram`) — new/modified types,
|
|
88
|
+
relationships, key methods. Mark scope with `:::new` / `:::modified` on a
|
|
89
|
+
dedicated `class <Name>:::<style>` statement — NOT on a relationship
|
|
90
|
+
endpoint or bare reference (classDiagram grammar rejects those; see
|
|
91
|
+
`shared/diagram-styling.md`).
|
|
92
|
+
2. **Runtime flowchart** (`flowchart TD`) — the feature's runtime flow,
|
|
93
|
+
decision points, external interactions, error paths.
|
|
94
|
+
3. **Sequence diagram** (`sequenceDiagram`, `autonumber`) — actor
|
|
95
|
+
interactions, call order, sync vs async, key payloads.
|
|
96
|
+
4. **Task dependency graph** (`flowchart LR`) — one node per task id, edges
|
|
97
|
+
from `depends_on`. Required for every story, even single-task ones.
|
|
98
|
+
|
|
99
|
+
## 5. Self-adversarial pass
|
|
100
|
+
|
|
101
|
+
Before finalizing: list ambiguities, risks, and unchecked assumptions in the
|
|
102
|
+
draft. Revise or flag them — don't ship a plan you haven't tried to break.
|
|
103
|
+
|
|
104
|
+
## 6. Register + advance
|
|
105
|
+
|
|
106
|
+
Mechanics (the `plan-register` call, gate advance) live in
|
|
107
|
+
`steps/plan.md` — this file is the content contract, that file is the
|
|
108
|
+
registration procedure. Don't duplicate one into the other.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Step: plan (planner shape)
|
|
2
|
+
|
|
3
|
+
0. **Repo-map freshness — this step is its SINGLE owner.** The repo-map is
|
|
4
|
+
first generated at `/init-workspace`; nothing between there and here
|
|
5
|
+
touches it (intake only reads it), so this is the one place in the
|
|
6
|
+
pipeline that confirms it's current. Its status is filesystem-only
|
|
7
|
+
(`.claude/context/repo-map/<name>/.meta.json`) — not in `state.yaml`, so
|
|
8
|
+
the `show` verb won't surface it; check it explicitly, per registered
|
|
9
|
+
repo:
|
|
10
|
+
`bin/harness repo-map-check --repo-name <name>
|
|
11
|
+
--repo <path>`.
|
|
12
|
+
- `fresh` → nothing to do (init already generated + stamped it; do NOT
|
|
13
|
+
re-stamp).
|
|
14
|
+
- `missing`/`stale` → regenerate (spawn `planner` with
|
|
15
|
+
`harness-mode: repo-map`, a declared out-of-run-legal pair) and stamp
|
|
16
|
+
via `bin/harness repo-map-stamp` after it
|
|
17
|
+
returns — a plan grounded in a stale map cites patterns that no longer
|
|
18
|
+
exist.
|
|
19
|
+
0b. **Re-entering plan** (gate rejection / approved mid-run amendment)?
|
|
20
|
+
Snapshot the current plan first — copy `<run>/plan.md` to
|
|
21
|
+
`<run>/plan-r<n>.md` — so the previously-approved text stays
|
|
22
|
+
recoverable. Never rewrite it silently.
|
|
23
|
+
|
|
24
|
+
Spawn `planner` with headers (`harness-mode: plan`, `harness-run`,
|
|
25
|
+
`harness-repo`) to produce `<run>/plan.md`. It follows `steps/plan-task.md`
|
|
26
|
+
(the content contract). The plan's REQUIRED content (coverage decisions
|
|
27
|
+
B1/B2/B7/B8 — the gate presents all of it):
|
|
28
|
+
|
|
29
|
+
- Tasks keyed by id (`T1`, `T2`…), each with: description, repo, edge-case
|
|
30
|
+
enumeration, risk tier, dependencies.
|
|
31
|
+
- **Per-task test-intents** (named tests + one-line intent each) — approved
|
|
32
|
+
at the plan gate; carry the NAMES (not the intent prose) into
|
|
33
|
+
`plan-register`'s `test_intents` field per task — `verify-red` mechanically
|
|
34
|
+
checks each declared name is written, no re-declaration needed later.
|
|
35
|
+
- **Approach options, two altitudes**: a top-level `## Solution Approaches`
|
|
36
|
+
section (2–3 whole-solution options + recommendation) only when a genuine
|
|
37
|
+
architectural fork exists, distinct from per-task options — both approved
|
|
38
|
+
at this one gate. Skipped → one line saying why, never silent.
|
|
39
|
+
- `[API: <lib> v<X>]` annotations where a task prescribes a library API.
|
|
40
|
+
- ≤2 existing-test-file **pattern hints** per task (bounded discovery).
|
|
41
|
+
- **Four diagrams** — class/type, runtime flowchart, sequence, task
|
|
42
|
+
dependency graph — per `shared/diagram-styling.md` (full spec in
|
|
43
|
+
`steps/plan-task.md`).
|
|
44
|
+
- A **self-adversarial pass**: ambiguities, risks, unchecked assumptions.
|
|
45
|
+
|
|
46
|
+
When the planner's status block reports the plan ready:
|
|
47
|
+
|
|
48
|
+
1. Register the tasks it declared (replaces the single fetch-seeded task):
|
|
49
|
+
`bin/harness plan-register --run <run> --tasks-json
|
|
50
|
+
'[{"id":"T1","repo":"<path>","risk":"low","test_intents":["test_name_one",
|
|
51
|
+
"test_name_two"]}, …]'` — `repo` must be the exact path string from this
|
|
52
|
+
workspace's `repos.yaml` (i.e. `config["repos"]`'s VALUE, e.g.
|
|
53
|
+
`/abs/path/to/backend`), never the short registered NAME (`backend`) —
|
|
54
|
+
a name instead of a path resolves to no registered repo and fails
|
|
55
|
+
silently until a later step (`verify-red`/task completion) reports a
|
|
56
|
+
confusing "no test command" error instead of a clear one here.
|
|
57
|
+
`risk` is free-form (defaults to `low` if omitted) — no enum is
|
|
58
|
+
enforced, but use `low`/`medium`/`high` for consistency with what the
|
|
59
|
+
plan itself declares. (`test_intents` is the plan's declared test
|
|
60
|
+
NAMES for that task, empty if none) — declare cross-repo contracts too if
|
|
61
|
+
the plan named any: `--contracts-json '[{"id":"C1","type":"http",
|
|
62
|
+
"producer":"a","consumers":["b"],"signature":["POST /v2/items",
|
|
63
|
+
"field: item_id"]}]'` (`type` is `http | service-bus | dto`, descriptive
|
|
64
|
+
only; `signature` is one string or a list of fragments, and **each must be
|
|
65
|
+
a grep-able code token/signature that appears verbatim in source** —
|
|
66
|
+
`archived`, `filter_notes(notes, tag)`, `POST /v2/items` — NOT an English
|
|
67
|
+
description: reconcile-contracts matches by literal source search, so a
|
|
68
|
+
prose fragment is rejected at plan-register and would false-report drift.
|
|
69
|
+
All fragments must be present; the flat legacy `"repos":["a","b"]` form
|
|
70
|
+
still works in place of `producer`/`consumers`. Legal only at cursor `plan`.
|
|
71
|
+
2. Check the diagrams: `bin/harness validate-mermaid
|
|
72
|
+
--file <run>/plan.md`. A non-zero exit names structural rule violations
|
|
73
|
+
(`failures` in the JSON) — send the planner back to fix them, never
|
|
74
|
+
advance past a failure. Purely structural (well-formed Mermaid that
|
|
75
|
+
exists); it doesn't check the four diagrams are actually present — that
|
|
76
|
+
stays plan-task.md's content-contract job.
|
|
77
|
+
3. Record the declared artifact: `bin/harness
|
|
78
|
+
artifact --name plan --value plan.md --run <run>` (the gate presents it
|
|
79
|
+
by this name).
|
|
80
|
+
4. Advance to the gate: `bin/harness cursor --to approve-plan --run <run>`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Step: pre-pr-fixes (developer shape, mode `fixup`; reached on gate rejection)
|
|
2
|
+
|
|
3
|
+
Task commits are already squashed — fixes need the fixup path (never new
|
|
4
|
+
loose commits, never history edits by hand):
|
|
5
|
+
|
|
6
|
+
1. Spawn `developer` with `harness-mode: fixup` + the gate's findings.
|
|
7
|
+
It follows `steps/fixup-task.md`.
|
|
8
|
+
2. After its fixup commits land:
|
|
9
|
+
`bin/harness merge-task --repo <repo> --autosquash --base <default-branch>
|
|
10
|
+
--run <run>` — folds them into their task commits and re-derives the
|
|
11
|
+
tracker SHAs.
|
|
12
|
+
3. Record the declared artifact: `bin/harness
|
|
13
|
+
artifact --name fixup-commits --value "<findings addressed> @ <new HEAD
|
|
14
|
+
sha>" --run <run>`.
|
|
15
|
+
4. Return via the declared edge: `bin/harness cursor --to pre-pr --run <run>`
|
|
16
|
+
(the pre-PR review re-runs on the corrected branch).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Instruction: holistic pre-PR review (reviewer shape, mode `pre-pr`)
|
|
2
|
+
|
|
3
|
+
Review the ENTIRE feature branch (all squashed task commits) as one change:
|
|
4
|
+
|
|
5
|
+
- Re-run build + full test suite yourself — never trust reported results.
|
|
6
|
+
- Check each review-policy rule from config (assertion-depth,
|
|
7
|
+
patch-dto-wrapper, team rules) and cite violations by file:line.
|
|
8
|
+
- Check plan-vs-implementation drift: does what shipped match what was
|
|
9
|
+
approved? Are the declared test-intents all realized?
|
|
10
|
+
- Hunt the TDD residuals: semantically-empty tests (red for the wrong
|
|
11
|
+
reason), impl overfit to the test, weakened shared fixtures.
|
|
12
|
+
- Findings numbered `[R<n>]` with severity CRITICAL | WARNING | SUGGESTION.
|
|
13
|
+
- Deliver the full report text in your status block `details` (the
|
|
14
|
+
orchestrator persists it — you cannot write files).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Step: pre-pr (reviewer shape, mode `pre-pr`)
|
|
2
|
+
|
|
3
|
+
1. Multi-repo runs first: `bin/harness reconcile-contracts --run <run>` — drift
|
|
4
|
+
goes in front of the human at the gate, never auto-fixed.
|
|
5
|
+
2. Spawn `reviewer` with `harness-mode: pre-pr` (+ run/repo headers): a
|
|
6
|
+
holistic review of the full feature branch — cohesion across tasks,
|
|
7
|
+
review-policy rules, plan-vs-implementation drift, the residuals the TDD
|
|
8
|
+
lock can't catch (semantically-empty tests, impl-overfit).
|
|
9
|
+
3. The reviewer is read-only: it reports the review in its status block; YOU
|
|
10
|
+
persist it to `<run>/reports/pre-pr.md` verbatim and record the declared
|
|
11
|
+
artifact: `bin/harness artifact --name pre-pr-report
|
|
12
|
+
--value reports/pre-pr.md --run <run>`.
|
|
13
|
+
4. Advance to ⟨approve-pre-pr⟩ (`gate.md`); present the report AND the
|
|
14
|
+
contracts verdict. Rejection routes to `pre-pr-fixes` (declared edge).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Step: preflight (orchestrator-owned, fully mechanical)
|
|
2
|
+
|
|
3
|
+
Create the feature branch in each affected repo from the declared naming
|
|
4
|
+
template — one owned command per repo:
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
bin/harness preflight --repo <repo-path> --run <run>
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
First ensures the repo is clean and on its default branch (the reusable
|
|
11
|
+
precondition `discover` also uses at `/init-workspace` time, standalone as
|
|
12
|
+
`bin/harness ensure-default-branch --repo <repo-path>
|
|
13
|
+
[--branch <name>]` for any future step that needs it) — a dirty repo, or
|
|
14
|
+
one mid-rebase/merge, refuses
|
|
15
|
+
(surface to the human, never auto-stash/discard/continue); a clean repo on
|
|
16
|
+
a different branch is switched, no confirmation needed. Pass `--branch
|
|
17
|
+
<name>` to override the auto-resolved guess. Idempotent on retry, per
|
|
18
|
+
repo: a `branches` entry already recorded for *this* repo is returned
|
|
19
|
+
directly rather than re-derived — a second repo's preflight is never
|
|
20
|
+
satisfied by the first repo's record (each repo gets its own entry). **Known risk:** two runs started concurrently
|
|
21
|
+
against the *same* repo path can race here (no repo-level lock exists yet)
|
|
22
|
+
— use a separate clone/checkout per concurrent run against the same repo.
|
|
23
|
+
Then it renders `naming.branch` (`{type}/{id}-{slug}`) from state, creates
|
|
24
|
+
the branch, and records the `branches` artifact. It also pins
|
|
25
|
+
`.harness-key` into the repo's `.git/info/exclude` (shared with its task
|
|
26
|
+
worktrees), so a stray integrity key can never be swept into git history
|
|
27
|
+
by the commit verbs' `git add -A`; the commit verbs refuse-and-unstage as
|
|
28
|
+
backstop. Then:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
bin/harness cursor --to develop --run <run>
|
|
32
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Step: quick-recheck (orchestrator-owned; quick mode only)
|
|
2
|
+
|
|
3
|
+
The ex-ante classifier saw only work-item text; this step checks the REAL
|
|
4
|
+
diff against the declared disqualify patterns:
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
bin/harness quick-recheck --repo <repo> --base <default-branch> --run <run>
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
- `clean` → advance to `pre-pr`.
|
|
11
|
+
- `dirty` → the escalation edge is MANDATORY: `pre-pr` is now illegal;
|
|
12
|
+
advance to `security` (`bin/harness cursor --to security`) — the run switches
|
|
13
|
+
to full mode and continues from there. Tell the user why (the hits are in
|
|
14
|
+
the events ledger).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Step: reconcile (orchestrator-owned, fully mechanical)
|
|
2
|
+
|
|
3
|
+
## MCP-transport work-item providers (ado-mcp / jira / zoho)
|
|
4
|
+
|
|
5
|
+
A script can't call an MCP tool, so plain `bin/harness reconcile` would try to
|
|
6
|
+
dispatch `work_item.transition` itself and refuse every time write-back is on
|
|
7
|
+
(the default). Run the transition in the orchestrator instead, same pattern
|
|
8
|
+
as `fetch.md`:
|
|
9
|
+
|
|
10
|
+
1. If `write_back.on_done` (or the milestone in play) is enabled, invoke the
|
|
11
|
+
mapped `work_item.transition` tool (`bin/harness
|
|
12
|
+
provider --op work_item.transition --id <id> --to <status>` prints the
|
|
13
|
+
exact tool + args to call).
|
|
14
|
+
2. Then run reconcile with the transition skipped (already done above):
|
|
15
|
+
```
|
|
16
|
+
bin/harness reconcile --skip-transition --run <run>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## CLI-transport providers (github / gitlab / ado / local-markdown)
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
bin/harness reconcile --run <run>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Provider status write-back (conservative default: done), archives completed
|
|
26
|
+
tasks (declared FSM edge), sweeps leftover worktrees. Then advance to
|
|
27
|
+
`metrics`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Instruction: per-task review (reviewer shape, mode `review`)
|
|
2
|
+
|
|
3
|
+
Review ONE task's diff (its worktree branch vs the feature branch), inside
|
|
4
|
+
the develop loop:
|
|
5
|
+
|
|
6
|
+
- Re-run the task's tests yourself (`harness-test-cmd`) — independent
|
|
7
|
+
verification, never trust the developer's claim. Long output? Capture it
|
|
8
|
+
under /tmp (`… 2>&1 | tee /tmp/review.log`) — /tmp and /dev/null are
|
|
9
|
+
your only legal write targets; any other shell write is blocked. Spell
|
|
10
|
+
the path LITERALLY: a variable-held target (`$SCRATCH/x`, `$(mktemp -d)`)
|
|
11
|
+
can't be verified by the guard and blocks even when it points at /tmp.
|
|
12
|
+
- Check the diff against: the task's plan section (scope drift?), the
|
|
13
|
+
config review-policy rules, and the engineering baseline
|
|
14
|
+
(`shared/engineering.md`). For test-intents: run
|
|
15
|
+
`bin/harness show-redproof --task <T> --run <run>`
|
|
16
|
+
(chain-verified; a raw `.redproof/` read skips integrity verification
|
|
17
|
+
and is guard-BLOCKED — and type that full invocation exactly: the bare
|
|
18
|
+
`harness` spelling is neither on PATH nor allow-listed, so it dies as a
|
|
19
|
+
permission denial) and check its `missing_intents` field
|
|
20
|
+
(already mechanically checked, not yours to recompute) — any entry is a
|
|
21
|
+
finding. A present name isn't automatically a pass, though: judge whether
|
|
22
|
+
it genuinely tests its declared intent (design.md:392 — presence is
|
|
23
|
+
mechanical, semantic match stays yours).
|
|
24
|
+
- Findings numbered `[R<n>]` with severity CRITICAL | WARNING | SUGGESTION;
|
|
25
|
+
`verdict: APPROVED` only when nothing CRITICAL/WARNING remains. The
|
|
26
|
+
verdict is its OWN block line, before `outcome`/`details` (the template's
|
|
27
|
+
third line — never inside another field's prose): one run into the end
|
|
28
|
+
of a sentence is deliberately not captured (fail-closed) and costs a
|
|
29
|
+
full re-review by a fresh reviewer.
|
|
30
|
+
- Full findings in the status block `details` — the orchestrator routes
|
|
31
|
+
them; rejection costs a bounded review round (round N+ escalates to the
|
|
32
|
+
human), so make every finding actionable.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Step: security (orchestrator-owned, fully mechanical)
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
bin/harness security-scan --run <run>
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
One call scans every registered repo (`security.scan_cmd` is per repo,
|
|
8
|
+
language-config convention — different repos may need different scanners;
|
|
9
|
+
"no scanner" for a repo records informational). Runs concurrently, parses
|
|
10
|
+
each repo's max severity via the declared regex, aggregates to ONE true max
|
|
11
|
+
across all repos (never a per-call overwrite — a clean repo must not mask
|
|
12
|
+
another's critical finding), writes `<run>/reports/security.md`, records
|
|
13
|
+
the `security.max_severity` artifact.
|
|
14
|
+
|
|
15
|
+
Then advance. The manifest's `when` predicate decides the rest mechanically:
|
|
16
|
+
severity ≥ threshold → ⟨approve-security⟩ is REQUIRED next (fix-now / waive /
|
|
17
|
+
defer, see `gate.md`); below threshold → the gate is skipped and `pre-pr` is
|
|
18
|
+
next. `bin/harness show` + a refused advance tell you which.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Instruction: ad-hoc request triage (reviewer shape, mode `request-triage`)
|
|
2
|
+
|
|
3
|
+
A human made a request mid-run. Classify it against the APPROVED plan:
|
|
4
|
+
|
|
5
|
+
- `IN_SCOPE_BUG` — defect in work this run already did → route to the
|
|
6
|
+
develop/fixup loop.
|
|
7
|
+
- `IN_SCOPE_AC_MISS` — an approved acceptance criterion isn't met → same.
|
|
8
|
+
- `OUT_OF_SCOPE` — new scope → propose a follow-up work item; NEVER
|
|
9
|
+
silently merge it into this run.
|
|
10
|
+
- `PLAN_CONFLICT` — contradicts an approved decision → surface both sides
|
|
11
|
+
to the human; never resolve unilaterally.
|
|
12
|
+
- `DUPLICATE` / `INVALID` — with the evidence.
|
|
13
|
+
|
|
14
|
+
Verdict + reasoning in the status block; the orchestrator presents it to the
|
|
15
|
+
human — triage never mutates anything.
|