@entelligentsia/forgecli 1.0.10 → 1.0.20
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 +191 -0
- package/dist/CHANGELOG-forge-plugin.md +211 -0
- package/dist/bin/forge.js +0 -0
- package/dist/extensions/forgecli/config-layer.js.map +1 -1
- package/dist/extensions/forgecli/context-governor-compaction.d.ts +83 -0
- package/dist/extensions/forgecli/context-governor-compaction.js +302 -0
- package/dist/extensions/forgecli/context-governor-compaction.js.map +1 -0
- package/dist/extensions/forgecli/context-governor.d.ts +173 -0
- package/dist/extensions/forgecli/context-governor.js +618 -0
- package/dist/extensions/forgecli/context-governor.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/component.d.ts +105 -0
- package/dist/extensions/forgecli/dashboard/component.js +861 -0
- package/dist/extensions/forgecli/dashboard/component.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/register.d.ts +2 -0
- package/dist/extensions/forgecli/dashboard/register.js +31 -0
- package/dist/extensions/forgecli/dashboard/register.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/theme.d.ts +27 -0
- package/dist/extensions/forgecli/dashboard/theme.js +91 -0
- package/dist/extensions/forgecli/dashboard/theme.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/view-model.d.ts +35 -0
- package/dist/extensions/forgecli/dashboard/view-model.js +54 -0
- package/dist/extensions/forgecli/dashboard/view-model.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.js +126 -7
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js +2 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
- package/dist/extensions/forgecli/forge-commands.js +1 -0
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/phase4-register.js +53 -0
- package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +20 -1
- package/dist/extensions/forgecli/forge-subagent.js +23 -7
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-tools.js +3 -1
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/hook-dispatcher.d.ts +3 -1
- package/dist/extensions/forgecli/hook-dispatcher.js +37 -3
- package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
- package/dist/extensions/forgecli/index.js +38 -1
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/lib/halt-advisor.d.ts +59 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js +113 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js.map +1 -0
- package/dist/extensions/forgecli/migration-engine.js +25 -12
- package/dist/extensions/forgecli/migration-engine.js.map +1 -1
- package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +26 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js +213 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js.map +1 -0
- package/dist/extensions/forgecli/orchestrator-tree.d.ts +96 -0
- package/dist/extensions/forgecli/orchestrator-tree.js +390 -0
- package/dist/extensions/forgecli/orchestrator-tree.js.map +1 -0
- package/dist/extensions/forgecli/project-orientation.js +12 -8
- package/dist/extensions/forgecli/project-orientation.js.map +1 -1
- package/dist/extensions/forgecli/regenerate.d.ts +16 -0
- package/dist/extensions/forgecli/regenerate.js +110 -0
- package/dist/extensions/forgecli/regenerate.js.map +1 -1
- package/dist/extensions/forgecli/run-sprint.d.ts +3 -1
- package/dist/extensions/forgecli/run-sprint.js +34 -3
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +66 -1
- package/dist/extensions/forgecli/run-task.js +323 -12
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.d.ts +4 -1
- package/dist/extensions/forgecli/thread-switcher.js +118 -762
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/viewport-events.js +32 -0
- package/dist/extensions/forgecli/viewport-events.js.map +1 -1
- package/dist/forge-payload/.base-pack/commands/fix-bug.md +1 -1
- package/dist/forge-payload/.base-pack/commands/run-sprint.md +1 -1
- package/dist/forge-payload/.base-pack/commands/run-task.md +1 -1
- package/dist/forge-payload/.base-pack/personas/architect.md +1 -1
- package/dist/forge-payload/.base-pack/personas/bug-fixer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/collator.md +3 -3
- package/dist/forge-payload/.base-pack/personas/engineer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/librarian.md +1 -1
- package/dist/forge-payload/.base-pack/personas/orchestrator.md +1 -1
- package/dist/forge-payload/.base-pack/personas/product-manager.md +1 -1
- package/dist/forge-payload/.base-pack/personas/qa-engineer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/supervisor.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/friction-emit.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/progress-reporting.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/_fragments/store-cli-verbs.md +11 -2
- package/dist/forge-payload/.base-pack/workflows/architect_approve.md +6 -7
- package/dist/forge-payload/.base-pack/workflows/architect_review_sprint_completion.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/architect_sprint_intake.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/architect_sprint_plan.md +5 -5
- package/dist/forge-payload/.base-pack/workflows/collator_agent.md +4 -6
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +5 -6
- package/dist/forge-payload/.base-pack/workflows/enhance.md +5 -5
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +15 -7
- package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +12 -13
- package/dist/forge-payload/.base-pack/workflows/plan_task.md +12 -6
- package/dist/forge-payload/.base-pack/workflows/review_code.md +12 -11
- package/dist/forge-payload/.base-pack/workflows/review_plan.md +12 -11
- package/dist/forge-payload/.base-pack/workflows/sprint_retrospective.md +3 -3
- package/dist/forge-payload/.base-pack/workflows/triage.md +12 -9
- package/dist/forge-payload/.base-pack/workflows/update_implementation.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/update_plan.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/validate_task.md +9 -9
- package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +490 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-sprint.js +416 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +608 -0
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/config.schema.json +2 -3
- package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/.schemas/event.schema.json +16 -0
- package/dist/forge-payload/.schemas/migrations.json +359 -18
- package/dist/forge-payload/commands/health.md +29 -0
- package/dist/forge-payload/commands/rebuild.md +143 -15
- package/dist/forge-payload/commands/update.md +28 -27
- package/dist/forge-payload/hooks/preflight-session.cjs +99 -0
- package/dist/forge-payload/init/phases/phase-3-materialize.md +18 -5
- package/dist/forge-payload/integrity.json +7 -6
- package/dist/forge-payload/meta/fragments/tool-discipline.md +1 -1
- package/dist/forge-payload/meta/personas/meta-architect.md +1 -1
- package/dist/forge-payload/meta/personas/meta-bug-fixer.md +1 -1
- package/dist/forge-payload/meta/personas/meta-collator.md +7 -7
- package/dist/forge-payload/meta/personas/meta-engineer.md +1 -1
- package/dist/forge-payload/meta/personas/meta-orchestrator.md +1 -1
- package/dist/forge-payload/meta/personas/meta-supervisor.md +1 -1
- package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +2 -2
- package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +11 -2
- package/dist/forge-payload/meta/workflows/meta-approve.md +6 -7
- package/dist/forge-payload/meta/workflows/meta-bug-triage.md +12 -9
- package/dist/forge-payload/meta/workflows/meta-collate.md +5 -7
- package/dist/forge-payload/meta/workflows/meta-commit.md +5 -6
- package/dist/forge-payload/meta/workflows/meta-enhance.md +5 -5
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +35 -11
- package/dist/forge-payload/meta/workflows/meta-implement.md +15 -7
- package/dist/forge-payload/meta/workflows/meta-migrate.md +13 -14
- package/dist/forge-payload/meta/workflows/meta-new-sprint.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +138 -39
- package/dist/forge-payload/meta/workflows/meta-plan-sprint.md +6 -6
- package/dist/forge-payload/meta/workflows/meta-plan-task.md +12 -6
- package/dist/forge-payload/meta/workflows/meta-retro.md +4 -4
- package/dist/forge-payload/meta/workflows/meta-retrospective.md +4 -4
- package/dist/forge-payload/meta/workflows/meta-review-implementation.md +12 -11
- package/dist/forge-payload/meta/workflows/meta-review-plan.md +12 -11
- package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +6 -6
- package/dist/forge-payload/meta/workflows/meta-update-implementation.md +2 -2
- package/dist/forge-payload/meta/workflows/meta-update-plan.md +2 -2
- package/dist/forge-payload/meta/workflows/meta-validate.md +9 -9
- package/dist/forge-payload/schemas/config.schema.json +2 -3
- package/dist/forge-payload/schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/schemas/event.schema.json +16 -0
- package/dist/forge-payload/schemas/structure-manifest.json +75 -73
- package/dist/forge-payload/skills/refresh-kb-links/SKILL.md +14 -7
- package/dist/forge-payload/tools/banners.cjs +29 -10
- package/dist/forge-payload/tools/check-structure.cjs +88 -7
- package/dist/forge-payload/tools/collate.cjs +48 -2
- package/dist/forge-payload/tools/manage-config.cjs +5 -7
- package/dist/forge-payload/tools/parse-gates.cjs +73 -1
- package/dist/forge-payload/tools/postflight-gate.cjs +298 -0
- package/dist/forge-payload/tools/preflight-gate.cjs +47 -0
- package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -4
- package/dist/forge-payload/tools/verify-phase.cjs +17 -0
- package/package.json +2 -2
- package/dist/bin/forgecli.d.ts +0 -2
- package/dist/bin/forgecli.js +0 -6
- package/dist/bin/forgecli.js.map +0 -1
- package/dist/extensions/forgecli/config-tui/index.d.ts +0 -5
- package/dist/extensions/forgecli/config-tui/index.js +0 -5
- package/dist/extensions/forgecli/config-tui/index.js.map +0 -1
- package/dist/extensions/forgecli/loaders/persona-skill-loader.d.ts +0 -45
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js +0 -227
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js.map +0 -1
- package/dist/extensions/forgecli/loaders/template-render.d.ts +0 -20
- package/dist/extensions/forgecli/loaders/template-render.js +0 -85
- package/dist/extensions/forgecli/loaders/template-render.js.map +0 -1
- package/dist/extensions/forgecli/loaders/workflow-loader.d.ts +0 -41
- package/dist/extensions/forgecli/loaders/workflow-loader.js +0 -164
- package/dist/extensions/forgecli/loaders/workflow-loader.js.map +0 -1
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +0 -446
- package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +0 -928
- package/dist/forge-payload/.base-pack/workflows/run_sprint.md +0 -225
|
@@ -21,6 +21,38 @@ deps:
|
|
|
21
21
|
Wire the atomic workflows into a pipeline that drives a single task through
|
|
22
22
|
the complete lifecycle. This is the task state machine.
|
|
23
23
|
|
|
24
|
+
## Session Preflight (run once, before the phase loop)
|
|
25
|
+
|
|
26
|
+
The deterministic pre-dispatch glue — FORGE_ROOT resolution, config
|
|
27
|
+
reconciliation, generation-manifest state, calibration-baseline freshness,
|
|
28
|
+
MASTER_INDEX hashing, and the structure check — is bundled into a single
|
|
29
|
+
deterministic tool, `forge/tools/forge-preflight.cjs`. **Do NOT hand-run these
|
|
30
|
+
checks turn-by-turn.** Read the one compact blob it produces, once, at the top
|
|
31
|
+
of the orchestration:
|
|
32
|
+
|
|
33
|
+
1. The SessionStart hook (`hooks/preflight-session.cjs`) primes the blob at
|
|
34
|
+
`.forge/cache/preflight-status.json` for any project that has a `.forge/`
|
|
35
|
+
directory. Read that file. If it is absent or stale, run the tool once:
|
|
36
|
+
`node .forge/tools/forge-preflight.cjs` and read its stdout.
|
|
37
|
+
2. Branch on `blob.ok`:
|
|
38
|
+
- **`ok: true`** → proceed to the phase loop using `blob.forgeRoot` and the
|
|
39
|
+
recorded state. Do not re-derive any field the blob already carries
|
|
40
|
+
(`masterIndexHash`, `calibrationFresh`, `manifestState`, `structureOk`);
|
|
41
|
+
surface `calibrationFresh.suggest` to the operator if `fresh` is false, but
|
|
42
|
+
this is advisory and does not block the run.
|
|
43
|
+
- **`ok: false`** → **halt before phase 1** (fast-fail-safe). This is a
|
|
44
|
+
pre-dispatch halt: print `blob.warnings`, route through the existing
|
|
45
|
+
escalation idiom (see `§ Escalation Procedure`) — emit the standard
|
|
46
|
+
escalation event and message — and instruct the operator to fix the
|
|
47
|
+
surfaced preflight warning and re-run. A half-initialized run must never
|
|
48
|
+
proceed.
|
|
49
|
+
|
|
50
|
+
The blob is the single source of truth for these concerns for the remainder of
|
|
51
|
+
the run. The SessionStart hook is command-name-independent (SessionStart fires
|
|
52
|
+
before any command and carries no per-command signal); the scoping to
|
|
53
|
+
run-task / fix-bug / run-sprint contexts lives here, in the orchestration
|
|
54
|
+
preamble, which only those commands reach.
|
|
55
|
+
|
|
24
56
|
## Pipeline Phases
|
|
25
57
|
|
|
26
58
|
Each phase has:
|
|
@@ -116,7 +148,7 @@ Each phase subagent is responsible for reporting its own token usage via a sidec
|
|
|
116
148
|
Do NOT shell out to a `cost-cli.cjs` — there is no such tool.
|
|
117
149
|
2. Parse the output for the five fields:
|
|
118
150
|
`inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens`, `estimatedCostUSD`.
|
|
119
|
-
3. Write the usage sidecar via `node
|
|
151
|
+
3. Write the usage sidecar via `node .forge/tools/store-cli.cjs emit {sprintId} '{sidecar-json}' --sidecar` with the exact format:
|
|
120
152
|
```json
|
|
121
153
|
{
|
|
122
154
|
"inputTokens": <integer>,
|
|
@@ -234,11 +266,26 @@ def compose_role_block(persona_noun):
|
|
|
234
266
|
**Rollback:** set `FORGE_PROMPT_MODE=inline`. No persisted state to revert.
|
|
235
267
|
The `inline` branch will be removed one version after `reference` ships.
|
|
236
268
|
|
|
269
|
+
> **Scope note (added FORGE-S27-T02, 2026-05-31):** `FORGE_PROMPT_MODE=inline` restores
|
|
270
|
+
> the **role block only** — full verbatim persona + skill file contents. It does NOT restore
|
|
271
|
+
> the full `MASTER_INDEX`: the overlay (`build-overlay.cjs`, line 462) is unconditional and
|
|
272
|
+
> delivers the same task-scoped slice in both modes. It also does NOT affect the workflow file,
|
|
273
|
+
> which is read verbatim from disk in both modes. There is currently no per-call escape hatch
|
|
274
|
+
> to the full `MASTER_INDEX` — a separate overlay-bypass flag would be required.
|
|
275
|
+
|
|
237
276
|
## Execution Algorithm
|
|
238
277
|
|
|
239
278
|
The orchestrator MUST follow this procedure exactly. Do not deviate.
|
|
240
279
|
|
|
241
280
|
```
|
|
281
|
+
# --- Utility helpers ---
|
|
282
|
+
def safe_parse_json(text):
|
|
283
|
+
"""Attempt to parse a JSON string; return dict or None on failure."""
|
|
284
|
+
try:
|
|
285
|
+
return json.loads(text.strip()) if text and text.strip() else None
|
|
286
|
+
except Exception:
|
|
287
|
+
return None
|
|
288
|
+
|
|
242
289
|
# --- Persona symbol lookup (emoji, name, tagline) ---
|
|
243
290
|
PERSONA_MAP = {
|
|
244
291
|
"plan": ("🌱", "Engineer", "I plan what will be built before any code is written."),
|
|
@@ -314,7 +361,7 @@ for each task in dependency_sorted(tasks):
|
|
|
314
361
|
|
|
315
362
|
# --- Clear progress log for this sprint ---
|
|
316
363
|
progress_log_path = f".forge/store/events/{sprint_id}/progress.log"
|
|
317
|
-
run_bash(f'
|
|
364
|
+
run_bash(f'node .forge/tools/store-cli.cjs progress-clear {sprint_id}')
|
|
318
365
|
|
|
319
366
|
while i < len(phases):
|
|
320
367
|
phase = phases[i]
|
|
@@ -359,9 +406,27 @@ for each task in dependency_sorted(tasks):
|
|
|
359
406
|
agent_name = f"{task_id}:{persona_noun}:{phase.role}:{iteration}"
|
|
360
407
|
|
|
361
408
|
# --- Announce phase with identity banner (badge) + task context ---
|
|
409
|
+
# --quiet makes banners.cjs emit zero stdout (unconditional; no isTTY branch).
|
|
410
|
+
# The badge is fully suppressed during the automated run_bash call — it does
|
|
411
|
+
# not enter the LLM context window and is not shown on the human terminal.
|
|
412
|
+
# The human-visible per-phase marker is the print() line below.
|
|
413
|
+
#
|
|
414
|
+
# Digest-compliance note (FORGE-S27-T03): every deterministic tool call this
|
|
415
|
+
# loop body makes is already digest-compliant on its success path:
|
|
416
|
+
# store-cli write verbs (update-status, emit, merge-sidecar, set-summary,
|
|
417
|
+
# progress-clear) → silent on success.
|
|
418
|
+
# preflight-gate.cjs → silent on success (stderr only on failure).
|
|
419
|
+
# read-verdict.cjs → one load-bearing token (e.g. "approved"); orchestrator
|
|
420
|
+
# branches on it — must not be suppressed.
|
|
421
|
+
# banners.cjs --badge → 1-line ANSI badge; made zero-cost via --quiet below.
|
|
422
|
+
# build-overlay.cjs → ~1185 chars captured into overlay_md and injected into
|
|
423
|
+
# the subagent prompt as Project Context. This is payload
|
|
424
|
+
# data, not a log — reducing it would break prompt assembly.
|
|
425
|
+
# Reference-mode redesign is deferred to the T02/forge-compress
|
|
426
|
+
# work; leave unchanged here.
|
|
362
427
|
emoji, persona_name, tagline = PERSONA_MAP.get(phase.role, ("🌊", "Orchestrator", "I move tasks through their lifecycle."))
|
|
363
428
|
banner_name = BANNER_MAP.get(phase.role, "forge")
|
|
364
|
-
run_bash(f'
|
|
429
|
+
run_bash(f'node .forge/tools/banners.cjs --badge {banner_name} --quiet')
|
|
365
430
|
print(f" → {task_id} [{display_model}]\n")
|
|
366
431
|
|
|
367
432
|
# --- Start progress Monitor before spawning subagent ---
|
|
@@ -374,23 +439,35 @@ for each task in dependency_sorted(tasks):
|
|
|
374
439
|
)
|
|
375
440
|
|
|
376
441
|
# --- Pre-flight gate check (see Phase Gates below) ---
|
|
377
|
-
# Resolve FORGE_ROOT once
|
|
442
|
+
# Resolve FORGE_ROOT once (needed for meta/workflows fragment reads below).
|
|
378
443
|
FORGE_ROOT = resolve_forge_root()
|
|
379
444
|
preflight_result = run_bash(
|
|
380
|
-
f'node
|
|
445
|
+
f'node .forge/tools/preflight-gate.cjs --phase {phase.role} --task {task_id}'
|
|
381
446
|
)
|
|
382
447
|
if preflight_result.exit_code == 1:
|
|
383
448
|
# Gate failed: halt the orchestrator loop for THIS task. Do not retry,
|
|
384
|
-
# do not spawn.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
449
|
+
# do not spawn. Structured failure JSON is on stdout; human-readable detail on stderr.
|
|
450
|
+
# Parse the structured JSON for a user-friendly advisory.
|
|
451
|
+
gate_failure = safe_parse_json(preflight_result.stdout)
|
|
452
|
+
if gate_failure:
|
|
453
|
+
reason_code = gate_failure.get("reasonCode", "unknown")
|
|
454
|
+
gate_detail = gate_failure.get("detail", preflight_result.stderr.strip())
|
|
455
|
+
gate_remedy = gate_failure.get("remediation", "")
|
|
456
|
+
print(f" ✗ {task_id} {phase.role} — gate failed [{reason_code}]")
|
|
457
|
+
print(f" Detail: {gate_detail}")
|
|
458
|
+
print(f" Remediation: {gate_remedy}")
|
|
459
|
+
gate_notes = f"gate_failed [{reason_code}]: {gate_detail}"
|
|
460
|
+
else:
|
|
461
|
+
print(f" ✗ {task_id} {phase.role} — gate failed\n{preflight_result.stderr}")
|
|
462
|
+
gate_notes = f"gate_failed: {preflight_result.stderr}"
|
|
463
|
+
append_progress(progress_log_path, f"❌ Gate failed for {phase.role}: {gate_notes}")
|
|
464
|
+
emit_event(task, phase, action="gate_failed", notes=gate_notes)
|
|
388
465
|
# ---- ESCALATION (mandatory hard stop — do NOT continue) ----
|
|
389
|
-
run_bash(f'node
|
|
466
|
+
run_bash(f'node .forge/tools/store-cli.cjs update-status task {task_id} status escalated')
|
|
390
467
|
emit_event(task, phase, eventId=event_id, iteration=iteration,
|
|
391
468
|
action="escalated", verdict="escalated",
|
|
392
|
-
notes=
|
|
393
|
-
print(f" ⚠ Task {task_id} escalated:
|
|
469
|
+
notes=gate_notes)
|
|
470
|
+
print(f" ⚠ Task {task_id} escalated: {gate_notes}\n")
|
|
394
471
|
print(f" Review artifact: {artifact_path}\n")
|
|
395
472
|
print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
|
|
396
473
|
break # stop processing this task
|
|
@@ -398,7 +475,7 @@ for each task in dependency_sorted(tasks):
|
|
|
398
475
|
# Misconfiguration (unknown phase, malformed gates block). Fail loud.
|
|
399
476
|
print(f" ⚠ {task_id} {phase.role} — gate misconfigured\n{preflight_result.stderr}")
|
|
400
477
|
# ---- ESCALATION (mandatory hard stop — do NOT continue) ----
|
|
401
|
-
run_bash(f'node
|
|
478
|
+
run_bash(f'node .forge/tools/store-cli.cjs update-status task {task_id} status escalated')
|
|
402
479
|
emit_event(task, phase, eventId=event_id, iteration=iteration,
|
|
403
480
|
action="escalated", verdict="escalated",
|
|
404
481
|
notes=f"gate_misconfigured: {preflight_result.stderr}")
|
|
@@ -428,7 +505,7 @@ for each task in dependency_sorted(tasks):
|
|
|
428
505
|
|
|
429
506
|
# --- Materialize project overlay (replaces MASTER_INDEX.md read in subagent) ---
|
|
430
507
|
overlay_result = run_bash(
|
|
431
|
-
f'node
|
|
508
|
+
f'node .forge/tools/build-overlay.cjs --task {task_id} --format md'
|
|
432
509
|
)
|
|
433
510
|
overlay_md = overlay_result.stdout if overlay_result.exit_code == 0 else ""
|
|
434
511
|
|
|
@@ -526,7 +603,7 @@ for each task in dependency_sorted(tasks):
|
|
|
526
603
|
emit_event(task, phase, action="subagent_escalated",
|
|
527
604
|
notes=f"second failure: {subagent_failure_reason(result)}")
|
|
528
605
|
# ---- ESCALATION (mandatory hard stop — do NOT continue) ----
|
|
529
|
-
run_bash(f'node
|
|
606
|
+
run_bash(f'node .forge/tools/store-cli.cjs update-status task {task_id} status escalated')
|
|
530
607
|
emit_event(task, phase, eventId=event_id, iteration=iteration,
|
|
531
608
|
action="escalated", verdict="escalated",
|
|
532
609
|
notes=f"subagent failed after retry: {subagent_failure_reason(result)}")
|
|
@@ -539,7 +616,7 @@ for each task in dependency_sorted(tasks):
|
|
|
539
616
|
emit_event(task, phase, action="subagent_escalated",
|
|
540
617
|
notes=f"second failure: {subagent_failure_reason(result)}")
|
|
541
618
|
# ---- ESCALATION (mandatory hard stop — do NOT continue) ----
|
|
542
|
-
run_bash(f'node
|
|
619
|
+
run_bash(f'node .forge/tools/store-cli.cjs update-status task {task_id} status escalated')
|
|
543
620
|
emit_event(task, phase, eventId=event_id, iteration=iteration,
|
|
544
621
|
action="escalated", verdict="escalated",
|
|
545
622
|
notes=f"subagent failed after retry: {subagent_failure_reason(result)}")
|
|
@@ -548,10 +625,9 @@ for each task in dependency_sorted(tasks):
|
|
|
548
625
|
break
|
|
549
626
|
|
|
550
627
|
# --- Sidecar merge: merge token usage written by subagent via custodian ---
|
|
551
|
-
# The subagent wrote the sidecar via node
|
|
628
|
+
# The subagent wrote the sidecar via node .forge/tools/store-cli.cjs emit {sprintId} '{sidecar-json}' --sidecar
|
|
552
629
|
# Merge the sidecar into the canonical event and delete the sidecar file
|
|
553
|
-
|
|
554
|
-
run: node "$FORGE_ROOT/tools/store-cli.cjs" merge-sidecar {sprint_id} {event_id}
|
|
630
|
+
run: node .forge/tools/store-cli.cjs merge-sidecar {sprint_id} {event_id}
|
|
555
631
|
# merge-sidecar reads the sidecar, merges token fields into the canonical event, and deletes the sidecar
|
|
556
632
|
# If the sidecar does not exist, merge-sidecar exits 1 — treat as non-fatal (subagent may have skipped it)
|
|
557
633
|
emit_event(task, phase, action="complete")
|
|
@@ -561,7 +637,10 @@ for each task in dependency_sorted(tasks):
|
|
|
561
637
|
if phase.role not in ("review-plan", "review-code", "validate"):
|
|
562
638
|
print(f" ✓ {task_id} {phase.role} — completed\n")
|
|
563
639
|
i += 1
|
|
564
|
-
#
|
|
640
|
+
# State-ledger compaction: the [checkpoint] line IS the state ledger — it carries
|
|
641
|
+
# the loop bookkeeping (task_id, sprint_id, phase_index, iteration_counts) that
|
|
642
|
+
# /compact must preserve verbatim. Raw tool output and subagent return text is
|
|
643
|
+
# shed here; do not retain it between phases. The durable state is on disk.
|
|
565
644
|
print(f"[checkpoint] task={task_id} sprint={sprint_id} phase_index={i} iterations={iteration_counts}")
|
|
566
645
|
/compact
|
|
567
646
|
continue
|
|
@@ -572,7 +651,7 @@ for each task in dependency_sorted(tasks):
|
|
|
572
651
|
# stdout is one of: approved | revision | n/a | unknown. Never pattern-match a
|
|
573
652
|
# **Verdict:** line — the closed vocabulary lives in the tool.
|
|
574
653
|
verdict_result = run_bash(
|
|
575
|
-
f'node
|
|
654
|
+
f'node .forge/tools/read-verdict.cjs --phase {phase.role} --task {task_id}'
|
|
576
655
|
)
|
|
577
656
|
verdict_token = verdict_result.stdout.strip()
|
|
578
657
|
if verdict_token == "approved":
|
|
@@ -586,19 +665,22 @@ for each task in dependency_sorted(tasks):
|
|
|
586
665
|
emit_event(task, phase, action="verdict_malformed",
|
|
587
666
|
notes=f"read-verdict stdout='{verdict_token}' exit={verdict_result.exit_code}")
|
|
588
667
|
# ---- ESCALATION (mandatory hard stop — do NOT continue) ----
|
|
589
|
-
run_bash(f'node
|
|
668
|
+
run_bash(f'node .forge/tools/store-cli.cjs update-status task {task_id} status escalated')
|
|
590
669
|
emit_event(task, phase, eventId=event_id, iteration=iteration,
|
|
591
670
|
action="escalated", verdict="escalated",
|
|
592
671
|
notes="verdict_malformed: no verdict recorded in the phase summary / record")
|
|
593
672
|
print(f" ⚠ Task {task_id} escalated: verdict_malformed — no verdict recorded for {phase.role}\n")
|
|
594
|
-
print(f" Inspect with: node
|
|
673
|
+
print(f" Inspect with: node \.forge/tools/read-verdict.cjs\" --phase {phase.role} --task {task_id}\n")
|
|
595
674
|
print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
|
|
596
675
|
break
|
|
597
676
|
|
|
598
677
|
if verdict == "Approved":
|
|
599
678
|
print(f" ✓ {task_id} {phase.role} — Approved\n")
|
|
600
679
|
i += 1 # advance to next phase
|
|
601
|
-
#
|
|
680
|
+
# State-ledger compaction: the [checkpoint] line IS the state ledger — it carries
|
|
681
|
+
# the loop bookkeeping (task_id, sprint_id, phase_index, iteration_counts) that
|
|
682
|
+
# /compact must preserve verbatim. Raw tool output and subagent return text is
|
|
683
|
+
# shed here; do not retain it between phases. The durable state is on disk.
|
|
602
684
|
print(f"[checkpoint] task={task_id} sprint={sprint_id} phase_index={i} iterations={iteration_counts}")
|
|
603
685
|
/compact
|
|
604
686
|
|
|
@@ -608,12 +690,12 @@ for each task in dependency_sorted(tasks):
|
|
|
608
690
|
|
|
609
691
|
if iteration_counts[phase.command] >= phase.maxIterations: # default 3
|
|
610
692
|
# ---- ESCALATION (mandatory hard stop — do NOT continue) ----
|
|
611
|
-
run_bash(f'node
|
|
693
|
+
run_bash(f'node .forge/tools/store-cli.cjs update-status task {task_id} status escalated')
|
|
612
694
|
emit_event(task, phase, eventId=event_id, iteration=iteration,
|
|
613
695
|
action="escalated", verdict="escalated",
|
|
614
696
|
notes="max iterations reached")
|
|
615
697
|
print(f" ⚠ Task {task_id} escalated: max iterations reached\n")
|
|
616
|
-
print(f" Inspect with: node
|
|
698
|
+
print(f" Inspect with: node \.forge/tools/read-verdict.cjs\" --phase {phase.role} --task {task_id}\n")
|
|
617
699
|
print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
|
|
618
700
|
break
|
|
619
701
|
break # stop processing this task
|
|
@@ -621,7 +703,10 @@ for each task in dependency_sorted(tasks):
|
|
|
621
703
|
# Route back to the revision target
|
|
622
704
|
target = phase.on_revision or nearest_preceding_non_review(phases, i)
|
|
623
705
|
i = index_of(phases, target) # loop back
|
|
624
|
-
#
|
|
706
|
+
# State-ledger compaction: the [checkpoint] line IS the state ledger — it carries
|
|
707
|
+
# the loop bookkeeping (task_id, sprint_id, phase_index, iteration_counts) that
|
|
708
|
+
# /compact must preserve verbatim. Raw tool output and subagent return text is
|
|
709
|
+
# shed here; do not retain it between phases. The durable state is on disk.
|
|
625
710
|
print(f"[checkpoint] task={task_id} sprint={sprint_id} phase_index={i} iterations={iteration_counts}")
|
|
626
711
|
/compact
|
|
627
712
|
|
|
@@ -696,8 +781,7 @@ enforces a closed vocabulary so typos, case drift, and reviewer prose cannot
|
|
|
696
781
|
cause silent misclassification:
|
|
697
782
|
|
|
698
783
|
```
|
|
699
|
-
|
|
700
|
-
result = run_bash(f'node "$FORGE_ROOT/tools/read-verdict.cjs" --phase {phase.role} --task {task_id}')
|
|
784
|
+
result = run_bash(f'node .forge/tools/read-verdict.cjs --phase {phase.role} --task {task_id}')
|
|
701
785
|
# stdout "approved" → approved
|
|
702
786
|
# stdout "revision" → revision
|
|
703
787
|
# stdout "n/a" | "unknown" → no verdict recorded (treat as malformed; do NOT guess)
|
|
@@ -724,7 +808,7 @@ applies the bug-specific phase→summary map.)
|
|
|
724
808
|
|
|
725
809
|
When escalating to the human:
|
|
726
810
|
|
|
727
|
-
1. Update task status via `node
|
|
811
|
+
1. Update task status via `node .forge/tools/store-cli.cjs update-status task {taskId} status escalated`
|
|
728
812
|
2. Emit a final event with `verdict: "escalated"` and `notes` explaining the reason
|
|
729
813
|
3. Output a clear message:
|
|
730
814
|
```
|
|
@@ -880,7 +964,7 @@ subagent returns, the orchestrator:
|
|
|
880
964
|
4. Composes the canonical event with `eventId`, `taskId`, `sprintId`, `role`,
|
|
881
965
|
`action`, `phase`, `iteration` from its own task state and `tokenSource:
|
|
882
966
|
"reported"` when the runtime surfaced usage.
|
|
883
|
-
5. Calls `node
|
|
967
|
+
5. Calls `node .forge/tools/store-cli.cjs emit {sprintId} '{event-json}'`
|
|
884
968
|
with the complete record.
|
|
885
969
|
|
|
886
970
|
Do not include hardcoded example `model` or `provider` strings in the
|
|
@@ -904,7 +988,7 @@ Refer subagents to `.forge/schemas/event.schema.json` instead.
|
|
|
904
988
|
Do NOT generate a "Model Assignments" table — the Model Resolution section
|
|
905
989
|
above is the single source of truth.
|
|
906
990
|
- **Include the sidecar merge pattern.** After each subagent returns, run
|
|
907
|
-
`node
|
|
991
|
+
`node .forge/tools/store-cli.cjs merge-sidecar {sprintId} {eventId}` to merge token fields from the
|
|
908
992
|
sidecar into the canonical event and delete the sidecar. If the sidecar does not
|
|
909
993
|
exist (merge-sidecar exits 1), treat as non-fatal and emit the event without token
|
|
910
994
|
fields (graceful fallback — no error).
|
|
@@ -932,7 +1016,7 @@ Refer subagents to `.forge/schemas/event.schema.json` instead.
|
|
|
932
1016
|
subagents do not display banners. Instead, include progress reporting instructions
|
|
933
1017
|
in the subagent prompt with the agent name, progress log path, and banner key.
|
|
934
1018
|
- **Include the progress IPC pattern.** Each generated orchestrator MUST:
|
|
935
|
-
1. Clear the progress log at task start: `node
|
|
1019
|
+
1. Clear the progress log at task start: `node .forge/tools/store-cli.cjs progress-clear {sprintId}`
|
|
936
1020
|
2. Compute the agent name before each spawn: `{taskId}:{persona_noun}:{phase.role}:{iteration}`
|
|
937
1021
|
3. Start a Monitor on the progress log before each subagent spawn
|
|
938
1022
|
4. Include progress reporting instructions in the subagent prompt (agent name,
|
|
@@ -952,13 +1036,28 @@ Refer subagents to `.forge/schemas/event.schema.json` instead.
|
|
|
952
1036
|
`Read engineering/architecture/stack.md` calls with a single cached summary.
|
|
953
1037
|
Subagents instructed by this block should read full docs **only** when the
|
|
954
1038
|
summary is insufficient.
|
|
955
|
-
- **Include post-phase /compact calls
|
|
956
|
-
non-escalation outcome), the generated orchestrator
|
|
1039
|
+
- **Include post-phase /compact calls with state-ledger discipline.** After each
|
|
1040
|
+
phase-exit signal (for every non-escalation outcome), the generated orchestrator
|
|
1041
|
+
MUST:
|
|
957
1042
|
1. Print a checkpoint line: `[checkpoint] task={task_id} sprint={sprint_id} phase_index={i} iterations={iteration_counts}`
|
|
958
1043
|
2. Run `/compact` to free orchestrator context before the next phase.
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1044
|
+
|
|
1045
|
+
The `[checkpoint]` line IS the state ledger. It carries the loop bookkeeping
|
|
1046
|
+
(task ID, sprint ID, current phase index, iteration counts) that `/compact` must
|
|
1047
|
+
preserve verbatim in its summary. It is not an optional debug breadcrumb — it is
|
|
1048
|
+
the one line the orchestrator must carry forward through each compaction boundary.
|
|
1049
|
+
|
|
1050
|
+
Raw tool output (bash stdout, subagent return blobs, multi-KB phase responses)
|
|
1051
|
+
is shed at every `/compact` call. The generated orchestrator MUST NOT retain
|
|
1052
|
+
verbatim tool output or subagent return text between phases — only the
|
|
1053
|
+
checkpoint ledger line and on-disk artifact pointers survive compaction.
|
|
1054
|
+
|
|
1055
|
+
The compact summary MUST contain: the checkpoint line verbatim, the task/sprint
|
|
1056
|
+
IDs, and the current phase index. The compact summary MUST NOT contain: raw
|
|
1057
|
+
subagent return text, bash stdout blobs, or multi-line phase responses.
|
|
1058
|
+
|
|
1059
|
+
Do NOT compact on escalation (verdict_malformed or max-iterations break paths) —
|
|
1060
|
+
the human needs the full uncompacted context to diagnose and resume.
|
|
962
1061
|
|
|
963
1062
|
## Friction Emit
|
|
964
1063
|
|
|
@@ -978,7 +1077,7 @@ When the Orchestrator detects skill friction during orchestrate-task — a refer
|
|
|
978
1077
|
|
|
979
1078
|
1. **Subagent-experienced friction** (the persona running plan / implement /
|
|
980
1079
|
validate / etc. detects skill friction). The subagent records the signal
|
|
981
|
-
via `node
|
|
1080
|
+
via `node .forge/tools/friction-emit.cjs --workflow {wf} --persona {p}
|
|
982
1081
|
--issue {token} [--subkind {token}] [--evidence '{...}']`, which appends a
|
|
983
1082
|
judgement-only record to `.forge/cache/FRICTION-{wf}.jsonl`. After the
|
|
984
1083
|
subagent returns, the orchestrator drains this file, stamps the
|
|
@@ -31,8 +31,8 @@ Break sprint requirements into a set of estimated tasks with a dependency graph.
|
|
|
31
31
|
1. Load Context:
|
|
32
32
|
- Query the store to orient on current project state before reading docs:
|
|
33
33
|
```sh
|
|
34
|
-
node
|
|
35
|
-
node
|
|
34
|
+
node .forge/tools/store-cli.cjs nlp "latest sprint"
|
|
35
|
+
node .forge/tools/store-cli.cjs nlp "open bugs"
|
|
36
36
|
```
|
|
37
37
|
Use results (titles, statuses, excerpts, file refs) to skip manual MASTER_INDEX.md navigation where sufficient.
|
|
38
38
|
- Read SPRINT_REQUIREMENTS.md
|
|
@@ -52,11 +52,11 @@ Break sprint requirements into a set of estimated tasks with a dependency graph.
|
|
|
52
52
|
|
|
53
53
|
4. Documentation:
|
|
54
54
|
- Write SPRINT_PLAN.md to `engineering/sprints/{sprintId}/SPRINT_PLAN.md`
|
|
55
|
-
- Create each task via `node
|
|
55
|
+
- Create each task via `node .forge/tools/store-cli.cjs write task '{task-json}'`.
|
|
56
56
|
If the command exits non-zero or the PreToolUse hook blocks the write:
|
|
57
57
|
parse the error, correct the JSON, and retry (see Store-Write Verification).
|
|
58
58
|
Do not proceed to the next task until this write succeeds.
|
|
59
|
-
- Update the sprint record with all new task IDs via `node
|
|
59
|
+
- Update the sprint record with all new task IDs via `node .forge/tools/store-cli.cjs write sprint '{updated-sprint-json}'` (the sprint JSON must include the complete `taskIds` array with all newly created task IDs).
|
|
60
60
|
If the command exits non-zero or the PreToolUse hook blocks the write:
|
|
61
61
|
parse the error, correct the JSON, and retry (see Store-Write Verification).
|
|
62
62
|
Do not proceed until this write succeeds.
|
|
@@ -64,7 +64,7 @@ Break sprint requirements into a set of estimated tasks with a dependency graph.
|
|
|
64
64
|
* Folder: `engineering/sprints/{sprintId}/{taskId}/`
|
|
65
65
|
* File: `TASK_PROMPT.md` — populate from `.forge/templates/TASK_PROMPT_TEMPLATE.md`
|
|
66
66
|
filling in title, objective, acceptance criteria, entities, DSL/CLI changes, and operational impact
|
|
67
|
-
- Update sprint status via `node
|
|
67
|
+
- Update sprint status via `node .forge/tools/store-cli.cjs update-status sprint {sprintId} status active`.
|
|
68
68
|
If the command exits non-zero, parse the error and retry
|
|
69
69
|
(see Store-Write Verification). Do not proceed until this write succeeds.
|
|
70
70
|
|
|
@@ -141,7 +141,7 @@ environment variable is reserved for emergency operator repair only.
|
|
|
141
141
|
- Set token fields to `null`: `"inputTokens": null, "outputTokens": null, "estimatedCostUSD": null`.
|
|
142
142
|
- Add `"source": "missing"` to sidecar JSON.
|
|
143
143
|
- Log: "Token data unavailable (cost probe failed). Backfill later via estimate-usage.cjs."
|
|
144
|
-
4. Write the usage sidecar via `node
|
|
144
|
+
4. Write the usage sidecar via `node .forge/tools/store-cli.cjs emit {sprintId} '{sidecar-json}' --sidecar`.
|
|
145
145
|
5. **NEVER skip sidecar write.** Always emit (reported or placeholder with nulls).
|
|
146
146
|
- **Event Emission:** Ensure the "complete" event includes the `eventId` passed by the orchestrator.
|
|
147
147
|
- **Store-Write Verification:** The generated workflow MUST include the "Store-Write
|
|
@@ -31,9 +31,8 @@ The Engineer reads the task prompt, researches the codebase, and produces an imp
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
0a. Pre-flight Gate Check:
|
|
34
|
-
- Resolve FORGE_ROOT (`node -e "console.log(require('./.forge/config.json').paths.forgeRoot)"`).
|
|
35
34
|
- **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.
|
|
36
|
-
- Run: `node
|
|
35
|
+
- Run: `node .forge/tools/preflight-gate.cjs --phase plan --{entity_kind} {record_id}`
|
|
37
36
|
- Exit 1 (gate failed) → print stderr and HALT. Do not proceed; do not attempt to produce the artifact.
|
|
38
37
|
- Exit 2 (misconfiguration) → print stderr and HALT.
|
|
39
38
|
- Exit 0 → continue.
|
|
@@ -42,7 +41,7 @@ The Engineer reads the task prompt, researches the codebase, and produces an imp
|
|
|
42
41
|
- If `--force` is present in the invocation arguments, skip this step entirely.
|
|
43
42
|
- If `entity_kind == "bug"`, skip this step entirely (bug state is managed by meta-fix-bug.md).
|
|
44
43
|
- Read current task state:
|
|
45
|
-
`node
|
|
44
|
+
`node .forge/tools/store-cli.cjs read task {record_id} --json`
|
|
46
45
|
- Extract the `status` field from the JSON output.
|
|
47
46
|
- Allowed states for this phase: `draft`, `planned`, `plan-revision-required`.
|
|
48
47
|
- If the current status is NOT in the allowed set:
|
|
@@ -55,7 +54,7 @@ The Engineer reads the task prompt, researches the codebase, and produces an imp
|
|
|
55
54
|
- Read task prompt (source of truth)
|
|
56
55
|
- Query the store for this task and any related entities:
|
|
57
56
|
```sh
|
|
58
|
-
node
|
|
57
|
+
node .forge/tools/store-cli.cjs nlp "{taskId} with sprint with feature"
|
|
59
58
|
```
|
|
60
59
|
Use store results directly if they include title, status, sprint, and excerpt.
|
|
61
60
|
- Read the architecture summary from your injected context (if present).
|
|
@@ -86,7 +85,7 @@ The Engineer reads the task prompt, researches the codebase, and produces an imp
|
|
|
86
85
|
5. Finalize:
|
|
87
86
|
- Transitions:
|
|
88
87
|
- **Task mode** — legal target from this step: `draft → planned`. Out-of-band escapes (any state): `plan-revision-required`, `code-revision-required`, `blocked`, `escalated`, `abandoned`.
|
|
89
|
-
Update status: `node
|
|
88
|
+
Update status: `node .forge/tools/store-cli.cjs update-status task {taskId} status planned`
|
|
90
89
|
- **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`.
|
|
91
90
|
- **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.
|
|
92
91
|
|
|
@@ -110,6 +109,13 @@ The Engineer reads the task prompt, researches the codebase, and produces an imp
|
|
|
110
109
|
Or (bug mode):
|
|
111
110
|
`forge_store({ command:"set-bug-summary", args:["{record_id}", "plan"] })`
|
|
112
111
|
- If the set-summary call exits non-zero, fix the sidecar JSON and retry. Do not proceed without a valid summary.
|
|
112
|
+
|
|
113
|
+
7. Post-Phase Output Guard: satisfy the `outputs` block before returning.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```outputs phase=plan
|
|
117
|
+
artifact {engineering}/{sprint}/{task}/PLAN.md min=200
|
|
118
|
+
require summaries.plan.verdict == n/a
|
|
113
119
|
```
|
|
114
120
|
|
|
115
121
|
<!-- See _fragments/iron-laws.md for Iron Laws section structure guidance -->
|
|
@@ -117,7 +123,7 @@ The Engineer reads the task prompt, researches the codebase, and produces an imp
|
|
|
117
123
|
|
|
118
124
|
- Follow the Algorithm step by step. No code, pseudocode, or implementation sketches in the plan.
|
|
119
125
|
- Read `.forge/personas/architect.md` first; print the persona identity line (emoji, name, tagline) to stdout before any other tool use.
|
|
120
|
-
- All store I/O via `forge_store` (or `node
|
|
126
|
+
- All store I/O via `forge_store` (or `node .forge/tools/store-cli.cjs`). Never edit `.forge/store/*.json` directly.
|
|
121
127
|
|
|
122
128
|
## Store-Write Verification
|
|
123
129
|
|
|
@@ -23,7 +23,7 @@ Close a sprint by reviewing learnings, updating the knowledge base, and improvin
|
|
|
23
23
|
|
|
24
24
|
- Never mutate JSON records during retrospective; the store is the source of truth and retrospective flows downstream from it. Retrospective operations read store data and write markdown views only.
|
|
25
25
|
- Read `.forge/personas/architect.md` first; print the persona identity line (emoji, name, tagline) to stdout before any other tool use.
|
|
26
|
-
- All store I/O via `forge_store` (or `node
|
|
26
|
+
- All store I/O via `forge_store` (or `node .forge/tools/store-cli.cjs`). Never edit `.forge/store/*.json` directly.
|
|
27
27
|
|
|
28
28
|
## Algorithm
|
|
29
29
|
|
|
@@ -45,8 +45,8 @@ Close a sprint by reviewing learnings, updating the knowledge base, and improvin
|
|
|
45
45
|
|
|
46
46
|
4. Finalize:
|
|
47
47
|
- Write SPRINT_RETROSPECTIVE.md
|
|
48
|
-
- Update sprint status via `node
|
|
49
|
-
- Run `node
|
|
48
|
+
- Update sprint status via `node .forge/tools/store-cli.cjs update-status sprint {sprintId} status retrospective-done`
|
|
49
|
+
- Run `node .forge/tools/collate.cjs {sprintId} --purge-events`
|
|
50
50
|
This single deterministic step: generates COST_REPORT.md from all
|
|
51
51
|
accumulated events, then deletes `.forge/store/events/{sprintId}/`.
|
|
52
52
|
COST_REPORT.md is the durable record; the raw event files are not
|
|
@@ -69,5 +69,5 @@ Close a sprint by reviewing learnings, updating the knowledge base, and improvin
|
|
|
69
69
|
(Claude Code only); on any other runtime treat as unavailable and proceed.
|
|
70
70
|
Do NOT shell out to a `cost-cli.cjs` — there is no such tool.
|
|
71
71
|
2. Parse: `inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens`, `estimatedCostUSD`.
|
|
72
|
-
3. Write the usage sidecar via `node
|
|
72
|
+
3. Write the usage sidecar via `node .forge/tools/store-cli.cjs emit {sprintId} '{sidecar-json}' --sidecar`.
|
|
73
73
|
- **Event Emission:** Ensure the "complete" event includes the `eventId` passed by the orchestrator.
|
|
@@ -23,7 +23,7 @@ Close a sprint by reviewing learnings, updating the knowledge base, and improvin
|
|
|
23
23
|
|
|
24
24
|
- Never mutate JSON records during retrospective; the store is the source of truth and retrospective flows downstream from it. Retrospective operations read store data and write markdown views only.
|
|
25
25
|
- Read `.forge/personas/architect.md` first; print the persona identity line (emoji, name, tagline) to stdout before any other tool use.
|
|
26
|
-
- All store I/O via `forge_store` (or `node
|
|
26
|
+
- All store I/O via `forge_store` (or `node .forge/tools/store-cli.cjs`). Never edit `.forge/store/*.json` directly.
|
|
27
27
|
|
|
28
28
|
## Algorithm
|
|
29
29
|
|
|
@@ -45,8 +45,8 @@ Close a sprint by reviewing learnings, updating the knowledge base, and improvin
|
|
|
45
45
|
|
|
46
46
|
4. Finalize:
|
|
47
47
|
- Write SPRINT_RETROSPECTIVE.md
|
|
48
|
-
- Update sprint status via `node
|
|
49
|
-
- Run `node
|
|
48
|
+
- Update sprint status via `node .forge/tools/store-cli.cjs update-status sprint {sprintId} status retrospective-done`
|
|
49
|
+
- Run `node .forge/tools/collate.cjs {sprintId} --purge-events`
|
|
50
50
|
This single deterministic step: generates COST_REPORT.md from all
|
|
51
51
|
accumulated events, then deletes `.forge/store/events/{sprintId}/`.
|
|
52
52
|
COST_REPORT.md is the durable record; the raw event files are not
|
|
@@ -69,5 +69,5 @@ Close a sprint by reviewing learnings, updating the knowledge base, and improvin
|
|
|
69
69
|
(Claude Code only); on any other runtime treat as unavailable and proceed.
|
|
70
70
|
Do NOT shell out to a `cost-cli.cjs` — there is no such tool.
|
|
71
71
|
2. Parse: `inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens`, `estimatedCostUSD`.
|
|
72
|
-
3. Write the usage sidecar via `node
|
|
72
|
+
3. Write the usage sidecar via `node .forge/tools/store-cli.cjs emit {sprintId} '{sidecar-json}' --sidecar`.
|
|
73
73
|
- **Event Emission:** Ensure the "complete" event includes the `eventId` passed by the orchestrator.
|
|
@@ -31,7 +31,7 @@ The Supervisor reviews the Engineer's implementation for correctness, quality, a
|
|
|
31
31
|
|
|
32
32
|
- Evaluate the code against the approved PLAN.md and the original task prompt. Do not accept "it works" as a substitute for "it is correct and maintainable."
|
|
33
33
|
- Read `.forge/personas/supervisor.md` first; print the persona identity line (emoji, name, tagline) to stdout before any other tool use.
|
|
34
|
-
- All store I/O via `forge_store` (or `node
|
|
34
|
+
- All store I/O via `forge_store` (or `node .forge/tools/store-cli.cjs`). Never edit `.forge/store/*.json` directly.
|
|
35
35
|
|
|
36
36
|
## Store-Write Verification
|
|
37
37
|
|
|
@@ -42,9 +42,8 @@ The Supervisor reviews the Engineer's implementation for correctness, quality, a
|
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
0a. Pre-flight Gate Check:
|
|
45
|
-
- Resolve FORGE_ROOT (`node -e "console.log(require('./.forge/config.json').paths.forgeRoot)"`).
|
|
46
45
|
- **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.
|
|
47
|
-
- Run: `node
|
|
46
|
+
- Run: `node .forge/tools/preflight-gate.cjs --phase review-code --{entity_kind} {record_id}`
|
|
48
47
|
- Exit 1 (gate failed) → print stderr and HALT. Do not proceed; do not attempt to produce the artifact.
|
|
49
48
|
- Exit 2 (misconfiguration) → print stderr and HALT.
|
|
50
49
|
- Exit 0 → continue.
|
|
@@ -53,7 +52,7 @@ The Supervisor reviews the Engineer's implementation for correctness, quality, a
|
|
|
53
52
|
- If `--force` is present in the invocation arguments, skip this step entirely.
|
|
54
53
|
- If `entity_kind == "bug"`, skip this step entirely (bug state is managed by meta-fix-bug.md).
|
|
55
54
|
- Read current task state:
|
|
56
|
-
`node
|
|
55
|
+
`node .forge/tools/store-cli.cjs read task {record_id} --json`
|
|
57
56
|
- Extract the `status` field from the JSON output.
|
|
58
57
|
- Allowed states for this phase: `implemented`, `implementing`.
|
|
59
58
|
- If the current status is NOT in the allowed set:
|
|
@@ -65,9 +64,10 @@ The Supervisor reviews the Engineer's implementation for correctness, quality, a
|
|
|
65
64
|
- If present, extract:
|
|
66
65
|
- `Iteration: N of M` — current attempt number and the configured limit
|
|
67
66
|
- `Is final iteration: true/false`
|
|
68
|
-
- If absent (user-invoked, not orchestrated): treat as iteration 1
|
|
69
|
-
read from
|
|
70
|
-
|
|
67
|
+
- If absent (user-invoked, not orchestrated): treat as `iteration 1`, no limit — do
|
|
68
|
+
NOT read any iteration cap from config. The orchestrator owns loop budgets; a human
|
|
69
|
+
standalone re-run is the escape hatch for stuck items (forge-engineering#34).
|
|
70
|
+
- Include `(iteration N of M)` (orchestrated) or `(standalone review)` in the opening line of the `CODE_REVIEW.md` artifact.
|
|
71
71
|
- If this is the final iteration (`N == M`) and the verdict is `Revision Required`,
|
|
72
72
|
append a `### Next Steps` section to the artifact showing:
|
|
73
73
|
```
|
|
@@ -103,7 +103,7 @@ The Supervisor reviews the Engineer's implementation for correctness, quality, a
|
|
|
103
103
|
|
|
104
104
|
6. Finalize:
|
|
105
105
|
- Transitions:
|
|
106
|
-
- **Task mode** — Update status: `node
|
|
106
|
+
- **Task mode** — Update status: `node .forge/tools/store-cli.cjs update-status task {taskId} status review-approved` (if Approved) or `... status code-revision-required` (if Revision Required).
|
|
107
107
|
- **Bug mode** — NO status write. The bug remains `in-progress`. The verdict signal travels through `summaries.code_review.verdict` (read by `read-verdict.cjs § BUG_PHASE_VERDICT_SOURCE`), not `bug.status`. Writing `bug.status` here violates `meta-fix-bug.md § Iron Laws #2`.
|
|
108
108
|
- **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.
|
|
109
109
|
|
|
@@ -121,10 +121,11 @@ The Supervisor reviews the Engineer's implementation for correctness, quality, a
|
|
|
121
121
|
}
|
|
122
122
|
```
|
|
123
123
|
- Call (task mode):
|
|
124
|
-
`forge_store({ command:"set-summary",
|
|
124
|
+
`forge_store({ command:"set-summary", args:["{taskId}", "code_review"] })`
|
|
125
125
|
Or (bug mode):
|
|
126
|
-
`forge_store({ command:"set-bug-summary",
|
|
127
|
-
|
|
126
|
+
`forge_store({ command:"set-bug-summary", args:["{bugId}", "code_review"] })`
|
|
127
|
+
`args[1]` is the LITERAL phase key `code_review`, never the record id; `forge_store` has no `entity`/`id`/`phase` field (see `_fragments/store-cli-verbs.md`).
|
|
128
|
+
- If set-summary exits non-zero, `args[1]` was wrong — fix it to `code_review` and retry. Do not return without a valid summary; the orchestrator halts as "verdict missing" if `summaries.code_review` is absent.
|
|
128
129
|
```
|
|
129
130
|
|
|
130
131
|
<!-- See _fragments/generation-instructions.md for Generation Instructions template -->
|