@entelligentsia/forgecli 0.10.0 → 0.11.2
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 +95 -0
- package/README.md +21 -3
- package/dist/CHANGELOG-forge-plugin.md +90 -0
- package/dist/bin/config.js +6 -0
- package/dist/bin/config.js.map +1 -1
- package/dist/extensions/forgecli/add-pipeline.d.ts +19 -0
- package/dist/extensions/forgecli/add-pipeline.js +143 -0
- package/dist/extensions/forgecli/add-pipeline.js.map +1 -0
- package/dist/extensions/forgecli/add-task.d.ts +20 -0
- package/dist/extensions/forgecli/add-task.js +154 -0
- package/dist/extensions/forgecli/add-task.js.map +1 -0
- package/dist/extensions/forgecli/calibrate.d.ts +61 -0
- package/dist/extensions/forgecli/calibrate.js +488 -0
- package/dist/extensions/forgecli/calibrate.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.d.ts +9 -1
- package/dist/extensions/forgecli/fix-bug.js +155 -45
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-commands.js +15 -22
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +16 -1
- package/dist/extensions/forgecli/forge-subagent.js +45 -8
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-update-command.d.ts +9 -0
- package/dist/extensions/forgecli/forge-update-command.js +106 -7
- package/dist/extensions/forgecli/forge-update-command.js.map +1 -1
- package/dist/extensions/forgecli/health-check.d.ts +22 -1
- package/dist/extensions/forgecli/health-check.js +177 -4
- package/dist/extensions/forgecli/health-check.js.map +1 -1
- package/dist/extensions/forgecli/hook-dispatcher.d.ts +25 -1
- package/dist/extensions/forgecli/hook-dispatcher.js +104 -9
- package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
- package/dist/extensions/forgecli/hooks/check-update.d.ts +81 -0
- package/dist/extensions/forgecli/hooks/check-update.js +308 -0
- package/dist/extensions/forgecli/hooks/check-update.js.map +1 -0
- package/dist/extensions/forgecli/hooks/forge-permissions.d.ts +32 -0
- package/dist/extensions/forgecli/hooks/forge-permissions.js +119 -0
- package/dist/extensions/forgecli/hooks/forge-permissions.js.map +1 -0
- package/dist/extensions/forgecli/hooks/triage-error.d.ts +23 -0
- package/dist/extensions/forgecli/hooks/triage-error.js +62 -0
- package/dist/extensions/forgecli/hooks/triage-error.js.map +1 -0
- package/dist/extensions/forgecli/hooks/write-guard.d.ts +28 -0
- package/dist/extensions/forgecli/hooks/write-guard.js +225 -0
- package/dist/extensions/forgecli/hooks/write-guard.js.map +1 -0
- package/dist/extensions/forgecli/index.js +60 -0
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/init-context.d.ts +1 -1
- package/dist/extensions/forgecli/init-context.js +21 -6
- package/dist/extensions/forgecli/init-context.js.map +1 -1
- package/dist/extensions/forgecli/materialize.d.ts +16 -0
- package/dist/extensions/forgecli/materialize.js +195 -0
- package/dist/extensions/forgecli/materialize.js.map +1 -0
- package/dist/extensions/forgecli/migrate.d.ts +19 -0
- package/dist/extensions/forgecli/migrate.js +258 -0
- package/dist/extensions/forgecli/migrate.js.map +1 -0
- package/dist/extensions/forgecli/migration-engine.d.ts +111 -0
- package/dist/extensions/forgecli/migration-engine.js +533 -0
- package/dist/extensions/forgecli/migration-engine.js.map +1 -0
- package/dist/extensions/forgecli/quiz-agent.d.ts +17 -0
- package/dist/extensions/forgecli/quiz-agent.js +98 -0
- package/dist/extensions/forgecli/quiz-agent.js.map +1 -0
- package/dist/extensions/forgecli/remove-command.d.ts +17 -0
- package/dist/extensions/forgecli/remove-command.js +124 -0
- package/dist/extensions/forgecli/remove-command.js.map +1 -0
- package/dist/extensions/forgecli/report-bug.d.ts +25 -0
- package/dist/extensions/forgecli/report-bug.js +159 -0
- package/dist/extensions/forgecli/report-bug.js.map +1 -0
- package/dist/extensions/forgecli/retrospective.d.ts +19 -0
- package/dist/extensions/forgecli/retrospective.js +156 -0
- package/dist/extensions/forgecli/retrospective.js.map +1 -0
- package/dist/extensions/forgecli/run-sprint.js +36 -3
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +9 -1
- package/dist/extensions/forgecli/run-task.js +66 -13
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/session-registry.d.ts +40 -2
- package/dist/extensions/forgecli/session-registry.js +71 -1
- package/dist/extensions/forgecli/session-registry.js.map +1 -1
- package/dist/extensions/forgecli/status-command.d.ts +19 -0
- package/dist/extensions/forgecli/status-command.js +140 -0
- package/dist/extensions/forgecli/status-command.js.map +1 -0
- package/dist/extensions/forgecli/store-query.d.ts +22 -0
- package/dist/extensions/forgecli/store-query.js +107 -0
- package/dist/extensions/forgecli/store-query.js.map +1 -0
- package/dist/extensions/forgecli/store-repair.d.ts +17 -0
- package/dist/extensions/forgecli/store-repair.js +123 -0
- package/dist/extensions/forgecli/store-repair.js.map +1 -0
- package/dist/extensions/forgecli/test-orchestrate.js +1 -0
- package/dist/extensions/forgecli/test-orchestrate.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.js +286 -41
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/transition-guard.js +7 -2
- package/dist/extensions/forgecli/transition-guard.js.map +1 -1
- package/dist/extensions/forgecli/update-tools.d.ts +23 -0
- package/dist/extensions/forgecli/update-tools.js +136 -0
- package/dist/extensions/forgecli/update-tools.js.map +1 -0
- package/dist/extensions/forgecli/viewport-events.js +10 -0
- package/dist/extensions/forgecli/viewport-events.js.map +1 -1
- package/dist/extensions/forgecli/viewport-renderer.d.ts +18 -0
- package/dist/extensions/forgecli/viewport-renderer.js +27 -0
- package/dist/extensions/forgecli/viewport-renderer.js.map +1 -1
- package/dist/extensions/forgecli/viewport-theme.js +4 -0
- package/dist/extensions/forgecli/viewport-theme.js.map +1 -1
- package/dist/extensions/forgecli/whats-new-widget.d.ts +13 -8
- package/dist/extensions/forgecli/whats-new-widget.js +111 -42
- package/dist/extensions/forgecli/whats-new-widget.js.map +1 -1
- package/dist/forge-payload/.base-pack/workflows/architect_approve.md +29 -3
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +15 -8
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +327 -185
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +18 -10
- package/dist/forge-payload/.base-pack/workflows/plan_task.md +15 -9
- package/dist/forge-payload/.base-pack/workflows/review_code.md +14 -6
- package/dist/forge-payload/.base-pack/workflows/review_plan.md +18 -10
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/bug.schema.json +3 -2
- package/dist/forge-payload/.schemas/config.schema.json +83 -0
- package/dist/forge-payload/.schemas/migrations.json +2049 -0
- package/dist/forge-payload/commands/regenerate.md +17 -1
- package/dist/forge-payload/meta/personas/README.md +16 -0
- package/dist/forge-payload/meta/personas/meta-architect.md +70 -0
- package/dist/forge-payload/meta/personas/meta-bug-fixer.md +73 -0
- package/dist/forge-payload/meta/personas/meta-collator.md +72 -0
- package/dist/forge-payload/meta/personas/meta-engineer.md +70 -0
- package/dist/forge-payload/meta/personas/meta-orchestrator.md +71 -0
- package/dist/forge-payload/meta/personas/meta-product-manager.md +82 -0
- package/dist/forge-payload/meta/personas/meta-qa-engineer.md +91 -0
- package/dist/forge-payload/meta/personas/meta-supervisor.md +92 -0
- package/dist/forge-payload/meta/skill-recommendations.md +154 -0
- package/dist/forge-payload/meta/skills/meta-architect-skills.md +43 -0
- package/dist/forge-payload/meta/skills/meta-bug-fixer-skills.md +43 -0
- package/dist/forge-payload/meta/skills/meta-collator-skills.md +41 -0
- package/dist/forge-payload/meta/skills/meta-engineer-skills.md +43 -0
- package/dist/forge-payload/meta/skills/meta-generic-skills.md +58 -0
- package/dist/forge-payload/meta/skills/meta-qa-engineer-skills.md +46 -0
- package/dist/forge-payload/meta/skills/meta-supervisor-skills.md +43 -0
- package/dist/forge-payload/meta/store-schema/bug.schema.md +71 -0
- package/dist/forge-payload/meta/store-schema/event.schema.md +76 -0
- package/dist/forge-payload/meta/store-schema/feature.schema.md +65 -0
- package/dist/forge-payload/meta/store-schema/sprint.schema.md +64 -0
- package/dist/forge-payload/meta/store-schema/task.schema.md +78 -0
- package/dist/forge-payload/meta/templates/meta-code-review.md +26 -0
- package/dist/forge-payload/meta/templates/meta-plan-review.md +28 -0
- package/dist/forge-payload/meta/templates/meta-plan.md +28 -0
- package/dist/forge-payload/meta/templates/meta-progress.md +25 -0
- package/dist/forge-payload/meta/templates/meta-retrospective.md +28 -0
- package/dist/forge-payload/meta/templates/meta-sprint-manifest.md +26 -0
- package/dist/forge-payload/meta/templates/meta-sprint-requirements.md +91 -0
- package/dist/forge-payload/meta/templates/meta-task-prompt.md +26 -0
- package/dist/forge-payload/meta/tool-specs/collate.spec.md +88 -0
- package/dist/forge-payload/meta/tool-specs/generation-manifest.spec.md +139 -0
- package/dist/forge-payload/meta/tool-specs/manage-config.spec.md +143 -0
- package/dist/forge-payload/meta/tool-specs/seed-store.spec.md +91 -0
- package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +328 -0
- package/dist/forge-payload/meta/tool-specs/validate-store.spec.md +191 -0
- package/dist/forge-payload/meta/workflows/_fragments/context-injection.md +75 -0
- package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +73 -0
- package/dist/forge-payload/meta/workflows/_fragments/finalize.md +13 -0
- package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +73 -0
- package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +38 -0
- package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +39 -0
- package/dist/forge-payload/meta/workflows/meta-approve.md +119 -0
- package/dist/forge-payload/meta/workflows/meta-collate.md +89 -0
- package/dist/forge-payload/meta/workflows/meta-commit.md +93 -0
- package/dist/forge-payload/meta/workflows/meta-enhance.md +286 -0
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +501 -0
- package/dist/forge-payload/meta/workflows/meta-implement.md +132 -0
- package/dist/forge-payload/meta/workflows/meta-migrate.md +455 -0
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +993 -0
- package/dist/forge-payload/meta/workflows/meta-plan-task.md +133 -0
- package/dist/forge-payload/meta/workflows/meta-quiz-agent.md +135 -0
- package/dist/forge-payload/meta/workflows/meta-retrospective.md +65 -0
- package/dist/forge-payload/meta/workflows/meta-review-implementation.md +119 -0
- package/dist/forge-payload/meta/workflows/meta-review-plan.md +108 -0
- package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +65 -0
- package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +76 -0
- package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +147 -0
- package/dist/forge-payload/meta/workflows/meta-update-implementation.md +76 -0
- package/dist/forge-payload/meta/workflows/meta-update-plan.md +76 -0
- package/dist/forge-payload/meta/workflows/meta-validate.md +111 -0
- package/dist/forge-payload/tools/check-structure.cjs +344 -0
- package/dist/forge-payload/tools/collate.cjs +34 -9
- package/dist/forge-payload/tools/list-skills.js +76 -0
- package/dist/forge-payload/tools/parse-gates.cjs +8 -2
- package/dist/forge-payload/tools/store-cli.cjs +56 -11
- package/dist/forge-payload/tools/store.cjs +61 -0
- package/dist/forge-payload/tools/substitute-placeholders.cjs +60 -8
- package/dist/forge-payload/tools/validate-store.cjs +6 -2
- package/dist/forge-payload/tools/verify-integrity.cjs +86 -0
- package/package.json +2 -2
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Tool Spec: validate-store
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Check store integrity: required fields present, referential integrity
|
|
6
|
+
between sprints/tasks/bugs/events, no orphaned records.
|
|
7
|
+
|
|
8
|
+
## Inputs
|
|
9
|
+
|
|
10
|
+
- `.forge/config.json` — paths
|
|
11
|
+
- `.forge/schemas/` — JSON Schema files (task, event, sprint, bug, feature); written during init Phase 8
|
|
12
|
+
- `.forge/store/` — all JSON files including `features/`
|
|
13
|
+
|
|
14
|
+
## Outputs
|
|
15
|
+
|
|
16
|
+
- Validation report to stdout (text or JSON)
|
|
17
|
+
- Exit 0 if valid, 1 if errors found
|
|
18
|
+
|
|
19
|
+
## CLI Interface
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
<tool> validate-store # full validation (text output)
|
|
23
|
+
<tool> validate-store --dry-run # same checks, just report (text)
|
|
24
|
+
<tool> validate-store --fix # auto-fix where possible
|
|
25
|
+
<tool> validate-store --fix --dry-run # preview fixes without writing
|
|
26
|
+
<tool> validate-store --json # JSON structured output
|
|
27
|
+
<tool> validate-store --dry-run --json # JSON diagnosis, no fixes
|
|
28
|
+
<tool> validate-store --fix --dry-run --json # JSON preview of fixes, no writes
|
|
29
|
+
<tool> validate-store --fix --json # JSON output with fixes applied
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## JSON Output Mode (`--json`)
|
|
33
|
+
|
|
34
|
+
When `--json` is present, the tool emits a single JSON object to stdout instead
|
|
35
|
+
of human-readable text. The JSON structure:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"ok": true,
|
|
40
|
+
"errors": [
|
|
41
|
+
{
|
|
42
|
+
"entity": "sprint",
|
|
43
|
+
"id": "FORGE-S07",
|
|
44
|
+
"category": "invalid-enum",
|
|
45
|
+
"field": "status",
|
|
46
|
+
"message": "field \"status\": value \"in-progress\" not in [planning, active, ...]",
|
|
47
|
+
"value": "in-progress",
|
|
48
|
+
"expected": ["planning", "active", "completed", ...]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"warnings": [
|
|
52
|
+
{
|
|
53
|
+
"entity": "sprint",
|
|
54
|
+
"id": "FORGE-S03",
|
|
55
|
+
"category": "orphan-directory",
|
|
56
|
+
"field": null,
|
|
57
|
+
"message": "directory \"FORGE-S03-lean-migration\" has no sprint record in store"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"fixes": [
|
|
61
|
+
{
|
|
62
|
+
"entity": "sprint",
|
|
63
|
+
"id": "FORGE-S01",
|
|
64
|
+
"category": "backfill",
|
|
65
|
+
"field": "createdAt",
|
|
66
|
+
"message": "backfilled \"createdAt\" = \"2026-01-15T10:00:00.000Z\"",
|
|
67
|
+
"applied": true
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"summary": {
|
|
71
|
+
"sprints": 7,
|
|
72
|
+
"tasks": 50,
|
|
73
|
+
"bugs": 4,
|
|
74
|
+
"features": 1,
|
|
75
|
+
"errors": 3,
|
|
76
|
+
"warnings": 2,
|
|
77
|
+
"fixes": 1
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Error Categories
|
|
83
|
+
|
|
84
|
+
| Category | Description |
|
|
85
|
+
|----------|-------------|
|
|
86
|
+
| `missing-required` | Required field is null, undefined, or empty string |
|
|
87
|
+
| `type-mismatch` | Field value has wrong JSON type (e.g., string where number expected) |
|
|
88
|
+
| `invalid-enum` | Field value is not in the declared enum set |
|
|
89
|
+
| `undeclared-field` | Field not in schema with `additionalProperties: false` |
|
|
90
|
+
| `orphaned-fk` | Foreign key references a non-existent entity |
|
|
91
|
+
| `filename-mismatch` | Event filename does not match its eventId |
|
|
92
|
+
| `minimum-violation` | Numeric value below declared minimum |
|
|
93
|
+
| `orphan-directory` | Filesystem directory has no corresponding store record |
|
|
94
|
+
| `stale-path` | `path` field references a nonexistent directory |
|
|
95
|
+
| `missing-optional` | Optional field is absent (warning, not error) |
|
|
96
|
+
|
|
97
|
+
### Fix Categories
|
|
98
|
+
|
|
99
|
+
| Category | Description |
|
|
100
|
+
|----------|-------------|
|
|
101
|
+
| `backfill` | Missing field filled with a derived default |
|
|
102
|
+
| `orphaned-fk` | Orphaned foreign key nullified |
|
|
103
|
+
| `filename-mismatch` | Event file renamed or eventId corrected |
|
|
104
|
+
|
|
105
|
+
The `applied` field on fixes is `true` when the fix was actually written to disk,
|
|
106
|
+
`false` when `--dry-run` is active (preview only).
|
|
107
|
+
|
|
108
|
+
### `--fix --dry-run` Combination
|
|
109
|
+
|
|
110
|
+
When both `--fix` and `--dry-run` are specified, the tool previews what fixes
|
|
111
|
+
*would* be applied without writing anything. Each fix in the JSON output has
|
|
112
|
+
`applied: false`. This is useful for the `/forge:store:repair` skill to assess
|
|
113
|
+
what auto-fixes are available before applying them.
|
|
114
|
+
|
|
115
|
+
## Validation Rules
|
|
116
|
+
|
|
117
|
+
### Required Fields
|
|
118
|
+
|
|
119
|
+
Load the JSON Schema files from `.forge/schemas/` at runtime and derive required
|
|
120
|
+
fields from each schema's `"required"` array. Do NOT hardcode field names.
|
|
121
|
+
|
|
122
|
+
If a schema file is missing, fall back to these defaults and warn:
|
|
123
|
+
- Sprint: `sprintId`, `title`, `status`
|
|
124
|
+
- Task: `taskId`, `sprintId`, `title`, `status`, `path`
|
|
125
|
+
- Bug: `bugId`, `title`, `severity`, `status`, `path`, `reportedAt`
|
|
126
|
+
- Event: `eventId`, `sprintId`, `role`, `action`, `startTimestamp`, `endTimestamp`, `durationMinutes`
|
|
127
|
+
|
|
128
|
+
When schemas are present, also validate field types and enum values per the
|
|
129
|
+
schema definitions — not just field presence.
|
|
130
|
+
|
|
131
|
+
### Nullable Foreign Keys
|
|
132
|
+
|
|
133
|
+
`sprintId` and `taskId` are nullable foreign keys — `null` means "not associated"
|
|
134
|
+
(e.g. standalone bug fix with no sprint, sprint-level event with no task).
|
|
135
|
+
The validator must accept `null` for these fields without reporting an error.
|
|
136
|
+
|
|
137
|
+
`feature_id` on sprint and task records is a nullable FK pointing to
|
|
138
|
+
`.forge/store/features/{FEATURE_ID}.json`. A `null` value is valid (the record is
|
|
139
|
+
not associated with any feature). A non-null value must match the `id` field of an
|
|
140
|
+
existing feature record.
|
|
141
|
+
|
|
142
|
+
### Referential Integrity
|
|
143
|
+
- Every task.sprintId references an existing sprint (when non-null)
|
|
144
|
+
- Every event.taskId references an existing task OR bug (when non-null)
|
|
145
|
+
- Every event.sprintId references an existing sprint OR matches the parent directory name (virtual sprint dirs like `events/bugs/`, `events/ops/`)
|
|
146
|
+
- Every bug.similarBugs[] references existing bugs
|
|
147
|
+
- Every sprint.feature_id and task.feature_id references an existing feature (when non-null)
|
|
148
|
+
|
|
149
|
+
### Orphan Detection
|
|
150
|
+
- Task directories in `engineering/sprints/` without corresponding store JSON
|
|
151
|
+
- Store JSON without corresponding artifact directory
|
|
152
|
+
|
|
153
|
+
### Status Consistency
|
|
154
|
+
- Task status matches artifact presence (e.g., `committed` tasks should have all artifacts)
|
|
155
|
+
- Sprint status consistent with task statuses
|
|
156
|
+
|
|
157
|
+
### Undeclared Fields
|
|
158
|
+
|
|
159
|
+
When a schema has `additionalProperties: false`, any field not in the schema's
|
|
160
|
+
`properties` is reported as an error with category `undeclared-field`. This
|
|
161
|
+
catches fields that were valid in older schema versions but are no longer accepted.
|
|
162
|
+
|
|
163
|
+
## Error Handling
|
|
164
|
+
|
|
165
|
+
- Wrap the entire entry point in a top-level exception handler.
|
|
166
|
+
- On unexpected errors (missing files, JSON parse failures, unhandled
|
|
167
|
+
exceptions), print a clear one-line message to stderr and exit 1.
|
|
168
|
+
- Never let the tool crash with an unhandled exception or stack trace visible
|
|
169
|
+
to the caller — all errors are caught and reported cleanly.
|
|
170
|
+
- Python pattern:
|
|
171
|
+
```python
|
|
172
|
+
if __name__ == "__main__":
|
|
173
|
+
try:
|
|
174
|
+
sys.exit(main())
|
|
175
|
+
except Exception as e:
|
|
176
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
177
|
+
sys.exit(1)
|
|
178
|
+
```
|
|
179
|
+
- JS/TS pattern:
|
|
180
|
+
```js
|
|
181
|
+
process.on('uncaughtException', (e) => {
|
|
182
|
+
process.stderr.write(`Error: ${e.message}\n`);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Auto-Fix Rules (--fix mode)
|
|
188
|
+
- Add missing optional fields with defaults
|
|
189
|
+
- Create missing `.gitkeep` files in empty directories
|
|
190
|
+
- Nullify orphaned `feature_id` references on sprint and task records (log each fix)
|
|
191
|
+
- Do NOT delete orphaned records — only report them
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Fragment: Context Injection
|
|
2
|
+
|
|
3
|
+
<!-- Canonical definition of architecture_block + summary_block assembly patterns.
|
|
4
|
+
Referenced by meta-orchestrate.md and meta-fix-bug.md. -->
|
|
5
|
+
|
|
6
|
+
## Architecture Context Block
|
|
7
|
+
|
|
8
|
+
Read `.forge/cache/context-pack.md` (if it exists) and inject into the subagent prompt
|
|
9
|
+
under the heading `### Architecture context (summary — full docs available at paths listed below)`.
|
|
10
|
+
If the pack is absent, omit this block silently — the subagent falls back to reading
|
|
11
|
+
architecture docs directly.
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
context_pack_path = ".forge/cache/context-pack.md"
|
|
15
|
+
context_pack_json_path = ".forge/cache/context-pack.json"
|
|
16
|
+
if file_exists(context_pack_path):
|
|
17
|
+
context_pack_md = read_file(context_pack_path)
|
|
18
|
+
try:
|
|
19
|
+
context_pack_json = read_json(context_pack_json_path)
|
|
20
|
+
full_doc_paths = "\n".join(f"- {s['path']}" for s in context_pack_json.get("sources", []))
|
|
21
|
+
except:
|
|
22
|
+
full_doc_paths = "engineering/architecture/ (see context-pack.json for full list)"
|
|
23
|
+
architecture_block = (
|
|
24
|
+
"### Architecture context (summary — full docs available at paths listed below)\n\n"
|
|
25
|
+
+ context_pack_md
|
|
26
|
+
+ "\n\nRead full architecture docs only if the summary above is insufficient for "
|
|
27
|
+
+ "your decision. Full docs:\n"
|
|
28
|
+
+ full_doc_paths
|
|
29
|
+
+ "\n\n"
|
|
30
|
+
)
|
|
31
|
+
else:
|
|
32
|
+
architecture_block = ""
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Prior Phase Summary Block
|
|
36
|
+
|
|
37
|
+
Re-read the record from disk after each phase so summaries accumulate.
|
|
38
|
+
For bugs, pass `record_type="bug"` to read from the bugs store path.
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# record_type: "task" (default) or "bug"
|
|
42
|
+
if record_type == "bug":
|
|
43
|
+
record_fresh = read_json(f".forge/store/bugs/{record_id}.json")
|
|
44
|
+
else:
|
|
45
|
+
record_fresh = read_json(f".forge/store/tasks/{record_id}.json")
|
|
46
|
+
summaries = (record_fresh or {}).get("summaries", {})
|
|
47
|
+
|
|
48
|
+
SUMMARY_PHASE_LABELS = {
|
|
49
|
+
"plan": "Plan", "review_plan": "Plan review",
|
|
50
|
+
"implementation": "Implementation", "code_review": "Code review",
|
|
51
|
+
"validation": "Validation", "approve": "Approve", "triage": "Triage"
|
|
52
|
+
}
|
|
53
|
+
summary_lines = []
|
|
54
|
+
for phase_key, label in SUMMARY_PHASE_LABELS.items():
|
|
55
|
+
s = summaries.get(phase_key)
|
|
56
|
+
if s:
|
|
57
|
+
summary_lines.append(f"- {label}: {s.get('objective', '(no objective)')}")
|
|
58
|
+
if s.get('key_changes'):
|
|
59
|
+
for c in s['key_changes'][:3]:
|
|
60
|
+
summary_lines.append(f" • {c}")
|
|
61
|
+
if s.get('findings'):
|
|
62
|
+
for f_ in s['findings'][:3]:
|
|
63
|
+
summary_lines.append(f" • {f_}")
|
|
64
|
+
if s.get('verdict') and s['verdict'] != 'n/a':
|
|
65
|
+
summary_lines.append(f" Verdict: {s['verdict']} Full: {s.get('artifact_ref', '(unknown)')}")
|
|
66
|
+
|
|
67
|
+
if summary_lines:
|
|
68
|
+
summary_block = (
|
|
69
|
+
"### Prior phase summaries (fast path — read full artifacts if you need more detail)\n\n"
|
|
70
|
+
+ "\n".join(summary_lines)
|
|
71
|
+
+ "\n\nIf any summary above is missing or insufficient, read the corresponding full artifact from disk before proceeding.\n\n"
|
|
72
|
+
)
|
|
73
|
+
else:
|
|
74
|
+
summary_block = ""
|
|
75
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Fragment: Event Emission Schema
|
|
2
|
+
|
|
3
|
+
<!-- Canonical contract: subagents write judgement-only SUMMARY files; the
|
|
4
|
+
orchestrator stitches runtime telemetry + judgement into the canonical
|
|
5
|
+
event and emits it. Referenced by meta-orchestrate.md and meta-fix-bug.md.
|
|
6
|
+
|
|
7
|
+
PLAN-11 / SLICE-2 (2026-05-14): the LLM no longer hand-builds event JSON.
|
|
8
|
+
Runtime facts (model, provider, eventId, timestamps, iteration, tokens)
|
|
9
|
+
are owned by the orchestrator, never the subagent. The subagent only
|
|
10
|
+
produces judgement and lets the orchestrator complete the record. -->
|
|
11
|
+
|
|
12
|
+
## Who writes what
|
|
13
|
+
|
|
14
|
+
| Actor | Owns (writes) | Never touches |
|
|
15
|
+
|--------------------|-------------------------------------------------------------------------------------------------|---------------|
|
|
16
|
+
| **Subagent (LLM)** | judgement fields: `verdict`, `notes`, `findings`, `objective`, `type` | `eventId`, `model`, `provider`, `startTimestamp`, `endTimestamp`, `durationMinutes`, `iteration`, `inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens`, `tokenSource` |
|
|
17
|
+
| **Orchestrator** | everything else — composes the canonical event from runtime telemetry + the subagent's SUMMARY | the judgement fields themselves (copies them through unchanged) |
|
|
18
|
+
|
|
19
|
+
The LLM is the wrong actor for runtime facts: it has no privileged access to
|
|
20
|
+
the model/provider it ran under, the wall clock at spawn time, or the token
|
|
21
|
+
counts reported by the runtime stream. Every LLM guess at these fields is
|
|
22
|
+
wrong by construction.
|
|
23
|
+
|
|
24
|
+
## What the subagent does
|
|
25
|
+
|
|
26
|
+
After completing its phase, the subagent writes one file:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
.forge/cache/{PHASE}-SUMMARY.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Examples: `PLAN-SUMMARY.json`, `REVIEW-PLAN-SUMMARY.json`,
|
|
33
|
+
`IMPLEMENT-SUMMARY.json`, `REVIEW-CODE-SUMMARY.json`, `COMMIT-SUMMARY.json`.
|
|
34
|
+
|
|
35
|
+
The SUMMARY contains judgement only. Required keys are phase-specific
|
|
36
|
+
(see `forge/schemas/phase-summary.schema.json` for the exact shape per
|
|
37
|
+
phase) but typically include `verdict`, `notes`, and any `findings`
|
|
38
|
+
the phase produces. The subagent **must not** include runtime fields —
|
|
39
|
+
adding `model`, `provider`, timestamps, or token counts to the SUMMARY is
|
|
40
|
+
ignored at best and rejected at worst.
|
|
41
|
+
|
|
42
|
+
The subagent **does not** call `store-cli emit` for phase events. That
|
|
43
|
+
shell-out is reserved for the orchestrator.
|
|
44
|
+
|
|
45
|
+
## What the orchestrator does
|
|
46
|
+
|
|
47
|
+
After the subagent returns, the orchestrator constructs the event from:
|
|
48
|
+
|
|
49
|
+
1. **Runtime telemetry** captured during the subagent run:
|
|
50
|
+
`model`, `provider`, token usage (`inputTokens`, `outputTokens`,
|
|
51
|
+
`cacheReadTokens`, `cacheWriteTokens`, `tokenSource: "reported"`).
|
|
52
|
+
2. **Known task context** the orchestrator already tracks for run-task:
|
|
53
|
+
`taskId`, `sprintId`, `phase`, `iteration`.
|
|
54
|
+
3. **Bracketed wall times** the orchestrator records around the subagent
|
|
55
|
+
call: `startTimestamp`, `endTimestamp`, `durationMinutes`.
|
|
56
|
+
4. **Judgement blob** read from `{PHASE}-SUMMARY.json`: `verdict`, `notes`,
|
|
57
|
+
`findings`, etc.
|
|
58
|
+
|
|
59
|
+
The orchestrator then emits via:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
node "$FORGE_ROOT/tools/store-cli.cjs" emit {sprintId} '{complete-event-json}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Why no example record here
|
|
66
|
+
|
|
67
|
+
This fragment intentionally contains **no hardcoded example model strings,
|
|
68
|
+
provider names, or timestamps**. Such examples were the historical source of
|
|
69
|
+
LLM hallucination — subagents would copy the example verbatim ("the model
|
|
70
|
+
is claude-sonnet-4-6 because the workflow says so") even when running on a
|
|
71
|
+
completely different runtime. The schema lives at
|
|
72
|
+
`.forge/schemas/event.schema.json`; consult it directly when verifying a
|
|
73
|
+
field set.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## Finalize: Subagent Closure
|
|
2
|
+
|
|
3
|
+
Before returning, every subagent MUST:
|
|
4
|
+
|
|
5
|
+
1. Write any phase-specific summary the workflow body requires (e.g. PLAN.md, CODE_REVIEW.md).
|
|
6
|
+
2. Confirm `task.status` reflects the phase outcome (via `store-cli update-status` if applicable).
|
|
7
|
+
3. Return cleanly.
|
|
8
|
+
|
|
9
|
+
**Subagents MUST NOT write token-usage sidecars.** Token telemetry is owned by the orchestrator, which captures provider-reported usage from the runtime as the subagent runs and emits the canonical event (with `provider`, `model`, `inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens`, `tokenSource: "reported"`) on the subagent's behalf.
|
|
10
|
+
|
|
11
|
+
If the runtime does not surface usage (rare), the orchestrator emits the event **without** the token fields — never with placeholder zeros or a `"missing"` marker. Honest absence beats misleading presence.
|
|
12
|
+
|
|
13
|
+
The `eventId` is passed by the orchestrator in the subagent prompt and is used only for non-token writes (e.g. `set-summary`, `update-status` history).
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<!-- Canonical Friction Emit fragment.
|
|
2
|
+
Referenced from meta-implement.md, meta-fix-bug.md, meta-validate.md,
|
|
3
|
+
meta-plan-task.md, and meta-orchestrate.md. /forge:enhance --phase 2
|
|
4
|
+
greps generated workflows for `## Friction Emit` to discover the channel.
|
|
5
|
+
|
|
6
|
+
PLAN-11 / SLICE-2 (2026-05-14): friction is now recorded via the
|
|
7
|
+
`friction-emit.cjs` tool which appends judgement-only records to
|
|
8
|
+
`.forge/cache/FRICTION-{workflow}.jsonl`. The orchestrator drains this
|
|
9
|
+
file at phase-end, stamps runtime attribution (model/provider/usage/
|
|
10
|
+
timestamps/eventId) onto each record, and emits the events. The LLM
|
|
11
|
+
never hand-builds a friction event JSON. -->
|
|
12
|
+
|
|
13
|
+
# Friction Emit (Fragment)
|
|
14
|
+
|
|
15
|
+
When the persona detects skill friction during the workflow — a referenced
|
|
16
|
+
skill is unused, fails on invocation, is missing from the registry, has gone
|
|
17
|
+
stale relative to current architecture, or is redundant with another skill —
|
|
18
|
+
record a judgement-only friction signal. The orchestrator drains the
|
|
19
|
+
signals and emits the corresponding events so `/forge:enhance --phase 2`
|
|
20
|
+
can act on them.
|
|
21
|
+
|
|
22
|
+
## Trigger conditions
|
|
23
|
+
|
|
24
|
+
Set `--issue` on the emitted record to one of the following tokens:
|
|
25
|
+
|
|
26
|
+
| Token | When to emit |
|
|
27
|
+
|--------------------|----------------------------------------------------------------------------------|
|
|
28
|
+
| `skill_unused` | A skill listed in the persona's skill block was loaded but never consulted. |
|
|
29
|
+
| `skill_failed` | A skill was consulted but its guidance produced an error or required correction. |
|
|
30
|
+
| `skill_missing` | The workflow needed guidance the available skills did not cover. |
|
|
31
|
+
| `skill_stale` | A skill's guidance contradicts current architecture / supersedes its own advice. |
|
|
32
|
+
| `skill_redundant` | Two skills provided overlapping or conflicting guidance for the same decision. |
|
|
33
|
+
|
|
34
|
+
Emit one record per distinct friction signal — do not coalesce multiple
|
|
35
|
+
findings into a single record.
|
|
36
|
+
|
|
37
|
+
## Judgement-only contract
|
|
38
|
+
|
|
39
|
+
The friction recorder accepts only judgement fields. Runtime-attribution
|
|
40
|
+
fields (`model`, `provider`, `eventId`, timestamps, token counts) are
|
|
41
|
+
**rejected** if passed — they belong to the orchestrator and are stamped on
|
|
42
|
+
at drain time.
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
node "$FORGE_ROOT/tools/friction-emit.cjs" \
|
|
46
|
+
--workflow {workflow-key} \
|
|
47
|
+
--persona {persona-noun} \
|
|
48
|
+
--issue skill_unused \
|
|
49
|
+
[--subkind skill_unused] \
|
|
50
|
+
[--evidence '{"trajectory_excerpt":"...","tool_errors":["..."],"retrieval_score":0.0,"skillId":"..."}']
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Required flags: `--workflow`, `--persona`, `--issue`.
|
|
54
|
+
Optional flags: `--subkind` (frozen enum
|
|
55
|
+
`skill_unused|skill_failed|skill_missing|skill_stale|skill_redundant`
|
|
56
|
+
or experimental `^x_[a-z_]+$`), `--evidence` (JSON object with
|
|
57
|
+
`trajectory_excerpt`, `tool_errors`, `retrieval_score` (0..1), `skillId`).
|
|
58
|
+
|
|
59
|
+
The tool appends one line of judgement-only JSON to
|
|
60
|
+
`.forge/cache/FRICTION-{workflow}.jsonl`. The orchestrator reads this file
|
|
61
|
+
after the phase completes, stamps each record with the captured runtime
|
|
62
|
+
attribution (model, provider, usage, wall times, eventId), and emits the
|
|
63
|
+
resulting events via `store-cli emit`.
|
|
64
|
+
|
|
65
|
+
## Per-workflow values
|
|
66
|
+
|
|
67
|
+
| Workflow | `workflow` | `persona` | `phase` |
|
|
68
|
+
|------------------|------------|---------------|--------------|
|
|
69
|
+
| meta-implement | implement | engineer | implement |
|
|
70
|
+
| meta-fix-bug | fix-bug | bug-fixer | fix-bug |
|
|
71
|
+
| meta-validate | validate | qa-engineer | validate |
|
|
72
|
+
| meta-plan-task | plan-task | architect | plan |
|
|
73
|
+
| meta-orchestrate | orchestrate| orchestrator | orchestrate |
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Fragment: Progress Reporting
|
|
2
|
+
|
|
3
|
+
<!-- Canonical progress log format and store-cli commands for orchestrator subagents.
|
|
4
|
+
Referenced by meta-orchestrate.md and meta-fix-bug.md. -->
|
|
5
|
+
|
|
6
|
+
Each subagent writes progress entries to a transient log file that the
|
|
7
|
+
orchestrator monitors in real time.
|
|
8
|
+
|
|
9
|
+
**Log path:** `.forge/store/events/{sprintId}/progress.log`
|
|
10
|
+
|
|
11
|
+
**Format per line:**
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
{ISO_TIMESTAMP}|{agent_name}|{banner_key}|{status}|{detail}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
| Field | Format | Example |
|
|
18
|
+
|-------|--------|---------|
|
|
19
|
+
| `ISO_TIMESTAMP` | ISO 8601 UTC | `2026-04-16T14:15:23Z` |
|
|
20
|
+
| `agent_name` | `{taskId}:{persona_noun}:{phase.role}:{iteration}` | `FORGE-S09-T01:engineer:plan:1` |
|
|
21
|
+
| `banner_key` | Banner identity key from BANNER_MAP | `forge` |
|
|
22
|
+
| `status` | One of: `start`, `progress`, `done`, `error` | `progress` |
|
|
23
|
+
| `detail` | Free text (no pipe characters) | `Reading codebase` |
|
|
24
|
+
|
|
25
|
+
**Writing entries:** Use `store-cli progress`:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
node "$FORGE_ROOT/tools/store-cli.cjs" progress {sprintId} {agentName} {bannerKey} {status} "detail text"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Monitoring:** The orchestrator starts a Monitor on the progress log before
|
|
32
|
+
spawning each subagent and stops it after the subagent returns.
|
|
33
|
+
|
|
34
|
+
**Clearing:** The orchestrator clears the progress log at task start:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
node "$FORGE_ROOT/tools/store-cli.cjs" progress-clear {sprintId}
|
|
38
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Fragment: store-cli Verb Cheat-Sheet
|
|
2
|
+
|
|
3
|
+
<!-- Canonical store-cli verb list. Referenced by meta workflows that issue
|
|
4
|
+
store-cli calls. Surface it inline near the first store-cli invocation
|
|
5
|
+
so subagents stop inventing REST-style verbs (`get`, `set`, `delete`)
|
|
6
|
+
when they have to improvise a follow-up call. See forge#95 and
|
|
7
|
+
FORGE-S22-T02 (read-aliases). -->
|
|
8
|
+
|
|
9
|
+
store-cli verbs: `read` | `list` | `write` | `emit` | `update-status` | `set-summary` | `set-bug-summary` | `describe` | `template` | `nlp` | `query` | `delete`
|
|
10
|
+
|
|
11
|
+
Read-aliases (FORGE-S22-T02): `get` | `get-task` | `get-bug` | `get-sprint` | `get-summary` | `get-bug-summary`
|
|
12
|
+
|
|
13
|
+
Notes for subagents:
|
|
14
|
+
|
|
15
|
+
- **`read`** is the canonical "fetch one record" verb. The aliases
|
|
16
|
+
`get <entity> <id>`, `get-task <id>`, `get-bug <id>`, `get-sprint <id>`
|
|
17
|
+
are accepted and delegate byte-equally to `read`. Prefer the canonical
|
|
18
|
+
`read` form in new code; aliases exist to reduce friction when an agent
|
|
19
|
+
reaches for REST-style verbs.
|
|
20
|
+
- **`get-summary <taskId> <phase>`** and **`get-bug-summary <bugId> <phase>`**
|
|
21
|
+
are direct summary readers — they extract `record.summaries[phase]` and
|
|
22
|
+
exit 1 if the phase is absent. They are NOT write verbs (do not confuse
|
|
23
|
+
with `set-summary` / `set-bug-summary`).
|
|
24
|
+
- **`list`** filters by entity (`sprint`, `task`, `bug`, `event`, `feature`)
|
|
25
|
+
and optional flags. There is no `find` or `search` — use `nlp` for
|
|
26
|
+
natural-language lookup.
|
|
27
|
+
- **`update-status`** is the ONLY supported task/bug status mutation path.
|
|
28
|
+
Do not `write` a task back with a new `status` field; the FSM is enforced
|
|
29
|
+
by `update-status`.
|
|
30
|
+
- **`emit`** appends an event. There is no `append-event` / `add-event`.
|
|
31
|
+
- **`set-summary`** / **`set-bug-summary`** write summary sidecars referenced
|
|
32
|
+
from the entity record. Do not inline summaries into the entity via `write`.
|
|
33
|
+
- If you need a verb not on this list, run
|
|
34
|
+
`node "$FORGE_ROOT/tools/store-cli.cjs" --help` before improvising.
|
|
35
|
+
- If you supply an unknown verb, entity type, enum value, or field name,
|
|
36
|
+
store-cli appends a **Did you mean?** suggestion to the error message.
|
|
37
|
+
Suggestions use Levenshtein distance (≤ 2) and a curated drift map for
|
|
38
|
+
common agent misconceptions (e.g., `completed` → `committed`,
|
|
39
|
+
`task` → `taskId`, `set` → `set-summary`). See FORGE-S22-T03.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
requirements:
|
|
3
|
+
reasoning: High
|
|
4
|
+
context: Medium
|
|
5
|
+
speed: Low
|
|
6
|
+
audience: subagent
|
|
7
|
+
phase: approve
|
|
8
|
+
context:
|
|
9
|
+
architecture: true
|
|
10
|
+
prior_summaries: all
|
|
11
|
+
persona: summary
|
|
12
|
+
master_index: false
|
|
13
|
+
diff_mode: false
|
|
14
|
+
deps:
|
|
15
|
+
personas: [architect]
|
|
16
|
+
skills: [architect, generic]
|
|
17
|
+
templates: []
|
|
18
|
+
sub_workflows: []
|
|
19
|
+
kb_docs: [architecture/stack.md]
|
|
20
|
+
config_fields: [paths.engineering]
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# 🗻 Meta-Workflow: Approve Task
|
|
24
|
+
|
|
25
|
+
## Purpose
|
|
26
|
+
|
|
27
|
+
The Architect gives final sign-off on a completed task after Supervisor approval. This is the last gate before commit.
|
|
28
|
+
|
|
29
|
+
## Iron Laws
|
|
30
|
+
|
|
31
|
+
- Approve only when the implementation is consistent with the project's architecture and the deployment posture is understood. Architectural sign-off is not a rubber stamp — it is the last point at which cross-cutting concerns can be caught cheaply.
|
|
32
|
+
- Read `.forge/personas/architect.md` first; print the persona identity line (emoji, name, tagline) to stdout before any other tool use.
|
|
33
|
+
- All store I/O via `forge_store` (or `node "$FORGE_ROOT/tools/store-cli.cjs"`). Never edit `.forge/store/*.json` directly.
|
|
34
|
+
|
|
35
|
+
## Store-Write Verification
|
|
36
|
+
|
|
37
|
+
Every `forge_store` write MUST succeed before advancing. If `store-cli` exits
|
|
38
|
+
non-zero or the `PreToolUse` write-boundary hook blocks the call (exit 2):
|
|
39
|
+
|
|
40
|
+
1. Parse the structured error (names the offending field + schema file).
|
|
41
|
+
2. Correct the JSON to satisfy the schema.
|
|
42
|
+
3. Retry. Repeat up to 3 times.
|
|
43
|
+
4. After 3 failures, halt and escalate with original payload, corrected payload, and all error messages.
|
|
44
|
+
|
|
45
|
+
Never set `FORGE_SKIP_WRITE_VALIDATION=1` — operator-only emergency switch.
|
|
46
|
+
|
|
47
|
+
## Algorithm
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
0. Pre-flight Gate Check:
|
|
52
|
+
- Resolve FORGE_ROOT (`node -e "console.log(require('./.forge/config.json').paths.forgeRoot)"`).
|
|
53
|
+
- **Entity-mode resolution:** read the kickoff arguments. `--task {id}` → `entity_kind = "task"`, `record_id = {id}`. `--bug {id}` → `entity_kind = "bug"`, `record_id = {id}`. All store-cli calls below substitute `{entity_kind}` and `{record_id}` for the literal "task"/{taskId} placeholders.
|
|
54
|
+
- Run: `node "$FORGE_ROOT/tools/preflight-gate.cjs" --phase approve --{entity_kind} {record_id}`
|
|
55
|
+
- Exit 1 (gate failed) → print stderr and HALT. Do not proceed; do not attempt to produce the artifact.
|
|
56
|
+
- Exit 2 (misconfiguration) → print stderr and HALT.
|
|
57
|
+
- Exit 0 → continue.
|
|
58
|
+
1. Load Context:
|
|
59
|
+
- Read task prompt
|
|
60
|
+
- Read final PLAN.md
|
|
61
|
+
- Read approved CODE_REVIEW.md
|
|
62
|
+
- Read PROGRESS.md
|
|
63
|
+
|
|
64
|
+
2. Architectural Review:
|
|
65
|
+
- Verify implementation aligns with project architecture
|
|
66
|
+
- Check for cross-cutting concerns (impact on other modules)
|
|
67
|
+
- Assess operational impact (deployment changes, migrations)
|
|
68
|
+
|
|
69
|
+
3. Sign Off:
|
|
70
|
+
- Write ARCHITECT_APPROVAL.md containing:
|
|
71
|
+
- A canonical verdict line for human readers, on its own line, in this exact form:
|
|
72
|
+
```
|
|
73
|
+
**Verdict:** [Approved | Revision Required]
|
|
74
|
+
```
|
|
75
|
+
- Approval status rationale
|
|
76
|
+
- Deployment notes
|
|
77
|
+
- Follow-up items for future sprints
|
|
78
|
+
- The downstream commit-phase preflight gate does NOT read this markdown. **Task mode:** it reads `task.status === "approved"` set in step 4. **Bug mode:** it reads `bug.summaries.approve.verdict === "approved"` set in step 5. The `**Verdict:**` line is a human breadcrumb only.
|
|
79
|
+
|
|
80
|
+
4. Finalize:
|
|
81
|
+
- Transitions:
|
|
82
|
+
- **Task mode** — Update status: `node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {taskId} status approved`. The status IS the verdict signal for task-mode commit gate (`STATUS_SOURCE` in `read-verdict.cjs`).
|
|
83
|
+
- **Bug mode** — NO status write. The bug remains `in-progress`. The verdict signal travels through `summaries.approve.verdict` written in step 5 below (read by `read-verdict.cjs § BUG_PHASE_VERDICT_SOURCE`). Writing `bug.status` here — especially writing `approved` or `verified` — violates `meta-fix-bug.md § Iron Laws #2` and is the trap that produced the FORGE-BUG-002 regression.
|
|
84
|
+
- **Do NOT emit a phase event yourself.** The orchestrator (or kickoff handler) 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.
|
|
85
|
+
|
|
86
|
+
5. Emit Summary Sidecar:
|
|
87
|
+
- Write `APPROVE-SUMMARY.json` to the record's directory with the following shape:
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"objective": "<one sentence — what this approval covered>",
|
|
91
|
+
"findings": ["<up to 12 bullets, 200 chars each — architectural notes, deployment concerns>"],
|
|
92
|
+
"verdict": "<approved | revision>",
|
|
93
|
+
"written_at": "<current ISO 8601 timestamp>",
|
|
94
|
+
"artifact_ref":"ARCHITECT_APPROVAL.md"
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
- Call (task mode) — optional for tasks, since `task.status` is the canonical signal:
|
|
98
|
+
```
|
|
99
|
+
node "$FORGE_ROOT/tools/store-cli.cjs" set-summary {taskId} approve \
|
|
100
|
+
engineering/sprints/{sprint}/{task}/APPROVE-SUMMARY.json
|
|
101
|
+
```
|
|
102
|
+
Or (bug mode) — REQUIRED for bugs, this is the canonical verdict signal:
|
|
103
|
+
```
|
|
104
|
+
node "$FORGE_ROOT/tools/store-cli.cjs" set-bug-summary {bugId} approve \
|
|
105
|
+
engineering/bugs/{bugDir}/APPROVE-SUMMARY.json
|
|
106
|
+
```
|
|
107
|
+
- In bug mode, if the set-bug-summary call exits non-zero, fix the sidecar JSON and retry. Do not return without a valid summary — the downstream commit gate has no other way to read the approval verdict.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Generation Instructions
|
|
111
|
+
|
|
112
|
+
- **Workflow Structure:** The generated `approve_task.md` must follow the strict "Algorithm" block format.
|
|
113
|
+
- **Verdict Detection:** Instruct the architect to write a literal `**Verdict:** [Approved | Revision Required]` line in ARCHITECT_APPROVAL.md for human readability. Downstream gates read `task.status` via read-verdict.cjs, not this markdown — but the line remains a useful breadcrumb for operators reviewing artifacts.
|
|
114
|
+
- **Context Isolation:** Forbid inline execution of complex architectural analysis; use the `Agent` tool for sub-tasks.
|
|
115
|
+
- **Project Specifics:**
|
|
116
|
+
- Reference project's architecture docs.
|
|
117
|
+
- Include project-specific deployment concerns.
|
|
118
|
+
- **Token Reporting:** See `_fragments/finalize.md` — wire via `file_ref:`.
|
|
119
|
+
- **Event Emission:** Ensure the "complete" event includes the `eventId` passed by the orchestrator.
|