dsh-tower 2.4.2 → 2.6.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/CHANGELOG.md +72 -0
- package/COMPATIBILITY.md +2 -0
- package/CONTRIBUTING.md +5 -3
- package/GLOSSARY.md +73 -0
- package/PRINCIPLES.md +15 -7
- package/README.en.md +16 -15
- package/README.md +18 -10
- package/app/archive.js +16 -1
- package/app/board.js +16 -1
- package/app/gate.js +14 -0
- package/app/review.js +7 -0
- package/app/spawn-prechecks.js +30 -5
- package/app/tower.js +5 -5
- package/client.js +321 -0
- package/cordis.patch.yml +26 -9
- package/docs/adr/0004-surface-budget.md +10 -4
- package/docs/adr/0005-component-surface.md +222 -11
- package/docs/architecture/overview.md +12 -6
- package/docs/examples/first-mission.md +3 -2
- package/docs/faq.md +9 -7
- package/docs/guide/install-upgrade-migration.md +53 -7
- package/docs/guide/quickstart.md +91 -10
- package/docs/guide/release.md +60 -19
- package/docs/guide/scenarios-and-philosophy.md +35 -28
- package/docs/operations/security.md +11 -10
- package/docs/reference/blockers.md +12 -7
- package/docs/reference/component-surface.md +40 -21
- package/docs/reference/config.generated.md +6 -8
- package/docs/reference/config.md +36 -8
- package/docs/reference/doctor.md +11 -5
- package/docs/reference/errors.generated.md +1 -0
- package/docs/reference/errors.md +2 -1
- package/docs/reference/surface-budget.md +47 -12
- package/docs/reference/testing.md +1 -1
- package/docs/reference/tools.generated.md +5 -5
- package/docs/reference/tools.md +5 -5
- package/docs/zh/faq.md +7 -5
- package/docs/zh/guide/install-upgrade-migration.md +26 -7
- package/docs/zh/guide/quickstart.md +17 -10
- package/docs/zh/guide/scenarios-and-philosophy.md +23 -15
- package/docs/zh/operations/security.md +9 -8
- package/docs/zh/reference/blockers.md +11 -7
- package/docs/zh/reference/config.md +28 -8
- package/docs/zh/reference/doctor.md +7 -2
- package/docs/zh/reference/errors.md +2 -1
- package/docs/zh/reference/testing.md +2 -2
- package/docs/zh/reference/tools.md +6 -5
- package/domain/component-rules.js +216 -0
- package/domain/components.js +181 -53
- package/domain/config/schema.js +86 -28
- package/domain/contracts/outputs.js +2 -0
- package/domain/contracts/tool-inputs/missions.js +1 -1
- package/domain/errors.js +6 -0
- package/domain/gate.js +23 -5
- package/domain/integration/review.js +203 -9
- package/domain/scope.js +176 -5
- package/domain/surface.js +21 -7
- package/host/capability-archive.js +18 -0
- package/host/capability-board.js +18 -0
- package/host/capability-registry.js +4 -0
- package/host/config.js +40 -3
- package/host/doctor.js +68 -12
- package/host/presets.js +26 -8
- package/host/tool-registry.js +30 -5
- package/index.js +17 -6
- package/locale/archive/en.json +6 -0
- package/locale/archive/zh.json +6 -0
- package/locale/batch/en.json +1 -1
- package/locale/batch/zh.json +1 -1
- package/locale/board/en.json +6 -0
- package/locale/board/zh.json +6 -0
- package/locale/en.json +37 -22
- package/locale/hmr/en.json +2 -2
- package/locale/hmr/zh.json +1 -1
- package/locale/import/en.json +1 -1
- package/locale/import/zh.json +1 -1
- package/locale/leases/en.json +2 -2
- package/locale/leases/zh.json +2 -2
- package/locale/preset-reviewer/en.json +1 -1
- package/locale/preset-reviewer/zh.json +1 -1
- package/locale/preset-worker/en.json +1 -1
- package/locale/preset-worker/zh.json +1 -1
- package/locale/skills/en.json +1 -1
- package/locale/skills/zh.json +1 -1
- package/locale/tests/en.json +2 -2
- package/locale/tests/zh.json +2 -2
- package/locale/zh.json +36 -21
- package/package.json +17 -2
- package/scripts/check-components.mjs +698 -44
- package/scripts/check-pack.mjs +3 -0
- package/scripts/component-surface.json +101 -37
- package/scripts/generate-capability-locale.mjs +3 -0
- package/scripts/mount-smoke/surface.mjs +2 -0
- package/scripts/pack-manifest.txt +10 -0
- package/scripts/release-notes.mjs +256 -0
- package/scripts/surface-baseline.json +39 -3
- package/scripts/surface-baseline.mjs +15 -5
- package/scripts/types-coverage.mjs +7 -0
- package/skills.js +4 -1
- package/tools/complete.js +3 -1
- package/tools/preflight.js +1 -1
- package/tools/review.js +1 -1
- package/tools/spawn.js +7 -7
- package/tools/status.js +8 -1
- package/tools/test.js +7 -7
- package/types/index.d.ts +10 -0
- package/ui-bundle/locale/en.json +1 -1
- package/ui-bundle/locale/zh.json +1 -1
|
@@ -12,9 +12,14 @@ escape keep working.
|
|
|
12
12
|
|
|
13
13
|
[Principle 11](../../PRINCIPLES.md) and
|
|
14
14
|
[ADR 0005](../adr/0005-component-surface.md) say a component may exist only for
|
|
15
|
-
a capability whose off state leaves the rest intact, and that the host,
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
a capability whose off state leaves the rest intact, and that the host, the
|
|
16
|
+
health contract, the recovery escape and the merge gates are never switches.
|
|
17
|
+
The review policy is not one of them: `review.mode` is a single tri-state
|
|
18
|
+
control (`off`, `optional` or `required`) on the plugin-page configuration
|
|
19
|
+
form, not a component row and never one row per mode, and only the review gate
|
|
20
|
+
it turns on in `required` mode — the clean, tip-bound evidence and the
|
|
21
|
+
exemption path — is non-disableable. Which keys are allowed to be switches is a
|
|
22
|
+
table lookup in
|
|
18
23
|
[component-surface.md](../reference/component-surface.md), generated from
|
|
19
24
|
`scripts/component-surface.json`; the component count is baselined and checked by
|
|
20
25
|
`npm run docs:check:components`. That gate also refuses a `tools.expose*` route
|
|
@@ -236,9 +241,10 @@ set by `tower_merge`/reconciliation.
|
|
|
236
241
|
3. Survey missions must not change files; build missions must stay inside `scope`.
|
|
237
242
|
4. The main checkout must be clean for the files this merge would overwrite and on the base branch.
|
|
238
243
|
5. Dependency missions must be merged/abandoned, except a completed survey dependency which is its terminal success state (#107).
|
|
239
|
-
6. If `review.
|
|
240
|
-
clean, approve merge, and be bound to the tip (unless a clean
|
|
241
|
-
|
|
244
|
+
6. If the review policy is `required` (`review.mode:required`; the default is `optional`), a review
|
|
245
|
+
must exist, belong to this mission, be clean, approve merge, and be bound to the tip (unless a clean
|
|
246
|
+
rebase waived it). With `off`, review is intentionally unavailable and the gate ignores it. No
|
|
247
|
+
worker may be running.
|
|
242
248
|
|
|
243
249
|
## Merge
|
|
244
250
|
|
|
@@ -23,8 +23,9 @@ Wait for the worker's final report (delivered to this session) or check `tower_r
|
|
|
23
23
|
creates `src/greet.txt`, commits on `tower/m1-add-greeting`, marks both tasks done, and calls
|
|
24
24
|
`tower_complete`.
|
|
25
25
|
|
|
26
|
-
This example follows the strict workflow:
|
|
27
|
-
repository config
|
|
26
|
+
This example follows the strict workflow: set the review policy to `required` (`review.mode:required`
|
|
27
|
+
in the profile or repository config, or the one tri-state control on the Plugins page) before the
|
|
28
|
+
review step; the default is `optional`. Spawn the reviewer:
|
|
28
29
|
|
|
29
30
|
```json
|
|
30
31
|
{"repoRoot":"D:\\work\\demo","missionId":"M1","role":"reviewer"}
|
package/docs/faq.md
CHANGED
|
@@ -14,9 +14,9 @@ phase instead—use Workflow/Team to analyze and decide, then start Tower to exe
|
|
|
14
14
|
review) the repository change. See the [full guide](guide/scenarios-and-philosophy.md#4-how-tower-differs-from-other-dsh-workflow-patterns).
|
|
15
15
|
|
|
16
16
|
**Why did `tower_preflight` fail with `no-review` right after the worker finished?**
|
|
17
|
-
That happens only when `review.
|
|
18
|
-
independent review. Spawn a reviewer; after a clean review the gate turns green. With the
|
|
19
|
-
`review.
|
|
17
|
+
That happens only when the review policy is `required` (`review.mode:required`): a completed mission
|
|
18
|
+
awaits an independent review. Spawn a reviewer; after a clean review the gate turns green. With the
|
|
19
|
+
default `review.mode:optional`, review is optional and no `no-review` blocker is produced.
|
|
20
20
|
|
|
21
21
|
**Do I need to poll the worker?**
|
|
22
22
|
No. The worker's final report is delivered to this session; `tower_roster` shows live activity. Polling
|
|
@@ -40,10 +40,12 @@ Correct: the branch is already contained in the base. Call `tower_merge` to reco
|
|
|
40
40
|
instead of rebasing.
|
|
41
41
|
|
|
42
42
|
**Can I require independent review?**
|
|
43
|
-
Yes. Set
|
|
44
|
-
|
|
45
|
-
reason + `gates.allowReviewExemption:true` is the narrower
|
|
46
|
-
verdicts
|
|
43
|
+
Yes. Set the review policy to `required` — the one tri-state control on the Plugins page, or
|
|
44
|
+
`review.mode:required` in the profile or repository config (the default is `optional`). When required,
|
|
45
|
+
mission-level `reviewPolicy:"none"` + a reason + `gates.allowReviewExemption:true` is the narrower
|
|
46
|
+
exemption. `tower_review` works and records verdicts in `optional` mode too. The old boolean toggle is
|
|
47
|
+
a deprecated one-release alias; the mapping is in
|
|
48
|
+
[install, upgrade and migration](guide/install-upgrade-migration.md).
|
|
47
49
|
|
|
48
50
|
**Can a reviewer edit files?**
|
|
49
51
|
No. Reviewers use the read-only `tower-reviewer` preset (no write/edit/pwsh); a branch changed after the
|
|
@@ -29,6 +29,50 @@ The Host plugin loads at DSH startup: **restart DSH after install or update**.
|
|
|
29
29
|
|
|
30
30
|
## Migration notes
|
|
31
31
|
|
|
32
|
+
- **2.5.0 → 2.6.0 (#M39/#M40) — review modes replace the boolean**: the review policy is one
|
|
33
|
+
tri-state control on the Plugins page in the `dsh-tower` configuration section, and the config key
|
|
34
|
+
is `review.mode`: `off`, `optional` (the default) or `required`.
|
|
35
|
+
- `off` is supported and documented: `tower_review` is not registered, reviewer spawn is refused,
|
|
36
|
+
and the merge gate ignores review.
|
|
37
|
+
- `optional` keeps `tower_review` but never blocks a merge.
|
|
38
|
+
- `required` keeps the merge gate: a completed mission needs a clean review bound to the branch tip
|
|
39
|
+
(the existing per-mission exemption still applies).
|
|
40
|
+
`review.requireReview` is a deprecated one-release alias: `true` resolves to `required`, `false`
|
|
41
|
+
to `optional`, and leaving it unset means `optional`. A `true` next to an explicit non-`required`
|
|
42
|
+
mode is rejected with `config-invalid`; `false` never overrides an explicit mode. Saving from the
|
|
43
|
+
plugin page always writes `review.mode` and normalizes the alias to `false`. The policy is not a
|
|
44
|
+
component row and there are no mutually exclusive review rows: `preset-tower-reviewer` remains an
|
|
45
|
+
optional capability the policy may leave unused. The row may be off while `review.mode` is `off`
|
|
46
|
+
or `optional`; when `review.mode` is `required` and the reviewer row is off, planning and mode
|
|
47
|
+
entry refuse the combination with an explanatory `preset-missing` error.
|
|
48
|
+
A profile that starts with the policy `off` never registered `tower_review`; switching to
|
|
49
|
+
`optional` or `required` changes the merge gate immediately, but the tool appears only after a DSH
|
|
50
|
+
restart (or a profile reload), and the plugin page states that after such a save.
|
|
51
|
+
Upgrade: replace `review.requireReview: true|false` with `review.mode: required|optional`; keep the
|
|
52
|
+
alias only if the same config is shared with older 2.5 installations, and remove it after this
|
|
53
|
+
release. No state migration.
|
|
54
|
+
|
|
55
|
+
- **2.4.2 → 2.5.0 (#131/#133/#135/#136/#142)**: three component-shaped config
|
|
56
|
+
keys are gone — `tests.enabled`, `docs.board`, and `archive.enabled`. The
|
|
57
|
+
`tower-tests`, `tower-board`, and `tower-archive` component rows are the only
|
|
58
|
+
switches. A profile or repository config that still writes any of these keys is
|
|
59
|
+
rejected as `config-unknown-key` with an upgrade note and the host stops
|
|
60
|
+
mounting, so delete the key and enable or disable the row in the plugin page
|
|
61
|
+
instead. `docs.boardLocation` and `archive.afterDays`/`archive.maxMissions`
|
|
62
|
+
remain tuning keys. With `tower-tests` off there is no `tower_test` tool and no
|
|
63
|
+
receipt, which also means `gates.requireTests` cannot be satisfied: planning and
|
|
64
|
+
mode entry refuse that combination, and the merge gate's `tests-missing` blocker
|
|
65
|
+
names the disabled row and the fix. `tower_test` no longer reports "not
|
|
66
|
+
configured" for a component cause; it reports `disabled by component
|
|
67
|
+
tower-tests` with the remedy.
|
|
68
|
+
Two more runtime rules became explicit: a config that sets `spawn.requireLease`
|
|
69
|
+
while the `tower-leases` row is off is refused up front with `config-invalid`
|
|
70
|
+
naming the row and both remedies (previously every spawn failed at `lease-busy`
|
|
71
|
+
advising an unregistered `tower_resource`), and `/tower` re-validates the runtime
|
|
72
|
+
preconditions only when it enters the mode, so `/tower off` and a forwarded
|
|
73
|
+
`/tower <text>` keep working while an unrelated row is disabled. No state
|
|
74
|
+
migration; see [component rows and messages](quickstart.md#component-rows-runtime-preconditions-and-message-language).
|
|
75
|
+
|
|
32
76
|
- **state schema v1 → v2 (unreleased)**: `state.json` migrates automatically. The first **write** after
|
|
33
77
|
upgrading keeps a `state.json.v1.bak` backup, advances `revision` once, and appends
|
|
34
78
|
`state.migrated {from,to}` to `activity.jsonl`; read-only tools keep reading a v1 file without
|
|
@@ -49,14 +93,14 @@ The Host plugin loads at DSH startup: **restart DSH after install or update**.
|
|
|
49
93
|
now ships the mandatory `tower` host anchor (the Host plugin and the worker preset are its internal
|
|
50
94
|
sections) plus individually switchable top-level rows: `tower-skills`, `tower-batch`, `tower-import`,
|
|
51
95
|
`tower-leases`, `tower-tests`, `tower-hmr` (shipped off) and `preset-tower-reviewer` (conditional on
|
|
52
|
-
`review.
|
|
53
|
-
still carries them is now rejected as an unknown key (`config-unknown-key`) and the host stops
|
|
96
|
+
the review policy, today `review.mode`). The `tools` config group and `dev.hotReload` were removed: a
|
|
97
|
+
profile that still carries them is now rejected as an unknown key (`config-unknown-key`) and the host stops
|
|
54
98
|
mounting until they are deleted, so no silent no-op switch remains. Move each capability to its row
|
|
55
99
|
in the plugin page instead; `tower-hmr` ships off, so `tower_reload` and `/tower reload` are reported
|
|
56
100
|
as "disabled by component tower-hmr" until you enable it for a linked dev profile. `tower_doctor` and
|
|
57
101
|
`tower_recover` are registered for every configuration and need no key. The reviewer row may be off
|
|
58
|
-
|
|
59
|
-
combination with an explanatory error. No state migration is needed.
|
|
102
|
+
while the policy is `off` or `optional`; with `review.mode:required`, planning and mode entry refuse
|
|
103
|
+
the combination with an explanatory error. No state migration is needed.
|
|
60
104
|
|
|
61
105
|
- **2.0.4 → 2.1.0-beta.1**: no config migration; the state file migrates automatically (v1/v2 → v3) as
|
|
62
106
|
described above. This is a **pre-release** published on the
|
|
@@ -68,10 +112,12 @@ The Host plugin loads at DSH startup: **restart DSH after install or update**.
|
|
|
68
112
|
runs `npm publish --tag next`, and `latest` stays on 2.0.4 until a stable release.
|
|
69
113
|
- **2.0.3 → 2.0.4**: no state/config migration. This is a security-hardening and integrity release
|
|
70
114
|
(authorization, merge SHA binding, dirty-worktree completion, stale-lock recovery, limited test/git
|
|
71
|
-
process environment, `tower_recover`, UI 0.2.2). Review `review.
|
|
72
|
-
worker tool permissions against your
|
|
115
|
+
process environment, `tower_recover`, UI 0.2.2). Review the review policy (`review.mode`, or the
|
|
116
|
+
deprecated `review.requireReview` alias), `tests.admission` and worker tool permissions against your
|
|
117
|
+
threat model after upgrading.
|
|
73
118
|
- **2.0.1 → 2.0.3**: no state migration. Independent review became **optional by default** in 2.0.3
|
|
74
|
-
(`review.
|
|
119
|
+
(today's `review.mode:optional`); set `review.mode:required` to keep the old review-gated merges.
|
|
120
|
+
2.0.1 added
|
|
75
121
|
`tower_batch` `abandon`, accepted merged members in batch close, made doctor skip torn-down worktrees,
|
|
76
122
|
and fixed terminal-mission spawn/preflight edge cases. The optional `ui-bundle` 0.2.1 adds the
|
|
77
123
|
persistent Tower-mode chip and mode-aware denied-tool rows.
|
package/docs/guide/quickstart.md
CHANGED
|
@@ -33,15 +33,25 @@ session. Use `tower_roster` to observe activity; do not poll in a loop.
|
|
|
33
33
|
|
|
34
34
|
## 4. Optional: review
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
The review policy is one tri-state control — `off`, `optional` (the default) or `required` — on the
|
|
37
|
+
Plugins page in the `dsh-tower` configuration section, or `review.mode` in the profile/repository
|
|
38
|
+
config. It is one control, not a component row and not three rows. Set it to `required` for the strict
|
|
39
|
+
workflow, then:
|
|
38
40
|
|
|
39
41
|
```
|
|
40
42
|
tower_spawn repoRoot=D:\work\repo missionId=M1 role=reviewer
|
|
41
43
|
```
|
|
42
44
|
|
|
43
45
|
Reviewers use the read-only `tower-reviewer` preset. They inspect `tower_diff` and submit
|
|
44
|
-
`tower_review`; with `review.
|
|
46
|
+
`tower_review`; with `review.mode:required`, a `clean` + `merge` verdict is required to merge.
|
|
47
|
+
`optional` records reviews but never blocks a merge, and `off` is a supported mode that does not
|
|
48
|
+
register `tower_review`.
|
|
49
|
+
|
|
50
|
+
The old boolean review toggle is a one-release alias (`true` → `required`, `false` → `optional`;
|
|
51
|
+
unset → `optional`). Prefer `review.mode`. A profile that started with
|
|
52
|
+
`off` only registers `tower_review` after a restart/reload, although the merge gate changes
|
|
53
|
+
immediately. See [install, upgrade and migration](install-upgrade-migration.md) for the full
|
|
54
|
+
migration.
|
|
45
55
|
|
|
46
56
|
## 5. Gate, merge, clean up
|
|
47
57
|
|
|
@@ -51,10 +61,10 @@ tower_merge repoRoot=D:\work\repo missionId=M1
|
|
|
51
61
|
tower_teardown repoRoot=D:\work\repo
|
|
52
62
|
```
|
|
53
63
|
|
|
54
|
-
With
|
|
55
|
-
review it should be `ok:true`. With the default (`
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
With `review.mode:required`, `tower_preflight` before review reports `no-review`, and after a clean
|
|
65
|
+
review it should be `ok:true`. With the default (`optional`), no review blocker is required.
|
|
66
|
+
`tower_merge` refuses while blockers remain. `tower_teardown` removes merged/abandoned worktrees and
|
|
67
|
+
branches.
|
|
58
68
|
|
|
59
69
|
```
|
|
60
70
|
/tower off
|
|
@@ -63,8 +73,8 @@ worktrees and branches.
|
|
|
63
73
|
## If something fails
|
|
64
74
|
|
|
65
75
|
Read the blocker code and use [the blocker reference](../reference/blockers.md). The most common cases:
|
|
66
|
-
`stale-base` (run `tower_rebase`), `no-review` (only with `review.
|
|
67
|
-
|
|
76
|
+
`stale-base` (run `tower_rebase`), `no-review` (only with `review.mode:required`; spawn a reviewer),
|
|
77
|
+
`merge-hook-failed` (retry, or raise `timeoutMs`), `tip-moved` (only when the policy is `required`;
|
|
68
78
|
the branch changed after review, review again).
|
|
69
79
|
|
|
70
80
|
Thrown tool failures carry a `[tower:<code>]` prefix; see [error codes](../reference/errors.md)
|
|
@@ -78,7 +88,7 @@ JSON file at `<git-common-dir>/dsh-tower/config.json` (usually `.git/dsh-tower/c
|
|
|
78
88
|
|
|
79
89
|
```json
|
|
80
90
|
{
|
|
81
|
-
"review": { "
|
|
91
|
+
"review": { "mode": "required", "maxRoundsPerReviewer": 3 },
|
|
82
92
|
"merge": { "timeoutMs": 1800000 },
|
|
83
93
|
"worktrees": { "root": "D:/tower-worktrees" }
|
|
84
94
|
}
|
|
@@ -100,3 +110,74 @@ Statuses are `open → triaged → fixed` / `wontfix`, and `fixed`/`wontfix` can
|
|
|
100
110
|
tower or a worker may change a finding; reviewers can list and read.
|
|
101
111
|
|
|
102
112
|
A complete copy-paste example: [examples/first-mission.md](../examples/first-mission.md).
|
|
113
|
+
|
|
114
|
+
## Component rows, runtime preconditions and message language
|
|
115
|
+
|
|
116
|
+
The optional component rows are the only switches in this bundle (#121, #136). Three runtime rules
|
|
117
|
+
follow from that, plus the language policy for everything a tool prints.
|
|
118
|
+
|
|
119
|
+
### A row is the only switch
|
|
120
|
+
|
|
121
|
+
`tests.enabled` was removed (#136). Discovery is on exactly while the `tower-tests` row is mounted:
|
|
122
|
+
with the row off there is no `tower_test` tool and no test receipt to gate on, so a second boolean
|
|
123
|
+
could only disagree with the mounted profile. A repository config that still writes
|
|
124
|
+
`tests.enabled` is rejected as `config-unknown-key`; delete the key and enable or disable the row
|
|
125
|
+
instead.
|
|
126
|
+
|
|
127
|
+
The same reasoning covers the other rows:
|
|
128
|
+
|
|
129
|
+
- `tower-leases` owns `tower_resource`. `spawn.requireLease` is satisfied through that tool, so a
|
|
130
|
+
config that requires a lease while the row is off is refused by the runtime preconditions with
|
|
131
|
+
`config-invalid`, naming the row and both remedies ("re-enable the tower-leases component or clear
|
|
132
|
+
spawn.requireLease") instead of failing every spawn at `lease-busy` with advice to use a tool that
|
|
133
|
+
is not registered (#131).
|
|
134
|
+
- `tower-tests` must stay mounted while `gates.requireTests` is true. Planning and mode entry refuse
|
|
135
|
+
the combination; the merge gate's `tests-missing` blocker also names the disabled row as the cause
|
|
136
|
+
(#140).
|
|
137
|
+
- `tower-hmr` ships off; `/tower reload` reports it by row name.
|
|
138
|
+
|
|
139
|
+
No runtime path may claim a repository is "not configured" when a component row is the reason.
|
|
140
|
+
Runtime refusals report the cause as `disabled by component <id>` and come with the fix (`enable the
|
|
141
|
+
<id> row in the plugin page and restart DSH`).
|
|
142
|
+
|
|
143
|
+
### Preconditions run on mode entry, not on every `/tower` input (#142)
|
|
144
|
+
|
|
145
|
+
`/tower` re-validates the runtime preconditions (presets, component/config contradictions) only when
|
|
146
|
+
it **enters** Tower mode:
|
|
147
|
+
|
|
148
|
+
| Input | Preconditions |
|
|
149
|
+
|---|---|
|
|
150
|
+
| `/tower`, `/tower on`, `/tower <text>` while the mode is off | validated |
|
|
151
|
+
| `/tower off`, `/tower off <text>` | not validated |
|
|
152
|
+
| `/tower <text>` while the mode is already on | not validated |
|
|
153
|
+
| `/tower ack`, `/tower base <branch>`, `/tower reload` | not validated |
|
|
154
|
+
|
|
155
|
+
The reason: a row disabled after the session started (or a profile reloaded with a stricter config)
|
|
156
|
+
must not make `/tower off` — the command a human needs to leave the mode — or an ordinary forwarded
|
|
157
|
+
instruction fail. Capability guards still run where the work happens: `tower_spawn`, planning and
|
|
158
|
+
merge/preflight evaluate their own preconditions, so the checks cannot be bypassed by entering the
|
|
159
|
+
mode first.
|
|
160
|
+
|
|
161
|
+
### Language of tool output
|
|
162
|
+
|
|
163
|
+
Machine-facing output is **English only**, regardless of the request locale:
|
|
164
|
+
|
|
165
|
+
- tool errors (`[tower:<code>] ...`), `nextAction`, blocker `detail` strings, `tower_status` /
|
|
166
|
+
`tower_doctor` detail lines, and completion reports;
|
|
167
|
+
- anything that a script, a log search or another agent is expected to pattern-match.
|
|
168
|
+
|
|
169
|
+
Localized, human-facing copy lives in `locale/*.json` (component descriptions, UI labels) and is the
|
|
170
|
+
only translated surface. Two rules keep the split honest:
|
|
171
|
+
|
|
172
|
+
1. New detail/error strings are written in English even when the surrounding UI is Chinese; they are
|
|
173
|
+
not added to `locale/*.json`.
|
|
174
|
+
2. A localized label never shadows a machine-readable cause. The row id, the error code and the
|
|
175
|
+
English remedy phrase stay verbatim inside the message, so a grep for
|
|
176
|
+
`disabled by component tower-tests` works in every locale.
|
|
177
|
+
|
|
178
|
+
`tower_status` and `tower_doctor` follow this policy but are not textually identical: `tower_status`
|
|
179
|
+
returns the cause only — `components.disabled` is `[{id, reason}]` with `reason` set to
|
|
180
|
+
`disabled by component <id>` — while `tower_doctor` repeats that reason and adds the English remedy
|
|
181
|
+
(`enable the reported row in the plugin page and restart DSH` for the `components` check; a
|
|
182
|
+
capability-specific check names the row directly, e.g. `enable the tower-tests row and restart DSH`).
|
|
183
|
+
Neither interpolates a translated label.
|
package/docs/guide/release.md
CHANGED
|
@@ -97,29 +97,70 @@ git for-each-ref refs/tags/v2.1.0-beta.1 --format='%(objecttype)|%(subject)'
|
|
|
97
97
|
The pushed tag must be exactly `v<version>`. The tag push re-runs `release:check` against
|
|
98
98
|
`<tag>^`; this is why tagging a commit whose `package.json` did not move fails.
|
|
99
99
|
|
|
100
|
-
## 6. GitHub Release
|
|
100
|
+
## 6. GitHub Release with cumulative notes
|
|
101
|
+
|
|
102
|
+
A Release body is not just its own CHANGELOG section: it carries **every** section after the
|
|
103
|
+
previous GitHub Release (see [Cumulative Release notes](#cumulative-release-notes--累积发布说明)
|
|
104
|
+
below). `scripts/release-notes.mjs` is the authority for that body — do not hand-extract a single
|
|
105
|
+
section. The checklist step is `npm run release:notes -- --version <v> --since <prev-release> --output notes.md`, then pass that file to `gh release create`/`gh release edit` with `--notes-file notes.md`.
|
|
101
106
|
|
|
102
107
|
```bash
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
# Stable release (the common case): no pre-release flags.
|
|
109
|
+
VERSION=2.3.0
|
|
110
|
+
SINCE=2.1.0 # the previous GitHub Release, not the previous tag
|
|
111
|
+
npm run release:notes -- --version "$VERSION" --since "$SINCE" --output notes.md
|
|
112
|
+
npm run release:notes -- --version "$VERSION" --since "$SINCE" --check notes.md
|
|
113
|
+
gh release create "v$VERSION" --title "dsh-tower $VERSION" --notes-file notes.md --verify-tag
|
|
114
|
+
# editing a Release that already exists (for example, to correct its window):
|
|
115
|
+
gh release edit "v$VERSION" --notes-file notes.md
|
|
109
116
|
gh release view "v$VERSION" --json tagName,isPrerelease,body
|
|
110
117
|
```
|
|
111
118
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
($lines[$start..$end] -join "`n").Trim() | Set-Content release-notes.md -Encoding utf8
|
|
119
|
+
```bash
|
|
120
|
+
# Pre-release variant (a beta, for example 2.5.0-beta.1): mark the Release and keep "latest"
|
|
121
|
+
# on the previous stable Release.
|
|
122
|
+
VERSION=2.5.0-beta.1
|
|
123
|
+
SINCE=2.4.2 # the previous GitHub Release; a pre-release counts as one too
|
|
124
|
+
npm run release:notes -- --version "$VERSION" --since "$SINCE" --output notes.md
|
|
125
|
+
gh release create "v$VERSION" --title "dsh-tower $VERSION" --notes-file notes.md \
|
|
126
|
+
--prerelease --verify-tag --latest=false
|
|
121
127
|
```
|
|
122
128
|
|
|
123
|
-
`--
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
`--check notes.md` exits 1 when the file differs from the generated text (it prints the first
|
|
130
|
+
differing line and both byte counts), so a correction is verifiable. The script exits 2 on a
|
|
131
|
+
missing/unknown flag, an invalid version, `since >= version`, or an empty window; it never emits
|
|
132
|
+
a Release body it cannot justify.
|
|
133
|
+
|
|
134
|
+
`--verify-tag` refuses to create the tag at the default branch when the pushed tag is missing.
|
|
135
|
+
A beta Release adds `--prerelease --latest=false`: GitHub marks it as a pre-release and keeps
|
|
136
|
+
the "latest" marker on the stable Release. Releases are what consumers and the plugin directory
|
|
137
|
+
can see — a tag alone is not a release.
|
|
138
|
+
|
|
139
|
+
## Cumulative Release notes / 累积发布说明
|
|
140
|
+
|
|
141
|
+
A GitHub Release is cumulative: it aggregates every CHANGELOG section **after the previous
|
|
142
|
+
Release**, up to and including the version being released.
|
|
143
|
+
|
|
144
|
+
- The **previous Release** is the latest published GitHub Release by version. Pre-releases
|
|
145
|
+
created with `--prerelease` count as Releases, so a `2.1.0-beta.1` Release is a boundary too.
|
|
146
|
+
- **Tag-only versions have no Release.** A version that was tagged or published to npm without
|
|
147
|
+
creating a GitHub Release — 2.1.1 and 2.1.2 were tag-only, and 2.2.0 too — would otherwise
|
|
148
|
+
lose its notes; its CHANGELOG section rolls into the next Release.
|
|
149
|
+
- Example: once 2.1.0 is the previous Release, the 2.3.0 Release includes 2.1.1, 2.1.2, 2.2.0
|
|
150
|
+
and 2.3.0:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npm run release:notes -- --version 2.3.0 --since 2.1.0 --output notes.md
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The window is `(2.1.0, 2.3.0]`; `2.1.0-beta.1` sorts before 2.1.0 and therefore stays out.
|
|
157
|
+
- `npm run release:notes` (`scripts/release-notes.mjs`) is the authoritative generator: it reads
|
|
158
|
+
`CHANGELOG.md`, filters the window, orders sections by SemVer (pre-release identifiers
|
|
159
|
+
included), and emits the `# dsh-tower <v>` title, a provenance quote naming the previous
|
|
160
|
+
Release and the included versions, then the sections separated by `---`.
|
|
161
|
+
- `--check <file>` re-verifies an existing notes file byte-for-byte (exit 1 on a mismatch), so
|
|
162
|
+
the body of a published Release can be audited without editing it. Use `--root <dir>` to check
|
|
163
|
+
another checkout.
|
|
164
|
+
|
|
165
|
+
Never hand-extract only the current version's section: that is what produced single-section
|
|
166
|
+
Releases whose tag-only predecessors were invisible.
|
|
@@ -10,8 +10,8 @@ a better fit.
|
|
|
10
10
|
|
|
11
11
|
If you only remember one sentence: **use Tower when the output is an integrated repository change that
|
|
12
12
|
must land through a controlled merge; use the other patterns when the output is exploration, repeated
|
|
13
|
-
attempts, or programmatic fan-out.**
|
|
14
|
-
independent reviewer
|
|
13
|
+
attempts, or programmatic fan-out.** Set the review policy to `required` when the change also needs
|
|
14
|
+
an independent reviewer; the default policy is `optional`.
|
|
15
15
|
|
|
16
16
|
## 1. The design philosophy
|
|
17
17
|
|
|
@@ -45,11 +45,13 @@ When review is enabled, a reviewer also inspects a specific branch tip and the g
|
|
|
45
45
|
binding. Separation of duties is the point when review is on: the agent that wrote the code is not the
|
|
46
46
|
agent that approves it, and neither is the agent that merges.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
mission must carry a clean, merge-approved review from a
|
|
50
|
-
to
|
|
51
|
-
remains available as a per-mission exemption when the
|
|
52
|
-
|
|
48
|
+
The review policy is one tri-state control: `off`, `optional` (the default) or `required`. `required`
|
|
49
|
+
enforces independent review (a complete mission must carry a clean, merge-approved review from a
|
|
50
|
+
reviewer bound to the branch tip). Choose it for sensitive repositories; `reviewPolicy:"none"` + a
|
|
51
|
+
reason + `gates.allowReviewExemption:true` remains available as a per-mission exemption when the
|
|
52
|
+
policy is required. `optional` records reviews but never blocks a merge, and `off` is a supported
|
|
53
|
+
mode that removes the review tool. The policy is configuration, not a component row: there is one
|
|
54
|
+
control on the plugin page, not three mutually exclusive rows.
|
|
53
55
|
|
|
54
56
|
### 1.5 Evidence over assertion
|
|
55
57
|
|
|
@@ -184,7 +186,7 @@ integration, and what "done" means.**
|
|
|
184
186
|
| Isolation | Git worktree + branch per mission; one writer per mission | Shared workspace; coordination by task ownership | Fresh child per round; no built-in branch/merge contract | Per-step child; no Git isolation | Child sessions; may share workspace |
|
|
185
187
|
| Durable state | Git metadata + JSON state + activity + board | Team task board + sessions | Minimal; each round starts fresh | Run record/results; not a merge ledger | Session/subagent records |
|
|
186
188
|
| Integration authority | Tower only, after preflight/gate (plus review when enabled) | Humans/teammates merge or edit manually | Usually the parent/worker applies results | Script applies results | Parent applies results |
|
|
187
|
-
| Review / gate | Optional independent review (
|
|
189
|
+
| Review / gate | Optional independent review (one `review.mode` control: off/optional/required) + preflight/merge gate | Review is a collaboration convention, not a hard gate | No built-in review gate | No built-in review gate | No built-in review gate |
|
|
188
190
|
| Parallelism | Multiple missions, disjoint scopes, serialized merges | Many teammates, shared board | Sequential rounds (or external fan-out) | High fan-out, script-controlled | High fan-out |
|
|
189
191
|
| Human role | Owns the mode; can inspect evidence and release | Collaborator/coordinator | Author of the repeated objective | Author of the orchestration script | Delegator |
|
|
190
192
|
| Best for | Feature delivery, migrations, release-bound changes | Design, research, cross-cutting collaboration | Iterative search/repair with fresh context | Large audits, batch analysis, deterministic pipelines | Quick exploration or independent subtasks |
|
|
@@ -195,8 +197,8 @@ integration, and what "done" means.**
|
|
|
195
197
|
Ordinary `subagent`/`subagent_fork` calls are cheap and flexible. They are the right tool for "read
|
|
196
198
|
these five files in parallel" or "try three approaches". They do not provide a write scope, a
|
|
197
199
|
dedicated worktree, a durable mission, independent review, or a merge gate. Tower wraps the same
|
|
198
|
-
subagent primitive in those contracts; it also costs more per child. (Review is optional:
|
|
199
|
-
`
|
|
200
|
+
subagent primitive in those contracts; it also costs more per child. (Review is optional: set the
|
|
201
|
+
policy to `required` when you need the reviewer role to gate a merge.)
|
|
200
202
|
|
|
201
203
|
Choose subagents when the work is read-mostly, short-lived, or you will integrate the result
|
|
202
204
|
yourself. Choose Tower when the result must land on a branch under a controlled merge; enable review
|
|
@@ -245,14 +247,19 @@ Tower entry clears an active plan (or refuses entry under `mode.planModePolicy:"
|
|
|
245
247
|
Tower session cannot use the goal/todo/team/workflow tools. Plan first, then execute; do not expect
|
|
246
248
|
Tower to discover the plan for you.
|
|
247
249
|
|
|
248
|
-
### 4.6
|
|
250
|
+
### 4.6 The review policy is one tri-state control
|
|
249
251
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
+
The review policy is one control — `off`, `optional` (the default) or `required` — in the plugin-page
|
|
253
|
+
`dsh-tower` configuration section, mirrored by `review.mode` in config. It is not a component row and
|
|
254
|
+
not three mutually exclusive rows. `optional` means a completed mission can merge without a reviewer
|
|
255
|
+
for low-risk repositories, scratch work, or human-supervised sessions. `required` enforces the
|
|
252
256
|
independent review gate; the gate then re-checks `no-review`, `not-clean`, `review-hold`,
|
|
253
|
-
`review-not-approved`, `tip-moved`, and `review-mission-mismatch`. `
|
|
254
|
-
|
|
255
|
-
`reviewPolicy:"none"` + a reason and
|
|
257
|
+
`review-not-approved`, `tip-moved`, and `review-mission-mismatch`. `off` is a supported mode that
|
|
258
|
+
does not register `tower_review`; `optional` records verdicts but never blocks a merge. For one
|
|
259
|
+
mission only, with the policy `required`, set `reviewPolicy:"none"` + a reason and
|
|
260
|
+
`gates.allowReviewExemption:true`. The deprecated one-release boolean alias maps `true` → `required`
|
|
261
|
+
and `false` → `optional`; see
|
|
262
|
+
[install, upgrade and migration](install-upgrade-migration.md).
|
|
256
263
|
|
|
257
264
|
### 4.7 Concrete examples by workflow
|
|
258
265
|
|
|
@@ -309,8 +316,8 @@ A team wants "organization invitations": token model, email delivery, accept/dec
|
|
|
309
316
|
`src/ui/invites/**`; make the API depend on tokens and email.
|
|
310
317
|
2. Spawn workers for the independent missions; the API waits for its deps.
|
|
311
318
|
3. Each worker commits on its branch, completes with checks.
|
|
312
|
-
4. With `review.
|
|
313
|
-
|
|
319
|
+
4. With `review.mode:required`, spawn reviewers and require a clean+merge verdict; otherwise review
|
|
320
|
+
is optional or off.
|
|
314
321
|
5. `tower_preflight` and `tower_merge` each mission; resolve scope/base/review blockers.
|
|
315
322
|
6. `tower_teardown`; `MISSIONS.md` is the human-readable record.
|
|
316
323
|
|
|
@@ -344,9 +351,9 @@ Tower missions from those findings.
|
|
|
344
351
|
### Scenario E: sensitive release
|
|
345
352
|
|
|
346
353
|
A library release with external consumers. Plan missions for the change, migration guide, and
|
|
347
|
-
release notes;
|
|
348
|
-
|
|
349
|
-
|
|
354
|
+
release notes; set `review.mode:required` if the release requires independent review, require tests,
|
|
355
|
+
and use `tower_batch` to close the release evidence only when all required checks are present; merge
|
|
356
|
+
and tag outside Tower as your release process requires.
|
|
350
357
|
|
|
351
358
|
## 6. Choosing in practice: a short decision path
|
|
352
359
|
|
|
@@ -354,9 +361,9 @@ merge and tag outside Tower as your release process requires.
|
|
|
354
361
|
2. **Would you open a PR for it?** No → Tower is too heavy; use a normal agent.
|
|
355
362
|
3. **Do the slices have stable scopes and a known definition of done?** No → plan/explore first; then
|
|
356
363
|
return to Tower.
|
|
357
|
-
4. **Do you need a merge gate?** Repository changes with integration risk → Tower.
|
|
358
|
-
`
|
|
359
|
-
|
|
364
|
+
4. **Do you need a merge gate?** Repository changes with integration risk → Tower. Set the review
|
|
365
|
+
policy to `required` if you also need independent review. If neither isolation nor evidence is
|
|
366
|
+
needed, plain subagents may be enough.
|
|
360
367
|
5. **Do you need many parallel analyses or repeated fresh attempts?** Use Workflow/Ralph for that
|
|
361
368
|
phase; encode the resulting changes as Tower missions.
|
|
362
369
|
6. **Do you need cross-cutting human collaboration?** Use Agent Teams to decide; execute the decided
|
|
@@ -368,9 +375,9 @@ merge and tag outside Tower as your release process requires.
|
|
|
368
375
|
round, gate, merge. Keep missions meaningful (roughly a PR-sized slice), not one task per function.
|
|
369
376
|
- **Merges serialize**: overlapping scopes auto-add dependencies; independent missions still merge
|
|
370
377
|
one at a time onto the base. Do not expect linear speedup for merge-heavy work.
|
|
371
|
-
- **Review is not free when
|
|
372
|
-
`review.
|
|
373
|
-
are opt-in and require a reason.
|
|
378
|
+
- **Review is not free when required**: each mission then needs a reviewer and a clean verdict.
|
|
379
|
+
`review.mode:optional` (the default) makes review non-blocking, and `off` removes the review tool;
|
|
380
|
+
when the policy is `required`, exemptions are opt-in and require a reason.
|
|
374
381
|
- **Too-fine missions** increase coordination and merge cost. **Too-coarse missions** lose the benefit
|
|
375
382
|
of parallel review and make scope conflicts likely.
|
|
376
383
|
- **Tower is not a sandbox**: it is a coordination protocol. Host permissions, repository hooks, and
|
|
@@ -385,7 +392,7 @@ merge and tag outside Tower as your release process requires.
|
|
|
385
392
|
- [ ] The work produces a repository change that deserves a PR-style review.
|
|
386
393
|
- [ ] I can name 2–8 missions with non-overlapping scopes and a rough dependency order.
|
|
387
394
|
- [ ] Each mission has a testable definition of done (tasks, checks/tests, optional review).
|
|
388
|
-
- [ ] If this change needs independent review,
|
|
395
|
+
- [ ] If this change needs independent review, the review policy is `required` (default is `optional`).
|
|
389
396
|
- [ ] I know which missions can run in parallel and which must wait.
|
|
390
397
|
- [ ] I accept the merge-gate overhead (and review overhead if enabled) and will inspect
|
|
391
398
|
`MISSIONS.md`/the branch.
|
|
@@ -4,15 +4,16 @@ Tower's guarantees are **coordination guarantees**, not a sandbox. Understand wh
|
|
|
4
4
|
|
|
5
5
|
## Enforced by the plugin
|
|
6
6
|
|
|
7
|
-
- **Review binding (when
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
- **Review binding (when required).** `tower_review` records the branch tip it inspected; with
|
|
8
|
+
`review.mode:required`, the gate rejects a moved tip (`tip-moved`) unless a clean conflict-free
|
|
9
|
+
rebase waived it. A reviewer that modifies the branch after spawning is rejected
|
|
10
10
|
(`reviewer must not modify the mission branch`).
|
|
11
|
-
- **Review is optional by default, enforceable by
|
|
12
|
-
default
|
|
13
|
-
`reviewPolicy:"none"` + reason is the narrower exemption when the
|
|
14
|
-
off
|
|
15
|
-
repositories.
|
|
11
|
+
- **Review is optional by default, enforceable by the tri-state policy.** `review.mode` is `off`,
|
|
12
|
+
`optional` (the default) or `required`. Set it to `required` to enforce the independent-review gate.
|
|
13
|
+
Mission-level `reviewPolicy:"none"` + reason is the narrower exemption when the policy is required.
|
|
14
|
+
With `off`, review is intentionally unavailable; with `optional`, separation of duties is not
|
|
15
|
+
enforced by the plugin, so use it only for trusted or human-supervised repositories. The policy is
|
|
16
|
+
one control on the plugin page, not a component row.
|
|
16
17
|
- **Role enforcement.** The caller is resolved against the roster. Worker mission updates are limited to
|
|
17
18
|
task/blocker/note; `completed`, `abandoned`, scope widening and blocker clearing are tower-only, and
|
|
18
19
|
completion (with its unread-inbox/commit gates) must go through `tower_complete`. Tower-only tools reject
|
|
@@ -84,8 +85,8 @@ intent behind that entry. What it does provide:
|
|
|
84
85
|
It does **not** defend against: a model that legitimately passes every gate while acting on malicious
|
|
85
86
|
instructions; repository hooks or test commands the repository itself declares; or filesystem/shell
|
|
86
87
|
access outside the worktree by a worker that ignores its instructions. For a higher-assurance team,
|
|
87
|
-
set `mode.allowAgentControl:false`, keep `review.
|
|
88
|
-
Tower work, and run the host under OS-level isolation.
|
|
88
|
+
set `mode.allowAgentControl:false`, keep the review policy at `review.mode:required`, review the
|
|
89
|
+
repository before Tower work, and run the host under OS-level isolation.
|
|
89
90
|
|
|
90
91
|
## Not enforced by the plugin (deployment concerns)
|
|
91
92
|
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
return the same shape for operation failures. Codes are stable; the detail is human-facing. The
|
|
5
5
|
tables below define 32 stable blocker/failure codes.
|
|
6
6
|
|
|
7
|
+
The review blockers below (`no-review`, `review-mission-mismatch`, `not-clean`, `review-hold`,
|
|
8
|
+
`review-not-approved`, `tip-moved`, `review-exemption-invalid`) exist only when `review.mode` is
|
|
9
|
+
`required`. With `off` or `optional` no review blocker is produced; `off` additionally removes
|
|
10
|
+
`tower_review` and refuses reviewer spawn.
|
|
11
|
+
|
|
7
12
|
## Gate blockers (26)
|
|
8
13
|
|
|
9
14
|
| Code | Meaning / next action |
|
|
@@ -19,12 +24,12 @@ tables below define 32 stable blocker/failure codes.
|
|
|
19
24
|
| `out-of-scope` | Changed files outside the mission scope; widen scope deliberately or revert. On a case-sensitive checkout a case-only mismatch is still rejected and the detail names the scope entry it would match if case were folded. |
|
|
20
25
|
| `base-dirty` | The main checkout has uncommitted changes the merge would overwrite. |
|
|
21
26
|
| `deps-unmerged` | A dependency mission is not satisfied: a build dependency must be `merged`/`abandoned`, while a survey dependency is satisfied at `completed` (archived entries included). |
|
|
22
|
-
| `no-review` | `review.
|
|
23
|
-
| `review-mission-mismatch` | `review.
|
|
24
|
-
| `not-clean` | `review.
|
|
25
|
-
| `review-hold` | `review.
|
|
26
|
-
| `review-not-approved` | `review.
|
|
27
|
-
| `tip-moved` | `review.
|
|
27
|
+
| `no-review` | `review.mode:required` and no review exists on the branch: spawn a reviewer (or disable the review gate). |
|
|
28
|
+
| `review-mission-mismatch` | `review.mode:required` and the latest review belongs to another mission. |
|
|
29
|
+
| `not-clean` | `review.mode:required` and latest review is `p1-Nitems`/`p2-Nitems`; another round is required. Verdicts from later routes of the same round are appended to it instead of flipping the mission again. |
|
|
30
|
+
| `review-hold` | `review.mode:required` and latest review recommends hold; a later clean review must supersede it. |
|
|
31
|
+
| `review-not-approved` | `review.mode:required` and latest clean review says `fix-then-merge` or `hold`; only `merge` approves. |
|
|
32
|
+
| `tip-moved` | `review.mode:required` and the branch changed after review; review again (or use a clean rebase waiver). |
|
|
28
33
|
| `worker-busy` | A roster agent for this mission is running; wait or retire it. |
|
|
29
34
|
| `worker-status-unknown` | The parent catalog is unavailable, so a live roster agent cannot be proven stopped; retry after the catalog recovers or adopt it. |
|
|
30
35
|
| `base-wrong-branch` | The main checkout is not on the recorded base branch. |
|
|
@@ -32,7 +37,7 @@ tables below define 32 stable blocker/failure codes.
|
|
|
32
37
|
| `worker-stale` | A roster worker for this mission has no catalog activity beyond `spawn.staleMs`; adopt it (or interrupt it only if it is actually running) before merge. |
|
|
33
38
|
| `tests-missing` | `gates.requireTests` is enabled and there is no passing discovery receipt for the current branch tip; run `tower_test` or `tower_complete`. |
|
|
34
39
|
| `tests-failed` | The latest discovery receipt failed or did not meet minCount/required checks. Fix the tests and re-run. |
|
|
35
|
-
| `review-exemption-invalid` | `review.
|
|
40
|
+
| `review-exemption-invalid` | `review.mode:required` and the mission requests `reviewPolicy:"none"` while `gates.allowReviewExemption` is off (or the reason is missing). |
|
|
36
41
|
| `merge-intent-pending` | A merge intent was recorded before a crash/failure; run `tower_merge` to reconcile before another gate. |
|
|
37
42
|
|
|
38
43
|
## Merge failures (4)
|