@entelligentsia/forgecli 1.0.21 → 1.0.25
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/CHANGELOG.md +88 -0
- package/dist/CHANGELOG-forge-plugin.md +118 -0
- package/dist/extensions/forgecli/forge-tools.d.ts +1 -0
- package/dist/extensions/forgecli/forge-tools.js +73 -0
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/lib/forge-root.d.ts +5 -0
- package/dist/extensions/forgecli/lib/forge-root.js +14 -1
- package/dist/extensions/forgecli/lib/forge-root.js.map +1 -1
- package/dist/extensions/forgecli/orchestrators/fix-bug.d.ts +1 -0
- package/dist/extensions/forgecli/orchestrators/fix-bug.js +26 -0
- package/dist/extensions/forgecli/orchestrators/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/orchestrators/run-sprint.js +49 -0
- package/dist/extensions/forgecli/orchestrators/run-sprint.js.map +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +4 -0
- package/dist/forge-payload/.base-pack/workflows/_fragments/event-vocabulary.md +88 -0
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +41 -38
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +3 -3
- package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +42 -6
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +32 -1
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/.schemas/event.schema.json +8 -3
- package/dist/forge-payload/.schemas/migrations.json +56 -0
- package/dist/forge-payload/integrity.json +3 -3
- package/dist/forge-payload/meta/store-schema/event.schema.md +7 -0
- package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +4 -0
- package/dist/forge-payload/meta/workflows/_fragments/event-vocabulary.md +88 -0
- package/dist/forge-payload/meta/workflows/meta-commit.md +46 -43
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +7 -2
- package/dist/forge-payload/meta/workflows/meta-implement.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +4 -1
- package/dist/forge-payload/schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/schemas/event.schema.json +8 -3
- package/dist/forge-payload/schemas/structure-manifest.json +4 -2
- package/dist/forge-payload/tools/commit-task.cjs +218 -0
- package/dist/forge-payload/tools/store-cli.cjs +6 -1
- package/node_modules/@mariozechner/clipboard/package.json +2 -1
- package/node_modules/@mariozechner/clipboard-linux-x64-musl/README.md +3 -0
- package/node_modules/@mariozechner/clipboard-linux-x64-musl/package.json +25 -0
- package/package.json +2 -2
- package/dist/extensions/forgecli/add-pipeline.d.ts +0 -19
- package/dist/extensions/forgecli/add-pipeline.js +0 -143
- package/dist/extensions/forgecli/add-pipeline.js.map +0 -1
- package/dist/extensions/forgecli/add-task.d.ts +0 -20
- package/dist/extensions/forgecli/add-task.js +0 -154
- package/dist/extensions/forgecli/add-task.js.map +0 -1
- package/dist/extensions/forgecli/approve.d.ts +0 -22
- package/dist/extensions/forgecli/approve.js +0 -152
- package/dist/extensions/forgecli/approve.js.map +0 -1
- package/dist/extensions/forgecli/banner.d.ts +0 -10
- package/dist/extensions/forgecli/banner.js +0 -36
- package/dist/extensions/forgecli/banner.js.map +0 -1
- package/dist/extensions/forgecli/calibrate.d.ts +0 -64
- package/dist/extensions/forgecli/calibrate.js +0 -481
- package/dist/extensions/forgecli/calibrate.js.map +0 -1
- package/dist/extensions/forgecli/collate.d.ts +0 -22
- package/dist/extensions/forgecli/collate.js +0 -134
- package/dist/extensions/forgecli/collate.js.map +0 -1
- package/dist/extensions/forgecli/commit.d.ts +0 -22
- package/dist/extensions/forgecli/commit.js +0 -152
- package/dist/extensions/forgecli/commit.js.map +0 -1
- package/dist/extensions/forgecli/config-command.d.ts +0 -8
- package/dist/extensions/forgecli/config-command.js +0 -67
- package/dist/extensions/forgecli/config-command.js.map +0 -1
- package/dist/extensions/forgecli/config-layer.d.ts +0 -53
- package/dist/extensions/forgecli/config-layer.js +0 -72
- package/dist/extensions/forgecli/config-layer.js.map +0 -1
- package/dist/extensions/forgecli/config-writer.d.ts +0 -16
- package/dist/extensions/forgecli/config-writer.js +0 -69
- package/dist/extensions/forgecli/config-writer.js.map +0 -1
- package/dist/extensions/forgecli/enhance.d.ts +0 -27
- package/dist/extensions/forgecli/enhance.js +0 -199
- package/dist/extensions/forgecli/enhance.js.map +0 -1
- package/dist/extensions/forgecli/fix-bug.d.ts +0 -85
- package/dist/extensions/forgecli/fix-bug.js +0 -1580
- package/dist/extensions/forgecli/fix-bug.js.map +0 -1
- package/dist/extensions/forgecli/forge-header.d.ts +0 -12
- package/dist/extensions/forgecli/forge-header.js +0 -114
- package/dist/extensions/forgecli/forge-header.js.map +0 -1
- package/dist/extensions/forgecli/forge-init.d.ts +0 -26
- package/dist/extensions/forgecli/forge-init.js +0 -514
- package/dist/extensions/forgecli/forge-init.js.map +0 -1
- package/dist/extensions/forgecli/forge-root.d.ts +0 -10
- package/dist/extensions/forgecli/forge-root.js +0 -62
- package/dist/extensions/forgecli/forge-root.js.map +0 -1
- package/dist/extensions/forgecli/forge-update-command.d.ts +0 -100
- package/dist/extensions/forgecli/forge-update-command.js +0 -435
- package/dist/extensions/forgecli/forge-update-command.js.map +0 -1
- package/dist/extensions/forgecli/friction-emit.d.ts +0 -99
- package/dist/extensions/forgecli/friction-emit.js +0 -245
- package/dist/extensions/forgecli/friction-emit.js.map +0 -1
- package/dist/extensions/forgecli/implement.d.ts +0 -22
- package/dist/extensions/forgecli/implement.js +0 -170
- package/dist/extensions/forgecli/implement.js.map +0 -1
- package/dist/extensions/forgecli/init-context.d.ts +0 -99
- package/dist/extensions/forgecli/init-context.js +0 -178
- package/dist/extensions/forgecli/init-context.js.map +0 -1
- package/dist/extensions/forgecli/init-progress.d.ts +0 -39
- package/dist/extensions/forgecli/init-progress.js +0 -117
- package/dist/extensions/forgecli/init-progress.js.map +0 -1
- package/dist/extensions/forgecli/input-router.d.ts +0 -33
- package/dist/extensions/forgecli/input-router.js +0 -136
- package/dist/extensions/forgecli/input-router.js.map +0 -1
- package/dist/extensions/forgecli/lib/halt-advisor.d.ts +0 -59
- package/dist/extensions/forgecli/lib/halt-advisor.js +0 -113
- package/dist/extensions/forgecli/lib/halt-advisor.js.map +0 -1
- package/dist/extensions/forgecli/lib/orchestrator-preflight.d.ts +0 -46
- package/dist/extensions/forgecli/lib/orchestrator-preflight.js +0 -64
- package/dist/extensions/forgecli/lib/orchestrator-preflight.js.map +0 -1
- package/dist/extensions/forgecli/materialize.d.ts +0 -16
- package/dist/extensions/forgecli/materialize.js +0 -195
- package/dist/extensions/forgecli/materialize.js.map +0 -1
- package/dist/extensions/forgecli/migrate.d.ts +0 -22
- package/dist/extensions/forgecli/migrate.js +0 -260
- package/dist/extensions/forgecli/migrate.js.map +0 -1
- package/dist/extensions/forgecli/migration-engine.d.ts +0 -117
- package/dist/extensions/forgecli/migration-engine.js +0 -563
- package/dist/extensions/forgecli/migration-engine.js.map +0 -1
- package/dist/extensions/forgecli/model-registry.d.ts +0 -61
- package/dist/extensions/forgecli/model-registry.js +0 -127
- package/dist/extensions/forgecli/model-registry.js.map +0 -1
- package/dist/extensions/forgecli/model-resolver.d.ts +0 -32
- package/dist/extensions/forgecli/model-resolver.js +0 -65
- package/dist/extensions/forgecli/model-resolver.js.map +0 -1
- package/dist/extensions/forgecli/model-validator.d.ts +0 -29
- package/dist/extensions/forgecli/model-validator.js +0 -107
- package/dist/extensions/forgecli/model-validator.js.map +0 -1
- package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +0 -26
- package/dist/extensions/forgecli/orchestrator-status-bar.js +0 -213
- package/dist/extensions/forgecli/orchestrator-status-bar.js.map +0 -1
- package/dist/extensions/forgecli/plan.d.ts +0 -22
- package/dist/extensions/forgecli/plan.js +0 -167
- package/dist/extensions/forgecli/plan.js.map +0 -1
- package/dist/extensions/forgecli/quiz-agent.d.ts +0 -17
- package/dist/extensions/forgecli/quiz-agent.js +0 -98
- package/dist/extensions/forgecli/quiz-agent.js.map +0 -1
- package/dist/extensions/forgecli/read-command.d.ts +0 -2
- package/dist/extensions/forgecli/read-command.js +0 -100
- package/dist/extensions/forgecli/read-command.js.map +0 -1
- package/dist/extensions/forgecli/regenerate.d.ts +0 -40
- package/dist/extensions/forgecli/regenerate.js +0 -438
- package/dist/extensions/forgecli/regenerate.js.map +0 -1
- package/dist/extensions/forgecli/remove-command.d.ts +0 -17
- package/dist/extensions/forgecli/remove-command.js +0 -124
- package/dist/extensions/forgecli/remove-command.js.map +0 -1
- package/dist/extensions/forgecli/report-bug.d.ts +0 -25
- package/dist/extensions/forgecli/report-bug.js +0 -159
- package/dist/extensions/forgecli/report-bug.js.map +0 -1
- package/dist/extensions/forgecli/retrospective.d.ts +0 -20
- package/dist/extensions/forgecli/retrospective.js +0 -126
- package/dist/extensions/forgecli/retrospective.js.map +0 -1
- package/dist/extensions/forgecli/review-code.d.ts +0 -35
- package/dist/extensions/forgecli/review-code.js +0 -196
- package/dist/extensions/forgecli/review-code.js.map +0 -1
- package/dist/extensions/forgecli/review-plan.d.ts +0 -35
- package/dist/extensions/forgecli/review-plan.js +0 -200
- package/dist/extensions/forgecli/review-plan.js.map +0 -1
- package/dist/extensions/forgecli/run-sprint.d.ts +0 -27
- package/dist/extensions/forgecli/run-sprint.js +0 -716
- package/dist/extensions/forgecli/run-sprint.js.map +0 -1
- package/dist/extensions/forgecli/run-task.d.ts +0 -204
- package/dist/extensions/forgecli/run-task.js +0 -1403
- package/dist/extensions/forgecli/run-task.js.map +0 -1
- package/dist/extensions/forgecli/skill-curation-flag.d.ts +0 -21
- package/dist/extensions/forgecli/skill-curation-flag.js +0 -71
- package/dist/extensions/forgecli/skill-curation-flag.js.map +0 -1
- package/dist/extensions/forgecli/skill-curator-subagent.d.ts +0 -102
- package/dist/extensions/forgecli/skill-curator-subagent.js +0 -339
- package/dist/extensions/forgecli/skill-curator-subagent.js.map +0 -1
- package/dist/extensions/forgecli/skill-retriever.d.ts +0 -84
- package/dist/extensions/forgecli/skill-retriever.js +0 -246
- package/dist/extensions/forgecli/skill-retriever.js.map +0 -1
- package/dist/extensions/forgecli/skill-usage-tracker.d.ts +0 -91
- package/dist/extensions/forgecli/skill-usage-tracker.js +0 -224
- package/dist/extensions/forgecli/skill-usage-tracker.js.map +0 -1
- package/dist/extensions/forgecli/sprint-intake.d.ts +0 -10
- package/dist/extensions/forgecli/sprint-intake.js +0 -91
- package/dist/extensions/forgecli/sprint-intake.js.map +0 -1
- package/dist/extensions/forgecli/sprint-plan.d.ts +0 -14
- package/dist/extensions/forgecli/sprint-plan.js +0 -122
- package/dist/extensions/forgecli/sprint-plan.js.map +0 -1
- package/dist/extensions/forgecli/status-command.d.ts +0 -19
- package/dist/extensions/forgecli/status-command.js +0 -140
- package/dist/extensions/forgecli/status-command.js.map +0 -1
- package/dist/extensions/forgecli/store-error-remediation.d.ts +0 -65
- package/dist/extensions/forgecli/store-error-remediation.js +0 -307
- package/dist/extensions/forgecli/store-error-remediation.js.map +0 -1
- package/dist/extensions/forgecli/store-query.d.ts +0 -22
- package/dist/extensions/forgecli/store-query.js +0 -107
- package/dist/extensions/forgecli/store-query.js.map +0 -1
- package/dist/extensions/forgecli/store-repair.d.ts +0 -17
- package/dist/extensions/forgecli/store-repair.js +0 -123
- package/dist/extensions/forgecli/store-repair.js.map +0 -1
- package/dist/extensions/forgecli/store-resolver.d.ts +0 -56
- package/dist/extensions/forgecli/store-resolver.js +0 -263
- package/dist/extensions/forgecli/store-resolver.js.map +0 -1
- package/dist/extensions/forgecli/store-validator.d.ts +0 -16
- package/dist/extensions/forgecli/store-validator.js +0 -32
- package/dist/extensions/forgecli/store-validator.js.map +0 -1
- package/dist/extensions/forgecli/test-orchestrate.d.ts +0 -2
- package/dist/extensions/forgecli/test-orchestrate.js +0 -182
- package/dist/extensions/forgecli/test-orchestrate.js.map +0 -1
- package/dist/extensions/forgecli/thread-switcher.d.ts +0 -5
- package/dist/extensions/forgecli/thread-switcher.js +0 -189
- package/dist/extensions/forgecli/thread-switcher.js.map +0 -1
- package/dist/extensions/forgecli/transition-guard.d.ts +0 -20
- package/dist/extensions/forgecli/transition-guard.js +0 -89
- package/dist/extensions/forgecli/transition-guard.js.map +0 -1
- package/dist/extensions/forgecli/update-check.d.ts +0 -37
- package/dist/extensions/forgecli/update-check.js +0 -185
- package/dist/extensions/forgecli/update-check.js.map +0 -1
- package/dist/extensions/forgecli/update-tools.d.ts +0 -23
- package/dist/extensions/forgecli/update-tools.js +0 -135
- package/dist/extensions/forgecli/update-tools.js.map +0 -1
- package/dist/extensions/forgecli/validate.d.ts +0 -22
- package/dist/extensions/forgecli/validate.js +0 -152
- package/dist/extensions/forgecli/validate.js.map +0 -1
- package/dist/extensions/forgecli/viewport-events.d.ts +0 -78
- package/dist/extensions/forgecli/viewport-events.js +0 -243
- package/dist/extensions/forgecli/viewport-events.js.map +0 -1
- package/dist/extensions/forgecli/viewport-renderer.d.ts +0 -83
- package/dist/extensions/forgecli/viewport-renderer.js +0 -233
- package/dist/extensions/forgecli/viewport-renderer.js.map +0 -1
- package/dist/extensions/forgecli/viewport-theme.d.ts +0 -11
- package/dist/extensions/forgecli/viewport-theme.js +0 -128
- package/dist/extensions/forgecli/viewport-theme.js.map +0 -1
- package/dist/extensions/forgecli/whats-new-widget.d.ts +0 -26
- package/dist/extensions/forgecli/whats-new-widget.js +0 -376
- package/dist/extensions/forgecli/whats-new-widget.js.map +0 -1
- package/dist/extensions/forgecli/whats-new.d.ts +0 -120
- package/dist/extensions/forgecli/whats-new.js +0 -470
- package/dist/extensions/forgecli/whats-new.js.map +0 -1
|
@@ -27,6 +27,8 @@ deps:
|
|
|
27
27
|
- Commit only the artifacts produced for this task; do not sweep unrelated working-tree changes into the commit. The commit boundary mirrors the task boundary.
|
|
28
28
|
- Read `.forge/personas/engineer.md` first; print the persona identity line (emoji, name, tagline) to stdout before any other tool use.
|
|
29
29
|
- All store I/O via `forge_store` (or `node .forge/tools/store-cli.cjs`). Never edit `.forge/store/*.json` directly.
|
|
30
|
+
- **Never run `git add`/`git commit`/`git reset` yourself** — `commit-task.cjs` owns staging, boundary checks, committing, and the terminal transition (#40). Your judgement input is the message.
|
|
31
|
+
- **Commit writes NO summary** (`commit` ∉ `VALID_SUMMARY_PHASES` — any `set-summary` is rejected); the tool's terminal `update-status` is this phase's only store write.
|
|
30
32
|
|
|
31
33
|
## Store-Write Verification
|
|
32
34
|
|
|
@@ -36,48 +38,49 @@ deps:
|
|
|
36
38
|
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
- Run: `node .forge/tools/preflight-gate.cjs --phase commit --{entity_kind} {record_id}`
|
|
42
|
-
- Exit 1 (gate failed) → print stderr and HALT. Do not proceed; do not attempt to produce the artifact.
|
|
43
|
-
- Exit 2 (misconfiguration) → print stderr and HALT.
|
|
44
|
-
- Exit 0 → continue.
|
|
41
|
+
0. Entity-mode resolution:
|
|
42
|
+
- Read the kickoff arguments. `--task {id}` → `entity_kind = "task"`, `record_id = {id}`. `--bug {id}` → `entity_kind = "bug"`, `record_id = {id}`.
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
`node .forge/tools/store-cli.cjs read task {record_id} --json`
|
|
51
|
-
- Extract the `status` field from the JSON output.
|
|
52
|
-
- Allowed states for this phase: `approved`.
|
|
53
|
-
- If the current status is NOT in the allowed set:
|
|
54
|
-
Print the following and HALT (do not proceed):
|
|
55
|
-
`× Task {record_id} is in state '{status}' — /forge:approve must complete first. To run the full pipeline: /forge:run-task {record_id}`
|
|
44
|
+
1. Inspect ONCE (message material only — #40 batched-inspection rule):
|
|
45
|
+
- One `git diff --stat`; at most ONE combined `git diff` if the message needs detail.
|
|
46
|
+
Never per-file diffs, never repeated `git status` — each extra turn re-pays full context.
|
|
47
|
+
- Staging is NOT your decision — the tool derives it from the store record.
|
|
56
48
|
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
`
|
|
49
|
+
2. Craft the commit message:
|
|
50
|
+
- Follow project conventions; include the record ID ({taskId} / {bugId}) in the subject.
|
|
51
|
+
- `Co-authored-by:` trailer from the host runtime: Claude Code →
|
|
52
|
+
`Co-authored-by: Claude <noreply@anthropic.com>`; pi / Ollama / other →
|
|
53
|
+
`Co-authored-by: {modelId} <noreply@{provider}.ai>` from the session's `provider` and
|
|
54
|
+
`modelId`; if unresolvable, omit rather than guess. Never hardcode
|
|
55
|
+
`Claude Opus 4.6 <noreply@anthropic.com>` (forge#82 regression).
|
|
56
|
+
- Git's configured `user.name`/`user.email` own authorship; never `--author`.
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
58
|
+
3. Commit via the tool — ONE call:
|
|
59
|
+
- If the `forge_commit` named tool is available (forgecli): call it —
|
|
60
|
+
`forge_commit({ entity:"{entity_kind}", id:"{record_id}", message:"<message>", trailer:"<line>" })`.
|
|
61
|
+
Never pass the message through a bash string when the typed tool exists.
|
|
62
|
+
- Otherwise (Claude Code): `node .forge/tools/commit-task.cjs --{entity_kind} {record_id} --message "<message>" [--trailer "<Co-authored-by line>"]`
|
|
63
|
+
- The tool owns the choreography: preflight gate (`preflight-gate.cjs --phase commit`
|
|
64
|
+
internally), status precondition (task `approved` / bug `in-progress` — wrong-state runs
|
|
65
|
+
halt with `× {record_id} is in state '{status}' …; /forge:approve must complete first`),
|
|
66
|
+
staging (artifact dir + `summaries.implementation.files_changed` provenance),
|
|
67
|
+
commit-boundary guard (aborts on a pre-staged index), `git commit`, terminal transition
|
|
68
|
+
(task → `committed`; bug → `fixed`, the ONLY post-triage `bug.status` write).
|
|
69
|
+
- On `no files_changed provenance` warning: ONE `git status --porcelain`, then re-run the
|
|
70
|
+
tool with `--also <path>` per source file. Never manual `git add`.
|
|
71
|
+
- Success → JSON with `ok:true`. `committed:true` carries `sha` + `staged`;
|
|
72
|
+
`committed:false, reason:"nothing-to-commit"` is ALSO success (fix already at HEAD /
|
|
73
|
+
staging set clean — the tool still sealed the record's terminal status). Do not
|
|
74
|
+
"fix" a no-op by staging things yourself.
|
|
75
|
+
- Failure (exit 1 / ok:false) → print stderr and HALT — no manual staging, no
|
|
76
|
+
`git reset`, no `--force` retry (operator-gated). Tool file missing → HALT;
|
|
77
|
+
instruct `/forge:update` + `/forge:rebuild tools`.
|
|
78
|
+
- NEVER commit before the tool reports `ok: true` — the premature-commit/reset/redo loop
|
|
79
|
+
is forbidden.
|
|
67
80
|
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
- Append a `Co-authored-by:` trailer crediting the AI assistant that actually ran the session. Resolve the identity from the host runtime: on Claude Code use `Co-authored-by: Claude <noreply@anthropic.com>`; on pi / Ollama / any other runtime use `Co-authored-by: {modelId} <noreply@{provider}.ai>` derived from the session's `provider` and `modelId` (e.g. `Co-authored-by: glm-5.1:cloud <noreply@ollama.ai>`); if neither is resolvable, omit the trailer rather than guess. Do NOT hardcode `Claude Opus 4.6 <noreply@anthropic.com>` — that literal is rejected as a regression of forge#82 (commits authored under the wrong model).
|
|
72
|
-
- Let git's configured `user.name` / `user.email` own the commit author; never pass `--author` to override it.
|
|
73
|
-
|
|
74
|
-
4. Store Finalization:
|
|
75
|
-
- Transitions:
|
|
76
|
-
- **Task mode** — `approved → committed` (terminal): `node .forge/tools/store-cli.cjs update-status task {taskId} status committed`
|
|
77
|
-
- **Bug mode** — `in-progress → fixed` (terminal): `node .forge/tools/store-cli.cjs update-status bug {bugId} status fixed`. This is the ONLY phase in the bug pipeline that writes `bug.status` post-triage (see `meta-fix-bug.md § Iron Laws #2`). Do NOT write `approved` or `verified` — those values are vestigial enum members slated for removal.
|
|
78
|
-
|
|
79
|
-
5. Finalize:
|
|
80
|
-
- **Do NOT emit a phase event yourself.** The orchestrator owns event emission — it composes the canonical event from runtime telemetry (model, provider, tokens, wall times) plus the SUMMARY you write in the next step. Subagents that call `store-cli emit` for phase events hallucinate runtime facts (see Plan 11 / Slice 2). Write the SUMMARY and return.
|
|
81
|
+
4. Finalize:
|
|
82
|
+
- No summary, no `set-summary` (see Iron Laws). **Do NOT emit a phase event yourself** —
|
|
83
|
+
the orchestrator owns event emission. Return the tool's JSON result as your phase output.
|
|
81
84
|
```
|
|
82
85
|
|
|
83
86
|
<!-- See _fragments/generation-instructions.md for Generation Instructions template -->
|
|
@@ -83,13 +83,13 @@ deps:
|
|
|
83
83
|
`node .forge/tools/store-cli.cjs update-status task {taskId} status implementing`
|
|
84
84
|
`node .forge/tools/store-cli.cjs update-status task {taskId} status implemented`
|
|
85
85
|
- **Bug mode** — NO status write. The bug remains `in-progress` until the commit phase transitions it to `fixed`. Writing `bug.status` here violates `meta-fix-bug.md § Iron Laws #2`.
|
|
86
|
-
- **Do NOT emit a phase event yourself.** The orchestrator owns event emission — it composes the canonical event from runtime telemetry
|
|
86
|
+
- **Do NOT emit a phase event yourself.** The orchestrator owns event emission — it composes the canonical event from runtime telemetry plus the SUMMARY you write next. Subagents that call `store-cli emit` for phase events hallucinate runtime facts (Plan 11 / Slice 2). Write the SUMMARY and return.
|
|
87
87
|
|
|
88
88
|
7. Emit Summary Sidecar:
|
|
89
89
|
- Write `IMPLEMENTATION-SUMMARY.json` via `forge_artifact`:
|
|
90
90
|
`forge_artifact({ command:"write", entity:"{entity_kind}", entityId:"{record_id}", artifact:"implementation-summary", content:"<JSON>" })`
|
|
91
|
-
JSON shape: `{"objective":"<one sentence>", "key_changes":["<up to 12 bullets>"], "verdict":"n/a", "written_at":"<ISO 8601>", "artifact_ref":"PROGRESS.md"}`
|
|
92
|
-
|
|
91
|
+
JSON shape: `{"objective":"<one sentence>", "key_changes":["<up to 12 bullets>"], "files_changed":["<path>"], "verdict":"n/a", "written_at":"<ISO 8601>", "artifact_ref":"PROGRESS.md"}`
|
|
92
|
+
- `files_changed`: every repo path this phase changed (one `git status --porcelain`); `commit-task.cjs` stages from it.
|
|
93
93
|
- Then link sidecar to store (task mode):
|
|
94
94
|
`forge_store({ command:"set-summary", args:["{taskId}", "implementation"] })`
|
|
95
95
|
Or (bug mode):
|
|
@@ -66,6 +66,22 @@ const SKIP_STATUS = ['blocked', 'escalated', 'fixed', 'abandoned']
|
|
|
66
66
|
// non-review phase (the approve workflow self-escalates if it rejects).
|
|
67
67
|
const REVIEW_ROLES = ['review-plan', 'review-code']
|
|
68
68
|
|
|
69
|
+
// Bug-phase `type` tokens — verbatim port of the canonical table in
|
|
70
|
+
// .forge/workflows/_fragments/event-vocabulary.md § Bug pipeline
|
|
71
|
+
// (forge-engineering#39). The COMPLETE event carries the pass token (or the
|
|
72
|
+
// fail token when a review phase's verdict is "revision"); the START event is
|
|
73
|
+
// always untyped. Keyed by phase ROLE (matches PHASES_A/PHASES_B role names;
|
|
74
|
+
// triage is keyed separately since it runs outside the phase loop).
|
|
75
|
+
const BUG_TYPE_TOKENS = {
|
|
76
|
+
'triage': { pass: 'bug-triaged', fail: 'bug-triaged' },
|
|
77
|
+
'plan': { pass: 'fix-planned', fail: 'fix-planned' },
|
|
78
|
+
'review-plan': { pass: 'fix-review-passed', fail: 'fix-review-failed' },
|
|
79
|
+
'implement': { pass: 'fix-implemented', fail: 'fix-implemented' },
|
|
80
|
+
'review-code': { pass: 'fix-code-review-passed', fail: 'fix-code-review-failed' },
|
|
81
|
+
'approve': { pass: 'fix-approved', fail: 'fix-revision-requested' },
|
|
82
|
+
'commit': { pass: 'bug-committed', fail: 'bug-commit-failed' },
|
|
83
|
+
}
|
|
84
|
+
|
|
69
85
|
// Per-phase model tier — verbatim port of fix_bug.md § Role-to-Tier Mapping.
|
|
70
86
|
// Passed as the `model` opt to agent(); the host resolves the tier name to a model.
|
|
71
87
|
const ROLE_TIER = {
|
|
@@ -160,6 +176,16 @@ function revisionTarget(phases, reviewIdx) {
|
|
|
160
176
|
// The subagent owns ALL shell-dependent side-effects for this phase.
|
|
161
177
|
function runBugPhase(bugId, phase, iter) {
|
|
162
178
|
const sprintId = 'bugs' // virtual sprint dir for all emit/sidecar/progress
|
|
179
|
+
// forge-engineering#39: explicit type-token guidance per
|
|
180
|
+
// .forge/workflows/_fragments/event-vocabulary.md § Bug pipeline. Without
|
|
181
|
+
// it, subagents guessed and leaked the action value into `type`
|
|
182
|
+
// ("start"/"complete" — schema-rejected store residue in events/bugs/).
|
|
183
|
+
const typeTokens = BUG_TYPE_TOKENS[phase.role]
|
|
184
|
+
const typeTokenLine = typeTokens
|
|
185
|
+
? (REVIEW_ROLES.includes(phase.role)
|
|
186
|
+
? 'set type="' + typeTokens.pass + '" when your verdict is Approved, type="' + typeTokens.fail + '" when it is Revision Required.'
|
|
187
|
+
: 'set type="' + typeTokens.pass + '".')
|
|
188
|
+
: 'omit the "type" field entirely (untyped events are valid; this role has no table entry).'
|
|
163
189
|
return agent(
|
|
164
190
|
[
|
|
165
191
|
`You are running a SINGLE pipeline phase for Forge bug ${bugId} (sprint bugs).`,
|
|
@@ -175,11 +201,14 @@ function runBugPhase(bugId, phase, iter) {
|
|
|
175
201
|
' 3a. BEFORE running the phase workflow: note the start timestamp (startTimestamp = new Date().toISOString()).',
|
|
176
202
|
' Emit a start event via `node .forge/tools/store-cli.cjs emit bugs \'{event-json}\'`',
|
|
177
203
|
' with action="start", role="' + phase.role + '", iteration=' + iter + ', startTimestamp and endTimestamp both equal to startTimestamp (0-duration placeholder).',
|
|
204
|
+
' The start event MUST NOT include a "type" field.',
|
|
178
205
|
' 3b. AFTER the phase workflow completes: note the end timestamp (endTimestamp = new Date().toISOString()).',
|
|
179
206
|
' Compute durationMinutes = (new Date(endTimestamp) - new Date(startTimestamp)) / 60000.',
|
|
180
207
|
' Emit a complete event via `node .forge/tools/store-cli.cjs emit bugs \'{event-json}\'`',
|
|
181
|
-
' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=' + iter + ',',
|
|
208
|
+
' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=' + iter + ', bugId,',
|
|
182
209
|
' startTimestamp, endTimestamp, durationMinutes, plus your own model/provider/token usage — do NOT invent placeholder model strings).',
|
|
210
|
+
' COMPLETE-event type (per .forge/workflows/_fragments/event-vocabulary.md): ' + typeTokenLine,
|
|
211
|
+
' NEVER copy the action value ("start"/"complete") into "type" — those tokens are schema-rejected and the event would be dropped.',
|
|
183
212
|
' If `/cost` data is available, also write the token sidecar via the `--sidecar` form. Best-effort; skip silently if unavailable.',
|
|
184
213
|
' Then drain any `.forge/cache/FRICTION-*.jsonl` friction records you produced and emit them as type "friction".',
|
|
185
214
|
phase.role && REVIEW_ROLES.includes(phase.role)
|
|
@@ -230,14 +259,18 @@ const resolved = await agent(
|
|
|
230
259
|
|
|
231
260
|
if (!resolved) throw new Error(`Could not resolve bug record for ${bugId}`)
|
|
232
261
|
|
|
233
|
-
// Pre-loop status guard — fix_bug.md: skip at pre-loop with one
|
|
262
|
+
// Pre-loop status guard — fix_bug.md: skip at pre-loop with one bug-skipped event.
|
|
263
|
+
// Token + payload per _fragments/event-vocabulary.md (forge-engineering#39):
|
|
264
|
+
// bug-skipped requires bugId but no phase/iteration; driver-emitted skips carry
|
|
265
|
+
// model/provider "n/a"; the skip reason rides in "notes" (declared property).
|
|
234
266
|
if (SKIP_STATUS.includes(resolved.bugStatus)) {
|
|
235
267
|
log(`⚠ ${bugId} — status is ${resolved.bugStatus}, skipping run.`)
|
|
236
|
-
// Emit
|
|
268
|
+
// Emit bug-skipped event (not a silent return — Iron Law 3).
|
|
237
269
|
await agent(
|
|
238
270
|
[
|
|
239
|
-
`Emit a
|
|
240
|
-
`Run \`node .forge/tools/store-cli.cjs emit bugs '{"type":"
|
|
271
|
+
`Emit a bug-skipped event for ${bugId}.`,
|
|
272
|
+
`Run \`node .forge/tools/store-cli.cjs emit bugs '{"eventId":"<uuid-v4>","type":"bug-skipped","sprintId":"bugs","bugId":"${bugId}","role":"orchestrator","action":"skipped","notes":"status=${resolved.bugStatus}","startTimestamp":"'$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)'","endTimestamp":"'$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)'","durationMinutes":0,"model":"n/a","provider":"n/a"}'\`.`,
|
|
273
|
+
'Replace <uuid-v4> with a UUID v4 string (e.g. crypto.randomUUID()). Do NOT modify any other store records.',
|
|
241
274
|
`Best-effort. Return taskStatus="${resolved.bugStatus}", gatePassed=true, verdict="none", escalated=false, phase="skip", role="orchestrator".`,
|
|
242
275
|
].join(' '),
|
|
243
276
|
{ label: `${bugId}:skip`, phase: 'Skip', schema: BUG_PHASE_RESULT_SCHEMA, model: 'haiku' }
|
|
@@ -268,11 +301,14 @@ let triageResult = await agent(
|
|
|
268
301
|
' 3a. BEFORE running the triage workflow: note the start timestamp (startTimestamp = new Date().toISOString()).',
|
|
269
302
|
' Emit a start event via `node .forge/tools/store-cli.cjs emit bugs \'{event-json}\'`',
|
|
270
303
|
' with action="start", role="triage", iteration=1, startTimestamp and endTimestamp both equal to startTimestamp (0-duration placeholder).',
|
|
304
|
+
' The start event MUST NOT include a "type" field.',
|
|
271
305
|
' 3b. AFTER the triage workflow completes: note the end timestamp (endTimestamp = new Date().toISOString()).',
|
|
272
306
|
' Compute durationMinutes = (new Date(endTimestamp) - new Date(startTimestamp)) / 60000.',
|
|
273
307
|
' Emit a complete event via `node .forge/tools/store-cli.cjs emit bugs \'{event-json}\'`',
|
|
274
|
-
' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=1,',
|
|
308
|
+
' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=1, bugId,',
|
|
275
309
|
' startTimestamp, endTimestamp, durationMinutes, plus your own model/provider/token usage — do NOT invent placeholder model strings).',
|
|
310
|
+
' COMPLETE-event type (per .forge/workflows/_fragments/event-vocabulary.md): set type="bug-triaged".',
|
|
311
|
+
' NEVER copy the action value ("start"/"complete") into "type" — those tokens are schema-rejected and the event would be dropped.',
|
|
276
312
|
' If `/cost` data is available, also write the token sidecar via the `--sidecar` form. Best-effort; skip silently if unavailable.',
|
|
277
313
|
'4. NON-REVIEW phase: return verdict="none".',
|
|
278
314
|
'5. Read `.forge/store/bugs/' + bugId + '.json` and return its final status as taskStatus, plus a one-line note.',
|
|
@@ -133,6 +133,22 @@ const SKIP_STATUS = ['blocked', 'escalated', 'committed', 'abandoned']
|
|
|
133
133
|
// NOTE: `approve` is NOT here — orchestrate_task advances it on completion like a
|
|
134
134
|
// non-review phase (the approve workflow self-escalates if it rejects).
|
|
135
135
|
const REVIEW_ROLES = ['review-plan', 'review-code', 'validate']
|
|
136
|
+
|
|
137
|
+
// Task-phase `type` tokens — verbatim port of the canonical table in
|
|
138
|
+
// .forge/workflows/_fragments/event-vocabulary.md § Task pipeline
|
|
139
|
+
// (forge-engineering#39). The COMPLETE event carries the pass token (or the
|
|
140
|
+
// fail token when a review phase's verdict is "revision"); the START event is
|
|
141
|
+
// always untyped. Roles outside this map emit untyped events (valid).
|
|
142
|
+
const TASK_TYPE_TOKENS = {
|
|
143
|
+
'plan': { pass: 'task-planned', fail: 'task-planned' },
|
|
144
|
+
'review-plan': { pass: 'plan-approved', fail: 'review-failed' },
|
|
145
|
+
'implement': { pass: 'task-implemented', fail: 'task-implemented' },
|
|
146
|
+
'review-code': { pass: 'review-passed', fail: 'review-failed' },
|
|
147
|
+
'validate': { pass: 'task-validated', fail: 'review-failed' },
|
|
148
|
+
'approve': { pass: 'task-approved', fail: 'review-failed' },
|
|
149
|
+
'commit': { pass: 'task-committed', fail: 'task-committed' },
|
|
150
|
+
}
|
|
151
|
+
|
|
136
152
|
// Per-phase model tier — verbatim port of orchestrate_task.md § Role-to-Tier Mapping.
|
|
137
153
|
// The resolve agent uses this as a reference; JS loop calls resolveModel() not tierFor().
|
|
138
154
|
const ROLE_TIER = {
|
|
@@ -338,17 +354,30 @@ function runPhase(taskId, sprintId, phase, iteration, { firstPhase = false, simp
|
|
|
338
354
|
const eventIdLine = eventId
|
|
339
355
|
? ' Use eventId="' + eventId + '" for the COMPLETE event (the driver will call merge-sidecar with this id).'
|
|
340
356
|
: ' Use a fresh crypto.randomUUID() for both start and complete event ids.'
|
|
357
|
+
// forge-engineering#39: explicit type-token guidance per
|
|
358
|
+
// .forge/workflows/_fragments/event-vocabulary.md. Without it, subagents
|
|
359
|
+
// guessed and leaked the action value into `type` ("start"/"complete" —
|
|
360
|
+
// schema-rejected store residue).
|
|
361
|
+
const typeTokens = TASK_TYPE_TOKENS[phase.role]
|
|
362
|
+
const typeTokenLine = typeTokens
|
|
363
|
+
? (REVIEW_ROLES.includes(phase.role)
|
|
364
|
+
? 'set type="' + typeTokens.pass + '" when your verdict is Approved, type="' + typeTokens.fail + '" when it is Revision Required.'
|
|
365
|
+
: 'set type="' + typeTokens.pass + '".')
|
|
366
|
+
: 'omit the "type" field entirely (untyped events are valid; this role has no table entry).'
|
|
341
367
|
lines.push(
|
|
342
368
|
'',
|
|
343
369
|
'3. EMIT YOUR PHASE EVENTS. You are the only actor that knows your runtime attribution.',
|
|
344
370
|
' 3a. BEFORE running the phase workflow: note the start timestamp (startTimestamp = new Date().toISOString()).',
|
|
345
371
|
' Emit a start event via `node .forge/tools/store-cli.cjs emit ' + sprintId + " '{event-json}'\`",
|
|
346
372
|
' with action="start", role="' + phase.role + '", iteration=' + iteration + ', startTimestamp and endTimestamp both equal to startTimestamp (0-duration placeholder).',
|
|
373
|
+
' The start event MUST NOT include a "type" field.',
|
|
347
374
|
' 3b. AFTER the phase workflow completes: note the end timestamp (endTimestamp = new Date().toISOString()).',
|
|
348
375
|
' Compute durationMinutes = (new Date(endTimestamp) - new Date(startTimestamp)) / 60000.',
|
|
349
376
|
' Emit a complete event via `node .forge/tools/store-cli.cjs emit ' + sprintId + " '{event-json}'\`",
|
|
350
377
|
' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=' + iteration + ',',
|
|
351
378
|
' startTimestamp, endTimestamp, durationMinutes, plus your own model/provider/token usage — do NOT invent placeholder model strings).',
|
|
379
|
+
' COMPLETE-event type (per .forge/workflows/_fragments/event-vocabulary.md): ' + typeTokenLine,
|
|
380
|
+
' NEVER copy the action value ("start"/"complete") into "type" — those tokens are schema-rejected and the event would be dropped.',
|
|
352
381
|
' ' + eventIdLine,
|
|
353
382
|
' If `/cost` data is available, also write the token sidecar via the `--sidecar` form with the COMPLETE eventId. Best-effort; skip silently if unavailable.',
|
|
354
383
|
'',
|
|
@@ -404,7 +433,9 @@ function emitSkip(taskId, sprintId, taskStatus) {
|
|
|
404
433
|
`Emit a task_skipped event for Forge task ${taskId} (sprint ${sprintId}).`,
|
|
405
434
|
`node .forge/tools/store-cli.cjs emit ${sprintId}`,
|
|
406
435
|
`'{"type":"task-dispatch","action":"skip","taskId":"${taskId}","sprintId":"${sprintId}",`,
|
|
407
|
-
|
|
436
|
+
// forge-engineering#39: iteration must be >= 1 (schema minimum) — the
|
|
437
|
+
// former zero value made every skip event silently schema-rejected.
|
|
438
|
+
`"role":"orchestrator","phase":"pre-task","iteration":1,`,
|
|
408
439
|
`"notes":"pre-task SKIP_STATUS guard: task status is ${taskStatus}",`,
|
|
409
440
|
`"startTimestamp":"<ISO-now>","endTimestamp":"<ISO-now>","durationMinutes":0,`,
|
|
410
441
|
`"model":"<your-model-id>","provider":"anthropic"}'`,
|
|
@@ -59,11 +59,11 @@
|
|
|
59
59
|
"sprint-complete",
|
|
60
60
|
"sprint-halted",
|
|
61
61
|
"task-dispatch",
|
|
62
|
-
"bug-fixed",
|
|
63
62
|
|
|
64
63
|
"bug-triaged", "fix-planned", "fix-review-passed", "fix-review-failed",
|
|
65
64
|
"fix-implemented", "fix-code-review-passed", "fix-code-review-failed",
|
|
66
|
-
"fix-approved", "bug-committed",
|
|
65
|
+
"fix-approved", "fix-revision-requested", "bug-committed",
|
|
66
|
+
"bug-commit-failed", "bug-skipped",
|
|
67
67
|
|
|
68
68
|
"skill_usage"
|
|
69
69
|
]
|
|
@@ -129,7 +129,8 @@
|
|
|
129
129
|
"enum": [
|
|
130
130
|
"bug-triaged", "fix-planned", "fix-review-passed", "fix-review-failed",
|
|
131
131
|
"fix-implemented", "fix-code-review-passed", "fix-code-review-failed",
|
|
132
|
-
"fix-approved", "
|
|
132
|
+
"fix-approved", "fix-revision-requested", "bug-committed",
|
|
133
|
+
"bug-commit-failed"
|
|
133
134
|
]
|
|
134
135
|
}
|
|
135
136
|
},
|
|
@@ -137,6 +138,10 @@
|
|
|
137
138
|
},
|
|
138
139
|
"then": { "required": ["bugId", "phase", "iteration"] }
|
|
139
140
|
},
|
|
141
|
+
{
|
|
142
|
+
"if": { "properties": { "type": { "const": "bug-skipped" } }, "required": ["type"] },
|
|
143
|
+
"then": { "required": ["bugId"] }
|
|
144
|
+
},
|
|
140
145
|
{
|
|
141
146
|
"if": { "properties": { "type": { "const": "sprint-start" } }, "required": ["type"] },
|
|
142
147
|
"then": {
|
|
@@ -1,4 +1,60 @@
|
|
|
1
1
|
{
|
|
2
|
+
"1.2.20": {
|
|
3
|
+
"version": "1.2.21",
|
|
4
|
+
"date": "2026-06-06",
|
|
5
|
+
"notes": "commit-task.cjs hardening from its first live firing (HELLO-BUG-002 transcript analysis, forge-engineering#40). (1) Gitignored staging paths are pre-filtered with git check-ignore and warn-skipped — previously one ignored path aborted the all-or-nothing git add and the agent retried the identical command. (2) A clean staging set is now a legitimate no-op SUCCESS: the tool seals the record's terminal status and returns {ok:true, committed:false, reason:nothing-to-commit} — a bug whose fix is already at HEAD ends fixed without improvised manual transitions. Result JSON gains an explicit committed flag. meta-commit.md: forge_commit named tool is the primary surface on forgecli (typed args — no shell-quoting of the commit message); bash form stays as the Claude Code fallback; no-op outcome documented as success.",
|
|
6
|
+
"target": "tools:commit-task,workflows:commit_task",
|
|
7
|
+
"regenerate": [
|
|
8
|
+
"tools",
|
|
9
|
+
"workflows"
|
|
10
|
+
],
|
|
11
|
+
"breaking": false,
|
|
12
|
+
"manual": [
|
|
13
|
+
"Run /forge:update, then /forge:rebuild tools workflows to refresh .forge/tools/commit-task.cjs and .forge/workflows/commit_task.md."
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"1.2.19": {
|
|
17
|
+
"version": "1.2.20",
|
|
18
|
+
"date": "2026-06-06",
|
|
19
|
+
"notes": "Deterministic commit choreography (forge-engineering#40). The commit phase was the most expensive phase of the pipeline (15-31% of run input tokens) because an LLM re-derived deterministic choreography turn-by-turn. New tools/commit-task.cjs owns the whole sequence — preflight gate, status precondition, staging-set derivation (record artifact dir + implementation file provenance), commit-boundary guard (aborts on a pre-populated index), git commit, terminal status transition (task→committed / bug→fixed) — with --dry-run, argv-array spawns, and operator-gated --force. The implement phase now records files_changed provenance in IMPLEMENTATION-SUMMARY.json (new optional PHASE_SUMMARY_SCHEMA key, max 100 paths) so commit never re-derives the change surface from git. meta-commit.md rewritten: agent inspects once (git diff --stat), crafts the message, calls the tool once; explicit no-summary contract (commit is not in VALID_SUMMARY_PHASES — the previous prompt commanded writing a SUMMARY that the schema rejects, sending agents on an unwinnable format hunt plus 3 write-verification retries); batched-inspection rule; commit-early/reset/redo loop forbidden.",
|
|
20
|
+
"target": "tools:commit-task,tools:store-cli,workflows:commit_task,workflows:implement_plan",
|
|
21
|
+
"regenerate": [
|
|
22
|
+
"tools",
|
|
23
|
+
"workflows"
|
|
24
|
+
],
|
|
25
|
+
"breaking": false,
|
|
26
|
+
"manual": [
|
|
27
|
+
"Run /forge:update, then /forge:rebuild tools workflows to vendor .forge/tools/commit-task.cjs and refresh .forge/workflows/commit_task.md + implement_plan.md. Until the rebuild, the regenerated commit workflow will reference a tool that is not yet vendored and will halt loudly (by design)."
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"1.2.18": {
|
|
31
|
+
"version": "1.2.19",
|
|
32
|
+
"date": "2026-06-06",
|
|
33
|
+
"notes": "Event-type discipline in the JS workflow drivers (forge-engineering#39 Phase 3). wfl-run-task.js and wfl-fix-bug.js now carry TASK_TYPE_TOKENS / BUG_TYPE_TOKENS maps (verbatim ports of _fragments/event-vocabulary.md) and inject explicit per-phase type guidance into the subagent emit instructions: start events MUST NOT carry a type field, complete events set the exact pass/fail token for the phase, and copying the action value (start/complete) into type is explicitly forbidden — that guess-leak was the source of the schema-rejected type:start/type:complete store residue. Also fixes wfl-run-task emitSkip(): the skip event emitted iteration 0, violating the schema's minimum of 1, so every pre-task skip event was silently rejected; now 1.",
|
|
34
|
+
"target": "workflows-js:wfl-run-task,workflows-js:wfl-fix-bug",
|
|
35
|
+
"regenerate": [
|
|
36
|
+
"workflows-js"
|
|
37
|
+
],
|
|
38
|
+
"breaking": false,
|
|
39
|
+
"manual": [
|
|
40
|
+
"Run /forge:update, then /forge:rebuild to regenerate .claude/workflows/wfl-run-task.js and wfl-fix-bug.js from the base-pack. Prompt/instruction text + one literal fix — no schema or tool change."
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"1.2.17": {
|
|
44
|
+
"version": "1.2.18",
|
|
45
|
+
"date": "2026-06-06",
|
|
46
|
+
"notes": "Event-type vocabulary gets a spec owner (forge-engineering#39). New canonical fragment _fragments/event-vocabulary.md defines the phase→type token tables for task/bug/sprint events; schemas/event.schema.json now mirrors it: adds the bug-pipeline fail tokens fix-revision-requested (approve) and bug-commit-failed (commit) that forge-cli already emits (previously rejected by the enum — events and their token telemetry were silently dropped), adds bug-skipped (pre-loop skip; requires bugId, no phase/iteration), and retires bug-fixed (defined, emitted by nothing, zero store occurrences). The wfl-fix-bug.js base-pack driver's skip emit was triple-broken against the schema (underscore bug_skipped token, missing required eventId/model/provider, undeclared reason key) — now emits a valid bug-skipped event with the skip reason in notes and model/provider \"n/a\". meta-fix-bug.md and meta-orchestrate.md reference the vocabulary fragment; emitted tokens MUST come from its tables.",
|
|
47
|
+
"target": "schemas:event,fragments:event-vocabulary,fragments:event-emission-schema,workflows:fix_bug,workflows:orchestrate_task,workflows-js:wfl-fix-bug",
|
|
48
|
+
"regenerate": [
|
|
49
|
+
"schemas",
|
|
50
|
+
"workflows",
|
|
51
|
+
"workflows-js"
|
|
52
|
+
],
|
|
53
|
+
"breaking": false,
|
|
54
|
+
"manual": [
|
|
55
|
+
"Run /forge:update, then /forge:rebuild schemas workflows to refresh .forge/schemas/event.schema.json, .forge/workflows/ (fix_bug.md, orchestrate_task.md, _fragments/), and the regenerated .claude/workflows/wfl-fix-bug.js. Projects with the legacy invalid store events (type start/complete/feature_implemented) can clear them via /forge:repair — strip the invalid type field (untyped events are valid)."
|
|
56
|
+
]
|
|
57
|
+
},
|
|
2
58
|
"1.2.16": {
|
|
3
59
|
"version": "1.2.17",
|
|
4
60
|
"date": "2026-06-04",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.2.
|
|
3
|
-
"generated": "2026-06-
|
|
2
|
+
"version": "1.2.21",
|
|
3
|
+
"generated": "2026-06-06",
|
|
4
4
|
"note": "Tamper-evident only. Authoritative source: /forge:update from remote.",
|
|
5
5
|
"files": {
|
|
6
6
|
"commands/add-pipeline.md": "529a2fc01be49815efa2cf1147528827ff1bfc12ce2ac8663b5a3a9781f8682e",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"schemas/transitions/bug.json": "27b17da42d1cebffbd4f61ab3dcd432a0017aa71997d548ed80d22c2fc3fad6a",
|
|
31
31
|
"schemas/transitions/sprint.json": "2e0a629396e687b0ca88e1814ac3e35d84533a5d55b25237ab67feddce3c9deb",
|
|
32
32
|
"schemas/transitions/task.json": "4c71849747baa0d585756e57c56325ff6219c078178374e60815dff91e25e3e7",
|
|
33
|
-
"schemas/enum-catalog.json": "
|
|
33
|
+
"schemas/enum-catalog.json": "68260bed8e6fe347bc4a1c870fa1ea51ca1ebc45873aae929624837afe8f0bdb",
|
|
34
34
|
"tools/verify-integrity.cjs": "3ec3c970dd3d7c3001f8f373bcc40556803eadd2fc2afafb14f1c232cba4cc3f"
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -10,6 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
Example: `20260415T141523000Z_ACME-S02-T03_engineer_implement`
|
|
12
12
|
|
|
13
|
+
## Type Vocabulary
|
|
14
|
+
|
|
15
|
+
The optional `type` field, when present, must come from the canonical
|
|
16
|
+
phase→type tables in `meta/workflows/_fragments/event-vocabulary.md`
|
|
17
|
+
(task / bug / sprint / friction / skill_usage families). The schema enum in
|
|
18
|
+
`schemas/event.schema.json` mirrors that fragment.
|
|
19
|
+
|
|
13
20
|
## Fields
|
|
14
21
|
|
|
15
22
|
| Field | Type | Required | Description |
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
orchestrator stitches runtime telemetry + judgement into the canonical
|
|
5
5
|
event and emits it. Referenced by meta-orchestrate.md and meta-fix-bug.md.
|
|
6
6
|
|
|
7
|
+
Companion: _fragments/event-vocabulary.md owns the `type` token
|
|
8
|
+
vocabulary (phase→type tables for task/bug/sprint events). This fragment
|
|
9
|
+
owns WHO emits; that one owns WHAT token.
|
|
10
|
+
|
|
7
11
|
PLAN-11 / SLICE-2 (2026-05-14): the LLM no longer hand-builds event JSON.
|
|
8
12
|
Runtime facts (model, provider, eventId, timestamps, iteration, tokens)
|
|
9
13
|
are owned by the orchestrator, never the subagent. The subagent only
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Fragment: Event Type Vocabulary
|
|
2
|
+
|
|
3
|
+
<!-- Canonical phase→type vocabulary for store events (forge-engineering#39).
|
|
4
|
+
This fragment OWNS the `type` token vocabulary; `schemas/event.schema.json`
|
|
5
|
+
mirrors it. Any vocabulary change lands here first, then in the schema enum
|
|
6
|
+
(test-first via tools/__tests__/event-schema-variants.test.cjs), then in
|
|
7
|
+
emitters (forge-cli orchestrators, wfl JS drivers, meta workflows).
|
|
8
|
+
|
|
9
|
+
Companion: _fragments/event-emission-schema.md owns WHO emits (orchestrator
|
|
10
|
+
vs subagent field ownership). This fragment owns WHAT token each phase emits.
|
|
11
|
+
|
|
12
|
+
Invariant: every token emitted by any surface MUST appear in the schema
|
|
13
|
+
enum, and every enum token MUST have a named emitter below. Dead tokens are
|
|
14
|
+
removed (bug-fixed was retired by forge-engineering#39 — defined, never
|
|
15
|
+
emitted by anything). -->
|
|
16
|
+
|
|
17
|
+
## Rules
|
|
18
|
+
|
|
19
|
+
1. **Emitted tokens ⊆ schema enum.** An emitter never invents a token. If a new
|
|
20
|
+
phase outcome needs a token, add it here + the schema enum first.
|
|
21
|
+
2. **`type` is optional** on events. An untyped event is valid (task-pipeline
|
|
22
|
+
events from forge-cli run-task are currently untyped). When a `type` IS set,
|
|
23
|
+
it must come from the tables below.
|
|
24
|
+
3. **Kebab-case for lifecycle tokens.** Underscore names are reserved for the
|
|
25
|
+
`friction` and `skill_usage` event families.
|
|
26
|
+
4. **Conditional fields.** Typed events trigger schema conditionals — see the
|
|
27
|
+
"Requires" column. Driver-emitted skip events have no model/provider; emit
|
|
28
|
+
the literal `"n/a"` for both (never guess a model string — see
|
|
29
|
+
`_fragments/event-emission-schema.md` §Why no example record here).
|
|
30
|
+
5. **Skip reasons ride in `notes`.** `reason` is not a declared event property
|
|
31
|
+
(`additionalProperties: false` rejects it).
|
|
32
|
+
|
|
33
|
+
## Task pipeline (orchestrate_task / run-task / wfl:run-task)
|
|
34
|
+
|
|
35
|
+
| Phase | Pass token | Fail token | Requires |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| plan | `task-planned` | `task-planned` | taskId, phase, iteration |
|
|
38
|
+
| review-plan | `plan-approved` | `review-failed` | taskId, phase, iteration |
|
|
39
|
+
| implement | `task-implemented` | `task-implemented` | taskId, phase, iteration |
|
|
40
|
+
| review-code | `review-passed` | `review-failed` | taskId, phase, iteration |
|
|
41
|
+
| validate | `task-validated` | `review-failed` | taskId, phase, iteration |
|
|
42
|
+
| approve | `task-approved` | `review-failed` | taskId, phase, iteration |
|
|
43
|
+
| commit | `task-committed` | `task-committed` | taskId, phase, iteration |
|
|
44
|
+
|
|
45
|
+
`plan-complete` is a legacy alias accepted by the enum for plan-phase events;
|
|
46
|
+
new emitters use `task-planned`.
|
|
47
|
+
|
|
48
|
+
## Bug pipeline (fix_bug / fix-bug / wfl:fix-bug)
|
|
49
|
+
|
|
50
|
+
| Phase | Pass token | Fail token | Requires |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| pre-loop skip | `bug-skipped` | — | bugId (no phase/iteration; model/provider `"n/a"`) |
|
|
53
|
+
| triage | `bug-triaged` | `bug-triaged` | bugId, phase, iteration |
|
|
54
|
+
| plan-fix | `fix-planned` | `fix-planned` | bugId, phase, iteration |
|
|
55
|
+
| review-plan | `fix-review-passed` | `fix-review-failed` | bugId, phase, iteration |
|
|
56
|
+
| implement | `fix-implemented` | `fix-implemented` | bugId, phase, iteration |
|
|
57
|
+
| review-code | `fix-code-review-passed` | `fix-code-review-failed` | bugId, phase, iteration |
|
|
58
|
+
| approve | `fix-approved` | `fix-revision-requested` | bugId, phase, iteration |
|
|
59
|
+
| commit | `bug-committed` | `bug-commit-failed` | bugId, phase, iteration |
|
|
60
|
+
|
|
61
|
+
Non-review phases emit their single token regardless of outcome (the verdict
|
|
62
|
+
field carries the judgement); review phases (review-plan, review-code, approve)
|
|
63
|
+
select pass/fail on `verdict == "revision"`.
|
|
64
|
+
|
|
65
|
+
## Sprint grain (run_sprint / run-sprint / wfl:run-sprint)
|
|
66
|
+
|
|
67
|
+
| Moment | Token | Requires |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| before wave loop | `sprint-start` | sprintId (taskCount optional) |
|
|
70
|
+
| before each task dispatch | `task-dispatch` | taskId (convention; phase/iteration carried but not schema-enforced) |
|
|
71
|
+
| sprint finished | `sprint-complete` | taskCount, completedTaskIds, verdict |
|
|
72
|
+
| sprint aborted | `sprint-halted` | haltedAtTaskIndex, haltedAtTaskId, lastError |
|
|
73
|
+
|
|
74
|
+
## Other families
|
|
75
|
+
|
|
76
|
+
| Token | Emitter | Spec |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `friction` | any persona, drained by orchestrator | `_fragments/friction-emit.md` |
|
|
79
|
+
| `skill_usage` | forge-cli skill-curation telemetry | `event.schema.json` skill_usage conditional |
|
|
80
|
+
|
|
81
|
+
## Out of scope (known follow-ups)
|
|
82
|
+
|
|
83
|
+
- **Feature events** have no lifecycle tokens; feature-related events are
|
|
84
|
+
emitted untyped. Defining a feature vocabulary is a future change to this
|
|
85
|
+
fragment + the enum.
|
|
86
|
+
- **Task-pipeline typed emission in forge-cli** — run-task currently emits
|
|
87
|
+
untyped events (valid under Rule 2); adopting the task table above is
|
|
88
|
+
forward work tracked in forge-engineering#39 step 3.
|