forgedock 1.1.1 → 1.1.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/README.md +53 -8
- package/bin/batch-runner.mjs +339 -0
- package/bin/demo.mjs +92 -7
- package/bin/engine/phases.mjs +20 -0
- package/bin/engine/state.mjs +8 -3
- package/bin/engine-cli.mjs +177 -5
- package/bin/forgedock.mjs +409 -26
- package/bin/hooks/interactive-engine.mjs +509 -0
- package/bin/hooks/pre-tool-use.mjs +498 -0
- package/bin/hooks/subagent-stop-enforce.mjs +197 -0
- package/bin/journey.mjs +72 -14
- package/bin/registry.mjs +139 -0
- package/bin/report.mjs +447 -0
- package/bin/runner.mjs +68 -19
- package/bin/settings-hook.mjs +235 -1
- package/commands/adopt.md +4 -1
- package/commands/analytics.md +4 -1
- package/commands/audit-agents.md +110 -27
- package/commands/audit.md +20 -1
- package/commands/autopilot.md +80 -8
- package/commands/changelog.md +2 -1
- package/commands/ci-audit.md +2 -1
- package/commands/cleanup.md +161 -1
- package/commands/compat-audit.md +2 -1
- package/commands/deploy-info.md +58 -1
- package/commands/design-bench.md +5 -1
- package/commands/design-render-critique-loop.md +1 -1
- package/commands/diagnose.md +2 -1
- package/commands/explain.md +2 -1
- package/commands/forge-stats.md +121 -2
- package/commands/forgedock-init.md +1 -1
- package/commands/geo-audit.md +3 -0
- package/commands/incident-response.md +2 -1
- package/commands/issue.md +23 -2
- package/commands/milestone.md +77 -12
- package/commands/optimize.md +2 -1
- package/commands/orchestrate/config.md +67 -0
- package/commands/orchestrate/phase-1-resolve.md +159 -0
- package/commands/orchestrate/phase-2-triage.md +126 -0
- package/commands/orchestrate/phase-2.5-synthesis.md +156 -0
- package/commands/orchestrate/phase-3-dependency.md +591 -0
- package/commands/orchestrate/phase-4-execution.md +962 -0
- package/commands/orchestrate/phase-5-cleanup.md +47 -0
- package/commands/orchestrate/phase-6-report.md +198 -0
- package/commands/orchestrate/safety.md +62 -0
- package/commands/orchestrate.md +25 -2045
- package/commands/pipeline-health/config.md +34 -0
- package/commands/pipeline-health/phase-1-context.md +180 -0
- package/commands/pipeline-health/phase-2-metrics.md +1729 -0
- package/commands/pipeline-health/phase-3-analyze.md +204 -0
- package/commands/pipeline-health/phase-4-proposals.md +117 -0
- package/commands/pipeline-health/phase-5-report.md +284 -0
- package/commands/pipeline-health/phase-6-summary.md +52 -0
- package/commands/pipeline-health.md +25 -2401
- package/commands/pipeline-resume.md +24 -1
- package/commands/pipeline-status.md +65 -0
- package/commands/qa-sweep.md +4 -1
- package/commands/quality-gate.md +248 -10
- package/commands/replay.md +2 -1
- package/commands/review-pr-agents/api.md +135 -0
- package/commands/review-pr-agents/auth.md +137 -0
- package/commands/review-pr-agents/billing.md +101 -0
- package/commands/review-pr-agents/concurrency.md +145 -0
- package/commands/review-pr-agents/database.md +103 -0
- package/commands/review-pr-agents/frontend.md +89 -0
- package/commands/review-pr-agents/infra.md +385 -0
- package/commands/review-pr-agents/protocols.md +185 -0
- package/commands/review-pr-agents/scraper.md +185 -0
- package/commands/review-pr-agents/security.md +406 -0
- package/commands/review-pr-agents.md +45 -1722
- package/commands/review-pr-staging.md +196 -40
- package/commands/review-pr.md +591 -52
- package/commands/rollback.md +2 -1
- package/commands/scope.md +2 -1
- package/commands/security-audit.md +2 -1
- package/commands/signal-planner.md +623 -0
- package/commands/sync-ecosystem.md +1 -0
- package/commands/test-gate.md +17 -1
- package/commands/validate.md +2 -1
- package/commands/work-on/build/architect.md +28 -0
- package/commands/work-on/build/context.md +2 -0
- package/commands/work-on/build/implement.md +3 -1
- package/commands/work-on/build/validate.md +26 -7
- package/commands/work-on/build.md +163 -24
- package/commands/work-on/close.md +130 -3
- package/commands/work-on/decompose.md +19 -1
- package/commands/work-on/investigate.md +117 -2
- package/commands/work-on/review.md +24 -4
- package/commands/work-on-monolithic.md +7 -2
- package/commands/work-on.md +202 -4
- package/docs/BRAND.md +14 -7
- package/docs/CI.md +2 -2
- package/docs/CODEX.md +36 -1
- package/docs/CONFIG.md +5 -8
- package/docs/FORGE-PROTOCOL.md +15 -1064
- package/docs/anthropic-devrel-outreach.md +2 -2
- package/docs/articles/command-decomposition-token-savings.md +214 -0
- package/docs/articles/model-release-playbook.md +131 -0
- package/docs/articles/per-repo-adaptive-scripts-token-savings.md +27 -25
- package/docs/claude-breakpoints.json +75 -5
- package/docs/design/abc-benchmark.md +1 -1
- package/docs/design/design-spec-schema.md +1 -1
- package/docs/design/divergent-generation.md +1 -1
- package/docs/design/eval-gate-runbook.md +178 -0
- package/docs/design/show-hn-draft.md +26 -1
- package/docs/design/token-cost-baseline-1298.md +59 -0
- package/docs/eval/README.md +117 -0
- package/docs/eval/corpus/seed-v1.json +6 -0
- package/docs/eval/published/claude-sonnet-4-6-2026-07-04.json +33 -0
- package/docs/site/annotations-explained.md +24 -0
- package/docs/site/command-learning-path.md +51 -14
- package/docs/site/command-reference.md +339 -113
- package/docs/site/for-companies.md +95 -0
- package/docs/site/forge-annotation-protocol.md +12 -256
- package/docs/site/getting-started.md +43 -4
- package/docs/site/github-is-the-memory.md +113 -0
- package/docs/site/how-it-works.md +3 -13
- package/docs/site/index.md +9 -1
- package/docs/spec/eval-run-result.md +147 -0
- package/docs/spec/forge-protocol-v1.md +441 -18
- package/docs/spec/label-state-machine.md +55 -0
- package/docs/spec/review-protocol.md +158 -0
- package/docs/spec-graph-schema.md +28 -0
- package/docs/superpowers/specs/2026-07-04-economic-self-governance-design.md +181 -0
- package/docs/superpowers/specs/2026-07-04-provenance-trail-design.md +189 -0
- package/examples/forgedock-demo/README.md +41 -22
- package/examples/forgedock-demo/issues/06-bug-tags-type-validation.md +43 -0
- package/examples/forgedock-demo/issues/07-bug-negative-offset-pagination.md +42 -0
- package/examples/forgedock-demo/issues/08-bug-patch-mass-assignment.md +49 -0
- package/examples/forgedock-demo/issues/09-bug-count-injection.md +47 -0
- package/examples/forgedock-demo/issues/10-feature-sort-param.md +39 -0
- package/examples/forgedock-demo/issues/11-feature-patch-tags.md +37 -0
- package/examples/forgedock-demo/issues/12-feature-bulk-create.md +42 -0
- package/examples/forgedock-demo/issues/13-feature-archive-notes.md +46 -0
- package/examples/forgedock-demo/issues/14-refactor-extract-title-validation.md +41 -0
- package/examples/forgedock-demo/issues/15-refactor-protected-route-flag.md +43 -0
- package/examples/forgedock-demo/issues/16-refactor-extract-store.md +45 -0
- package/examples/forgedock-demo/issues/17-perf-tags-dedup-set.md +35 -0
- package/examples/forgedock-demo/issues/18-perf-remove-redundant-sort.md +37 -0
- package/examples/forgedock-demo/issues/19-docs-api-reference-full.md +53 -0
- package/examples/forgedock-demo/issues/20-docs-intentional-flaw-convention.md +46 -0
- package/examples/forgedock-demo/scripts/smoke.js +18 -1
- package/examples/forgedock-demo/src/db.js +36 -11
- package/examples/forgedock-demo/src/routes/notes.js +106 -9
- package/examples/forgedock-demo/src/server.js +4 -1
- package/package.json +3 -1
- package/packages/protocol/LICENSE +21 -0
- package/packages/protocol/src/cli.js +135 -0
- package/packages/protocol/src/emit.js +146 -0
- package/packages/protocol/src/index.js +43 -0
- package/packages/protocol/src/parse.js +229 -0
- package/packages/protocol/src/types.js +171 -0
- package/packages/protocol/src/validate.js +122 -0
- package/scripts/bench-topology-cost.mjs +372 -0
- package/scripts/check-command-docs-drift.sh +198 -0
- package/scripts/check-protocol-restatements.sh +176 -0
- package/scripts/check-registry/README.md +72 -0
- package/scripts/check-registry/manifest.json +6 -0
- package/scripts/code-index.sh +454 -0
- package/scripts/conformance-check.mjs +168 -0
- package/scripts/doctor-pipeline-state.sh +484 -0
- package/scripts/eval-gate-baseline.json +17 -0
- package/scripts/eval-gate-scorecard.mjs +242 -0
- package/scripts/eval-scorecard-aggregator.mjs +252 -0
- package/scripts/flaky-quarantine.sh +241 -0
- package/scripts/forge-annotation.sh +567 -0
- package/scripts/issue-dedup.sh +236 -0
- package/scripts/validate-annotation-node.mjs +233 -0
- package/scripts/worktree-lifecycle.sh +3 -3
- package/templates/devdocs/agent/using-forgedock.md +14 -0
- package/docs/site/.vitepress/config.mjs +0 -85
package/commands/rollback.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Create a revert PR to roll back a shipped feature or fix that caused a production incident
|
|
3
3
|
argument-hint: [PR number to revert, or "last" for most recent deploy]
|
|
4
|
+
install: extras
|
|
4
5
|
---
|
|
5
6
|
<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
|
|
6
7
|
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
|
@@ -15,7 +16,7 @@ argument-hint: [PR number to revert, or "last" for most recent deploy]
|
|
|
15
16
|
|
|
16
17
|
You are the pipeline's emergency rollback system. When a shipped feature or fix causes production issues, this command creates a revert PR and fast-tracks it through the pipeline.
|
|
17
18
|
|
|
18
|
-
**Agent model policy**:
|
|
19
|
+
**Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. User can override with `--model <name>`. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
19
20
|
|
|
20
21
|
**NEVER use plan mode (EnterPlanMode)** — it breaks execution context.
|
|
21
22
|
|
package/commands/scope.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Estimate issue complexity before running /work-on — affected files, blast radius, risk flags, and decomposition recommendation
|
|
3
3
|
argument-hint: <issue number> [--repo {owner}/{repo}]
|
|
4
|
+
install: extras
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# /scope — Pre-Flight Complexity Estimator
|
|
@@ -11,7 +12,7 @@ You are a read-only pre-flight analyst. Given a GitHub issue number, you estimat
|
|
|
11
12
|
|
|
12
13
|
**This command is strictly READ-ONLY.** No labels are written, no comments are posted, no worktrees are created.
|
|
13
14
|
|
|
14
|
-
**Agent model policy**:
|
|
15
|
+
**Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
|
|
15
16
|
**NEVER use plan mode (EnterPlanMode).**
|
|
16
17
|
|
|
17
18
|
---
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Periodic security posture audit — runs a scripted 4-phase checklist against repo files (not diffs), creates GitHub issues for confirmed findings
|
|
3
3
|
argument-hint: [--repo <prefix>] [--phase 1|2|3|4|all] [--dry-run]
|
|
4
|
+
install: extras
|
|
4
5
|
---
|
|
5
6
|
<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
|
|
6
7
|
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
|
@@ -18,7 +19,7 @@ This command is designed to be run:
|
|
|
18
19
|
|
|
19
20
|
This is NOT a PR review — it does not approve or block. It creates issues for each gap found.
|
|
20
21
|
|
|
21
|
-
**Agent model policy**:
|
|
22
|
+
**Agent model policy**: `model: "sonnet"`, `effort: xhigh` (deep tier — comprehensive security analysis). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` only on Claude Code >= 2.1.154.
|
|
22
23
|
**NEVER use plan mode (EnterPlanMode).**
|
|
23
24
|
|
|
24
25
|
---
|
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Closed-loop autonomy — convert a production/analytics/incident signal into a dependency-ordered issue DAG, execute via /orchestrate, then verify the originating signal is resolved. Event-driven companion to /autopilot.
|
|
3
|
+
argument-hint: [--signal '<json>' | --metric '<name> <threshold>' | --incident <issue#> | --geo | --dry-run | --max-issues N]
|
|
4
|
+
install: extras
|
|
5
|
+
---
|
|
6
|
+
<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
|
|
7
|
+
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
|
8
|
+
|
|
9
|
+
# /signal-planner — Closed-Loop Production Signal to Verified Resolution
|
|
10
|
+
|
|
11
|
+
**Input**: $ARGUMENTS
|
|
12
|
+
|
|
13
|
+
**Config variables used by this command** (set in `forge.yaml`):
|
|
14
|
+
- `{CREDENTIALS_FILE}` ← `paths.credentials.file` (optional) — path to credentials YAML for analytics APIs
|
|
15
|
+
- `{BILLING_ENABLED}` ← `billing.enabled` (optional, default `false`) — enable Stripe data in signal hydration
|
|
16
|
+
- `{GOVERNOR_MAX_ISSUES}` ← `governor.max_issues_per_run` (optional, default `10`) — hard cap on issues spawned per run
|
|
17
|
+
- `{GOVERNOR_MAX_COST_USD}` ← `governor.max_cost_usd` (optional, default `5.00`) — hard cap on estimated LLM spend per run
|
|
18
|
+
|
|
19
|
+
**NEVER use plan mode (EnterPlanMode).**
|
|
20
|
+
**NEVER use the Agent tool** for implementation work — dispatch issues via `Skill(skill="work-on", ...)` or via `/orchestrate`.
|
|
21
|
+
|
|
22
|
+
<!-- FORGE:SPEC_LOADED — signal-planner.md loaded and active. Agent is bound by this spec. -->
|
|
23
|
+
|
|
24
|
+
You are the closed-loop autonomy engine. Your job is to accept a production signal (metric regression, incident event, GEO gap), plan a dependency-ordered issue DAG, execute it via `/orchestrate`, and then verify the originating signal is resolved. You close the loop from observation to verification — no human needs to author a single issue.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Argument Parsing
|
|
29
|
+
|
|
30
|
+
Parse `$ARGUMENTS` and set:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
SIGNAL_JSON = raw JSON from --signal '...' (if provided)
|
|
34
|
+
SIGNAL_METRIC = metric name + threshold from --metric '<name> <threshold>' (if provided)
|
|
35
|
+
SIGNAL_INCIDENT = issue number from --incident <N> (if provided)
|
|
36
|
+
SIGNAL_GEO = true if --geo flag present
|
|
37
|
+
DRY_RUN = true if --dry-run present
|
|
38
|
+
MAX_ISSUES_OVERRIDE = N from --max-issues N (if provided)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Signal source priority** (first match wins):
|
|
42
|
+
1. `--signal` — structured JSON signal (most precise)
|
|
43
|
+
2. `--metric` — named metric with threshold breach
|
|
44
|
+
3. `--incident` — P0/P1 incident issue number
|
|
45
|
+
4. `--geo` — run geo-audit sensor for GEO gaps
|
|
46
|
+
5. *(no flag)* — interactive: print usage and exit
|
|
47
|
+
|
|
48
|
+
If no recognized signal flag is present, print:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
/signal-planner requires a signal source. Examples:
|
|
52
|
+
|
|
53
|
+
/signal-planner --signal '{"type":"metric","name":"gsc_clicks","value":1200,"baseline":2000,"window":"7d"}'
|
|
54
|
+
/signal-planner --metric "checkout_latency_p99 >2000ms"
|
|
55
|
+
/signal-planner --incident 55
|
|
56
|
+
/signal-planner --geo
|
|
57
|
+
/signal-planner --dry-run --signal '...' # plan only, no issues created
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Then exit.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Phase 0: Economic Governor (MANDATORY — run before ANY side effects)
|
|
65
|
+
|
|
66
|
+
**Goal**: Prevent runaway spend. Hard-fail if governor limits would be breached.
|
|
67
|
+
|
|
68
|
+
### 0A: Resolve governor config
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
FORGE_YAML="${FORGE_CONFIG:-$(git rev-parse --show-toplevel 2>/dev/null)/forge.yaml}"
|
|
72
|
+
|
|
73
|
+
GOVERNOR_MAX_ISSUES=$(python3 -c "
|
|
74
|
+
import yaml, sys
|
|
75
|
+
cfg = yaml.safe_load(open('$FORGE_YAML')) if __import__('os').path.exists('$FORGE_YAML') else {}
|
|
76
|
+
print(cfg.get('governor', {}).get('max_issues_per_run', 10))
|
|
77
|
+
" 2>/dev/null || echo "10")
|
|
78
|
+
|
|
79
|
+
GOVERNOR_MAX_COST=$(python3 -c "
|
|
80
|
+
import yaml, sys
|
|
81
|
+
cfg = yaml.safe_load(open('$FORGE_YAML')) if __import__('os').path.exists('$FORGE_YAML') else {}
|
|
82
|
+
print(cfg.get('governor', {}).get('max_cost_usd', 5.00))
|
|
83
|
+
" 2>/dev/null || echo "5.00")
|
|
84
|
+
|
|
85
|
+
# Apply per-run override
|
|
86
|
+
if [ -n "$MAX_ISSUES_OVERRIDE" ]; then
|
|
87
|
+
GOVERNOR_MAX_ISSUES=$(( MAX_ISSUES_OVERRIDE < GOVERNOR_MAX_ISSUES ? MAX_ISSUES_OVERRIDE : GOVERNOR_MAX_ISSUES ))
|
|
88
|
+
fi
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 0B: Record governor state
|
|
92
|
+
|
|
93
|
+
Store `GOVERNOR_MAX_ISSUES` and `GOVERNOR_MAX_COST` as the hard caps for this run. They are checked in Phase 3 before any issue is created. Exceeding them is a hard fail — not a warning.
|
|
94
|
+
|
|
95
|
+
Print:
|
|
96
|
+
```
|
|
97
|
+
[signal-planner] Governor: max_issues={GOVERNOR_MAX_ISSUES}, max_cost_usd={GOVERNOR_MAX_COST}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Phase 1: Signal Intake & Hydration
|
|
103
|
+
|
|
104
|
+
**Goal**: Normalize the raw input signal into a typed, structured `SIGNAL` object and hydrate it with enough context to plan work.
|
|
105
|
+
|
|
106
|
+
### 1A: Normalize the signal
|
|
107
|
+
|
|
108
|
+
Build `SIGNAL` from the input:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
SIGNAL = {
|
|
112
|
+
type: "metric" | "incident" | "geo" | "raw",
|
|
113
|
+
name: <human-readable signal name>,
|
|
114
|
+
raw_input: <original input string or JSON>,
|
|
115
|
+
severity: "P0" | "P1" | "P2" | null,
|
|
116
|
+
context: {} # filled in 1B
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**For `--signal <json>`**: Parse JSON directly. Map `type` field; if absent, classify from content.
|
|
121
|
+
|
|
122
|
+
**For `--metric <name> <threshold>`**: Set `type="metric"`, `name=<name>`. Parse threshold string (e.g., `>2000ms`, `<80%`, `dropped 30%`). Set `severity` based on magnitude:
|
|
123
|
+
- >50% regression or latency >5x baseline → P0
|
|
124
|
+
- 20–50% regression → P1
|
|
125
|
+
- 10–20% regression → P2
|
|
126
|
+
|
|
127
|
+
**For `--incident <N>`**: Fetch the issue:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
gh issue view {N} -R {GH_REPO} --json number,title,body,labels,state \
|
|
131
|
+
--jq '{number: .number, title: .title, severity: (.labels | map(.name) | map(select(startswith("priority:"))) | .[0]), state: .state}'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Set `type="incident"`, `name="incident #N: {title}"`, `severity` from label.
|
|
135
|
+
|
|
136
|
+
**For `--geo`**: Set `type="geo"`, `name="GEO compliance gap"`, `severity="P2"`. Hydration (1B) will call `/geo-audit`.
|
|
137
|
+
|
|
138
|
+
### 1B: Hydrate context
|
|
139
|
+
|
|
140
|
+
Fetch live data to fill `SIGNAL.context` based on signal type:
|
|
141
|
+
|
|
142
|
+
**For `type="metric"`**:
|
|
143
|
+
- Read credentials from `{CREDENTIALS_FILE}` (from `forge.yaml`)
|
|
144
|
+
- Pull the named metric from its source (GSC/GA4/Umami/Cloudflare/Stripe) using the same MCP tools as `/analytics`
|
|
145
|
+
- Compute: current value, baseline (same window, prior period), delta, % change
|
|
146
|
+
- Store: `SIGNAL.context = { metric_name, current, baseline, delta_pct, window, source }`
|
|
147
|
+
|
|
148
|
+
**For `type="incident"`**:
|
|
149
|
+
- Read all comments on issue `{N}` — extract timeline, error messages, affected components
|
|
150
|
+
- Check recent CI runs for failures correlated with incident time
|
|
151
|
+
- Store: `SIGNAL.context = { issue_number, title, body, timeline, affected_components, ci_failures }`
|
|
152
|
+
|
|
153
|
+
**For `type="geo"`**:
|
|
154
|
+
- Call `/geo-audit` sensors: Umami AI referral traffic, Clarity heatmaps, page compliance checks
|
|
155
|
+
- Collect gaps: missing structured data, broken OG tags, missing llms.txt entries, stale pages
|
|
156
|
+
- Store: `SIGNAL.context = { gaps: [{page, type, severity}], ai_referral_trend, compliance_score }`
|
|
157
|
+
|
|
158
|
+
**For `type="raw"`**:
|
|
159
|
+
- Parse prose for affected areas: look for file paths, feature names, metric names, error strings
|
|
160
|
+
- Store: `SIGNAL.context = { parsed_areas, raw_text }`
|
|
161
|
+
|
|
162
|
+
**Hydration timeout**: If any data source is unreachable, note it in `SIGNAL.context.hydration_warnings` and proceed — don't fail the whole run on a single unavailable API.
|
|
163
|
+
|
|
164
|
+
Print a compact hydration summary:
|
|
165
|
+
```
|
|
166
|
+
[signal-planner] Signal: {type} / {name} / {severity}
|
|
167
|
+
[signal-planner] Context: {key facts from hydration — 2-3 bullet points}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Phase 2: Plan DAG
|
|
173
|
+
|
|
174
|
+
**Goal**: Analyse the hydrated signal, cluster it into work units, resolve cross-unit dependencies, and emit a reviewable dependency DAG.
|
|
175
|
+
|
|
176
|
+
### 2A: Deduplication — check for existing open issues
|
|
177
|
+
|
|
178
|
+
Before planning ANY new issues, scan existing open issues:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
gh issue list -R {GH_REPO} --state open --limit 200 --json number,title,labels \
|
|
182
|
+
--jq '.[] | "\(.number) \(.title)"'
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
For each candidate work unit, check if an open issue already covers it. If yes — record it as `EXISTING_ISSUE` and use it in the DAG instead of creating a new one.
|
|
186
|
+
|
|
187
|
+
### 2B: Cluster signal into work units
|
|
188
|
+
|
|
189
|
+
Analyse `SIGNAL.context` and identify discrete, independently-deployable work units:
|
|
190
|
+
|
|
191
|
+
**Rules for clustering**:
|
|
192
|
+
- Each work unit must map to a single `commands/` area, module, or clearly scoped change
|
|
193
|
+
- A work unit must be completable in one `/work-on` run (not a multi-week epic)
|
|
194
|
+
- If a work unit depends on another's output (e.g., schema change before UI), record the dependency
|
|
195
|
+
- Maximum `GOVERNOR_MAX_ISSUES` work units total — if more are found, rank by impact and take the top N
|
|
196
|
+
|
|
197
|
+
**For each work unit, draft**:
|
|
198
|
+
```
|
|
199
|
+
{
|
|
200
|
+
title: "fix|feat|refactor: <concise description>",
|
|
201
|
+
type: "bug" | "feature" | "refactor",
|
|
202
|
+
priority: "P0" | "P1" | "P2" | "P3",
|
|
203
|
+
scope: <affected file or module>,
|
|
204
|
+
rationale: <1 sentence: why this addresses the signal>,
|
|
205
|
+
depends_on: [<work_unit_indices>], # empty = no deps
|
|
206
|
+
existing: <issue number if already open, else null>
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 2C: Resolve dependency order (topological sort)
|
|
211
|
+
|
|
212
|
+
Sort work units so no unit appears before all its dependencies:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
# Pseudocode — implement with standard topological sort
|
|
216
|
+
order = topological_sort(work_units, key=lambda u: u.depends_on)
|
|
217
|
+
# Result: ordered list where dependencies always precede dependents
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Detect cycles — if a cycle exists, break it by demoting the lower-priority unit to depend on the higher-priority one and log a `CYCLE_BROKEN` warning.
|
|
221
|
+
|
|
222
|
+
### 2D: Emit FORGE:PLAN_DAG annotation
|
|
223
|
+
|
|
224
|
+
Post the DAG to a tracker issue on GitHub. First, create the tracker issue:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
TRACKER_ISSUE=$(gh issue create -R {GH_REPO} \
|
|
228
|
+
--title "signal-planner: DAG tracker for {SIGNAL.name}" \
|
|
229
|
+
--label "signal-planner,priority:{SIGNAL.severity}" \
|
|
230
|
+
--body "$(cat <<'TRACKER_EOF'
|
|
231
|
+
## Signal
|
|
232
|
+
|
|
233
|
+
**Type**: {SIGNAL.type}
|
|
234
|
+
**Name**: {SIGNAL.name}
|
|
235
|
+
**Severity**: {SIGNAL.severity}
|
|
236
|
+
|
|
237
|
+
## Signal Context
|
|
238
|
+
|
|
239
|
+
{SIGNAL.context summary — key metrics, affected areas, evidence}
|
|
240
|
+
|
|
241
|
+
## Work Plan
|
|
242
|
+
|
|
243
|
+
This tracker was created by \`/signal-planner\`. The dependency DAG below represents the planned work to resolve the originating signal.
|
|
244
|
+
|
|
245
|
+
## Acceptance
|
|
246
|
+
|
|
247
|
+
- [ ] All DAG issues merged
|
|
248
|
+
- [ ] Originating signal verified resolved (FORGE:SIGNAL_RESOLVED posted)
|
|
249
|
+
TRACKER_EOF
|
|
250
|
+
)" --json number --jq '.number')
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Then post the `FORGE:PLAN_DAG` comment:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
gh issue comment $TRACKER_ISSUE -R {GH_REPO} --body "$(cat <<'DAG_EOF'
|
|
257
|
+
<!-- FORGE:PLAN_DAG -->
|
|
258
|
+
## Planned Dependency DAG
|
|
259
|
+
|
|
260
|
+
**Signal**: {SIGNAL.name}
|
|
261
|
+
**Generated**: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
262
|
+
**Governor**: max_issues={GOVERNOR_MAX_ISSUES}, max_cost_usd={GOVERNOR_MAX_COST}
|
|
263
|
+
|
|
264
|
+
### Work Units (execution order)
|
|
265
|
+
|
|
266
|
+
| Order | Issue | Title | Priority | Depends On | Status |
|
|
267
|
+
|-------|-------|-------|----------|------------|--------|
|
|
268
|
+
{rows — one per work unit, existing issues link to their number, new ones show "pending"}
|
|
269
|
+
|
|
270
|
+
### Dependency Graph
|
|
271
|
+
|
|
272
|
+
\`\`\`
|
|
273
|
+
{ASCII or text representation of the DAG edges}
|
|
274
|
+
\`\`\`
|
|
275
|
+
|
|
276
|
+
### Rationale
|
|
277
|
+
|
|
278
|
+
{1-2 sentence explanation of how this plan addresses the originating signal}
|
|
279
|
+
|
|
280
|
+
<!-- FORGE:PLAN_DAG:COMPLETE -->
|
|
281
|
+
DAG_EOF
|
|
282
|
+
)"
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**DRY_RUN check**: If `DRY_RUN == true`:
|
|
286
|
+
- Print the planned DAG to stdout
|
|
287
|
+
- Do NOT create the tracker issue or any work issues
|
|
288
|
+
- Print `[dry-run] No issues created. Re-run without --dry-run to execute.`
|
|
289
|
+
- Stop here
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Phase 3: Issue Creation (Governor-Gated)
|
|
294
|
+
|
|
295
|
+
**Goal**: Create GitHub issues for all new work units in the DAG.
|
|
296
|
+
|
|
297
|
+
### 3A: Governor pre-flight check
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
new_issues_needed = len([u for u in work_units if u.existing is None])
|
|
301
|
+
if new_issues_needed > GOVERNOR_MAX_ISSUES:
|
|
302
|
+
# Hard fail
|
|
303
|
+
print(f"GOVERNOR BREACH: {new_issues_needed} issues needed but governor cap is {GOVERNOR_MAX_ISSUES}")
|
|
304
|
+
print("Reduce scope or raise governor.max_issues_per_run in forge.yaml")
|
|
305
|
+
exit(1)
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
If governor would be breached, **hard fail** — do not create any issues, do not proceed to Phase 4.
|
|
309
|
+
|
|
310
|
+
### 3B: Create issues in dependency order
|
|
311
|
+
|
|
312
|
+
For each work unit with `existing == null`, create a GitHub issue:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
ISSUE_NUM=$(gh issue create -R {GH_REPO} \
|
|
316
|
+
--title "{work_unit.title}" \
|
|
317
|
+
--label "priority:{work_unit.priority},{work_unit.type}" \
|
|
318
|
+
--body "$(cat <<'ISSUE_EOF'
|
|
319
|
+
## Problem
|
|
320
|
+
|
|
321
|
+
{work_unit.rationale — why this is needed to resolve the originating signal}
|
|
322
|
+
|
|
323
|
+
## Signal Source
|
|
324
|
+
|
|
325
|
+
Generated by \`/signal-planner\` from signal: **{SIGNAL.name}** ({SIGNAL.type}, {SIGNAL.severity})
|
|
326
|
+
Tracker issue: #{TRACKER_ISSUE}
|
|
327
|
+
|
|
328
|
+
## Affected Files
|
|
329
|
+
|
|
330
|
+
1. `{work_unit.scope}` — address the signal-identified gap
|
|
331
|
+
|
|
332
|
+
## Acceptance Criteria
|
|
333
|
+
|
|
334
|
+
- [ ] {specific criterion derived from the signal context}
|
|
335
|
+
- [ ] Signal metric/incident verified not regressing after this change
|
|
336
|
+
|
|
337
|
+
## Context
|
|
338
|
+
|
|
339
|
+
Signal context: {relevant subset of SIGNAL.context for this work unit}
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
*Created by \`/signal-planner\` on $(date -u +%Y-%m-%dT%H:%M:%SZ). Will be investigated before any fix is applied.*
|
|
343
|
+
ISSUE_EOF
|
|
344
|
+
)" --json number --jq '.number')
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Record each created issue number and update the DAG table in the tracker issue.
|
|
348
|
+
|
|
349
|
+
### 3C: Compile final DAG issue list
|
|
350
|
+
|
|
351
|
+
Build `DAG_ISSUES` = ordered list of issue numbers (existing + newly created), in topological execution order.
|
|
352
|
+
|
|
353
|
+
Update the tracker issue `FORGE:PLAN_DAG` comment with the final resolved issue numbers.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Phase 4: Execute DAG via /orchestrate
|
|
358
|
+
|
|
359
|
+
**Goal**: Dispatch the ordered DAG to `/orchestrate` for parallel execution.
|
|
360
|
+
|
|
361
|
+
### 4A: Present execution plan to user
|
|
362
|
+
|
|
363
|
+
**MANDATORY CHECKPOINT** — do NOT proceed without confirmation.
|
|
364
|
+
|
|
365
|
+
```markdown
|
|
366
|
+
## Signal Planner — Execution Plan
|
|
367
|
+
|
|
368
|
+
**Signal**: {SIGNAL.name} ({SIGNAL.type} / {SIGNAL.severity})
|
|
369
|
+
**Tracker**: #{TRACKER_ISSUE}
|
|
370
|
+
|
|
371
|
+
I'll execute these {N} issues via /orchestrate (dependency order preserved):
|
|
372
|
+
|
|
373
|
+
| Order | Issue | Title | Priority |
|
|
374
|
+
|-------|-------|-------|----------|
|
|
375
|
+
| 1 | #{N} | ... | P1 |
|
|
376
|
+
| 2 | #{N} | ... | P2 |
|
|
377
|
+
|
|
378
|
+
Dependencies: {summary of any ordering constraints}
|
|
379
|
+
|
|
380
|
+
Each issue goes through: investigate → architect → build → review → merge to staging.
|
|
381
|
+
Nothing merges to `main` — you deploy when ready.
|
|
382
|
+
|
|
383
|
+
After all issues merge, I'll re-check the originating signal and post FORGE:SIGNAL_RESOLVED or FORGE:SIGNAL_UNRESOLVED.
|
|
384
|
+
|
|
385
|
+
**Proceed?** (yes / adjust / skip)
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Wait for user response. If they adjust (e.g., drop an issue, change priority), update `DAG_ISSUES` accordingly. If they skip, end here and leave the tracker issue open for manual execution.
|
|
389
|
+
|
|
390
|
+
### 4B: Dispatch to /orchestrate
|
|
391
|
+
|
|
392
|
+
Pass `DAG_ISSUES` as an ordered issue set to `/orchestrate`:
|
|
393
|
+
|
|
394
|
+
```
|
|
395
|
+
Skill(skill: "orchestrate", args: "{DAG_ISSUES joined by space — e.g. '42 43 45'}")
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
`/orchestrate` handles parallel execution where dependencies allow — signal-planner does not re-implement execution logic.
|
|
399
|
+
|
|
400
|
+
### 4C: Monitor completion
|
|
401
|
+
|
|
402
|
+
Poll until all DAG issues reach `workflow:merged`:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# Check each issue in DAG_ISSUES
|
|
406
|
+
for issue in $DAG_ISSUES; do
|
|
407
|
+
gh issue view $issue -R {GH_REPO} --json labels \
|
|
408
|
+
--jq '.labels | map(.name) | any(. == "workflow:merged")'
|
|
409
|
+
done
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Repeat every 5 minutes (or when notified by orchestrate completion) until all issues are merged or a timeout is reached (default: 2 hours). If timeout is reached, post an interim `FORGE:PLAN_DAG_STALLED` comment and exit — do not block indefinitely.
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## Phase 5: Signal Verification
|
|
417
|
+
|
|
418
|
+
**Goal**: Re-check the originating metric/incident after all DAG issues are merged. Post `FORGE:SIGNAL_RESOLVED` or `FORGE:SIGNAL_UNRESOLVED`.
|
|
419
|
+
|
|
420
|
+
### 5A: Re-fetch signal data
|
|
421
|
+
|
|
422
|
+
Repeat the same data collection from Phase 1B using the same source and parameters. This produces `SIGNAL_AFTER`.
|
|
423
|
+
|
|
424
|
+
**For `type="metric"`**: Pull the same metric with the same window — compare `SIGNAL_AFTER.current` vs `SIGNAL.context.current` (the pre-fix value) and vs `SIGNAL.context.baseline`.
|
|
425
|
+
|
|
426
|
+
**For `type="incident"`**: Check if the incident issue is closed and has `workflow:merged` label. Check CI runs since the merge for clean builds.
|
|
427
|
+
|
|
428
|
+
**For `type="geo"`**: Re-run the same compliance checks from Phase 1B. Compute new compliance score.
|
|
429
|
+
|
|
430
|
+
**For `type="raw"`**: Re-examine the affected areas identified in Phase 1B for the described problem.
|
|
431
|
+
|
|
432
|
+
### 5B: Evaluate resolution
|
|
433
|
+
|
|
434
|
+
```python
|
|
435
|
+
RESOLVED = False
|
|
436
|
+
|
|
437
|
+
if SIGNAL.type == "metric":
|
|
438
|
+
# Resolved if current value is within 10% of baseline (or above baseline)
|
|
439
|
+
recovery_pct = (SIGNAL_AFTER.current - SIGNAL.context.current) / abs(SIGNAL.context.delta_pct)
|
|
440
|
+
RESOLVED = SIGNAL_AFTER.current >= SIGNAL.context.baseline * 0.90
|
|
441
|
+
|
|
442
|
+
elif SIGNAL.type == "incident":
|
|
443
|
+
RESOLVED = incident_issue.state == "closed" and ci_clean_since_merge
|
|
444
|
+
|
|
445
|
+
elif SIGNAL.type == "geo":
|
|
446
|
+
RESOLVED = SIGNAL_AFTER.compliance_score >= SIGNAL.context.compliance_score + 0.10
|
|
447
|
+
|
|
448
|
+
elif SIGNAL.type == "raw":
|
|
449
|
+
# Conservative: mark unresolved, require human confirmation
|
|
450
|
+
RESOLVED = False
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### 5C: Post verification annotation
|
|
454
|
+
|
|
455
|
+
If `RESOLVED == True`, post `FORGE:SIGNAL_RESOLVED`:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
gh issue comment $TRACKER_ISSUE -R {GH_REPO} --body "$(cat <<'RESOLVED_EOF'
|
|
459
|
+
<!-- FORGE:SIGNAL_RESOLVED -->
|
|
460
|
+
## Signal Resolution Verified
|
|
461
|
+
|
|
462
|
+
**Signal**: {SIGNAL.name}
|
|
463
|
+
**Resolved**: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
464
|
+
|
|
465
|
+
### Before / After
|
|
466
|
+
|
|
467
|
+
| Metric | Before | After | Baseline |
|
|
468
|
+
|--------|--------|-------|----------|
|
|
469
|
+
| {name} | {SIGNAL.context.current} | {SIGNAL_AFTER.current} | {SIGNAL.context.baseline} |
|
|
470
|
+
|
|
471
|
+
### Conclusion
|
|
472
|
+
|
|
473
|
+
The originating signal is resolved. All {N} DAG issues merged to staging. Baseline metric recovered within tolerance.
|
|
474
|
+
|
|
475
|
+
**Next step**: Merge staging → main when ready to deploy.
|
|
476
|
+
|
|
477
|
+
<!-- FORGE:SIGNAL_RESOLVED:COMPLETE -->
|
|
478
|
+
RESOLVED_EOF
|
|
479
|
+
)"
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
If `RESOLVED == False`, post `FORGE:SIGNAL_UNRESOLVED`:
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
gh issue comment $TRACKER_ISSUE -R {GH_REPO} --body "$(cat <<'UNRESOLVED_EOF'
|
|
486
|
+
<!-- FORGE:SIGNAL_UNRESOLVED -->
|
|
487
|
+
## Signal Verification: UNRESOLVED
|
|
488
|
+
|
|
489
|
+
**Signal**: {SIGNAL.name}
|
|
490
|
+
**Checked**: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
491
|
+
|
|
492
|
+
### Before / After
|
|
493
|
+
|
|
494
|
+
| Metric | Before | After | Baseline |
|
|
495
|
+
|--------|--------|-------|----------|
|
|
496
|
+
| {name} | {SIGNAL.context.current} | {SIGNAL_AFTER.current} | {SIGNAL.context.baseline} |
|
|
497
|
+
|
|
498
|
+
### Conclusion
|
|
499
|
+
|
|
500
|
+
The signal is **not yet resolved** after DAG execution. Possible causes:
|
|
501
|
+
- The root cause spans more files than the DAG covered
|
|
502
|
+
- A dependency issue was excluded by the governor cap
|
|
503
|
+
- The signal is caused by an external factor outside this repo
|
|
504
|
+
|
|
505
|
+
### Recommended Actions
|
|
506
|
+
|
|
507
|
+
1. Review the DAG tracker issue: #{TRACKER_ISSUE}
|
|
508
|
+
2. Check if any work units were skipped or failed
|
|
509
|
+
3. Run \`/signal-planner\` again with a broader scope, or investigate manually with \`/work-on\`
|
|
510
|
+
|
|
511
|
+
<!-- FORGE:SIGNAL_UNRESOLVED:COMPLETE -->
|
|
512
|
+
UNRESOLVED_EOF
|
|
513
|
+
)"
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### 5D: Close the tracker issue
|
|
517
|
+
|
|
518
|
+
If `RESOLVED == True`:
|
|
519
|
+
```bash
|
|
520
|
+
gh issue close $TRACKER_ISSUE -R {GH_REPO} \
|
|
521
|
+
--comment "Closing tracker: originating signal verified resolved (FORGE:SIGNAL_RESOLVED posted)." \
|
|
522
|
+
--reason "completed"
|
|
523
|
+
gh issue edit $TRACKER_ISSUE -R {GH_REPO} --add-label "workflow:merged"
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
If `RESOLVED == False`, leave the tracker open for human review.
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Phase 6: Final Report
|
|
531
|
+
|
|
532
|
+
Print a summary regardless of resolution outcome:
|
|
533
|
+
|
|
534
|
+
```markdown
|
|
535
|
+
## Signal Planner — Cycle Complete
|
|
536
|
+
|
|
537
|
+
**Signal**: {SIGNAL.name} ({SIGNAL.type} / {SIGNAL.severity})
|
|
538
|
+
**Tracker**: #{TRACKER_ISSUE}
|
|
539
|
+
**Started**: {START_TIME}
|
|
540
|
+
**Completed**: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
541
|
+
|
|
542
|
+
### DAG Summary
|
|
543
|
+
|
|
544
|
+
| Issue | Title | Outcome |
|
|
545
|
+
|-------|-------|---------|
|
|
546
|
+
| #{N} | ... | merged |
|
|
547
|
+
|
|
548
|
+
**Issues created**: {new_count}
|
|
549
|
+
**Issues reused**: {existing_count}
|
|
550
|
+
**Governor headroom**: {GOVERNOR_MAX_ISSUES - total_issues} issues remaining
|
|
551
|
+
|
|
552
|
+
### Signal Resolution
|
|
553
|
+
|
|
554
|
+
**Status**: {RESOLVED / UNRESOLVED}
|
|
555
|
+
{resolution detail — 1-2 sentences}
|
|
556
|
+
|
|
557
|
+
### Next Steps
|
|
558
|
+
|
|
559
|
+
{If resolved}: Merge staging → main to deploy the fix.
|
|
560
|
+
{If unresolved}: Review tracker #{TRACKER_ISSUE} — consider /signal-planner with broader scope or /work-on for manual investigation.
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## FORGE Annotations Introduced by This Command
|
|
566
|
+
|
|
567
|
+
| Annotation | Writer | Consumer | Purpose |
|
|
568
|
+
|------------|--------|----------|---------|
|
|
569
|
+
| `FORGE:PLAN_DAG` | signal-planner (Phase 2D) | signal-planner (Phase 4), humans | Reviewable dependency DAG before execution |
|
|
570
|
+
| `FORGE:PLAN_DAG_STALLED` | signal-planner (Phase 4C) | humans | Execution timed out — DAG not fully merged |
|
|
571
|
+
| `FORGE:SIGNAL_RESOLVED` | signal-planner (Phase 5C) | humans, future autopilot cycles | Originating signal verified resolved |
|
|
572
|
+
| `FORGE:SIGNAL_UNRESOLVED` | signal-planner (Phase 5C) | humans | Post-execution signal check failed |
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Safety Rules
|
|
577
|
+
|
|
578
|
+
1. **NEVER merge to `main`** — all work goes to `staging`. User deploys manually.
|
|
579
|
+
2. **Governor is a hard fail** — if `new_issues > GOVERNOR_MAX_ISSUES`, abort Phase 3. Do not warn and continue.
|
|
580
|
+
3. **MANDATORY checkpoint before execution** — Phase 4A user gate is non-negotiable. Never auto-execute without confirmation.
|
|
581
|
+
4. **Dedup before creating** — always check existing open issues before creating any new one (Phase 2A).
|
|
582
|
+
5. **DRY_RUN means NO side effects** — no issues created, no comments, no label changes. Plan output only.
|
|
583
|
+
6. **Hydration failure is non-fatal** — if a sensor is unreachable, log a warning and continue with partial context.
|
|
584
|
+
7. **Resolution verdict is conservative** — when in doubt (type="raw", ambiguous metrics), post FORGE:SIGNAL_UNRESOLVED and let the human decide.
|
|
585
|
+
8. **Tracker issue is always created first** — even if all DAG issues are existing ones, the tracker provides the audit trail for this signal-planner run.
|
|
586
|
+
9. **NEVER fix `needs-human` issues** — issues with this label are excluded from the DAG automatically.
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## Relationship to Other Commands
|
|
591
|
+
|
|
592
|
+
| Command | Relationship |
|
|
593
|
+
|---------|-------------|
|
|
594
|
+
| `/autopilot` | Periodic improvement cycle. `/signal-planner` is its event-driven complement — triggered by a specific signal, not a timer. Use `/autopilot` for routine health checks; use `/signal-planner` when a specific signal fires. |
|
|
595
|
+
| `/analytics` | Signal sensor. `/signal-planner --metric` calls the same MCP tools as `/analytics` to hydrate metric signals. |
|
|
596
|
+
| `/geo-audit` | Signal sensor. `/signal-planner --geo` delegates GEO compliance checks to the `/geo-audit` sensor layer. |
|
|
597
|
+
| `/incident-response` | Signal sensor. `/signal-planner --incident` reads the incident issue and CI data as signal context. |
|
|
598
|
+
| `/orchestrate` | Execution engine. `/signal-planner` hands the ordered DAG issue list to `/orchestrate` for parallel dispatch. |
|
|
599
|
+
| `/work-on` | Per-issue pipeline. Called by `/orchestrate` for each DAG node. `/signal-planner` never calls `/work-on` directly. |
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## Examples
|
|
604
|
+
|
|
605
|
+
```bash
|
|
606
|
+
# Metric regression: GSC clicks dropped 40% week-over-week
|
|
607
|
+
/signal-planner --signal '{"type":"metric","name":"gsc_clicks","value":1200,"baseline":2000,"window":"7d"}'
|
|
608
|
+
|
|
609
|
+
# Latency alert from monitoring
|
|
610
|
+
/signal-planner --metric "checkout_latency_p99 >2000ms"
|
|
611
|
+
|
|
612
|
+
# Active P0 incident — plan fix DAG from the open incident issue
|
|
613
|
+
/signal-planner --incident 55
|
|
614
|
+
|
|
615
|
+
# GEO gap audit — plan issues for all compliance failures
|
|
616
|
+
/signal-planner --geo
|
|
617
|
+
|
|
618
|
+
# Dry run — see the plan without creating anything
|
|
619
|
+
/signal-planner --dry-run --signal '{"type":"metric","name":"conversion_rate","value":0.018,"baseline":0.031,"window":"7d"}'
|
|
620
|
+
|
|
621
|
+
# Conservative run — cap at 3 issues regardless of forge.yaml setting
|
|
622
|
+
/signal-planner --metric "error_rate >5%" --max-issues 3
|
|
623
|
+
```
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Detect API changes, sync satellite repos, and publish releases
|
|
3
3
|
argument-hint: [check | auto | status | publish | PR-number]
|
|
4
|
+
install: extras
|
|
4
5
|
---
|
|
5
6
|
<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
|
|
6
7
|
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|