@event4u/agent-config 14.7.0 → 14.8.0
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +245 -388
- package/README.md +1 -1
- package/dist/agent-src/commands/evals/git-pr-merge.json +13 -0
- package/dist/agent-src/commands/evals/roadmap.json +17 -1
- package/dist/agent-src/commands/pr/create.md +14 -2
- package/dist/agent-src/commands/pr/merge.md +379 -0
- package/dist/agent-src/commands/roadmap/process-full.md +157 -3
- package/dist/agent-src/commands/roadmap.md +1 -1
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +46 -36
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +37 -2
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +64 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
- package/dist/agent-src/rules/artifact-drafting-protocol.md +5 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +65 -33
- package/dist/agent-src/rules/recurring-criticism.md +1 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +19 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -1
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +7 -4
- package/dist/agent-src/scripts/dashboard_mode.ts +212 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +47 -48
- package/dist/agent-src/skills/adr-create/SKILL.md +124 -5
- package/dist/agent-src/skills/decision-record/SKILL.md +61 -3
- package/dist/agent-src/skills/decision-review/SKILL.md +65 -0
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +26 -0
- package/dist/agent-src/skills/security/SKILL.md +8 -0
- package/dist/agent-src/skills/security-audit/SKILL.md +12 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +20 -2
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-JZ4NR2TW.js → chunk-7PRE6ZV2.js} +1 -1
- package/dist/cli-delegate/{chunk-7F3VYSM2.js → chunk-EEJUMCDZ.js} +14 -14
- package/dist/cli-delegate/{chunk-74E3TKWV.js → chunk-H4VIVD4C.js} +5 -5
- package/dist/cli-delegate/chunk-I3EIN2YG.js +36 -0
- package/dist/cli-delegate/{chunk-4VR4ORQ6.js → chunk-LPPWO5CE.js} +4 -3
- package/dist/cli-delegate/{chunk-UEZ7D35A.js → chunk-N7CDDGI3.js} +4 -23
- package/dist/cli-delegate/cmd_adr_effective.js +1162 -0
- package/dist/cli-delegate/cmd_conformance.js +14 -14
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +7 -7
- package/dist/cli-delegate/cmd_export.js +6 -6
- package/dist/cli-delegate/cmd_handoff.js +7 -6
- package/dist/cli-delegate/cmd_memory_get.js +2 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_preflight.js +5 -5
- package/dist/cli-delegate/cmd_prune.js +6 -6
- package/dist/cli-delegate/cmd_route_audit.js +6 -5
- package/dist/cli-delegate/cmd_route_explain.js +3 -3
- package/dist/cli-delegate/cmd_session_recycle.js +3 -3
- package/dist/cli-delegate/cmd_settings_get.js +3 -3
- package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
- package/dist/cli-delegate/cmd_sync.js +6 -6
- package/dist/cli-delegate/cmd_uninstall.js +6 -6
- package/dist/cli-delegate/cmd_update.js +3 -3
- package/dist/cli-delegate/cmd_upgrade.js +3 -3
- package/dist/cli-delegate/cmd_validate.js +6 -6
- package/dist/cli-delegate/cmd_versions.js +3 -3
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +53 -22
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -6
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -5
- package/dist/hooks/dispatch.js +806 -681
- package/dist/install/globalRuleLayers.js +169 -0
- package/dist/install/globalRuleLayers.js.map +1 -0
- package/dist/install/partitionEligibility.js +156 -0
- package/dist/install/partitionEligibility.js.map +1 -1
- package/dist/install/ruleLayerPartition.js +157 -0
- package/dist/install/ruleLayerPartition.js.map +1 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +654 -578
- package/dist/scripts/_lib/prune_empty_dirs.js +85 -0
- package/dist/scripts/_lib/prune_empty_dirs.js.map +1 -0
- package/dist/scripts/condense.js +52 -89
- package/dist/scripts/condense.js.map +1 -1
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/false-green.md +47 -1
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +7 -4
- package/src/agent-src/scripts/dashboard_mode.ts +212 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +47 -48
- package/src/config/ci-local-parity.yml +21 -0
- package/src/config/estate-count-budget.json +275 -2
- package/src/config/evaluator-budgets.json +3 -3
- package/src/config/gate-coverage.yml +220 -12
- package/src/config/gate-violation-baselines.json +73 -63
- package/src/config/gitignore-block.txt +15 -2
- package/src/config/hook-latency-budget.json +5 -0
- package/src/config/rule-stub-ceilings.json +17 -3
- package/src/install/globalRuleLayers.ts +197 -0
- package/src/install/partitionEligibility.ts +177 -0
- package/src/install/ruleLayerPartition.ts +212 -0
- package/src/scripts/_cli/cmd_adr_effective.ts +484 -0
- package/src/scripts/_dispatch.bash +11 -0
- package/src/scripts/_lib/adr_frontmatter.test.ts +365 -0
- package/src/scripts/_lib/adr_frontmatter.ts +459 -0
- package/src/scripts/_lib/envelope_grounding.ts +11 -1
- package/src/scripts/_lib/layer_overlap_notice.ts +11 -2
- package/src/scripts/_lib/prune_empty_dirs.ts +80 -0
- package/src/scripts/adr/evidence_census.ts +899 -0
- package/src/scripts/adr/regenerate_index.ts +12 -32
- package/src/scripts/adr_cite_check.ts +540 -39
- package/src/scripts/audit_adr_coverage.ts +103 -17
- package/src/scripts/bench_hook_latency.ts +204 -0
- package/src/scripts/build_archive_index.ts +34 -0
- package/src/scripts/check_adr_frontmatter.ts +574 -39
- package/src/scripts/check_hook_bundle_content.ts +219 -0
- package/src/scripts/check_new_adr_evidence.ts +529 -0
- package/src/scripts/check_references.ts +18 -0
- package/src/scripts/check_rule_layer_partition.ts +531 -0
- package/src/scripts/check_single_delivery.ts +137 -4
- package/src/scripts/check_standing_rule_delivery.ts +8 -2
- package/src/scripts/condense.ts +61 -91
- package/src/scripts/external_sources_denylist.json +4 -1
- package/src/scripts/hooks/block_unauthorized_git.ts +22 -2
- package/src/scripts/hooks/dispatch_hook.ts +154 -187
- package/src/scripts/hooks/dispatch_issues.ts +38 -19
- package/src/scripts/hooks/fallback_yaml.ts +66 -0
- package/src/scripts/hooks/host_semantics.ts +21 -0
- package/src/scripts/hooks/injection_budget.ts +13 -3
- package/src/scripts/hooks/py_json_dumps.ts +103 -0
- package/src/scripts/hooks/state_io.ts +88 -1
- package/src/scripts/hooks/stdin_failure_policy.ts +96 -0
- package/src/scripts/injection_scan_hook.ts +137 -5
- package/src/scripts/lint_hook_manifest.ts +49 -0
- package/src/scripts/lint_provenance_vocabulary.ts +472 -4
- package/src/scripts/routing_doctor.ts +5 -1
- package/src/scripts/sync_pr_branch.ts +163 -20
- package/dist/cli-delegate/{chunk-PPQO4NGR.js → chunk-6RJA2F5A.js} +3 -3
- package/dist/cli-delegate/{chunk-6EOCNQAM.js → chunk-E4XIZDIB.js} +0 -0
- package/dist/cli-delegate/{chunk-FBKL6JWT.js → chunk-MMSGVZKV.js} +3 -3
- package/dist/cli-delegate/{chunk-GJ5BVHXM.js → chunk-PMEKGDED.js} +3 -3
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/event4u-app/agent-config/actions/workflows/smoke.yml) [](https://github.com/event4u-app/agent-config/actions/workflows/smoke-public-install.yml) [](https://www.npmjs.com/package/@event4u/agent-config) [](https://glama.ai/mcp/servers/event4u-app/agent-config) [](https://mcptoplist.com/server/glama%2Fevent4u-app%2Fagent-config)
|
|
6
6
|
|
|
7
|
-
[](dist/agent-src/skills/) [](dist/agent-src/rules/) [](dist/agent-src/skills/) [](dist/agent-src/rules/) [](dist/agent-src/commands/) [](docs/guidelines/) [](dist/agent-src/personas/) [](dist/agent-src/personas/advisors/)
|
|
8
8
|
|
|
9
9
|
**Try it in 30 seconds** — drop one read-only subagent into any repo and watch it gate "done": `@production-validator check this branch is actually done`. No wizard, no lock-in, nothing else installed — the [30-second wedge ↓](#quickstart) is the whole first step. Start at the proof, not the catalog: **[event4u-app.github.io/agent-config/proof/](https://event4u-app.github.io/agent-config/proof/)**.
|
|
10
10
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"command": "git-pr-merge",
|
|
3
|
+
"intent": "Prepare an open PR to mergeable — sync, resolve conflicts semantically, drive CI green — and merge it when the invocation says so",
|
|
4
|
+
"cases": [
|
|
5
|
+
{ "prompt": "merge PR 1478", "expected": "git-pr-merge" },
|
|
6
|
+
{ "prompt": "get this pull request mergeable and merge it", "expected": "git-pr-merge" },
|
|
7
|
+
{ "prompt": "drain all the open PRs — sync each one with main, fix CI, merge", "expected": "git-pr-merge" },
|
|
8
|
+
{ "prompt": "bring PR 1502 up to date with main and get its checks green, but don't merge it", "expected": "git-pr-merge" },
|
|
9
|
+
{ "prompt": "the open PRs all conflict with each other now — work through the queue", "expected": "git-pr-merge" },
|
|
10
|
+
{ "prompt": "open a pull request for this branch", "expected": "git-pr-create" },
|
|
11
|
+
{ "prompt": "write me a PR description I can paste", "expected": "git-pr-create-description-only" }
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"command": "roadmap",
|
|
3
|
-
"intent": "Roadmap dispatcher — create, process-step, process-phase, process-full, ai-council",
|
|
3
|
+
"intent": "Roadmap dispatcher — create, materialize, process-step, process-phase, process-full (incl. --all estate drain), next, ai-council",
|
|
4
4
|
"cases": [
|
|
5
5
|
{
|
|
6
6
|
"prompt": "create a roadmap for this initiative",
|
|
@@ -37,6 +37,22 @@
|
|
|
37
37
|
{
|
|
38
38
|
"prompt": "either roadmap it or turn it into a feature plan, your pick",
|
|
39
39
|
"expected": "roadmap"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"prompt": "drain every open roadmap, one PR each",
|
|
43
|
+
"expected": "roadmap"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"prompt": "arbeite alle Roadmaps der Reihe nach ab",
|
|
47
|
+
"expected": "roadmap"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"prompt": "work through the whole roadmap estate in a worktree",
|
|
51
|
+
"expected": "roadmap"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"prompt": "merge all the open pull requests",
|
|
55
|
+
"expected": "git-pr-merge"
|
|
40
56
|
}
|
|
41
57
|
]
|
|
42
58
|
}
|
|
@@ -153,8 +153,20 @@ merge into instead of against the repo default.
|
|
|
153
153
|
`./scripts-run src/scripts/sync_pr_branch` resolves the base from the open PR
|
|
154
154
|
(so a stacked or release-line PR is measured against what it actually merges
|
|
155
155
|
into), fetches, and merges it in when the branch is behind. On a conflict it
|
|
156
|
-
STOPS and splits the conflicted paths into generated and authored —
|
|
157
|
-
one correct resolution (regenerate), the second
|
|
156
|
+
STOPS and splits the conflicted paths into generated, remeasured and authored —
|
|
157
|
+
the first has one correct resolution (regenerate), the second's is to re-run the
|
|
158
|
+
measurement on the merged tree (a ratchet baseline, where picking a side is how
|
|
159
|
+
the ratchet silently loosens), and the third has none a script may choose.
|
|
160
|
+
|
|
161
|
+
**On `CONFLICTING`, run this before touching the GitHub web editor.** The web
|
|
162
|
+
editor cannot tell generated from authored, so it presents a mechanical
|
|
163
|
+
regenerate and a real human decision as the same three-way merge — which is the
|
|
164
|
+
failure path road-to-merge-hotspot-drawdown was opened over — a branch resolved
|
|
165
|
+
in the web editor while behind its base. The observation itself lives in the
|
|
166
|
+
maintainer handover that roadmap cites as its Source, not in the roadmap's own
|
|
167
|
+
§ 0, so do not expect to find it there. Adoption of this line is not measurable
|
|
168
|
+
without telemetry this repository has ruled out; it is a checklist item, not a
|
|
169
|
+
gate.
|
|
158
170
|
Deliberately not in the pre-push hook: it mutates the tree, and a hook that
|
|
159
171
|
rewrites the tree mid-push turns one rejected push into an unreviewed commit.
|
|
160
172
|
Detection belongs in the hook and is already there; resolution is a step you run
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
---
|
|
2
|
+
model_tier: medium
|
|
3
|
+
name: git-pr-merge
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
argument-hint: "[all|<pr-number>] [--no-merge]"
|
|
6
|
+
pack: git
|
|
7
|
+
intent: "Prepare an open PR to mergeable — sync the base in, resolve conflicts semantically, drive required checks green — merging itself is gated and inert"
|
|
8
|
+
routes_to: [git-workflow, github-ci]
|
|
9
|
+
replaces: []
|
|
10
|
+
visibility: advanced
|
|
11
|
+
cluster: git-pr-merge
|
|
12
|
+
skills: [git-workflow, github-ci]
|
|
13
|
+
description: Prepare one open PR to mergeable, or the whole open-PR queue with `all` — merging is specified but gated, so today every invocation stops at mergeable-and-open
|
|
14
|
+
suggestion:
|
|
15
|
+
eligible: false
|
|
16
|
+
rationale: "Merging is irreversible and gated on the user's own word in the invocation — a suggested merge would manufacture the authorization the Hard Floor requires the user to give."
|
|
17
|
+
workspaces:
|
|
18
|
+
- agent-config-maintainer
|
|
19
|
+
packs:
|
|
20
|
+
- git
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# /git-pr-merge
|
|
24
|
+
|
|
25
|
+
Prepare an open pull request until it is genuinely mergeable — its base merged
|
|
26
|
+
in, its conflicts resolved by class rather than by taste, its required checks
|
|
27
|
+
green on the head that will actually be merged — and then merge it, if and only
|
|
28
|
+
if the invocation authorised that.
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
THE MERGE STEP (§ 9) IS SPECIFIED AND NOT YET ACTIVE. `--no-merge` IS THE
|
|
32
|
+
OPERATIVE PATH TODAY, AND A BARE INVOCATION BEHAVES AS IF IT CARRIED IT.
|
|
33
|
+
ACTIVATION NEEDS THE OWNER DECISION IN THE `merge-authority` BLOCKER OF
|
|
34
|
+
`road-to-drain-commands` — NEVER A COMMAND EDIT, AND NEVER A GUARD EDIT.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**The invocation is the authorization, and nothing else is.** `pr-merge` is a
|
|
38
|
+
`BLOCK_OPS` member in `block_unauthorized_git.ts` because it is irreversible.
|
|
39
|
+
This command would consume the authorization the user's own prompt text already
|
|
40
|
+
wrote to the per-session ledger on `UserPromptSubmit`; it introduces no second
|
|
41
|
+
authorization store, and it never writes one. When that window closes the run
|
|
42
|
+
stops and reports (§ 7) — the window never grows.
|
|
43
|
+
|
|
44
|
+
Why it ships inert rather than not at all: everything before § 9 — the target
|
|
45
|
+
manifest, the four conflict classes, the superseded check, the bounded CI
|
|
46
|
+
repair, the cutoff — is the expensive, error-prone half, it is what the live
|
|
47
|
+
runs actually proved, and none of it merges anything. `--no-merge` delivers all
|
|
48
|
+
of it today.
|
|
49
|
+
|
|
50
|
+
## Sub-commands
|
|
51
|
+
|
|
52
|
+
| Sub-command | Routes to | Purpose |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
|
|
55
|
+
*(none, deliberately.)* `all` changes **cardinality**, not lifecycle, so it is
|
|
56
|
+
an argument rather than a second command — the locked registry's rule that
|
|
57
|
+
"sibling variants become a flag, never a second command"
|
|
58
|
+
([`command-clusters`](../../../../../docs/contracts/command-clusters.md)) applied
|
|
59
|
+
to this cluster. A future sub belongs here only if it has a materially
|
|
60
|
+
different lifecycle, not a different count.
|
|
61
|
+
|
|
62
|
+
## Dispatch
|
|
63
|
+
|
|
64
|
+
Every row below **prepares** — the merge step is gated (see the banner above),
|
|
65
|
+
so today every row ends at mergeable-and-open. The column says what each row
|
|
66
|
+
selects, not that it merges.
|
|
67
|
+
|
|
68
|
+
| Invocation | Selects | Prepares | Merges |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| `/pr:merge <N>` | exactly PR N | yes | only once the gate opens |
|
|
71
|
+
| `/pr:merge` | ONE PR: green first, then infrastructure/tooling before content, then smallest diff (`changedFiles`, then additions+deletions), tiebreak ascending number | yes | only once the gate opens |
|
|
72
|
+
| `/pr:merge all` | the whole open-PR list, under § 6's cutoff | yes | only once the gate opens |
|
|
73
|
+
| `… --no-merge` | as above | yes | **never**, explicitly. This is the form [`/roadmap:process-full`](../../../product-basic/roadmap/process-full/command.md) calls for its delivery loop. |
|
|
74
|
+
|
|
75
|
+
**Bare invocation** (`/pr:merge` with no argument) is a **documented default
|
|
76
|
+
flow**, not a menu: it runs the auto-selection in row 2 and says which PR it
|
|
77
|
+
picked and why, before touching it. A menu would be the wrong shape here —
|
|
78
|
+
selection is deterministic from the queue-order rule in § 1, so asking the user
|
|
79
|
+
to pick would hand back a decision the command can compute. When the open-PR
|
|
80
|
+
list is empty there is nothing to select and the command reports that and
|
|
81
|
+
stops.
|
|
82
|
+
|
|
83
|
+
## 1. Snapshot the target — an immutable manifest
|
|
84
|
+
|
|
85
|
+
Compute the queue ONCE at invocation and record it as a manifest of
|
|
86
|
+
`(PR number, head SHA)` pairs:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
gh pr list --state open --limit 100 \
|
|
90
|
+
--json number,title,headRefName,headRefOid,baseRefName,additions,deletions,changedFiles,mergeable,updatedAt
|
|
91
|
+
gh api repos/:owner/:repo/git/ref/heads/<baseRefName> --jq .object.sha # per distinct base
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`baseRefName` and the base SHA are part of the record, not incidental: § 2 and
|
|
95
|
+
§ 4 both consume `<base>`, and § 8's kill switch "the base advanced by an actor
|
|
96
|
+
other than this run" is undetectable without a base SHA to compare against.
|
|
97
|
+
|
|
98
|
+
`--limit 100` caps the manifest. A queue above 100 open PRs is drained
|
|
99
|
+
**partially**, and the run must say so rather than reporting completion — the
|
|
100
|
+
§ 6 bound reads "initial manifest + one batch", and the manifest is what the
|
|
101
|
+
cap truncated.
|
|
102
|
+
|
|
103
|
+
The manifest is the authorization's target set and is **never silently
|
|
104
|
+
refreshed by a third party's push**. It is, by design, advanced by *this run's
|
|
105
|
+
own* commits — § 2 merges the base in and § 5 pushes, so a prepared PR's head
|
|
106
|
+
is never the snapshot head, and a naive "refuse when the SHA moved" check would
|
|
107
|
+
fire on every PR the run touches.
|
|
108
|
+
|
|
109
|
+
So the record carries **two** SHAs per PR and they mean different things:
|
|
110
|
+
|
|
111
|
+
| Field | Set at | Meaning |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `pr_number` | snapshot | Immutable. A change is branch substitution — refuse. |
|
|
114
|
+
| `observed_head` | snapshot, then **updated by this run after each of its own pushes** | The head this run last produced. |
|
|
115
|
+
| `base_ref` + `base_sha` | snapshot | The base the PR was prepared against; § 8's "base advanced by another actor" compares against it. |
|
|
116
|
+
|
|
117
|
+
Before every merge, re-read the PR and refuse when the live head is **neither**
|
|
118
|
+
the snapshot head **nor** the head this run last pushed. That is the
|
|
119
|
+
force-push-after-authorization case, and it is the only one the check exists
|
|
120
|
+
for. A PR that appeared after the snapshot is not in scope for this run — § 6
|
|
121
|
+
says what happens to it.
|
|
122
|
+
|
|
123
|
+
## 2. Sync with the base
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
git fetch origin
|
|
127
|
+
gh pr checkout <N>
|
|
128
|
+
git merge origin/<base> --no-edit
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Merge the base **into** the branch. Never rebase a branch that is already
|
|
132
|
+
pushed ([`git-history-discipline`](../../../../rules/git-history-discipline.md)).
|
|
133
|
+
|
|
134
|
+
## 3. Resolve conflicts by class, never by taste
|
|
135
|
+
|
|
136
|
+
Conflicts between queued PRs are expected, not exceptional: in this repository
|
|
137
|
+
every roadmap PR touches `agents/roadmaps-progress.md` and
|
|
138
|
+
`src/config/estate-count-budget.json`, so each merge re-conflicts every
|
|
139
|
+
remaining PR. Resolve semantically, by these enumerated classes:
|
|
140
|
+
|
|
141
|
+
| Class | Files | Resolution |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| Roadmap files | `agents/roadmaps/**` | Union of completions. Never un-check a box either side checked; never resurrect a roadmap either side archived or parked. |
|
|
144
|
+
| Generated artefacts | `agents/roadmaps-progress.md` · `src/config/estate-count-budget.json` · `docs/catalog.md` · `docs/command-flows.md` · `agents/index.md` · any file whose first three lines say generated / do-not-edit | Never hand-merge. Take either side, then **regenerate** with the repo's own task and commit the regenerated output. |
|
|
145
|
+
| Archive move vs. edit | `agents/roadmaps/{archive,later,skipped}/**` — one side renamed or deleted, the other edited | The archived end-state wins. Re-apply the edit at the new path if it still matters; otherwise drop it and record the drop in the summary. |
|
|
146
|
+
| Evidence files | `agents/evidence/**` | Append-only. Keep both sides. |
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
A CONFLICT OUTSIDE THESE FOUR CLASSES HALTS THE RUN.
|
|
150
|
+
IT IS NOT RESOLVED BY JUDGEMENT AND NOT ESCALATED TO A WARNING.
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The classes exist so a merge resolution is reproducible by a second reader. An
|
|
154
|
+
unenumerated conflict is a case nobody has decided yet, and deciding it silently
|
|
155
|
+
inside a drain loop is how work disappears.
|
|
156
|
+
|
|
157
|
+
## 4. Superseded check — before any CI is spent
|
|
158
|
+
|
|
159
|
+
If the effective diff against the base is empty after syncing, the PR's content
|
|
160
|
+
already landed elsewhere. Distinguish genuinely empty from generated-artefact
|
|
161
|
+
churn that regeneration on the base would produce anyway — the latter is not
|
|
162
|
+
emptiness.
|
|
163
|
+
|
|
164
|
+
The probe is **not** a bare diff: taken literally, a bare diff closes every
|
|
165
|
+
roadmap PR in this repository, because after a base sync and a regenerate the
|
|
166
|
+
only remaining hunks are exactly the generated-artefact churn § 3 tells you to
|
|
167
|
+
regenerate. Exclude those paths before deciding:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
git diff origin/<base>...HEAD --stat -- . \
|
|
171
|
+
':(exclude)agents/roadmaps-progress.md' \
|
|
172
|
+
':(exclude)src/config/estate-count-budget.json' \
|
|
173
|
+
':(exclude)docs/catalog.md' ':(exclude)agents/index.md'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Empty **after that exclusion** ⇒ superseded. **Never merge an empty PR to make
|
|
177
|
+
the queue count fall — and never close one on a bare diff.**
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
CLOSING SOMEONE ELSE'S PR IS AN IRREVERSIBLE EXTERNAL ACTION AND IS NOT
|
|
181
|
+
GUARDED: `pr-close` IS NOT A `GitOp` AT ALL — NOT IN `BLOCK_OPS`, NOT EVEN
|
|
182
|
+
IN `WARN_OPS`. NOTHING WILL STOP IT, WHICH IS WHY THIS COMMAND MUST.
|
|
183
|
+
|
|
184
|
+
THE RUN NEVER CLOSES A PR ON ITS OWN HEURISTIC. IT STOPS AND ASKS, NAMING
|
|
185
|
+
THE EXACT OBJECT: THE PR NUMBER, ITS TITLE, ITS AUTHOR, AND THE PRs THE
|
|
186
|
+
CONTENT LANDED VIA. ONE CONFIRMATION PER PR, THIS TURN, PER
|
|
187
|
+
non-destructive-by-default. NEVER A BATCH APPROVAL FOR "THE SUPERSEDED ONES".
|
|
188
|
+
IT CANNOT NAME WHERE THE CONTENT LANDED → DO NOT EVEN ASK; LEAVE THE PR OPEN
|
|
189
|
+
AND RECORD IT AS `blocked-external`.
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The asymmetry is deliberate and worth stating, because it looks inconsistent:
|
|
193
|
+
merging is gated on an owner *decision* recorded once in a blocker, while
|
|
194
|
+
closing is gated on a *per-object* confirmation every time. Merging this run's
|
|
195
|
+
own PR is an action the run's whole design is about; closing a PR someone else
|
|
196
|
+
opened is not, it destroys their work in progress, and no guard in this tree
|
|
197
|
+
sees it happen. The cheaper gate goes on the action nothing else watches.
|
|
198
|
+
|
|
199
|
+
## 5. Drive CI green — bounded
|
|
200
|
+
|
|
201
|
+
Push, then wait for the verdict on the pushed head. Green means **the required
|
|
202
|
+
checks succeeded for the exact head SHA that will be merged** — never a local
|
|
203
|
+
run, never an earlier commit ([`/git-pr-create` § 4d](../create/command.md)).
|
|
204
|
+
|
|
205
|
+
- **Root-cause fixes only**, inside the PR's own scope.
|
|
206
|
+
- **One rerun for a known flake class** (`gh run rerun <id> --failed`) before
|
|
207
|
+
red counts as real.
|
|
208
|
+
- **N=3 per validation target, six touches per PR per pass — two different
|
|
209
|
+
units, and the smaller one binds first.** The always-loaded
|
|
210
|
+
[`autonomous-execution`](../../../../rules/autonomous-execution.md) cap is
|
|
211
|
+
three consecutive failed attempts on ONE target (a named failing test, a lint
|
|
212
|
+
rule id, one CI job) and it is not lifted here. The six is a per-PR ceiling
|
|
213
|
+
across *distinct* targets: a PR whose CI peels one failure to reveal a
|
|
214
|
+
different one may be worked six times, never one target four times. Hitting
|
|
215
|
+
N=3 on a single target ends the PR's pass immediately, whatever the six says.
|
|
216
|
+
Exhaustion of either posts a diagnosis comment and moves the PR to the end of
|
|
217
|
+
the queue once; a second exhaustion is terminal.
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
THESE ARE HALTS, NOT OPTIONS OF LAST RESORT:
|
|
221
|
+
DEPENDENCY CHANGES · WORKFLOW CHANGES · DELETING OR SKIPPING A TEST ·
|
|
222
|
+
LOOSENING A THRESHOLD · WEAKENING A GATE · AN EXPECTED-FAIL MARKER ·
|
|
223
|
+
A BRANCH-PROTECTION CHANGE.
|
|
224
|
+
"DRIVE CI GREEN" AUTHORIZES DIAGNOSIS AND REPAIR, NEVER REMOVING THE CHECK
|
|
225
|
+
THAT WOULD HAVE CAUGHT THE PROBLEM.
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## 6. `all` — the queue, and the cutoff that ends it
|
|
229
|
+
|
|
230
|
+
Process the manifest in the order § 1 recorded it — the queue-order rule in the
|
|
231
|
+
Dispatch table's second row is the traversal for `all` too, not only for
|
|
232
|
+
single-PR selection, so two runs over the same queue agree.
|
|
233
|
+
|
|
234
|
+
After each merge the base has moved, so the next PR is re-synced against the
|
|
235
|
+
NEW base — that is the loop, and it is why pre-greening several PRs ahead of
|
|
236
|
+
their merges is wasted work.
|
|
237
|
+
|
|
238
|
+
**While the merge step is gated, that loop does not turn**, and the section
|
|
239
|
+
below is written for when it does. Nothing merges, so the base does not
|
|
240
|
+
advance, no PR leaves the open list, and an `all` run is a **preparation
|
|
241
|
+
sweep**: it syncs, classifies, greens and reports each PR once, then stops. It
|
|
242
|
+
does not re-prepare a PR its own predecessor invalidated, because it has no
|
|
243
|
+
predecessor that landed. The cutoff below still bounds it; the window below
|
|
244
|
+
still cannot close it, for the reason § 7 gives.
|
|
245
|
+
|
|
246
|
+
**Cutoff.** When the manifest is exhausted, recompute the open-PR list
|
|
247
|
+
**exactly once**. PRs that appeared during the run are drained as ONE final
|
|
248
|
+
straggler batch. After that batch the run ends unconditionally; anything
|
|
249
|
+
arriving during or after it is recorded as `arrived-after-cutoff` and is not
|
|
250
|
+
processed.
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
THE CUTOFF IS THE TERMINATION PROOF.
|
|
254
|
+
WITHOUT IT, "THE QUEUE MUST SHRINK" DOES NOT TERMINATE AGAINST A SECOND
|
|
255
|
+
SESSION THAT KEEPS OPENING PRs — THE RECOMPUTE JUST REFILLS IT.
|
|
256
|
+
BOUND: INITIAL MANIFEST + ONE BATCH, WHATEVER ELSE IS HAPPENING IN THE REPO.
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Window-aware scheduling.** A green, waiting PR is spent authorization window,
|
|
260
|
+
because the next merge re-conflicts it. When the projected remaining work
|
|
261
|
+
exceeds the remaining window, stop entering CI-fix loops and merge everything
|
|
262
|
+
already green first. Pre-greening several PRs ahead of their merge is forbidden
|
|
263
|
+
under window pressure.
|
|
264
|
+
|
|
265
|
+
**The signal, named — otherwise neither this rule nor § 7 is actionable.** The
|
|
266
|
+
window is the per-session authorization ledger's own freshness bound. Read it,
|
|
267
|
+
never write it:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
cat "agents/state/git-authorization/$(<session-slug>).json" # detected_at
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Remaining window = `detected_at + LEDGER_MAX_AGE_MS − now`. Take the constant
|
|
274
|
+
from the guard source **only after** `check_hook_bundle_content` says the
|
|
275
|
+
source and the executing bundle agree — reading the source alone is the
|
|
276
|
+
2026-08-21 failure re-expressed as an instruction, since the bundle is what
|
|
277
|
+
enforces the value and a source edit without a rebuild is silently inert. Under
|
|
278
|
+
pressure means
|
|
279
|
+
the remaining window is shorter than one CI cycle on this repository. The read
|
|
280
|
+
is the whole interaction: the run never edits that file, the constant, or the
|
|
281
|
+
built bundle.
|
|
282
|
+
|
|
283
|
+
## 7. Expiry is a reported state, never a stall
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
WHEN THE AUTHORIZATION WINDOW CLOSES WITH WORK LEFT, THE RUN STOPS CLEANLY
|
|
287
|
+
AND REPORTS. IT NEVER RETRIES THE GUARD, AND IT NEVER EDITS THE GUARD,
|
|
288
|
+
ITS SOURCE, OR ITS BUNDLES — READ-ONLY VERIFICATION ONLY.
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Unreachable while the merge step is gated**, and stated rather than left for
|
|
292
|
+
a reader to discover: with nothing merging, the run performs no `BLOCK_OPS`
|
|
293
|
+
operation (`push` and `commit` are `WARN_OPS`), so the window governs nothing
|
|
294
|
+
it does. This section is the contract for when the gate opens.
|
|
295
|
+
|
|
296
|
+
Write the summary as-is with a `window-expired` disposition per unprocessed PR
|
|
297
|
+
and name the exact re-authorization needed. Widening `LEDGER_MAX_AGE_MS` is
|
|
298
|
+
forbidden practice: on 2026-08-21 it was patched to six hours for a drain run
|
|
299
|
+
and the widening reached the trunk.
|
|
300
|
+
|
|
301
|
+
## 8. Kill switches, and what happens after a merge
|
|
302
|
+
|
|
303
|
+
**Armed during preparation, not only before a merge** — otherwise every switch
|
|
304
|
+
below is unreachable while the merge step is gated, and a preparation sweep has
|
|
305
|
+
no way to stop at all. Each one aborts the current PR and ends the run on any
|
|
306
|
+
of:
|
|
307
|
+
|
|
308
|
+
- target number or head SHA differs from the manifest;
|
|
309
|
+
- the base advanced by an actor other than this run;
|
|
310
|
+
- a review was dismissed, or the required-check set changed;
|
|
311
|
+
- a conflict outside the four enumerated classes;
|
|
312
|
+
- guard or hook-bundle verification failed;
|
|
313
|
+
- the first unexplained CI-repair failure.
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
A COMPLETED MERGE IS THE COMMIT POINT.
|
|
317
|
+
NEVER AUTO-REVERT AN EARLIER MERGE AS "ROLLBACK" — AFTER FIVE MERGES THERE IS
|
|
318
|
+
NO ROLLBACK, ONLY COMPENSATION, AND COMPENSATION IS A SEPARATELY AUTHORIZED
|
|
319
|
+
HUMAN DECISION. STOP, EMIT THE MERGE SHAs AND THE REASON, HAND OVER.
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## 9. Merge, and the summary
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
gh pr merge <N> --<detected-method> --delete-branch
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Detect the method once, at invocation, and reuse it for the whole queue:
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
gh repo view --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
The mapping is explicit, because `<detected-method>` has to be derivable from
|
|
335
|
+
the text: `mergeCommitAllowed` → `--merge`, `squashMergeAllowed` → `--squash`,
|
|
336
|
+
`rebaseMergeAllowed` → `--rebase`.
|
|
337
|
+
|
|
338
|
+
Exactly one allowed → that is the method. More than one → read the last twenty
|
|
339
|
+
merges on the base (`git log --first-parent origin/<base> -20 --format=%s`) and
|
|
340
|
+
take the shape they overwhelmingly share. **A mixed history with no clear
|
|
341
|
+
majority is not a tie to break — it is a stop:** report it and let the operator
|
|
342
|
+
name the method. Inventing one is what the next sentence forbids, and a wrong
|
|
343
|
+
merge shape is not revertible by this command (§ 8). Never force-merge past a
|
|
344
|
+
failing required check, never admin-bypass.
|
|
345
|
+
|
|
346
|
+
On queue empty or terminal-only, `all` writes
|
|
347
|
+
`agents/evidence/pr-drain-run-summary.md` <!-- ref-ignore --> (created by the
|
|
348
|
+
run, so it does not exist until one has happened): one row per PR with queue
|
|
349
|
+
position, the `base_ref@base_sha` it was prepared against — without it a
|
|
350
|
+
"prepared" row records nothing checkable, since mergeability is a fact about a
|
|
351
|
+
base and not about a queue —
|
|
352
|
+
conflict classes hit, CI iterations used, disposition, and any edits dropped in
|
|
353
|
+
conflict resolution. The disposition set is closed:
|
|
354
|
+
|
|
355
|
+
`merged <sha>` · `superseded-closed` · `blocked-external` · `twice-exhausted` ·
|
|
356
|
+
`window-expired` · `arrived-after-cutoff`
|
|
357
|
+
|
|
358
|
+
## Rules
|
|
359
|
+
|
|
360
|
+
- **Never merge while the gate is closed.** Until the `merge-authority`
|
|
361
|
+
blocker resolves, every invocation stops at mergeable-and-open, `--no-merge`
|
|
362
|
+
or not. Once it opens, `--no-merge` is still the explicit way to say stop.
|
|
363
|
+
- **Never widen, patch, or rebuild-around the git guard.** Verification of the
|
|
364
|
+
authorization window is read-only.
|
|
365
|
+
- **Never rebase a pushed branch**; the base is merged in.
|
|
366
|
+
- **Never hand-merge a generated artefact**; regenerate it.
|
|
367
|
+
- **Never resolve a conflict outside the four classes**; halt instead.
|
|
368
|
+
- **Never call CI green off a local run**; re-verify on the pushed head.
|
|
369
|
+
- **Never auto-revert a completed merge.**
|
|
370
|
+
- **Mergeability is per-PR against a recorded base SHA**, never a property of
|
|
371
|
+
the queue: making PR *n* mergeable against base `M` says nothing about its
|
|
372
|
+
state once PR *n−1* advances the base.
|
|
373
|
+
|
|
374
|
+
## See also
|
|
375
|
+
|
|
376
|
+
- [`/git-pr-create`](../create/command.md) — opens the PR this command finishes.
|
|
377
|
+
- [`/roadmap:process-full`](../../../product-basic/roadmap/process-full/command.md) — delegates here for its delivery loop.
|
|
378
|
+
- [`git-history-discipline`](../../../../rules/git-history-discipline.md) — never rewrite pushed history.
|
|
379
|
+
- [`non-destructive-by-default`](../../../../rules/non-destructive-by-default.md) — the Hard Floor a merge sits under.
|
|
@@ -7,7 +7,7 @@ cluster: roadmap
|
|
|
7
7
|
sub: process-full
|
|
8
8
|
skills: [agent-docs-writing, ai-council, roadmap-management]
|
|
9
9
|
description: Autonomously process every open step across every phase of a roadmap until the file is fully closed. Largest execution scope of the /roadmap cluster — runs continuously across phase boundaries.
|
|
10
|
-
argument-hint: "[roadmap]"
|
|
10
|
+
argument-hint: "[roadmap] [--all] [--worktree]"
|
|
11
11
|
suggestion:
|
|
12
12
|
eligible: false
|
|
13
13
|
rationale: "Cluster sub-command — reached via its cluster head's routing or its explicit /cluster:sub name; not independently suggested (surface-consolidation)."
|
|
@@ -80,6 +80,116 @@ with the **scope delta below**.
|
|
|
80
80
|
archival check from
|
|
81
81
|
[`roadmap-process-loop § 6`](../../contexts/execution/roadmap-process-loop.md#6-final-report-and-archival).
|
|
82
82
|
|
|
83
|
+
## The three flags
|
|
84
|
+
|
|
85
|
+
### `--all` — the estate, one roadmap at a time
|
|
86
|
+
|
|
87
|
+
`--all` changes **cardinality, not lifecycle**: the same single-roadmap loop,
|
|
88
|
+
iterated over the whole active estate. It is a flag rather than a
|
|
89
|
+
`/roadmap:process-all` command because
|
|
90
|
+
[`command-clusters`](../../../../../docs/contracts/command-clusters.md) says
|
|
91
|
+
sibling variants become a flag, and a drain is a count of the thing this
|
|
92
|
+
command already does.
|
|
93
|
+
|
|
94
|
+
1. **Recompute the inventory live.** Never from memory, never from the
|
|
95
|
+
dashboard count — the same live-screen rule
|
|
96
|
+
[`/roadmap:next` § 1](../next/command.md) already carries. The corpus is the
|
|
97
|
+
non-draft roadmaps directly under `agents/roadmaps/`; `later/`, `skipped/`,
|
|
98
|
+
`archive/` and `stubs/` are out of scope.
|
|
99
|
+
2. **Order the queue.** Roadmaps at or above 10 % checkbox progress first, in
|
|
100
|
+
**descending** progress — nearly-done first, because they convert soonest.
|
|
101
|
+
Roadmaps below 10 % are appended after, ascending by declared `complexity:`
|
|
102
|
+
tier (lightweight → bounded → structural), tiebreak ascending total
|
|
103
|
+
checkbox count. Both buckets need a **total** order or two runs over the
|
|
104
|
+
same estate disagree: within the first, ties on progress break by ascending
|
|
105
|
+
total checkbox count and then by ascending filename; within the second, by
|
|
106
|
+
ascending filename after the checkbox count.
|
|
107
|
+
3. **Loop.** Per roadmap: branch from the updated default, run this command's
|
|
108
|
+
normal single-roadmap loop, deliver per § Delivery, then take the next
|
|
109
|
+
roadmap against the default **as it stands at that moment** — re-fetched,
|
|
110
|
+
never assumed. One roadmap = one branch = one PR, the existing invariant
|
|
111
|
+
iterated, not a new one.
|
|
112
|
+
|
|
113
|
+
**What `--all` can and cannot promise, stated plainly because the honest
|
|
114
|
+
version is weaker than the obvious one.** Nothing in the run
|
|
115
|
+
merges, so the default does not advance because of this run, and every PR after
|
|
116
|
+
the first is mergeable *against the base recorded when it was prepared* rather
|
|
117
|
+
than against the base after its predecessors land. In a repository where every
|
|
118
|
+
roadmap PR touches the same generated files, that means an `--all` hand-off is
|
|
119
|
+
**one immediately-mergeable PR plus N−1 prepared ones**, each needing a
|
|
120
|
+
re-sync at merge time. That is still the expensive half — conflicts classified,
|
|
121
|
+
CI green once, superseded PRs closed — but it is not "N mergeable PRs", and the
|
|
122
|
+
run reports it in those words.
|
|
123
|
+
|
|
124
|
+
**A blocked roadmap never stalls the estate queue.** Inside a roadmap the five
|
|
125
|
+
halt conditions and the terminal outcomes keep full authority. Between
|
|
126
|
+
roadmaps, the § Halt-conditions table below is the single statement of what
|
|
127
|
+
ends the roadmap and what ends the loop — including the two halts that are
|
|
128
|
+
safety floors and therefore end the run. A `blocked` roadmap is recorded and
|
|
129
|
+
the loop continues to the next one.
|
|
130
|
+
|
|
131
|
+
### Delivery — every run, flag or not
|
|
132
|
+
|
|
133
|
+
On outcome `complete`, open the PR as today, then run
|
|
134
|
+
[`/pr:merge <N> --no-merge`](../../../git/pr/merge/command.md) on it: sync the
|
|
135
|
+
base in, resolve conflicts by that command's four enumerated classes, drive the
|
|
136
|
+
required checks green on the pushed head. **This is unconditional** — a bare
|
|
137
|
+
`/roadmap:process-full` delivers a mergeable PR, not merely an open one, and
|
|
138
|
+
waiting on that remote CI is part of the run per the Iron Law below. It is
|
|
139
|
+
the whole of what this command delivers: there is no flag that carries it
|
|
140
|
+
further, and § Merging below says why.
|
|
141
|
+
|
|
142
|
+
### Merging — out of scope, cancelled rather than deferred
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
THIS COMMAND NEVER MERGES. THERE IS NO FLAG THAT MAKES IT MERGE.
|
|
146
|
+
THE RUN ENDS AT MERGEABLE-AND-OPEN, ALWAYS, AND SAYS SO.
|
|
147
|
+
A FUTURE MERGE CAPABILITY NEEDS A NEW ROADMAP AND AN OWNER RULING —
|
|
148
|
+
NOT A COMMAND EDIT, AND NOT A FLAG THAT ALREADY SITS HERE INERT.
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
A `--merge` flag was specified here and has been **removed**. The
|
|
152
|
+
`merge-authority` blocker of `road-to-drain-commands` closed as *not authorized
|
|
153
|
+
in this roadmap*: activating the flag would have lowered
|
|
154
|
+
[`non-destructive-by-default`](../../../../rules/non-destructive-by-default.md)'s
|
|
155
|
+
per-turn confirmation floor for a production-branch merge, which
|
|
156
|
+
[`decision-revisit-gate`](../../../../rules/decision-revisit-gate.md)'s
|
|
157
|
+
owner-reserved table reserves to the owner. No owner ruling was available to the
|
|
158
|
+
run that closed the roadmap, and an AI-council pass (2/2 convergent, 2026-08-22)
|
|
159
|
+
ruled that a council may cancel an unauthorized implementation but may not
|
|
160
|
+
manufacture the owner decision. The policy question is therefore **undecided,
|
|
161
|
+
not rejected** — see
|
|
162
|
+
[ADR-239](../../../../../docs/decisions/ADR-239-drain-command-surface-and-merge-authority.md)
|
|
163
|
+
§ Disposition.
|
|
164
|
+
|
|
165
|
+
The flag was removed rather than left inert deliberately: an archived roadmap
|
|
166
|
+
must not leave latent executable authority behind a documented switch.
|
|
167
|
+
|
|
168
|
+
Three independent findings stand behind the safety requirement, and any future
|
|
169
|
+
attempt starts from them rather than re-deriving them: the AI council's Q1
|
|
170
|
+
verdict (2026-08-21 — mergeability-only until authorization is target-bound and
|
|
171
|
+
tamper-resistant), the committed `road-to-gate-preauth-authorization` stub (an
|
|
172
|
+
authorization the agent can write is not an authorization), and the runtime
|
|
173
|
+
guard that refused this roadmap's own attempt to edit the canonical loop
|
|
174
|
+
contract.
|
|
175
|
+
|
|
176
|
+
**Mergeability is per-PR against a recorded base, never a queue property.**
|
|
177
|
+
When every PR in the estate touches the same generated files — in this
|
|
178
|
+
repository `agents/roadmaps-progress.md` and
|
|
179
|
+
`src/config/estate-count-budget.json` — making PR *n* mergeable against base
|
|
180
|
+
SHA `M` says nothing about its state once PR *n−1* advances the base to `M1`.
|
|
181
|
+
Report "mergeable against base `<SHA>`", never "the queue is mergeable".
|
|
182
|
+
|
|
183
|
+
### `--worktree` — isolate the workspace
|
|
184
|
+
|
|
185
|
+
Route workspace creation through [`/worktree:create`](../../../engineering-base/worktree/create/command.md)
|
|
186
|
+
in full, including its
|
|
187
|
+
[§ 4b seeding allow/deny list](../../../../skills/using-git-worktrees/SKILL.md#4b-seed-the-worktree--allow--deny-list),
|
|
188
|
+
which is the authority on what may be copied and what must never be — not
|
|
189
|
+
restated here, because a second copy of a safety list is a copy that can
|
|
190
|
+
drift. Under `--all` the worktree is created
|
|
191
|
+
once and re-branched per roadmap; `/worktree:cleanup` runs at end of run.
|
|
192
|
+
|
|
83
193
|
## Iron Law — Full is Full
|
|
84
194
|
|
|
85
195
|
```
|
|
@@ -87,9 +197,15 @@ with the **scope delta below**.
|
|
|
87
197
|
TO COMPLETION, ACROSS EVERY PHASE. ONLY THE FIVE HALT CONDITIONS STOP IT.
|
|
88
198
|
PHASE-INTERNAL "(DEFERRED)" / "(OPTIONAL)" / "GATED ON PHASE X" NOTES DO
|
|
89
199
|
NOT NARROW THE WORKING SET. A PHASE BOUNDARY IS NOT A STOP.
|
|
200
|
+
UNDER `--all`, A ROADMAP BOUNDARY IS NOT A STOP EITHER — BUT A HARD-FLOOR OR
|
|
201
|
+
SECURITY-SENSITIVE HALT ENDS THE WHOLE RUN, NOT JUST THE ROADMAP. THE TABLE
|
|
202
|
+
UNDER THE HALT CONDITIONS IS THE ONLY STATEMENT OF WHICH ENDS WHICH.
|
|
203
|
+
WAITING ON REMOTE CI FOR THE DELIVERY LOOP IS PART OF THE RUN. "CI IS
|
|
204
|
+
RUNNING" IS NOT A BOUNDARY, NOT A HALT, AND NOT A REPORT — THE RUN ENDS
|
|
205
|
+
AT A MERGEABLE PR, NEVER AT AN OFFER TO GO CHECK ON ONE.
|
|
90
206
|
```
|
|
91
207
|
|
|
92
|
-
The **
|
|
208
|
+
The **six — and only six — halt conditions** (exhaustive; nothing else
|
|
93
209
|
stops the run):
|
|
94
210
|
|
|
95
211
|
1. **Hard-Floor** trigger ([`non-destructive-by-default`](../../rules/non-destructive-by-default.md)).
|
|
@@ -97,6 +213,38 @@ stops the run):
|
|
|
97
213
|
3. **Security-sensitive** surface reached.
|
|
98
214
|
4. **Scope-out-of-roadmap** work discovered.
|
|
99
215
|
5. **Test / quality red** that cannot be cleared within the N=3 budget.
|
|
216
|
+
6. **A merge conflict outside the four enumerated classes** of
|
|
217
|
+
[`/pr:merge` § 3](../../../git/pr/merge/command.md), during the delivery
|
|
218
|
+
loop. Added when delivery became unconditional: the loop runs on every
|
|
219
|
+
completed run, `--all` or not, so its stop is a stop of this command and
|
|
220
|
+
calling it "a kill switch rather than a halt reason" would not change that —
|
|
221
|
+
a run that stops has stopped. It fires only where a run reaches delivery,
|
|
222
|
+
which is the one thing that distinguishes it from the five above.
|
|
223
|
+
|
|
224
|
+
**Under `--all`, which of these end the roadmap and which end the loop.** Two
|
|
225
|
+
of the five are safety floors and they end the **whole run**, not the current
|
|
226
|
+
roadmap:
|
|
227
|
+
|
|
228
|
+
| Halt | Under `--all` |
|
|
229
|
+
|---|---|
|
|
230
|
+
| 1. Hard-Floor trigger | **Ends the run.** Stop and obtain this-turn confirmation. [`non-destructive-by-default`](../../rules/non-destructive-by-default.md) states that no roadmap authorization lifts the floor, and "record it and take the next roadmap" is exactly the roadmap-as-authorization bypass it names. |
|
|
231
|
+
| 3. Security-sensitive surface | **Ends the run**, same reasoning. |
|
|
232
|
+
| 2. Council-off + genuine ambiguity | Ends the roadmap; the loop records it and continues. |
|
|
233
|
+
| 4. Scope-out-of-roadmap work | Ends the roadmap; the loop records it and continues. |
|
|
234
|
+
| 5. Test / quality red past N=3 | Ends the roadmap; the loop records it and continues. |
|
|
235
|
+
| 6. Unenumerated merge conflict in delivery | Ends the roadmap; the loop records it and continues. |
|
|
236
|
+
|
|
237
|
+
**And the conditions that end the loop without ending a roadmap:**
|
|
238
|
+
estate-queue exhaustion (always), a
|
|
239
|
+
[`/pr:merge` § 8](../../../git/pr/merge/command.md) kill switch (always — that
|
|
240
|
+
section arms its checks during **preparation**, not only before a merge, which
|
|
241
|
+
is what keeps them reachable while the merge step is gated), and
|
|
242
|
+
authorization-window expiry — which is **unreachable in this command**,
|
|
243
|
+
because it never performs a `BLOCK_OPS` operation for the window to govern. Three conditions, one of them currently inert, and this
|
|
244
|
+
table is the only place the set is stated.
|
|
245
|
+
|
|
246
|
+
Nothing here widens a run without `--all`: it still has exactly the six
|
|
247
|
+
above, all of them ending the run because there is no loop to continue.
|
|
100
248
|
|
|
101
249
|
```
|
|
102
250
|
FORBIDDEN NON-HALT REASONS — NEVER STOP THE RUN FOR ANY OF THESE:
|
|
@@ -109,7 +257,13 @@ FORBIDDEN NON-HALT REASONS — NEVER STOP THE RUN FOR ANY OF THESE:
|
|
|
109
257
|
runnable test over PRE-EXISTING blockers, never by how a step feels
|
|
110
258
|
· "the branch is not protected" / "a branch must be created"
|
|
111
259
|
· "a PR must be opened" / "a GitHub setting must change"
|
|
112
|
-
· "CI must be re-run" / "the merge base needs updating" / "there are
|
|
260
|
+
· "CI must be re-run" / "the merge base needs updating" / "there are
|
|
261
|
+
conflicts" — resolving these IS the work. The one exception, and it is a
|
|
262
|
+
kill switch rather than a halt reason: a conflict **outside** the four
|
|
263
|
+
enumerated classes of [`/pr:merge` § 3](../../../git/pr/merge/command.md)
|
|
264
|
+
stops the delivery loop, because that is a case nobody has decided yet and
|
|
265
|
+
deciding it silently is how work disappears. An enumerated conflict is
|
|
266
|
+
never a stop.
|
|
113
267
|
· "a paid service is needed" — authorised under the ceiling below
|
|
114
268
|
· "a maintainer should do this" when the agent can perform the same action
|
|
115
269
|
· any agent-invented caution not in the five halt conditions above.
|