@izkac/forgekit 0.3.11 → 0.3.13
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/forge.mjs +107 -107
- package/bin/forgekit.mjs +83 -83
- package/bin/review.mjs +81 -81
- package/package.json +1 -1
- package/scripts/prepack.mjs +78 -78
- package/scripts/run-tests.mjs +50 -50
- package/src/adr.mjs +236 -236
- package/src/adr.test.mjs +170 -170
- package/src/change.mjs +327 -234
- package/src/change.test.mjs +145 -83
- package/src/cleanup-sessions.mjs +84 -84
- package/src/config.mjs +103 -103
- package/src/defer.mjs +75 -75
- package/src/doctor.mjs +350 -341
- package/src/doctor.test.mjs +114 -114
- package/src/init.mjs +680 -621
- package/src/install.mjs +815 -815
- package/src/install.test.mjs +180 -180
- package/src/integrity-check.mjs +60 -60
- package/src/integrity.mjs +682 -682
- package/src/integrity.test.mjs +566 -566
- package/src/lib.mjs +143 -143
- package/src/models.defaults.json +41 -41
- package/src/new-session.mjs +99 -99
- package/src/openspec-overlays/README.md +19 -19
- package/src/openspec-overlays/openspec-apply-change-footer.md +14 -14
- package/src/openspec-overlays/opsx-apply-completion-step.md +1 -1
- package/src/openspec-overlays/opsx-apply-implement-step.md +11 -11
- package/src/paths.mjs +92 -92
- package/src/plan-engine.mjs +321 -278
- package/src/plan-engine.test.mjs +447 -283
- package/src/preferences.defaults.json +78 -78
- package/src/preferences.mjs +438 -438
- package/src/preferences.test.mjs +174 -174
- package/src/record-evidence.mjs +204 -204
- package/src/resolve-model.mjs +312 -312
- package/src/resolve-model.test.mjs +194 -194
- package/src/review/cli.test.mjs +117 -117
- package/src/review/export.mjs +172 -172
- package/src/review/export.test.mjs +197 -197
- package/src/review/fixtures/valid-review.json +42 -42
- package/src/review/lib.mjs +894 -894
- package/src/review/lib.test.mjs +266 -266
- package/src/review/schema.json +196 -196
- package/src/review/signals.test.mjs +62 -62
- package/src/score-cli.mjs +68 -68
- package/src/score.mjs +568 -566
- package/src/score.test.mjs +366 -340
- package/src/session-reminder.mjs +207 -207
- package/src/session-status.mjs +70 -70
- package/src/set-models.mjs +186 -186
- package/src/set-phase.mjs +205 -205
- package/src/set-prefs.mjs +294 -294
- package/src/specs-sync.mjs +234 -0
- package/src/specs-sync.test.mjs +114 -0
- package/src/spine.mjs +93 -93
- package/src/triage-prompt.mjs +175 -175
- package/src/triage-prompt.test.mjs +50 -50
- package/src/vendor-openspec-overlays.mjs +176 -176
- package/src/vendor-openspec-overlays.test.mjs +62 -62
- package/vendor/skills/archive-to-adr/SKILL.md +149 -149
- package/vendor/skills/forge/SKILL.md +136 -136
- package/vendor/skills/forge/docs/forge.md +650 -647
- package/vendor/skills/forge/phases/brainstorm.md +23 -23
- package/vendor/skills/forge/phases/finish.md +90 -87
- package/vendor/skills/forge/phases/implement.md +77 -77
- package/vendor/skills/forge/phases/plan-openspec.md +60 -60
- package/vendor/skills/forge/phases/plan-specs.md +163 -117
- package/vendor/skills/forge/phases/review.md +25 -25
- package/vendor/skills/forge/phases/verify.md +124 -124
- package/vendor/skills/forge/references/forge-layout.md +85 -85
- package/vendor/skills/forge/references/pace.md +115 -115
- package/vendor/skills/forge/references/plan-routing.md +52 -51
- package/vendor/skills/forge/references/runtime-integrity.md +232 -225
- package/vendor/skills/forge/references/substantial-work.md +37 -37
- package/vendor/skills/forge/references/test-evidence.md +30 -30
- package/vendor/skills/forge/references/test-strategy.md +68 -68
- package/vendor/skills/forge/skills/subagent-driven-development/SKILL.md +87 -87
- package/vendor/skills/forge/subagents/final-reviewer-prompt.md +56 -56
- package/vendor/skills/forge/subagents/implementer-prompt.md +38 -38
- package/vendor/skills/git-resolve-adr-conflict/SKILL.md +132 -132
- package/vendor/skills/thorough-code-review/SKILL.md +290 -290
- package/vendor/skills/thorough-code-review/examples.md +133 -133
- package/vendor/skills/thorough-code-review/reference/accepted-risks.md +26 -26
- package/vendor/skills/thorough-code-review/reference/lenses.md +96 -96
- package/vendor/skills/thorough-code-review/reference/phase1-scout.md +62 -62
- package/vendor/skills/thorough-code-review/reference/phase2-skeptic.md +105 -105
- package/vendor/skills/thorough-code-review/reference/report-schema.json +222 -222
- package/vendor/skills/thorough-code-review/reference/report-template.md +115 -115
- package/vendor/skills/thorough-code-review/reference/severity-rubric.md +49 -49
- package/vendor/skills/thorough-code-review/reference/signals-preflight.md +55 -55
- package/vendor/templates/adr/README.md +7 -7
- package/vendor/templates/adr/decisions.md +141 -141
- package/vendor/templates/adr/hooks/check-pending-adrs.mjs +74 -74
- package/vendor/templates/adr/hooks/check-pending-adrs.sh +3 -3
- package/vendor/templates/adr/hooks/openspec-archive-agent-message.mjs +52 -52
- package/vendor/templates/adr/hooks/openspec-archive-agent-message.sh +3 -3
- package/vendor/templates/project/claude/commands/forge-apply.md +75 -75
- package/vendor/templates/project/claude/commands/forge-brainstorm.md +7 -7
- package/vendor/templates/project/claude/commands/forge-build.md +17 -17
- package/vendor/templates/project/claude/commands/forge-plan.md +12 -12
- package/vendor/templates/project/claude/commands/forge-skip.md +14 -14
- package/vendor/templates/project/claude/commands/forge-status.md +16 -16
- package/vendor/templates/project/claude/commands/forge.md +16 -16
- package/vendor/templates/project/claude/hooks/forge-prompt-hook.mjs +73 -73
- package/vendor/templates/project/claude/hooks/forge-session-start.mjs +19 -19
- package/vendor/templates/project/claude/hooks/forge-triage-hook.mjs +77 -77
- package/vendor/templates/project/cursor/commands/forge-apply.md +75 -75
- package/vendor/templates/project/cursor/commands/forge-brainstorm.md +10 -10
- package/vendor/templates/project/cursor/commands/forge-build.md +17 -17
- package/vendor/templates/project/cursor/commands/forge-plan.md +15 -15
- package/vendor/templates/project/cursor/commands/forge-skip.md +14 -14
- package/vendor/templates/project/cursor/commands/forge-status.md +16 -16
- package/vendor/templates/project/cursor/commands/forge.md +16 -16
- package/vendor/templates/project/cursor/hooks/forge-session-start.mjs +30 -30
- package/vendor/templates/project/cursor/hooks/forge-session-start.sh +3 -3
|
@@ -1,225 +1,232 @@
|
|
|
1
|
-
# Runtime integrity (hard rules)
|
|
2
|
-
|
|
3
|
-
Forge verifies **outcomes of the system**, not only artifacts of work. These
|
|
4
|
-
rules apply at every pace. Coordinators, implementers, and reviewers must not
|
|
5
|
-
weaken them in briefs.
|
|
6
|
-
|
|
7
|
-
## 1. No stubs / no false success
|
|
8
|
-
|
|
9
|
-
A handler that only logs, bumps progress, or marks a job/request `succeeded`
|
|
10
|
-
without doing the domain work is **forbidden**.
|
|
11
|
-
|
|
12
|
-
- If a job kind (or API path) is enqueueable / callable in production, it MUST
|
|
13
|
-
run real domain logic, **or** fail closed with a clear error, **or** not be
|
|
14
|
-
exposed at all.
|
|
15
|
-
- Never authorize “stub OK”, “minimal poll loop only”, or “wire later” for a
|
|
16
|
-
path this change claims.
|
|
17
|
-
|
|
18
|
-
## 2. Runtime owner required
|
|
19
|
-
|
|
20
|
-
A capability requirement is **not** met by a library module alone.
|
|
21
|
-
|
|
22
|
-
- For every REQ / capability this change implements, name the **production
|
|
23
|
-
caller** (worker job kind, HTTP endpoint, CLI command, scheduled job, …).
|
|
24
|
-
- Library-only = incomplete. Add a wiring task before marking the section done.
|
|
25
|
-
|
|
26
|
-
## 3. Tests must fail on a no-op
|
|
27
|
-
|
|
28
|
-
Evidence that only asserts ceremony is invalid.
|
|
29
|
-
|
|
30
|
-
| Invalid | Valid |
|
|
31
|
-
| ------- | ----- |
|
|
32
|
-
| Job status became `succeeded` | Fixture upload/run left the expected domain side effects |
|
|
33
|
-
| Handler was called | Mongo/files/artifacts match the capability (or structured failure) |
|
|
34
|
-
| Queue claim/lease works | Pairing/stats/proposals/exports exist as specified |
|
|
35
|
-
|
|
36
|
-
If a test suite would still pass with a no-op handler, it does not prove the
|
|
37
|
-
task.
|
|
38
|
-
|
|
39
|
-
## 4. Briefs may not narrow scope
|
|
40
|
-
|
|
41
|
-
**Capability specs beat narrow task wording** when they conflict.
|
|
42
|
-
|
|
43
|
-
- Coordinator briefs MUST NOT redefine done downward (e.g. authorize a stub
|
|
44
|
-
when the spec requires real ETL).
|
|
45
|
-
- To shrink scope: stop and ask the user. Do not silently checkbox around gaps.
|
|
46
|
-
- Prefer `DONE_WITH_CONCERNS` / incomplete tasks over green checkboxes.
|
|
47
|
-
|
|
48
|
-
## 5. E2E means an executed product loop, not prose
|
|
49
|
-
|
|
50
|
-
Before claiming the change complete:
|
|
51
|
-
|
|
52
|
-
1. Author the **closed product loop** as executable steps in `e2e.json`
|
|
53
|
-
(`forge e2e init`), run it against the live entry points
|
|
54
|
-
(`forge e2e run`), and get a **green run** — **or**
|
|
55
|
-
2. Leave an explicit **`BLOCKED`** list in `verify-evidence.md` — and do **not**
|
|
56
|
-
mark the change complete / advance to `done`.
|
|
57
|
-
|
|
58
|
-
**A single job slice is not platform E2E.** When the design has a
|
|
59
|
-
producer/consumer split (analyze vs execute, proposals vs ratify, write vs
|
|
60
|
-
read), the required E2E is the full loop:
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
produce artifact → consumer reads it → decision/state change →
|
|
64
|
-
next run's OUTPUT DIFFERS from the baseline
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Example: ingest→Parquet plus a thin run→`.sav` does **not** verify a
|
|
68
|
-
governance loop; analyze→proposals→ratify→run-applies-decisions does.
|
|
69
|
-
|
|
70
|
-
The mechanical gate requires a green, **current** `e2e-results.json` (its
|
|
71
|
-
steps hash must match `e2e.json`) whenever the spine has real rows.
|
|
72
|
-
Describing the loop in `verify-evidence.md` no longer satisfies the gate —
|
|
73
|
-
prose cannot prove wiring. Each step is `{ name, cmd, expect?, timeoutMs? }`:
|
|
74
|
-
exit code 0 required, `expect` (regex) matched against the output. Steps must
|
|
75
|
-
assert **domain side effects** — a step list that would pass against a
|
|
76
|
-
stubbed handler is invalid (rule 3 applies to e2e steps too).
|
|
77
|
-
|
|
78
|
-
`e2e.json` may set `"notApplicable": "<reason>"` only when the loop cannot be
|
|
79
|
-
driven by any command (e.g. requires a physical device). Reviewers police the
|
|
80
|
-
reason; "no time" or "covered by unit tests" is a REJECT. Keep a short loop
|
|
81
|
-
narrative under `## Product loop` in `verify-evidence.md` as reviewer context.
|
|
82
|
-
|
|
83
|
-
**Project-level off switch (operator only).** `forge e2e disable "<reason>"`
|
|
84
|
-
records `e2e.disabled` in `.forge/config.json` and the gate stops demanding
|
|
85
|
-
executed runs project-wide (`forge e2e enable` restores it). This is the
|
|
86
|
-
**human's** trade-off to make — an agent must NEVER run `forge e2e disable`,
|
|
87
|
-
suggest it to dodge a red gate, or edit the config key. If the gate blocks
|
|
88
|
-
you, fix the loop or ask the operator. When it is disabled, keep the
|
|
89
|
-
`## Product loop` narrative in `verify-evidence.md` — with no executed run,
|
|
90
|
-
prose is the only loop evidence the scorecard can grade.
|
|
91
|
-
|
|
92
|
-
### Keeping the loop cheap (cost policy)
|
|
93
|
-
|
|
94
|
-
"Too complex to test" is usually a signal to test it, not to wave it through —
|
|
95
|
-
a loop is complex exactly when the feature has many wiring seams, which is
|
|
96
|
-
when wiring silently breaks. Never skip the loop for complexity; control its
|
|
97
|
-
cost instead:
|
|
98
|
-
|
|
99
|
-
- **Ask before building complex harness infrastructure — and only then.**
|
|
100
|
-
The ask-line is infrastructure: a rig built from scratch, new
|
|
101
|
-
servers/containers/services, third-party accounts or sandboxes (e.g. real
|
|
102
|
-
payment checkout), device farms. That is a project, not a test — stop and
|
|
103
|
-
ask the user. **Everything below that line never needs permission**: if a
|
|
104
|
-
harness already exists (test server, isolated ports, scratch DB), author
|
|
105
|
-
the loop; writing fixtures, seed data, helper scripts, or extra steps
|
|
106
|
-
inside the existing rig is normal test work — just do it. Asking for
|
|
107
|
-
fixture-level work is over-asking; skipping the loop because the rig is
|
|
108
|
-
missing is under-testing — the ask is exactly the moment the operator can
|
|
109
|
-
say "build it once" and make every future loop on the project cheap.
|
|
110
|
-
- **A built harness is permanent project infrastructure — record it, reuse
|
|
111
|
-
it.** When the operator approves building one: build it as committed
|
|
112
|
-
project code (never session scratch), then record it:
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
forge e2e harness --set "<what it is / where>" --start "<start command>" [--dir <path>]
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
This lands in `.forge/config.json` (committed), and every later session
|
|
119
|
-
sees it — `forge e2e init` and `forge e2e status` print the recorded
|
|
120
|
-
harness. Check `forge e2e harness` before proposing to build or asking the
|
|
121
|
-
operator; proposing a new rig while one is recorded is a REJECT.
|
|
122
|
-
- **One executed loop per capability, not per assertion.** Push edge cases
|
|
123
|
-
into unit tests; e2e proves the wiring exists.
|
|
124
|
-
- **Set `timeoutMs` from the step count up front.** A 10-step loop is never a
|
|
125
|
-
30s test — a too-small budget fails at whatever line the clock runs out on,
|
|
126
|
-
which reads as a phantom regression.
|
|
127
|
-
- **Run it once, at the end, serially** — never alongside unit suites; load
|
|
128
|
-
makes real assertions look flaky.
|
|
129
|
-
- **Prefer a production/preview build over the dev server** when the loop
|
|
130
|
-
drives a web app — compile-on-demand and dev-mode socket noise dominate the
|
|
131
|
-
per-run cost and bury the actual assertion.
|
|
132
|
-
|
|
133
|
-
## 6. Job-kind closure
|
|
134
|
-
|
|
135
|
-
Every job kind / entry point on the product surface (enums, API, UI) is, before
|
|
136
|
-
the change can be complete, exactly one of:
|
|
137
|
-
|
|
138
|
-
- **Wired end-to-end** (enqueueable + handled + domain side effects), or
|
|
139
|
-
- **Deleted** from the enums / API / UI surface.
|
|
140
|
-
|
|
141
|
-
“Fail closed for unsupported kind” is only a **temporary BLOCKED state**, never
|
|
142
|
-
“change complete.” Schema fiction (kinds nobody handles or enqueues) is a
|
|
143
|
-
verify failure.
|
|
144
|
-
|
|
145
|
-
## 7. Consumer–producer rule
|
|
146
|
-
|
|
147
|
-
If a UI page, API response, or downstream job **reads** a collection, artifact,
|
|
148
|
-
or field, verify must prove something in the **production path writes it**
|
|
149
|
-
(fixture evidence), or the change is BLOCKED. Empty-forever queues that only
|
|
150
|
-
tests can fill are a REJECT.
|
|
151
|
-
|
|
152
|
-
## 8. Deferrals are tracked debt, never checkboxes
|
|
153
|
-
|
|
154
|
-
“Wiring in a later task/section” is only acceptable when registered:
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
forge defer add --task <id> --reason "wiring lands in task <id>"
|
|
158
|
-
forge defer resolve --task <id> # when the wiring task actually lands
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
- Reviewers may only accept a deferral that names a **registered, still-open**
|
|
162
|
-
task (`forge defer list`).
|
|
163
|
-
- `forge phase done|finish` **refuses** while any deferral is unresolved.
|
|
164
|
-
- An unregistered "later" in a brief or review is a REJECT.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
1
|
+
# Runtime integrity (hard rules)
|
|
2
|
+
|
|
3
|
+
Forge verifies **outcomes of the system**, not only artifacts of work. These
|
|
4
|
+
rules apply at every pace. Coordinators, implementers, and reviewers must not
|
|
5
|
+
weaken them in briefs.
|
|
6
|
+
|
|
7
|
+
## 1. No stubs / no false success
|
|
8
|
+
|
|
9
|
+
A handler that only logs, bumps progress, or marks a job/request `succeeded`
|
|
10
|
+
without doing the domain work is **forbidden**.
|
|
11
|
+
|
|
12
|
+
- If a job kind (or API path) is enqueueable / callable in production, it MUST
|
|
13
|
+
run real domain logic, **or** fail closed with a clear error, **or** not be
|
|
14
|
+
exposed at all.
|
|
15
|
+
- Never authorize “stub OK”, “minimal poll loop only”, or “wire later” for a
|
|
16
|
+
path this change claims.
|
|
17
|
+
|
|
18
|
+
## 2. Runtime owner required
|
|
19
|
+
|
|
20
|
+
A capability requirement is **not** met by a library module alone.
|
|
21
|
+
|
|
22
|
+
- For every REQ / capability this change implements, name the **production
|
|
23
|
+
caller** (worker job kind, HTTP endpoint, CLI command, scheduled job, …).
|
|
24
|
+
- Library-only = incomplete. Add a wiring task before marking the section done.
|
|
25
|
+
|
|
26
|
+
## 3. Tests must fail on a no-op
|
|
27
|
+
|
|
28
|
+
Evidence that only asserts ceremony is invalid.
|
|
29
|
+
|
|
30
|
+
| Invalid | Valid |
|
|
31
|
+
| ------- | ----- |
|
|
32
|
+
| Job status became `succeeded` | Fixture upload/run left the expected domain side effects |
|
|
33
|
+
| Handler was called | Mongo/files/artifacts match the capability (or structured failure) |
|
|
34
|
+
| Queue claim/lease works | Pairing/stats/proposals/exports exist as specified |
|
|
35
|
+
|
|
36
|
+
If a test suite would still pass with a no-op handler, it does not prove the
|
|
37
|
+
task.
|
|
38
|
+
|
|
39
|
+
## 4. Briefs may not narrow scope
|
|
40
|
+
|
|
41
|
+
**Capability specs beat narrow task wording** when they conflict.
|
|
42
|
+
|
|
43
|
+
- Coordinator briefs MUST NOT redefine done downward (e.g. authorize a stub
|
|
44
|
+
when the spec requires real ETL).
|
|
45
|
+
- To shrink scope: stop and ask the user. Do not silently checkbox around gaps.
|
|
46
|
+
- Prefer `DONE_WITH_CONCERNS` / incomplete tasks over green checkboxes.
|
|
47
|
+
|
|
48
|
+
## 5. E2E means an executed product loop, not prose
|
|
49
|
+
|
|
50
|
+
Before claiming the change complete:
|
|
51
|
+
|
|
52
|
+
1. Author the **closed product loop** as executable steps in `e2e.json`
|
|
53
|
+
(`forge e2e init`), run it against the live entry points
|
|
54
|
+
(`forge e2e run`), and get a **green run** — **or**
|
|
55
|
+
2. Leave an explicit **`BLOCKED`** list in `verify-evidence.md` — and do **not**
|
|
56
|
+
mark the change complete / advance to `done`.
|
|
57
|
+
|
|
58
|
+
**A single job slice is not platform E2E.** When the design has a
|
|
59
|
+
producer/consumer split (analyze vs execute, proposals vs ratify, write vs
|
|
60
|
+
read), the required E2E is the full loop:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
produce artifact → consumer reads it → decision/state change →
|
|
64
|
+
next run's OUTPUT DIFFERS from the baseline
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Example: ingest→Parquet plus a thin run→`.sav` does **not** verify a
|
|
68
|
+
governance loop; analyze→proposals→ratify→run-applies-decisions does.
|
|
69
|
+
|
|
70
|
+
The mechanical gate requires a green, **current** `e2e-results.json` (its
|
|
71
|
+
steps hash must match `e2e.json`) whenever the spine has real rows.
|
|
72
|
+
Describing the loop in `verify-evidence.md` no longer satisfies the gate —
|
|
73
|
+
prose cannot prove wiring. Each step is `{ name, cmd, expect?, timeoutMs? }`:
|
|
74
|
+
exit code 0 required, `expect` (regex) matched against the output. Steps must
|
|
75
|
+
assert **domain side effects** — a step list that would pass against a
|
|
76
|
+
stubbed handler is invalid (rule 3 applies to e2e steps too).
|
|
77
|
+
|
|
78
|
+
`e2e.json` may set `"notApplicable": "<reason>"` only when the loop cannot be
|
|
79
|
+
driven by any command (e.g. requires a physical device). Reviewers police the
|
|
80
|
+
reason; "no time" or "covered by unit tests" is a REJECT. Keep a short loop
|
|
81
|
+
narrative under `## Product loop` in `verify-evidence.md` as reviewer context.
|
|
82
|
+
|
|
83
|
+
**Project-level off switch (operator only).** `forge e2e disable "<reason>"`
|
|
84
|
+
records `e2e.disabled` in `.forge/config.json` and the gate stops demanding
|
|
85
|
+
executed runs project-wide (`forge e2e enable` restores it). This is the
|
|
86
|
+
**human's** trade-off to make — an agent must NEVER run `forge e2e disable`,
|
|
87
|
+
suggest it to dodge a red gate, or edit the config key. If the gate blocks
|
|
88
|
+
you, fix the loop or ask the operator. When it is disabled, keep the
|
|
89
|
+
`## Product loop` narrative in `verify-evidence.md` — with no executed run,
|
|
90
|
+
prose is the only loop evidence the scorecard can grade.
|
|
91
|
+
|
|
92
|
+
### Keeping the loop cheap (cost policy)
|
|
93
|
+
|
|
94
|
+
"Too complex to test" is usually a signal to test it, not to wave it through —
|
|
95
|
+
a loop is complex exactly when the feature has many wiring seams, which is
|
|
96
|
+
when wiring silently breaks. Never skip the loop for complexity; control its
|
|
97
|
+
cost instead:
|
|
98
|
+
|
|
99
|
+
- **Ask before building complex harness infrastructure — and only then.**
|
|
100
|
+
The ask-line is infrastructure: a rig built from scratch, new
|
|
101
|
+
servers/containers/services, third-party accounts or sandboxes (e.g. real
|
|
102
|
+
payment checkout), device farms. That is a project, not a test — stop and
|
|
103
|
+
ask the user. **Everything below that line never needs permission**: if a
|
|
104
|
+
harness already exists (test server, isolated ports, scratch DB), author
|
|
105
|
+
the loop; writing fixtures, seed data, helper scripts, or extra steps
|
|
106
|
+
inside the existing rig is normal test work — just do it. Asking for
|
|
107
|
+
fixture-level work is over-asking; skipping the loop because the rig is
|
|
108
|
+
missing is under-testing — the ask is exactly the moment the operator can
|
|
109
|
+
say "build it once" and make every future loop on the project cheap.
|
|
110
|
+
- **A built harness is permanent project infrastructure — record it, reuse
|
|
111
|
+
it.** When the operator approves building one: build it as committed
|
|
112
|
+
project code (never session scratch), then record it:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
forge e2e harness --set "<what it is / where>" --start "<start command>" [--dir <path>]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This lands in `.forge/config.json` (committed), and every later session
|
|
119
|
+
sees it — `forge e2e init` and `forge e2e status` print the recorded
|
|
120
|
+
harness. Check `forge e2e harness` before proposing to build or asking the
|
|
121
|
+
operator; proposing a new rig while one is recorded is a REJECT.
|
|
122
|
+
- **One executed loop per capability, not per assertion.** Push edge cases
|
|
123
|
+
into unit tests; e2e proves the wiring exists.
|
|
124
|
+
- **Set `timeoutMs` from the step count up front.** A 10-step loop is never a
|
|
125
|
+
30s test — a too-small budget fails at whatever line the clock runs out on,
|
|
126
|
+
which reads as a phantom regression.
|
|
127
|
+
- **Run it once, at the end, serially** — never alongside unit suites; load
|
|
128
|
+
makes real assertions look flaky.
|
|
129
|
+
- **Prefer a production/preview build over the dev server** when the loop
|
|
130
|
+
drives a web app — compile-on-demand and dev-mode socket noise dominate the
|
|
131
|
+
per-run cost and bury the actual assertion.
|
|
132
|
+
|
|
133
|
+
## 6. Job-kind closure
|
|
134
|
+
|
|
135
|
+
Every job kind / entry point on the product surface (enums, API, UI) is, before
|
|
136
|
+
the change can be complete, exactly one of:
|
|
137
|
+
|
|
138
|
+
- **Wired end-to-end** (enqueueable + handled + domain side effects), or
|
|
139
|
+
- **Deleted** from the enums / API / UI surface.
|
|
140
|
+
|
|
141
|
+
“Fail closed for unsupported kind” is only a **temporary BLOCKED state**, never
|
|
142
|
+
“change complete.” Schema fiction (kinds nobody handles or enqueues) is a
|
|
143
|
+
verify failure.
|
|
144
|
+
|
|
145
|
+
## 7. Consumer–producer rule
|
|
146
|
+
|
|
147
|
+
If a UI page, API response, or downstream job **reads** a collection, artifact,
|
|
148
|
+
or field, verify must prove something in the **production path writes it**
|
|
149
|
+
(fixture evidence), or the change is BLOCKED. Empty-forever queues that only
|
|
150
|
+
tests can fill are a REJECT.
|
|
151
|
+
|
|
152
|
+
## 8. Deferrals are tracked debt, never checkboxes
|
|
153
|
+
|
|
154
|
+
“Wiring in a later task/section” is only acceptable when registered:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
forge defer add --task <id> --reason "wiring lands in task <id>"
|
|
158
|
+
forge defer resolve --task <id> # when the wiring task actually lands
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- Reviewers may only accept a deferral that names a **registered, still-open**
|
|
162
|
+
task (`forge defer list`).
|
|
163
|
+
- `forge phase done|finish` **refuses** while any deferral is unresolved.
|
|
164
|
+
- An unregistered "later" in a brief or review is a REJECT.
|
|
165
|
+
|
|
166
|
+
**Prose caveats don't survive — checkboxes and deferrals do.** Never tick a
|
|
167
|
+
`tasks.md` box while a note says the work is unproven ("gate was never taken",
|
|
168
|
+
"not yet verified", "should work"). Scorers, gates, and future sessions see
|
|
169
|
+
the `[x]`, not the sentence above it. If a task is incomplete in any way, the
|
|
170
|
+
box **stays open** or the gap becomes a `forge defer` entry — a ticked box
|
|
171
|
+
documenting its own incompleteness is worse than an open one.
|
|
172
|
+
|
|
173
|
+
## Spine matrix (mechanical — `forge spine`)
|
|
174
|
+
|
|
175
|
+
**Spine is mandatory for every Forge change** — not gated on pace, and not
|
|
176
|
+
inferred from slug keywords (that miss is how hollow platforms shipped).
|
|
177
|
+
|
|
178
|
+
At plan time (every change):
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
forge spine init
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Then either:
|
|
185
|
+
|
|
186
|
+
1. **Fill rows** — one per capability/REQ cluster:
|
|
187
|
+
|
|
188
|
+
| capability | library | runtimeOwner | writes | reads | uiConsumer | evidence |
|
|
189
|
+
|
|
190
|
+
Every cell filled (`reads` / `uiConsumer` may be `"N/A"`); `evidence` points
|
|
191
|
+
at the tier-2/E2E proof of the **wired** path. Library-only rows fail
|
|
192
|
+
`forge spine check` — and `forge phase done` runs the same check.
|
|
193
|
+
|
|
194
|
+
2. **Or** set `"notApplicable": "<reason>"` for sync-only / docs-only work
|
|
195
|
+
(e.g. `"sync HTTP only — no async producer/consumer"`). That is the honest
|
|
196
|
+
opt-out; missing `spine.json` is not.
|
|
197
|
+
|
|
198
|
+
An executed product loop (`forge e2e run`, green + current results) is
|
|
199
|
+
required when the spine has real rows. Prefer `notApplicable` for sync-only
|
|
200
|
+
changes instead of inventing a fake loop.
|
|
201
|
+
|
|
202
|
+
## Reviewer REJECT checklist (mandatory)
|
|
203
|
+
|
|
204
|
+
REJECT the task (or final review → `NOT READY`) if any of:
|
|
205
|
+
|
|
206
|
+
- Success path has no domain side effects required by the capability
|
|
207
|
+
- Tests would pass with a no-op handler
|
|
208
|
+
- API / UI can enqueue or trigger a kind the runtime cannot truly execute
|
|
209
|
+
- UI / consumers depend on data nothing in the production path writes
|
|
210
|
+
- Spec requirement has a library but no named runtime owner
|
|
211
|
+
- Deferred wiring without a registered open deferral (`forge defer list`)
|
|
212
|
+
- Spine row for this capability missing or library-only
|
|
213
|
+
- E2E steps would pass against a stubbed handler (no domain side-effect
|
|
214
|
+
assertions), or `e2e.json` opts out via `notApplicable` without a real reason
|
|
215
|
+
|
|
216
|
+
## Plan seam (every change)
|
|
217
|
+
|
|
218
|
+
Before apply-ready:
|
|
219
|
+
|
|
220
|
+
1. `forge spine init` — **always**. Fill rows for each capability, or set
|
|
221
|
+
`notApplicable` with a reason (sync-only / docs-only).
|
|
222
|
+
2. When the spine has real rows, `forge e2e init` — the acceptance **steps are
|
|
223
|
+
a plan deliverable**: author (or task out) the `e2e.json` step list that
|
|
224
|
+
drives the loop and asserts its side effects.
|
|
225
|
+
3. If the change involves workers, job queues, handlers, or cross-runtime
|
|
226
|
+
calls, `tasks.md` MUST also include:
|
|
227
|
+
- Explicit **wiring** tasks per job kind / entry point → domain pipeline
|
|
228
|
+
- One **product-loop acceptance** task (last implement task, before
|
|
229
|
+
verify) — its output is a green `forge e2e run`
|
|
230
|
+
|
|
231
|
+
Missing spine = plan not ready. Keyword guesses about “jobs in scope” are not
|
|
232
|
+
an excuse to skip the spine.
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
# Substantial work triage
|
|
2
|
-
|
|
3
|
-
Run this check **before** implementation on every agent turn unless the user
|
|
4
|
-
sent **`/forge:skip`**.
|
|
5
|
-
|
|
6
|
-
**Forge = OpenSpec.** If work is substantial enough for Forge, it is substantial enough for a
|
|
7
|
-
tracked OpenSpec change. Smaller work skips Forge entirely (direct execution).
|
|
8
|
-
|
|
9
|
-
## Enter Forge when ANY apply
|
|
10
|
-
|
|
11
|
-
- New feature or behavior change
|
|
12
|
-
- Bug fix that changes logic (not typo-only)
|
|
13
|
-
- Multi-file or multi-workspace edit
|
|
14
|
-
- Public API, Zod schema, OpenAPI, shared package export, or config schema change
|
|
15
|
-
- Cross-package / cross-product impact (grep consumers)
|
|
16
|
-
- User invokes `/forge` or any `/forge:*` command (except `/forge:skip`)
|
|
17
|
-
- Work would likely produce an ADR or new `openspec/specs/` capability
|
|
18
|
-
|
|
19
|
-
## Skip Forge (execute directly) when ALL apply
|
|
20
|
-
|
|
21
|
-
- Pure question, explanation, or read-only review
|
|
22
|
-
- Typo, comment, formatting-only, or rename with zero behavior change
|
|
23
|
-
- User explicitly sent **`/forge:skip`** for this task
|
|
24
|
-
|
|
25
|
-
## `/forge:skip` behaviour
|
|
26
|
-
|
|
27
|
-
1. If an active Forge session exists, run:
|
|
28
|
-
```bash
|
|
29
|
-
forge phase skipped
|
|
30
|
-
```
|
|
31
|
-
2. Do **not** start brainstorm or plan for this task.
|
|
32
|
-
3. Proceed with the user's request under normal project rules.
|
|
33
|
-
|
|
34
|
-
## Ambiguous cases
|
|
35
|
-
|
|
36
|
-
Ask one clarifying question: **would this produce an OpenSpec change?** If yes → Forge (OpenSpec).
|
|
37
|
-
If no → execute directly. Skip requires explicit user opt-out (`/forge:skip`).
|
|
1
|
+
# Substantial work triage
|
|
2
|
+
|
|
3
|
+
Run this check **before** implementation on every agent turn unless the user
|
|
4
|
+
sent **`/forge:skip`**.
|
|
5
|
+
|
|
6
|
+
**Forge = OpenSpec.** If work is substantial enough for Forge, it is substantial enough for a
|
|
7
|
+
tracked OpenSpec change. Smaller work skips Forge entirely (direct execution).
|
|
8
|
+
|
|
9
|
+
## Enter Forge when ANY apply
|
|
10
|
+
|
|
11
|
+
- New feature or behavior change
|
|
12
|
+
- Bug fix that changes logic (not typo-only)
|
|
13
|
+
- Multi-file or multi-workspace edit
|
|
14
|
+
- Public API, Zod schema, OpenAPI, shared package export, or config schema change
|
|
15
|
+
- Cross-package / cross-product impact (grep consumers)
|
|
16
|
+
- User invokes `/forge` or any `/forge:*` command (except `/forge:skip`)
|
|
17
|
+
- Work would likely produce an ADR or new `openspec/specs/` capability
|
|
18
|
+
|
|
19
|
+
## Skip Forge (execute directly) when ALL apply
|
|
20
|
+
|
|
21
|
+
- Pure question, explanation, or read-only review
|
|
22
|
+
- Typo, comment, formatting-only, or rename with zero behavior change
|
|
23
|
+
- User explicitly sent **`/forge:skip`** for this task
|
|
24
|
+
|
|
25
|
+
## `/forge:skip` behaviour
|
|
26
|
+
|
|
27
|
+
1. If an active Forge session exists, run:
|
|
28
|
+
```bash
|
|
29
|
+
forge phase skipped
|
|
30
|
+
```
|
|
31
|
+
2. Do **not** start brainstorm or plan for this task.
|
|
32
|
+
3. Proceed with the user's request under normal project rules.
|
|
33
|
+
|
|
34
|
+
## Ambiguous cases
|
|
35
|
+
|
|
36
|
+
Ask one clarifying question: **would this produce an OpenSpec change?** If yes → Forge (OpenSpec).
|
|
37
|
+
If no → execute directly. Skip requires explicit user opt-out (`/forge:skip`).
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
# Per-task test evidence (tier 2)
|
|
2
|
-
|
|
3
|
-
Each implement task records **tier 2** proof that subagents ran tests. See [test-strategy.md](./test-strategy.md) for all three tiers.
|
|
4
|
-
|
|
5
|
-
The **coordinator** records this file after the implementer reports — use `forge evidence --task <nn>-<slug> --command "<cmd>" --exit <code> --summary "<text>"` (machine timestamp; refuses non-zero exit without `--allow-fail`) rather than hand-writing it. Verify **audits** these files — it does **not** re-run the same tier 2 commands. Verify runs **tier 3** (full workspace) once separately; see [../phases/verify.md](../phases/verify.md).
|
|
6
|
-
|
|
7
|
-
## Path
|
|
8
|
-
|
|
9
|
-
`.forge/sessions/<session-id>/tasks/<nn>-<slug>/test-evidence.md`
|
|
10
|
-
|
|
11
|
-
## Template
|
|
12
|
-
|
|
13
|
-
```markdown
|
|
14
|
-
# Test evidence — Task {nn}-{slug}
|
|
15
|
-
|
|
16
|
-
- **Tier:** 2 (task-scoped — not full workspace unless noted)
|
|
17
|
-
- **Command:** `npm test -- path/to/scoped.test.ts -- src/foo.test.ts`
|
|
18
|
-
- **Exit code:** 0
|
|
19
|
-
- **Summary:** 3/3 pass (or paste last ~20 lines of output)
|
|
20
|
-
- **Run at:** 2026-06-05T15:04:22Z
|
|
21
|
-
- **Recorded by:** implementer subagent (coordinator transcript)
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Rules
|
|
25
|
-
|
|
26
|
-
- **Exit code must be `0`** before the task is marked complete.
|
|
27
|
-
- **Default:** narrowest command — changed test file(s) + directly related tests. **Not** the full workspace suite.
|
|
28
|
-
- **Full workspace at tier 2** only when the task changes shared contracts, cross-module integration, or the brief explicitly requires it. Note `Tier: 2 (full workspace — contract/integration)` in the file.
|
|
29
|
-
- If the implementer re-ran tests after a fix, overwrite with the latest successful tier 2 run.
|
|
30
|
-
- Verify **audits** tier 2 files and runs **tier 3** (full workspace) once — see [test-strategy.md](./test-strategy.md).
|
|
1
|
+
# Per-task test evidence (tier 2)
|
|
2
|
+
|
|
3
|
+
Each implement task records **tier 2** proof that subagents ran tests. See [test-strategy.md](./test-strategy.md) for all three tiers.
|
|
4
|
+
|
|
5
|
+
The **coordinator** records this file after the implementer reports — use `forge evidence --task <nn>-<slug> --command "<cmd>" --exit <code> --summary "<text>"` (machine timestamp; refuses non-zero exit without `--allow-fail`) rather than hand-writing it. Verify **audits** these files — it does **not** re-run the same tier 2 commands. Verify runs **tier 3** (full workspace) once separately; see [../phases/verify.md](../phases/verify.md).
|
|
6
|
+
|
|
7
|
+
## Path
|
|
8
|
+
|
|
9
|
+
`.forge/sessions/<session-id>/tasks/<nn>-<slug>/test-evidence.md`
|
|
10
|
+
|
|
11
|
+
## Template
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
# Test evidence — Task {nn}-{slug}
|
|
15
|
+
|
|
16
|
+
- **Tier:** 2 (task-scoped — not full workspace unless noted)
|
|
17
|
+
- **Command:** `npm test -- path/to/scoped.test.ts -- src/foo.test.ts`
|
|
18
|
+
- **Exit code:** 0
|
|
19
|
+
- **Summary:** 3/3 pass (or paste last ~20 lines of output)
|
|
20
|
+
- **Run at:** 2026-06-05T15:04:22Z
|
|
21
|
+
- **Recorded by:** implementer subagent (coordinator transcript)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Rules
|
|
25
|
+
|
|
26
|
+
- **Exit code must be `0`** before the task is marked complete.
|
|
27
|
+
- **Default:** narrowest command — changed test file(s) + directly related tests. **Not** the full workspace suite.
|
|
28
|
+
- **Full workspace at tier 2** only when the task changes shared contracts, cross-module integration, or the brief explicitly requires it. Note `Tier: 2 (full workspace — contract/integration)` in the file.
|
|
29
|
+
- If the implementer re-ran tests after a fix, overwrite with the latest successful tier 2 run.
|
|
30
|
+
- Verify **audits** tier 2 files and runs **tier 3** (full workspace) once — see [test-strategy.md](./test-strategy.md).
|