dsh-tower 2.5.0 → 2.7.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 +114 -0
- package/COMPATIBILITY.md +2 -0
- package/CONTRIBUTING.md +1 -1
- package/GLOSSARY.md +6 -0
- package/PRINCIPLES.md +15 -7
- package/README.en.md +18 -16
- package/README.md +18 -11
- package/adapters/leases.js +20 -6
- package/adapters/legacy.js +149 -37
- package/adapters/stateFile.js +11 -1
- package/app/archive.js +30 -5
- package/app/briefing.js +95 -12
- package/app/checkCompletion.js +107 -18
- package/app/enrichedMissions.js +1 -1
- package/app/freshness.js +77 -0
- package/app/gate.js +26 -12
- package/app/merge.js +7 -4
- package/app/mission.js +24 -1
- package/app/missionContext.js +2 -1
- package/app/plan.js +64 -1
- package/app/provision.js +133 -22
- package/app/read.js +38 -5
- package/app/rebase.js +10 -8
- package/app/review.js +104 -61
- package/app/reviewCheckout.js +133 -0
- package/app/sandbox.js +121 -0
- package/app/sharedCheckout.js +90 -0
- package/app/spawn-prechecks.js +31 -20
- package/app/spawn-support.js +59 -8
- package/app/spawn.js +3 -0
- package/app/teardown.js +119 -2
- package/app/tower.js +34 -6
- package/client.js +321 -0
- package/cordis.patch.yml +55 -3
- package/docs/adr/0005-component-surface.md +58 -13
- package/docs/adr/0006-mission-shapes.md +306 -0
- package/docs/architecture/overview.md +18 -10
- package/docs/examples/first-mission.md +3 -2
- package/docs/faq.md +9 -7
- package/docs/guide/install-upgrade-migration.md +58 -7
- package/docs/guide/quickstart.md +20 -10
- package/docs/guide/scenarios-and-philosophy.md +35 -28
- package/docs/operations/runbook.md +1 -1
- package/docs/operations/security.md +11 -10
- package/docs/reference/blockers.md +20 -11
- package/docs/reference/component-surface.md +20 -8
- package/docs/reference/config.generated.md +8 -5
- package/docs/reference/config.md +30 -5
- package/docs/reference/doctor.md +7 -7
- package/docs/reference/errors.generated.md +1 -0
- package/docs/reference/errors.md +2 -1
- package/docs/reference/operations.md +1 -1
- package/docs/reference/shapes.md +123 -0
- package/docs/reference/surface-budget.md +53 -4
- package/docs/reference/testing.md +5 -3
- package/docs/reference/tools.generated.md +7 -7
- package/docs/reference/tools.md +5 -5
- package/docs/zh/faq.md +7 -5
- package/docs/zh/guide/install-upgrade-migration.md +25 -6
- 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 +13 -9
- package/docs/zh/reference/config.md +22 -5
- package/docs/zh/reference/errors.md +2 -1
- package/docs/zh/reference/testing.md +5 -4
- package/docs/zh/reference/tools.md +3 -3
- package/domain/batch.js +75 -105
- package/domain/collab/batch.js +30 -10
- package/domain/collab/spawn.js +53 -16
- package/domain/components.js +12 -4
- package/domain/config/schema.js +87 -22
- package/domain/contracts/outputs.js +2 -1
- package/domain/contracts/tool-inputs/missions.js +10 -2
- package/domain/errors.js +6 -0
- package/domain/evidence.js +283 -0
- package/domain/gate.js +17 -34
- package/domain/integration/gate.js +17 -43
- package/domain/integration/init.js +3 -2
- package/domain/integration/provision.js +51 -0
- package/domain/integration/rebase.js +16 -1
- package/domain/integration/review.js +203 -9
- package/domain/mission.js +16 -33
- package/domain/missions/completion.js +46 -8
- package/domain/missions/findings.js +2 -1
- package/domain/missions/lifecycle.js +131 -35
- package/domain/missions/plan.js +30 -6
- package/domain/missions/review.js +2 -18
- package/domain/planning.js +5 -5
- package/domain/read/missionContext.js +17 -3
- package/domain/read/views.js +5 -1
- package/domain/roles.js +222 -0
- package/domain/roster.js +9 -3
- package/domain/scope.js +51 -0
- package/domain/shapes/build.js +254 -0
- package/domain/shapes/index.js +171 -0
- package/domain/shapes/survey.js +445 -0
- package/domain/state/archive.js +28 -4
- package/domain/state/migrations.js +111 -4
- package/domain/state/schema.js +69 -7
- package/domain/state/semantics.js +93 -13
- package/domain/state.js +5 -1
- package/domain/summary.js +5 -11
- package/domain/vocabulary.js +15 -33
- package/host/capability-registry.js +25 -9
- package/host/config.js +40 -3
- package/host/doctor.js +20 -8
- package/host/preset-survey-sandbox.js +19 -0
- package/host/preset-survey.js +18 -0
- package/host/presets.js +17 -11
- package/host/tool-registry.js +23 -13
- package/locale/en.json +16 -1
- package/locale/preset-survey/en.json +6 -0
- package/locale/preset-survey/zh.json +6 -0
- package/locale/preset-survey-sandbox/en.json +6 -0
- package/locale/preset-survey-sandbox/zh.json +6 -0
- package/locale/zh.json +16 -1
- package/package.json +19 -2
- package/ports/state.js +8 -1
- package/scripts/architecture-waivers.json +3 -3
- package/scripts/check-components.mjs +120 -6
- package/scripts/check-docs.mjs +1 -1
- package/scripts/check-pack.mjs +5 -0
- package/scripts/component-surface.json +83 -29
- package/scripts/generate-capability-locale.mjs +5 -0
- package/scripts/generate-shapes-reference.mjs +171 -0
- package/scripts/mount-smoke/surface.mjs +3 -0
- package/scripts/pack-manifest.txt +22 -0
- package/scripts/shape-audit.mjs +361 -0
- package/scripts/surface-baseline.json +75 -4
- package/scripts/types-coverage.mjs +7 -0
- package/survey-sandbox.js +48 -0
- package/survey.js +40 -0
- package/tools/complete.js +5 -5
- package/tools/diff.js +5 -3
- package/tools/plan.js +1 -1
- package/tools/preflight.js +3 -2
- package/tools/review.js +1 -1
- package/tools/spawn.js +48 -50
- package/tools/status.js +8 -1
- package/tools/test.js +2 -1
- package/types/index.d.ts +76 -5
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Mission shapes (generated)
|
|
2
|
+
|
|
3
|
+
> Generated by `npm run docs:generate:shapes` from `domain/shapes/index.js`. Do not edit by hand.
|
|
4
|
+
|
|
5
|
+
A mission shape is the single place its kind's contract lives (#148/#149). Generic
|
|
6
|
+
layers resolve `shapeFor(mission.kind)` and never branch on a kind literal; the
|
|
7
|
+
shape audit (`npm run shape:audit`) refuses kind and role comparisons outside
|
|
8
|
+
`domain/shapes/`, the global `TERMINAL_STATUSES`/`TRANSITIONS` vocabulary,
|
|
9
|
+
one-argument `isTerminal`/`canTransition` calls, and the dimension regressions
|
|
10
|
+
recorded in the inventory below (review tip, batch status, lease ledger, blocked
|
|
11
|
+
writes, evidence reads, legacy vocabulary, path permission and role/shape
|
|
12
|
+
conflation).
|
|
13
|
+
|
|
14
|
+
## Kinds
|
|
15
|
+
|
|
16
|
+
| Kind | Statuses | Has terminal | Provisioning | Can merge | Can rebase | Reach (owns / fence) | Component | Accepts result |
|
|
17
|
+
|---|---|---|---|---|---|---|---|---|
|
|
18
|
+
| `build` | `planned`, `active`, `completed`, `blocked`, `paused`, `merged`, `abandoned` | yes | `branch-worktree` | true | true | true / `scope` | — | false |
|
|
19
|
+
| `survey` | `planned`, `active`, `completed`, `blocked`, `paused`, `abandoned` | yes | `shared` / `detached` | false | false | false / `read-only` | tower-survey | true |
|
|
20
|
+
|
|
21
|
+
## Transitions
|
|
22
|
+
|
|
23
|
+
### build
|
|
24
|
+
|
|
25
|
+
| From | To |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `planned` | `active`, `blocked`, `abandoned` |
|
|
28
|
+
| `active` | `completed`, `blocked`, `paused`, `abandoned` |
|
|
29
|
+
| `completed` | `active`, `blocked`, `abandoned` |
|
|
30
|
+
| `blocked` | `active`, `abandoned` |
|
|
31
|
+
| `paused` | `active`, `blocked`, `abandoned` |
|
|
32
|
+
| `merged` | terminal |
|
|
33
|
+
| `abandoned` | terminal |
|
|
34
|
+
|
|
35
|
+
### survey
|
|
36
|
+
|
|
37
|
+
| From | To |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `planned` | `active`, `blocked`, `abandoned` |
|
|
40
|
+
| `active` | `completed`, `blocked`, `paused`, `abandoned` |
|
|
41
|
+
| `completed` | terminal |
|
|
42
|
+
| `blocked` | `active`, `abandoned` |
|
|
43
|
+
| `paused` | `active`, `blocked`, `abandoned` |
|
|
44
|
+
| `abandoned` | terminal |
|
|
45
|
+
|
|
46
|
+
## Survey placement (#148 W2)
|
|
47
|
+
|
|
48
|
+
`survey.sandbox` is tuning, not a component: the `tower-survey` row stays the
|
|
49
|
+
switch. The shape resolves both the placement and the preset, so generic layers
|
|
50
|
+
never read the raw key or compare a kind.
|
|
51
|
+
|
|
52
|
+
The decision is made once, at provisioning time. A mission with a recorded
|
|
53
|
+
`mission.sandbox` keeps the detached placement and its completion invariants
|
|
54
|
+
even if `survey.sandbox` later changes — a config flip can neither skip the
|
|
55
|
+
sandbox HEAD/zero-commit checks nor strand the disposable checkout. A survey
|
|
56
|
+
that never got a sandbox keeps the shared invariants for the same reason.
|
|
57
|
+
|
|
58
|
+
| `survey.sandbox` | Provisioning | Preset | Completion invariants |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| `none` (default) | `shared`: no checkout, the agent reads the main checkout | `tower-survey` (strictly read-only: no write, edit, or shell tool) | HEAD equals `readCommit`, tracked-status fingerprint unchanged, zero commits |
|
|
61
|
+
| `detached` | `detached`: `git worktree add --detach <worktreeRoot>/<id>-sandbox <readCommit>` (no branch, no `baseCommit`, never merged) | `tower-survey-sandbox` (read/write/edit/pwsh plus the mission tools; spawn/merge/rebase/review/diff still absent) | sandbox HEAD equals `readCommit`, zero commits; disposable write/shell side effects are ignored; sandbox removed on completion, abandon or teardown with a bounded retry |
|
|
62
|
+
|
|
63
|
+
## Completion invariants
|
|
64
|
+
|
|
65
|
+
| Kind | Invariants | Check |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `build` | requiresWorktree=true, requiresCommits=true, requiresClean=true, requiresHeadMatch=false, requiresTrackedStatus=false | `checkCompletion` |
|
|
68
|
+
| `survey` | requiresWorktree=false, requiresSandbox=false, requiresCommits=false, requiresClean=false, requiresHeadMatch=true, requiresTrackedStatus=true | `checkCompletion` |
|
|
69
|
+
|
|
70
|
+
## Role
|
|
71
|
+
|
|
72
|
+
| Contract | Owner |
|
|
73
|
+
|---|---|
|
|
74
|
+
| Status, transitions, terminality, merge/rebase, provisioning, reach, plan fields, completion, dependencies, briefing, summary | `domain/shapes/<kind>.js` |
|
|
75
|
+
| Kind resolution and the action guard | `domain/shapes/index.js` |
|
|
76
|
+
| Role vocabulary and the role contract (preset, model, placement, briefing, prerequisites) | `domain/roles.js` |
|
|
77
|
+
| Generated reference and the audit | `scripts/generate-shapes-reference.mjs`, `scripts/shape-audit.mjs` |
|
|
78
|
+
|
|
79
|
+
## Dimension inventory (#149)
|
|
80
|
+
|
|
81
|
+
Every dimension the registry audit covers. A **shape-owned** verdict lives in
|
|
82
|
+
`domain/shapes/<kind>.js`; a **correctly generic** verdict has one owner module
|
|
83
|
+
outside the shapes; a **redesigned** verdict replaced an earlier ambiguous
|
|
84
|
+
contract. The fitness rule is the mechanical check the audit (or the generated
|
|
85
|
+
invariant) enforces.
|
|
86
|
+
|
|
87
|
+
| Dimension | Verdict | Owner module | Fitness rule |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| Mission lifecycle | **Shape-owned.** Statuses, transitions and terminality are per kind. | `domain/shapes/<kind>.js` | `kind-literal`, `global-status-vocabulary`, `shape-entry-point` |
|
|
90
|
+
| Role vocabulary | **Correctly generic.** Roles are actors, not mission kinds. | `domain/roles.js` | `role-literal` |
|
|
91
|
+
| Provisioning | **Shape-owned.** A build gets a branch worktree; a survey is shared or a detached sandbox. | `domain/shapes/<kind>.js` | Generated invariant: only a build creates a branch/worktree; a recorded `mission.sandbox` decides a survey's placement. |
|
|
92
|
+
| Read-only completion | **Shape-owned.** `resolveCompletion` derives invariants from the recorded placement. | `domain/shapes/survey.js` | Generated invariant: shared survey keeps HEAD and tracked status; detached survey keeps HEAD pinned; both make zero commits. |
|
|
93
|
+
| Dependency | **Shape-owned.** `dependencySatisfied` names the terminal statuses that satisfy a dependent. | `domain/shapes/<kind>.js` | Generated invariant: a completed survey satisfies a dependent build; a merged build does too. |
|
|
94
|
+
| Archive / reanchor / planning | **Shape-owned.** Terminality is the one archive/reanchor predicate. | `domain/shapes/<kind>.js` | Generated invariant: a terminal shape leaves open work and never blocks reanchor. |
|
|
95
|
+
| Completion result | **Shape-owned.** Only a survey may record a completion result. | `domain/shapes/<kind>.js` | Generated invariant: `shape.acceptsResult`. |
|
|
96
|
+
| Required component | **Shape-owned.** A survey needs the `tower-survey` row. | `domain/shapes/<kind>.js` | Generated invariant: planning refuses with an actionable code while the required component is off. |
|
|
97
|
+
| Review | **Redesigned.** Commit-stamped evidence: a reviewer reads a disposable checkout at the recorded review commit; only a shape with a branch is reviewable. | `app/review.js`, `app/reviewCheckout.js`, `domain/missions/review.js` | `review-tip-read` — A review never reads a live worktree HEAD; verdicts are stamped with a recorded commit. |
|
|
98
|
+
| Batch | **Correctly generic second lifecycle.** A batch is finite evidence over missions, not a mission kind; no shape knows about batches. | `domain/batch.js`, `domain/collab/batch.js`, `app/batch.js` | `batch-status-literal` — Batch status literals live in domain/batch.js; every other layer uses its constants. |
|
|
99
|
+
| Leases | **Correctly generic.** One fail-closed admission point; expiry is recovered only by an explicit `force` release. | `adapters/leases.js`, `app/spawn-prechecks.js` | `lease-ledger` — Only adapters/leases.js reads or writes the lease ledger. |
|
|
100
|
+
| Paused vs blocked | **Redesigned.** `blocked` is derived machine state; `paused` is a deliberate stop with a cause. | `domain/missions/lifecycle.js`, `domain/state/semantics.js` | `blocked-status-write` — blocked is derived from open blockers; only domain/missions/lifecycle.js writes it. |
|
|
101
|
+
| Test receipts / evidence | **Redesigned — one reader.** Completion checks and discovery receipts are one normalized evidence contract in `domain/evidence.js`; the shape declares whether a receipt is tip-bound. `tower_complete` no longer copies a synthetic `tests` check into the report. | `domain/evidence.js`; `domain/shapes/<kind>.js` declares `evidence` | `evidence-single-read` — Completion checks and test receipts have one reader: domain/evidence.js. |
|
|
102
|
+
| Legacy import | **Redesigned — strict adapter.** One payload is one declared format; status remaps, assumed kinds and non-carried fields are reported as `remapped`/`unresolved`/`dropped` instead of approximated. Import stays read-only and never resumes a paused mission. | `adapters/legacy.js`; `domain/batch.js` reads only the canonical `pausedMissionIds` | `legacy-vocabulary` — One live vocabulary: legacy formats/statuses are read only by adapters/legacy.js. |
|
|
103
|
+
| Scope ownership | **Redesigned — shape.reach.** The shape owns path permission (`reach.ownsPaths`, `reach.fence`); the gate, planner, lifecycle and auto-deps derive from it through one fence. | `domain/scope.js` + `shape.reach` in `domain/shapes/<kind>.js` | `scope-reach` — Path permission derives from shape.reach through domain/scope.js; no module owns or re-implements it. |
|
|
104
|
+
| Role vs kind | **Redesigned — orthogonal role contract.** Spawn, preset, model, placement, briefing, roster budget and gates resolve the role through `domain/roles.js`; the shape only supplies facts. | `domain/roles.js`; callers `tools/spawn.js`, `app/spawn-prechecks.js`, `app/spawn-support.js`, `domain/roster.js`, `host/presets.js` | `role-shape-conflation` — A role decision never combines with a shape decision; role facts live in domain/roles.js. |
|
|
105
|
+
|
|
106
|
+
## Fitness rules
|
|
107
|
+
|
|
108
|
+
Generated from `scripts/shape-audit.mjs` `RULES`; the audit is wired into `npm run check`.
|
|
109
|
+
|
|
110
|
+
| Rule | Owner module | Contract |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `kind-literal` | `domain/shapes/<kind>.js` | Generic layers never compare mission.kind with a literal. |
|
|
113
|
+
| `role-literal` | `domain/roles.js` | Generic layers use the vocabulary role predicates, never a role literal. |
|
|
114
|
+
| `global-status-vocabulary` | `domain/shapes/<kind>.js` | No module reaches for the global TERMINAL_STATUSES/TRANSITIONS tables. |
|
|
115
|
+
| `shape-entry-point` | `domain/shapes/index.js` | isTerminal(kind, status) and canTransition(kind, from, to) are the only entry points. |
|
|
116
|
+
| `review-tip-read` | `app/reviewCheckout.js` | A review never reads a live worktree HEAD; verdicts are stamped with a recorded commit. |
|
|
117
|
+
| `batch-status-literal` | `domain/batch.js` | Batch status literals live in domain/batch.js; every other layer uses its constants. |
|
|
118
|
+
| `lease-ledger` | `adapters/leases.js` | Only adapters/leases.js reads or writes the lease ledger. |
|
|
119
|
+
| `blocked-status-write` | `domain/missions/lifecycle.js` | blocked is derived from open blockers; only domain/missions/lifecycle.js writes it. |
|
|
120
|
+
| `evidence-single-read` | `domain/evidence.js` | Completion checks and test receipts have one reader: domain/evidence.js. |
|
|
121
|
+
| `legacy-vocabulary` | `adapters/legacy.js` | One live vocabulary: legacy formats/statuses are read only by adapters/legacy.js. |
|
|
122
|
+
| `scope-reach` | `domain/scope.js` | Path permission derives from shape.reach through domain/scope.js; no module owns or re-implements it. |
|
|
123
|
+
| `role-shape-conflation` | `domain/roles.js` | A role decision never combines with a shape decision; role facts live in domain/roles.js. |
|
|
@@ -65,8 +65,54 @@ config-key count is two-way: a later increase **or** decrease needs its own
|
|
|
65
65
|
decision naming an ADR, unlike sections and tools. The same wave makes the gate
|
|
66
66
|
import `OPERATIONAL_TOOLS` instead of scraping it, discover every shipped
|
|
67
67
|
`cordis.patch.yml` in both directions, review the non-boolean behaviour knobs
|
|
68
|
-
(`spawn.requireLease`, `tests.admission`), and refuse a row
|
|
69
|
-
component's `allowedOverrides`.
|
|
68
|
+
(`spawn.requireLease`, `tests.admission`, and now `review.mode`), and refuse a row
|
|
69
|
+
config outside its component's `allowedOverrides`.
|
|
70
|
+
|
|
71
|
+
#M39 grew the config surface by exactly one, 53 → 54: `review.mode`
|
|
72
|
+
(`off`/`optional`/`required`) is the review policy, and the deprecated
|
|
73
|
+
`review.requireReview` boolean stays accepted for one release as a normalized
|
|
74
|
+
alias. It is not a fifth component row: `preset-tower-reviewer` remains a
|
|
75
|
+
capability row and `review.mode:off` simply leaves it unused (no `tower_review`,
|
|
76
|
+
no reviewer spawn, no review blockers). The dated decision records both the new
|
|
77
|
+
key and why the old boolean was not removed in the same release.
|
|
78
|
+
|
|
79
|
+
#M42 reclassifies the deprecated alias from `forbidden-to-disable` to `core` in
|
|
80
|
+
the component surface: it is policy configuration and a compatibility alias, not
|
|
81
|
+
a capability a row may switch. The policy is one tri-state control on the
|
|
82
|
+
plugin-page form, not a row and not one row per mode; the review gate in
|
|
83
|
+
`required` mode, its tip-bound evidence and the exemption path remain
|
|
84
|
+
non-disableable. The component and config-key counts do not move (11 visible
|
|
85
|
+
components, 54 keys).
|
|
86
|
+
|
|
87
|
+
#148/#149 grow the surface by exactly one key and one visible component,
|
|
88
|
+
recorded in [ADR 0006](../adr/0006-mission-shapes.md): config keys 54 → 55,
|
|
89
|
+
sections stay 14, components 11 → 12. A first cut of the shape work added three
|
|
90
|
+
keys and a `survey` section, then contracted 57 → 55 before release in a second
|
|
91
|
+
dated decision: a survey's preset is shape-owned
|
|
92
|
+
(`SHAPES.survey.spawn.defaultPreset`), so a `spawn.surveyPreset` key could only
|
|
93
|
+
disagree with the registry, and `survey.sandbox` advertised a placement W1 does
|
|
94
|
+
not implement. What remains is `spawn.surveyModel`, the optional model route for
|
|
95
|
+
survey workers (the survey row owns the capability, not the key name). The
|
|
96
|
+
`tower-survey` row is the switch: off means surveys cannot be planned and no
|
|
97
|
+
survey agent is dispatched; build missions are unaffected. No existing key
|
|
98
|
+
changed class.
|
|
99
|
+
|
|
100
|
+
#148 W2 implements the detached survey sandbox, so it restores exactly the
|
|
101
|
+
placement key that W1 correctly withheld: `survey.sandbox` (`none`|`detached`,
|
|
102
|
+
default `none`) returns as tuning, and `gates.requireFreshSurvey` (default
|
|
103
|
+
`false`) joins it as merge-gate strictness; config keys 55 → 57 and sections
|
|
104
|
+
14 → 15. It
|
|
105
|
+
is not a capability: the `tower-survey` row stays the single switch and the
|
|
106
|
+
sandbox preset is an internal child of it, so the visible component count does
|
|
107
|
+
not move (12). `spawn.surveyPreset` stays removed: the shape resolves the preset
|
|
108
|
+
from `survey.sandbox`, so the key could still only disagree with the registry.
|
|
109
|
+
|
|
110
|
+
#149 W4 contracts the config surface by one: config keys 57 → 56. `tests.autoChecks`
|
|
111
|
+
only chose whether a discovery projection was copied into the completion report,
|
|
112
|
+
and that copy was the second evidence shape the W4 audit removed. The receipt in
|
|
113
|
+
`mission.testRuns` is the one evidence record now, so the switch had no meaning
|
|
114
|
+
left; it is deleted rather than kept as a dead tuning key. Sections and the
|
|
115
|
+
visible component count do not move.
|
|
70
116
|
|
|
71
117
|
## Config keys
|
|
72
118
|
|
|
@@ -92,13 +138,16 @@ component's `allowedOverrides`.
|
|
|
92
138
|
| `mode.storePath` | niche | Custom mode-store location added for one deployment workflow. Removal note: derive the path from `$DSH_HOME` in the next minor; no in-tree caller sets this key. |
|
|
93
139
|
| `mode.maxEntries` | tuning | Bounds the persisted mode store. |
|
|
94
140
|
| `mode.lockTimeoutMs` | tuning | Bounded wait for the cross-process mode lock. |
|
|
95
|
-
| `review.
|
|
141
|
+
| `review.mode` | core | The review policy itself (`off`/`optional`/`required`); it replaces the deprecated boolean as the single gate switch. |
|
|
142
|
+
| `review.requireReview` | core | Deprecated alias for `review.mode` (`true` → `required`, `false` → `optional`); retained for one release. |
|
|
96
143
|
| `review.maxRoundsPerReviewer` | core | Caps review rounds; changes the review lifecycle. |
|
|
97
144
|
| `merge.timeoutMs` | tuning | Default merge timeout; a per-call value wins. |
|
|
98
145
|
| `merge.maxBufferBytes` | tuning | Captured merge output buffer. |
|
|
99
146
|
| `git.timeoutMs` | tuning | Default Git command timeout outside merge. |
|
|
100
147
|
| `worktrees.root` | tuning | Default worktree placement. |
|
|
101
148
|
| `spawn.workerPreset` | core | Chooses the tool surface a worker receives. |
|
|
149
|
+
| `spawn.surveyModel` | tuning | Optional model route for survey agents. |
|
|
150
|
+
| `survey.sandbox` | tuning | Placement only: shared read-only checkout (default) or a disposable detached sandbox. The tower-survey row is still the switch. |
|
|
102
151
|
| `spawn.reviewerPreset` | core | Chooses the read-only reviewer surface. |
|
|
103
152
|
| `spawn.maxDepth` | tuning | Subagent depth requested at spawn. |
|
|
104
153
|
| `spawn.provider` | tuning | Provider route for spawned agents. |
|
|
@@ -113,11 +162,11 @@ component's `allowedOverrides`.
|
|
|
113
162
|
| `tests.admission` | core | Chooses when repository code is executed. |
|
|
114
163
|
| `tests.timeoutMs` | tuning | Per-command discovery timeout. |
|
|
115
164
|
| `tests.maxBytes` | tuning | Captured discovery output cap. |
|
|
116
|
-
| `tests.autoChecks` | tuning | Attaches a tests check to completion. |
|
|
117
165
|
| `tests.allowPackageDiscovery` | core | Allows repository code to execute; a security contract. |
|
|
118
166
|
| `gates.requireChecks` | core | Requires completion evidence before merge. |
|
|
119
167
|
| `gates.requireTests` | core | Requires a test receipt before merge. |
|
|
120
168
|
| `gates.allowReviewExemption` | core | Allows a review exemption and its reason. |
|
|
169
|
+
| `gates.requireFreshSurvey` | core | Promotes the survey-stale dependency warning to a merge blocker; `false` keeps it advisory. |
|
|
121
170
|
| `gates.maxReportBytes` | tuning | Report size cap; the refusal itself is not configurable. |
|
|
122
171
|
| `docs.boardLocation` | tuning | Chooses where the board is written; whether it is written is the tower-board row. |
|
|
123
172
|
| `archive.afterDays` | tuning | Archive age threshold; archival itself is the tower-archive row. |
|
|
@@ -48,10 +48,12 @@ overall `ok`. `state.missions[].testRuns` keeps the most recent 50 receipts. The
|
|
|
48
48
|
discovery fails.
|
|
49
49
|
|
|
50
50
|
- `tower_test({repoRoot,missionId})` runs discovery on demand and records a receipt.
|
|
51
|
-
- `
|
|
52
|
-
|
|
51
|
+
- The receipt in `testRuns` is the only evidence shape. `tower_complete` does not copy a `tests`
|
|
52
|
+
check into the completion report; completion checks, batch close and `gates.requireChecks` read the
|
|
53
|
+
same receipt.
|
|
54
|
+
- `gates.requireChecks` requires any recorded check or receipt; `gates.requireTests` requires a passing receipt
|
|
53
55
|
for the current mission branch tip (`tests-missing`). Review is independent of this gate: with
|
|
54
|
-
`review.
|
|
56
|
+
`review.mode:optional` (the default) or `off`, the tests gate still checks the branch tip.
|
|
55
57
|
|
|
56
58
|
## Trust boundary
|
|
57
59
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Tools overview (generated)
|
|
2
2
|
|
|
3
3
|
> Generated by `npm run docs:generate:tools` from the registered tool definitions. Do not edit by hand.
|
|
4
|
-
> Surface: config keys:
|
|
4
|
+
> Surface: config keys: 56 · sections: 15 · tools: 29 · baseline 2026-10-23. Generated from `scripts/surface-baseline.json`; do not edit by hand.
|
|
5
5
|
|
|
6
6
|
| Tool | Description |
|
|
7
7
|
|---|---|
|
|
8
8
|
| `tower_adopt` | Reconcile the roster with the durable subagent catalog after a restart or new session. Agents that are provably gone are marked retired (records are kept) or missing (retireMissing:false, so the tower can inspect/take over); agents whose parent catalog cannot be read stay unknown and are never changed. Only the tower may adopt. |
|
|
9
9
|
| `tower_batch` | Manage finite evidence batches: create freezes missionIds/requiredChecks/receiptPaths, status summarizes members, close verifies every required check and receipt hash, abandon retires a stale open batch. Membership and exclusions are immutable after create; close/abandon never remove missions. |
|
|
10
|
-
| `tower_complete` | Worker-only: report mission completion. Enforced by the store: every task done or dropped, no blockers, the current owner, the mission branch has at least one commit since its spawn base, and no unread inbox messages. checks records verifiable evidence (name/command/exitCode/evidence); gates.requireChecks can require at least one before merge. Stores the full report, capped at gates.maxReportBytes (default 32768 UTF-8 bytes); a larger report is rejected with invalid-argument and an actionable nextAction, never truncated. Persists reportBytes on the stored report. completion means ready for preflight and optional review, not merged. |
|
|
10
|
+
| `tower_complete` | Worker-only: report mission completion. Enforced by the store: every task done or dropped, no blockers, the current owner, the mission branch has at least one commit since its spawn base (zero commits plus HEAD pinned to readCommit for a survey; zero commits in its detached sandbox with HEAD pinned for a sandboxed survey), and no unread inbox messages. checks records verifiable evidence (name/command/exitCode/evidence); gates.requireChecks can require at least one before merge. result is survey-only evidence ({paths?,symbols?,plan?,notes?}); a build completion that carries one is refused. Stores the full report, capped at gates.maxReportBytes (default 32768 UTF-8 bytes); a larger report is rejected with invalid-argument and an actionable nextAction, never truncated. Persists reportBytes on the stored report. completion means ready for preflight and optional review, not merged. |
|
|
11
11
|
| `tower_control` | Enter or leave Tower mode for the calling agent. Allowed only when the deployment enables allowAgentControl; use it when the user intent or task state clearly calls for Tower orchestration or a return to normal collaboration, and always state a concrete reason. |
|
|
12
12
|
| `tower_diff` | Read-only view of a mission branch for review: merge base, changed files, commits, and a capped patch against the recorded base. Safe for reviewers; it never modifies the repository. |
|
|
13
13
|
| `tower_doctor` | Read-only environment and repository health check: the concept-budget surface (config keys/sections/tools), git, state schema, case-sensitivity detection (caseInsensitive and the active scope comparison mode), config, presets/subagents/HMR, the state lock age/heartbeat freshness, the repo-scoped git lock holder (gitLock: {held,pid,phase,heldMs}), workspace lock, roster staleness, worktree ownership, test discovery, leases, and the terminal-mission archive (count, bytes, years, unreadable diagnostics and the configured afterDays/maxMissions policy). Returns checks with pass/warn/fail, state-lock and git-lock reports and an environment contract. Never writes state and never probes the filesystem. |
|
|
@@ -21,16 +21,16 @@
|
|
|
21
21
|
| `tower_merge` | Merge a mission branch into the recorded base branch with --no-ff, after the hard gate passes. Verifies the two merge parents and records the mission as merged. If the merge commit already landed (manual merge, crashed or slow pre-merge hook), it detects the merge commit and records it as reconciled instead of merging again. A failed gate returns stable blocker codes without merging; a hook failure aborts cleanly and returns "merge-hook-failed" while a real content conflict returns "merge-conflict". |
|
|
22
22
|
| `tower_mission` | Update one mission: lifecycle status, decision note, blocker, clear blockers, mark a task done, drop a task with a reason, or widen the scope (tower only). "merged" is never set here; only a future tower_merge records it. Merged and abandoned are terminal. |
|
|
23
23
|
| `tower_mode` | Report whether Tower mode is active for the calling agent, who changed it last, whether the model may toggle it, any goal paused on entry, the workspace lock, HMR availability and the plugin version. |
|
|
24
|
-
| `tower_plan` | Plan one or more missions in an initialized repository. Each mission has a printable-Unicode title (NFC-normalized, at most 120 characters), relative scope globs, optional task checklist, optional mission-id dependencies, and kind build|survey. Assigns M1.. ids and auto-adds a dependency when build scopes overlap (serializes merges); rejects dependency cycles. |
|
|
25
|
-
| `tower_preflight` | Read-only merge gate for one mission: returns ok plus stable blocker codes (branch-missing, deps-unmerged,
|
|
24
|
+
| `tower_plan` | Plan one or more missions in an initialized repository. Each mission has a printable-Unicode title (NFC-normalized, at most 120 characters), relative scope globs, optional task checklist, optional mission-id dependencies, and kind build|survey. Assigns M1.. ids and auto-adds a dependency when build scopes overlap (serializes merges); rejects dependency cycles. Returns survey-stale warnings for a build that depends on a survey whose recorded readCommit is not an ancestor of the base; those warnings are advisory and gates.requireFreshSurvey promotes them to merge blockers. |
|
|
25
|
+
| `tower_preflight` | Read-only merge gate for one mission: returns ok plus stable blocker codes (branch-missing, deps-unmerged, stale-base, out-of-scope, base-dirty, branch-owned-by-closed-missions, and mission/worker guards) and warnings (survey-stale). Review blockers (no-review, review-hold, not-clean, review-not-approved, tip-moved, review-mission-mismatch) apply only when review.mode is required; review.mode off and optional skip them. survey-stale reports a build dependency on a survey whose readCommit is not an ancestor-or-equal of the build base; it is a warning by default and a blocker only when gates.requireFreshSurvey is true. A survey has no merge gate: it is refused with invalid-transition (tower_complete checks HEAD/readCommit and zero commits). Never changes anything. |
|
|
26
26
|
| `tower_rebase` | Rebase a mission branch onto the current base tip inside its own worktree. Refuses while its worker is running or the worktree is dirty. A clean conflict-free rebase waives re-review for the old review; a conflict is aborted and the mission is marked blocked. If the branch is already contained in the base, it returns alreadyMerged and leaves the branch untouched so tower_merge can record the landed merge. |
|
|
27
27
|
| `tower_recover` | Read-only recovery diagnostics and an explicit stale-state-lock repair. status reports the state lock owner with its age, heartbeat age and staleness; clear-stale-lock requires confirm:"CLEAR_STALE_LOCK" and only moves a lock whose PID is provably dead to a backup file. force:true additionally clears a live-but-silent PID (a recycled PID) and still renames the record to a .recovered-<ts> backup. It never resets Tower state or worktrees. |
|
|
28
28
|
| `tower_reload` | Dev-only: ask DSH HMR to reconcile this profile and reload the Tower Host plugin from disk. Registered only while the tower-hmr component is on (the row is shipped off). The reload is scheduled a few milliseconds after this call returns (so the result reaches the model first). Use after editing the plugin source in a linked profile; plugin_manager install/update already triggers reconciliation by itself. Fails with reload-unavailable when the HMR service is absent. |
|
|
29
29
|
| `tower_resource` | Advisory resource leases per repository (coordination only; no OS CPU/memory hard cap). acquire/release require a token and are tower-only; status is read-only. Expired leases are never taken over silently. |
|
|
30
|
-
| `tower_review` | Submit an independent review verdict bound to the current branch tip: a completed mission starts a review round, and while the mission is active a later route may still record a verdict for that same reviewed tip, appending to the same round without changing the status (a moved tip is rejected with an explanation). status is "clean", "p1-Nitems", or "p2-Nitems"; merge is "merge", "fix-then-merge", or "hold" (only clean + merge is later approval). Non-clean returns the mission to active. Reviewers are capped at 5 rounds per branch; a tower-submitted review is break-glass and requires breakGlassReason. |
|
|
30
|
+
| `tower_review` | Submit an independent review verdict bound to the current branch tip: a completed mission starts a review round, and while the mission is active a later route may still record a verdict for that same reviewed tip, appending to the same round without changing the status (a moved tip is rejected with an explanation). status is "clean", "p1-Nitems", or "p2-Nitems"; merge is "merge", "fix-then-merge", or "hold" (only clean + merge is later approval). Non-clean returns the mission to active. Reviewers are capped at 5 rounds per branch; a tower-submitted review is break-glass and requires breakGlassReason. The tool is not registered when review.mode is off. |
|
|
31
31
|
| `tower_roster` | List tower roster agents with authoritative live activity from the subagent catalog (running/inactive/missing/unknown). Read-only; never resumes children. Use before completion or merge decisions. |
|
|
32
32
|
| `tower_send` | Send a durable inbox message to a tower participant: a roster agent name, "tower", or "all" (broadcast). The message is persisted first; when the recipient is a currently running roster agent the tower also steers it into that child's current turn. Returns delivery results. |
|
|
33
|
-
| `tower_spawn` | Spawn a worker or reviewer for a mission. Workers use the tower-worker
|
|
34
|
-
| `tower_status` | Read the Tower dashboard for a repository: state path, base branch, revision, mission status counts, paged mission summaries (scope/deps/tasks/worktree/owner), roster size, findings, archive count, config path and the activity tail. Also reports the repo-scoped git lock holder (`gitLock: {held,pid,phase,heldMs}`) so a merge holding the mutex is visible. Pass missionId for one full mission (tasks, notes, reviews, findings, completion report; archived missions are loaded from their year file); offset/limit page the mission list (default 20, max 100); includeGate adds preflight gate digests for the page; includeArchived appends compact archived summaries after the active page; format:"markdown" returns the human-readable mission board (active missions plus an archived count). Read-only. |
|
|
33
|
+
| `tower_spawn` | Spawn a worker or reviewer for a mission. Workers use the mission shape's preset (tower-worker for a build, tower-survey for a read-only shared survey, tower-survey-sandbox for a detached survey with survey.sandbox=detached); reviewers require a completed build mission and use the read-only tower-reviewer preset, and the reviewer role is refused when review.mode is off. A build provisions (or reuses) the mission git worktree and branch; a shared survey runs in the shared checkout because it reads one commit; a detached survey provisions (or reuses) a disposable detached worktree at its readCommit with no branch. Generates a self-contained briefing (including dependency survey result evidence) and starts a background subagent. The child final report is delivered back to this session; tower_roster shows authoritative activity. Records the agent in the roster; reviewer spawns get a disposable detached checkout at the recorded branch tip, and the verdict is stamped with that commit (never a live worktree HEAD). Returns immediately unless wait=true. |
|
|
34
|
+
| `tower_status` | Read the Tower dashboard for a repository: state path, base branch, revision, mission status counts, paged mission summaries (scope/deps/tasks/worktree/owner), roster size, findings, archive count, config path and the activity tail. Also reports the repo-scoped git lock holder (`gitLock: {held,pid,phase,heldMs}`) so a merge holding the mutex is visible, and the resolved review policy (`review: {mode, available, required, detail}`; mode off means review is intentionally unavailable). Pass missionId for one full mission (tasks, notes, reviews, findings, completion report; archived missions are loaded from their year file); offset/limit page the mission list (default 20, max 100); includeGate adds preflight gate digests for the page; includeArchived appends compact archived summaries after the active page; format:"markdown" returns the human-readable mission board (active missions plus an archived count). Read-only. |
|
|
35
35
|
| `tower_teardown` | Tear down eligible mission worktrees after their missions are merged or abandoned. A worktree whose roster agent is running is always kept (force cannot override); dirty worktrees need force; exclude keeps named missions. dry_run previews the remove/keep decisions without changing anything. Terminal missions whose worktree is gone and whose configured archive policy is due (archive.afterDays / archive.maxMissions) are moved to <git-common-dir>/dsh-tower/archive/ so state.json stops rewriting them; nothing is deleted. |
|
|
36
36
|
| `tower_test` | Run the mission worktree's declared tower.testDiscovery (package.json) and record the receipt. Returns ok:false with diagnostics when discovery fails; does not change mission status. Use tower_complete for automatic admission checks. |
|
package/docs/reference/tools.md
CHANGED
|
@@ -36,9 +36,9 @@ findings but not mutate them. Violations throw `[tower:not-authorized]` or
|
|
|
36
36
|
|---|---|---|
|
|
37
37
|
| `tower_init` | `base?`, `autoGitInit?`, `snapshotDirty?`, `reanchor?` | Create `<git-common-dir>/dsh-tower/state.json`. `autoGitInit` runs `git init` + empty initial commit; `snapshotDirty` records a dangling snapshot commit of uncommitted tracked changes used as the mission baseline; `reanchor` changes base only when no non-terminal mission exists. Returns `dirty`, `snapshotCommit`, `reanchored`. |
|
|
38
38
|
| `tower_plan` | `missions[]` (`title` — printable Unicode, NFC-normalized, ≤120 characters, `scope[]`, `tasks[]?`, `deps[]?`, `kind?`, `context?`, `references[]?` ≤20, `reviewPolicy?`, `reviewExemptionReason?`) | Create missions `M1..`; overlapping build scopes auto-add a dependency; rejects unknown deps and cycles. Mission ids stay ASCII (`M1`, `M2`); invisible characters and over-long titles are rejected with `invalid-argument`. `reviewPolicy:"none"` requires a non-empty reason; when the review gate is on, preflight also requires `gates.allowReviewExemption`. |
|
|
39
|
-
| `tower_mission` | `id` (alias `missionId`), `status?`, `task_done?`, `task_drop?`+`task_drop_reason?`, `blocker?`, `clear_blockers?`, `note?`, `scope?`, `pause_cause?`, `authorization?` | Update one mission. Worker-safe fields are task/blocker/note; `merged` cannot be set here. Paused missions record `pause_cause` (user/failure/resource/dependency); resuming a user-paused mission honors `mode.requireResumeAuthorization`. |
|
|
39
|
+
| `tower_mission` | `id` (alias `missionId`), `status?`, `task_done?`, `task_drop?`+`task_drop_reason?`, `blocker?`, `clear_blockers?`, `note?`, `scope?`, `pause_cause?`, `authorization?` | Update one mission. Worker-safe fields are task/blocker/note; `merged` cannot be set here. `blocked` is derived from an open blocker (record `blocker`, never `status:"blocked"`); `clear_blockers` resumes it to `active`. Paused missions record `pause_cause` (user/failure/resource/dependency); resuming a user-paused mission honors `mode.requireResumeAuthorization`. |
|
|
40
40
|
\|\ `tower_status`\ \|\ `missionId\?`,\ `offset\?`,\ `limit\?`,\ `includeGate\?`,\ `includeArchived\?`,\ `format\?`\ \|\ Dashboard\ by\ default\.\ Paged\ missions\ carry\ `reportBytes`\ only;\ `missionId`\ returns\ full\ detail\ \(tasks/notes/reviews/findings/completionReport\ body\),\ and\ an\ archived\ mission\ is\ loaded\ from\ its\ year\ file\.\ `offset`/`limit`\ page\ active\ missions\ \(default\ 20,\ max\ 100\),\ `includeGate`\ adds\ gate\ digests,\ `includeArchived`\ appends\ compact\ archived\ summaries\ \(flagged\ `archived:true`,\ no\ report\ body\)\ after\ the\ active\ page,\ and\ `format:"markdown"`\ returns\ the\ board\ \(active\ rows\ plus\ an\ archived\ count\)\.\ Includes\ `mode`\ with\ `lastChange`\ and\ recent\ `history`\ when\ the\ host\ mode\ hook\ is\ available\.\ `archive`\ reports\ `\{count,\ years,\ unreadable,\ message}`;\ a\ corrupt\ archive\ degrades\ to\ `unreadable:true`\ instead\ of\ failing\ the\ dashboard\.\ Also\ returns\ `gitLock`\ \(`\{held,\ pid,\ phase,\ heldMs}`\)\ for\ the\ repo-scoped\ git\ mutex,\ and\ `\{held:\ false}`\ when\ it\ is\ free\.\ \|
|
|
41
|
-
| `tower_spawn` | `missionId` (alias `id`), `role` (`worker`/`reviewer`), `name?`, `instructions?`, `worktreeRoot?`, `wait?`, `waitMs?`, `takeover?`, `includeDirtyBase?` | Provision/reuse the worktree and start a subagent. Worker uses `tower-worker`; reviewer requires a `completed` mission and uses the read-only `tower-reviewer`. `takeover:true` replaces a live worker entry that is no longer running (increments ownerGeneration). Only one live worker per mission; `spawn.maxLiveWorkers` caps the repository. |
|
|
41
|
+
| `tower_spawn` | `missionId` (alias `id`), `role` (`worker`/`reviewer`), `name?`, `instructions?`, `worktreeRoot?`, `wait?`, `waitMs?`, `takeover?`, `includeDirtyBase?` | Provision/reuse the worktree and start a subagent. Worker uses `tower-worker`; reviewer requires a `completed` mission and uses the read-only `tower-reviewer`; with `review.mode:off` the reviewer role is refused with `[tower:review-disabled]`. `takeover:true` replaces a live worker entry that is no longer running (increments ownerGeneration). Only one live worker per mission; `spawn.maxLiveWorkers` caps the repository. |
|
|
42
42
|
| `tower_roster` | — | Roster with live activity (`running`/`inactive`/`missing`/`unknown`) and `stale` flags from the subagent catalog. Read-only. |
|
|
43
43
|
| `tower_adopt` | `retireMissing?` | Reconcile roster entries with the durable subagent catalog. Provably gone agents are retired (default) or marked `missing` (`retireMissing:false`) so they can be inspected/taken over. |
|
|
44
44
|
| `tower_diff` | `missionId` (alias `id`), `maxBytes?` | Read-only merge-base diff: files, commits, capped patch. Safe for reviewers. |
|
|
@@ -48,8 +48,8 @@ findings but not mutate them. Violations throw `[tower:not-authorized]` or
|
|
|
48
48
|
| `tower_interrupt` | `to?` (roster name), `agentId?`, `reason?` | Interrupt one running roster agent via `subagents.interrupt`, record `state:"interrupted"`. Idempotent (not running → `interrupted:false`). |
|
|
49
49
|
| `tower_finding` | `type`, `title`, `summary`, `details`, `suggested_fix`, `severity?`, `missionId?`, `location?` | Record an out-of-scope issue; reviewers use this instead of editing. Finds start as `open`. |
|
|
50
50
|
| `tower_findings` | `id?`, `status?`, `note?`, filters (`type?`, `severity?`, `missionId?`, `open?`, `limit?`) | Lifecycle tool: list/read/transition. Statuses `open → triaged → fixed`/`wontfix`, reopen allowed. Only the tower or a worker may mutate; a reviewer can list/read. |
|
|
51
|
-
| `tower_review` | `missionId` (alias `id`), `status` (`clean`/`p1-Nitems`/`p2-Nitems`), `merge` (`merge`/`fix-then-merge`/`hold`), `findings`, `decision`, `checks?`, `breakGlassReason?` | Reviewer verdict bound to the current tip. Reviewer must be the assigned reviewer (or tower break-glass). A later route may record a verdict for the same reviewed tip while the mission is active: it appends to that round (`appended:true`) without changing the status; a verdict for a moved tip is rejected with an explanation. |
|
|
52
|
-
| `tower_preflight` | `missionId` (alias `id`) | Read-only gate: returns `{ok, blockers[], branchTip, baseTip, changedFiles, review}`. |
|
|
51
|
+
| `tower_review` | `missionId` (alias `id`), `status` (`clean`/`p1-Nitems`/`p2-Nitems`), `merge` (`merge`/`fix-then-merge`/`hold`), `findings`, `decision`, `checks?`, `breakGlassReason?` | Reviewer verdict bound to the current tip. Reviewer must be the assigned reviewer (or tower break-glass). Not registered when `review.mode:off`; a repository-level `off` refuses the submission with `[tower:review-disabled]`. A later route may record a verdict for the same reviewed tip while the mission is active: it appends to that round (`appended:true`) without changing the status; a verdict for a moved tip is rejected with an explanation. |
|
|
52
|
+
| `tower_preflight` | `missionId` (alias `id`) | Read-only gate: returns `{ok, blockers[], branchTip, baseTip, changedFiles, review}`. Review blockers appear only with `review.mode:required`; `off`/`optional` skip them. |
|
|
53
53
|
| `tower_merge` | `missionId` (alias `id`), `timeoutMs?` (alias `timeout_ms`) | Merge after a green gate. Records already-landed merges (`reconciled`), recovers a failed call whose commit exists (`recoveredFromFailure`), and separates `merge-hook-failed` from `merge-conflict`. |
|
|
54
54
|
| `tower_rebase` | `missionId` (alias `id`) | Rebase the branch onto the base in its worktree. Refuses while the worker runs or the worktree is dirty. Already-contained branches return `alreadyMerged` untouched. |
|
|
55
55
|
| `tower_teardown` | `force?`, `exclude?`, `dry_run?` (alias `dryRun`) | Remove eligible merged/abandoned worktrees and branches; running agents are always kept. The final pass applies the `archive` policy while the `tower-archive` component row is mounted: terminal missions whose worktree is gone are moved to `<git-common-dir>/dsh-tower/archive/` once `archive.afterDays`/`archive.maxMissions` says so, and `archived` lists their ids. Nothing is deleted; `archive.afterDays:0` archives a just-torn-down mission immediately. |
|
|
@@ -60,7 +60,7 @@ findings but not mutate them. Violations throw `[tower:not-authorized]` or
|
|
|
60
60
|
| `tower_recover` | `action` (`status`/`clear-stale-lock`), `confirm?`, `force?` | Recovery diagnostics plus an explicit stale state-lock repair. `clear-stale-lock` requires `confirm:"CLEAR_STALE_LOCK"` and only moves a lock whose PID is provably dead to a `.recovered-<ts>` backup. `force:true` additionally clears a live-but-silent PID (a recycled PID): the output names `{pid, startedAt, ageMs, heartbeatAgeMs}` and the record is still renamed, never unlinked. It never resets state/worktrees. |
|
|
61
61
|
| `tower_test` | `missionId` (alias `id`) | Run the worktree's `package.json` `tower.testDiscovery` and record a receipt; `ok:false` on failure. Use `tower_complete` for automatic admission checks. |
|
|
62
62
|
| `tower_batch` | `action` (`create`/`status`/`close`/`abandon`), `missionIds?`, `exclusions?`, `requiredChecks?`, `receiptPaths?`, `batchId?`, `checks?`, `treeTip?`, `receiptHashes?`, `reason?` | Finite evidence batch. Create freezes members/checks/receipts; close verifies every required check and receipt hash; merged members are eligible; abandon retires a stale open batch without deleting missions. Membership is immutable. |
|
|
63
|
-
| `tower_resource` | `action` (`acquire`/`release`/`status`), `name?`, `holder?`, `token?`, `ttlMs?`, `force?` | Advisory per-repository lease in `<common>/dsh-tower/leases.json`. No OS CPU/memory hard cap; expired
|
|
63
|
+
| `tower_resource` | `action` (`acquire`/`release`/`status`), `name?`, `holder?`, `token?`, `ttlMs?`, `force?` | Advisory per-repository lease in `<common>/dsh-tower/leases.json`. No OS CPU/memory hard cap. A live lease is released only by its holder token; an **expired** lease is recovered by an explicit `force: true` release (never taken over automatically). |
|
|
64
64
|
| `tower_import_legacy` | `sourcePath` | Read-only import of a Tower Codex `schemaVersion:1` or DSH legacy state. Full payload goes under `<common>/dsh-tower/legacy/<sha256>.json`; state stores a summary only. Never activates/adopts/resumes paused missions. |
|
|
65
65
|
| `tower_legacy_map` | `action` (`map`/`status`), `sourceHash?`, `oldId?`, `newMissionId?` | Audit-only legacy-id mapping; mappings are append-only and never adopt a mission. |
|
|
66
66
|
|
package/docs/zh/faq.md
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
分析与决策,再启动 Tower 执行(可选审查)仓库变更。详见[完整指南](guide/scenarios-and-philosophy.md#4-tower-与其他-dsh-工作流模式的区别)。
|
|
13
13
|
|
|
14
14
|
**为什么 worker 刚完成,`tower_preflight` 就因 `no-review` 失败?**
|
|
15
|
-
|
|
16
|
-
reviewer;干净审查后门禁就会变绿。默认 `review.
|
|
15
|
+
只有在审查策略为 `required`(`review.mode:required`)时才会如此:已完成的 mission 在等待独立审查。
|
|
16
|
+
spawn 一个 reviewer;干净审查后门禁就会变绿。默认 `review.mode:optional` 时审查可选,不会产生
|
|
17
17
|
`no-review` blocker。
|
|
18
18
|
|
|
19
19
|
**需要轮询 worker 吗?**
|
|
@@ -35,9 +35,11 @@ reviewer;干净审查后门禁就会变绿。默认 `review.requireReview:fals
|
|
|
35
35
|
正确:分支已经包含在基线中。此时调用 `tower_merge` 记录已落地的合并,而不是 rebase。
|
|
36
36
|
|
|
37
37
|
**可以要求强制独立审查吗?**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
做更窄的豁免。`
|
|
38
|
+
可以。把审查策略设为 `required` —— 插件页上的一个三态控件,或在 profile/仓库配置中写
|
|
39
|
+
`review.mode:required`(默认 `optional`)。策略为 `required` 时,可用 mission 级
|
|
40
|
+
`reviewPolicy:"none"` + 理由 + `gates.allowReviewExemption:true` 做更窄的豁免。`optional` 模式下
|
|
41
|
+
`tower_review` 同样可用并记录结论。旧布尔开关是已弃用、保留一个版本的别名;映射关系见
|
|
42
|
+
[安装、升级与迁移](guide/install-upgrade-migration.md)。
|
|
41
43
|
|
|
42
44
|
**reviewer 能修改文件吗?**
|
|
43
45
|
不能。reviewer 使用只读的 `tower-reviewer` preset(没有 write/edit/pwsh);reviewer spawn 之后分支
|
|
@@ -31,6 +31,23 @@ Host 插件在 DSH 启动时加载:**安装或更新后需要重启 DSH**。
|
|
|
31
31
|
|
|
32
32
|
## 迁移说明
|
|
33
33
|
|
|
34
|
+
- **2.5.0 → 2.6.0(#M39/#M40)—— 审查模式取代布尔开关**:审查策略是插件页 `dsh-tower` 配置区里的
|
|
35
|
+
一个三态控件,配置键为 `review.mode`:`off`、`optional`(默认)或 `required`。
|
|
36
|
+
- `off` 是受支持且有文档的模式:不注册 `tower_review`,拒绝 reviewer spawn,合并门禁忽略审查。
|
|
37
|
+
- `optional` 保留 `tower_review`,但从不阻塞合并。
|
|
38
|
+
- `required` 保留合并门禁:已完成 mission 必须有绑定分支 tip 的 clean 审查(原有的单 mission
|
|
39
|
+
豁免仍适用)。
|
|
40
|
+
`review.requireReview` 是已弃用、保留一个版本的别名:`true` 解析为 `required`,`false` 解析为
|
|
41
|
+
`optional`,不设置则为 `optional`。`true` 与非 `required` 的显式 mode 同时出现会以 `config-invalid`
|
|
42
|
+
拒绝;`false` 不会覆盖显式 mode。从插件页保存时总是写入 `review.mode`,并把别名归一化为 `false`。
|
|
43
|
+
该策略不是组件行,也不存在互斥的审查行:`preset-tower-reviewer` 仍是策略可以不使用的可选能力。
|
|
44
|
+
`review.mode` 为 `off` 或 `optional` 时该行可以关闭;当 `review.mode` 为 `required` 且该 reviewer
|
|
45
|
+
行关闭时,规划与模式进入会以带解释的 `preset-missing` 错误拒绝该组合。
|
|
46
|
+
以 `off` 启动的 profile 从未注册 `tower_review`;切换到 `optional` 或 `required` 会立即改变合并门禁,
|
|
47
|
+
但工具本身要等 DSH 重启(或 profile 重载)后才出现,插件页在保存后会说明这一点。
|
|
48
|
+
升级方式:把 `review.requireReview: true|false` 替换为 `review.mode: required|optional`;仅当同一份
|
|
49
|
+
配置还要供旧 2.5 安装使用时保留别名,并在本版本后移除。不需要迁移 state。
|
|
50
|
+
|
|
34
51
|
- **state schema v1 → v2(未发布)**:`state.json` 会自动迁移。升级后的第一次**写入**会保留
|
|
35
52
|
`state.json.v1.bak` 备份、`revision` 只 +1,并向 `activity.jsonl` 追加 `state.migrated {from,to}`;
|
|
36
53
|
只读工具仍可读取 v1 文件且不改写它。`tower_doctor` 报告磁盘上的版本与待执行的迁移。由更新插件
|
|
@@ -45,13 +62,13 @@ Host 插件在 DSH 启动时加载:**安装或更新后需要重启 DSH**。
|
|
|
45
62
|
- **2.3.0 → 2.4.0(未发布)**:所有能力合一的 `tower-bundle` 组行已移除。`cordis.patch.yml`
|
|
46
63
|
现在随包提供强制的 `tower` host 锚点(Host 插件与 worker preset 是它的内部 section),以及可单独
|
|
47
64
|
开关的顶层行:`tower-skills`、`tower-batch`、`tower-import`、`tower-leases`、`tower-tests`、
|
|
48
|
-
`tower-hmr`(随包关闭)与 `preset-tower-reviewer
|
|
65
|
+
`tower-hmr`(随包关闭)与 `preset-tower-reviewer`(受审查策略 `review.mode` 条件约束)。
|
|
49
66
|
`tools` 配置组与 `dev.hotReload` 已删除:仍带这些键的 profile 现在会作为未知键被拒绝
|
|
50
67
|
(`config-unknown-key`),在删除它们之前 host 不会挂载,因此不再存在静默无效的开关。请改为在插件页
|
|
51
68
|
使用对应的组件行;`tower-hmr` 随包关闭,因此在为联动开发 profile 开启它之前,`tower_reload` 与
|
|
52
69
|
`/tower reload` 会报告为 “disabled by component tower-hmr”。`tower_doctor` 与 `tower_recover`
|
|
53
|
-
|
|
54
|
-
|
|
70
|
+
在任何配置下都会注册,无需配置键。策略为 `off` 或 `optional` 时 reviewer 行可以关闭;策略为
|
|
71
|
+
`review.mode:required` 时,规划与模式进入会以带解释的错误拒绝该组合。不需要迁移 state。
|
|
55
72
|
- **2.0.4 → 2.1.0-beta.1**:不需要迁移 config;state 会按上述说明自动迁移(v1/v2 → v3)。
|
|
56
73
|
这是发布到 `next` dist-tag 的**预发布**,
|
|
57
74
|
`latest` 仍指向 2.0.4——请用 `dsh plugin --profile web add dsh-tower@next`(或精确版本号)安装。
|
|
@@ -60,9 +77,11 @@ Host 插件在 DSH 启动时加载:**安装或更新后需要重启 DSH**。
|
|
|
60
77
|
`npm publish --tag next` 之后,`next` 才会解析到 2.1.0-beta.1;`latest` 在稳定版发布前保持 2.0.4。
|
|
61
78
|
- **2.0.3 → 2.0.4**:不需要迁移 state/config。本版本是安全加固与完整性修复(授权、merge SHA 绑定、
|
|
62
79
|
dirty worktree 完成拒绝、stale lock 恢复、限制 test/git 进程环境、`tower_recover`、UI 0.2.2)。
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
80
|
+
升级后请按威胁模型重新检查审查策略(`review.mode`,或已弃用的 `review.requireReview` 别名)、
|
|
81
|
+
`tests.admission` 与 worker 工具权限。
|
|
82
|
+
- **2.0.1 → 2.0.3**:不需要迁移状态。2.0.3 起独立审查**默认可选**(即今天的
|
|
83
|
+
`review.mode:optional`);若要保留旧的审查门禁行为,请显式设为 `review.mode:required`。
|
|
84
|
+
2.0.1 为 `tower_batch` 增加 `abandon`、允许 merged
|
|
66
85
|
成员 close、让 doctor 跳过已 teardown 的 worktree,并修复终态 mission spawn/preflight 边界。
|
|
67
86
|
可选 `ui-bundle` 0.2.1 增加常驻 Tower 模式 chip 与模式感知的 disabled 工具行。
|
|
68
87
|
- **1.x → 2.0(已发布)**:不需要迁移状态(`schemaVersion` 保持 1;新字段都是可选的)。需要留意的
|
|
@@ -34,15 +34,22 @@ tower_spawn repoRoot=D:\work\repo missionId=M1 role=worker
|
|
|
34
34
|
|
|
35
35
|
## 4. 可选:审查
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
`review.
|
|
37
|
+
审查策略是插件页 `dsh-tower` 配置区里的一个三态控件:`off`、`optional`(默认)或 `required`;
|
|
38
|
+
也可以在 profile 或仓库配置中写 `review.mode`。它是一个控件,不是组件行,也不是三个行。需要严格
|
|
39
|
+
流程时设为 `required`,然后:
|
|
39
40
|
|
|
40
41
|
```
|
|
41
42
|
tower_spawn repoRoot=D:\work\repo missionId=M1 role=reviewer
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
reviewer 使用只读的 `tower-reviewer` preset,查看 `tower_diff` 并提交 `tower_review
|
|
45
|
-
`review.
|
|
45
|
+
reviewer 使用只读的 `tower-reviewer` preset,查看 `tower_diff` 并提交 `tower_review`。设为
|
|
46
|
+
`review.mode:required` 后,只有 `clean` + `merge` 的结论才允许合并。`optional` 会记录审查但从不
|
|
47
|
+
阻塞合并;`off` 是受支持的模式,不会注册 `tower_review`。
|
|
48
|
+
|
|
49
|
+
旧布尔审查开关是保留一个版本的别名(`true` → `required`,`false` → `optional`;不设置 →
|
|
50
|
+
`optional`)。请优先使用 `review.mode`。以 `off` 启动的 profile 需要
|
|
51
|
+
重启或重载后才会注册 `tower_review`,但合并门禁会立即改变。完整迁移说明见
|
|
52
|
+
[安装、升级与迁移](install-upgrade-migration.md)。
|
|
46
53
|
|
|
47
54
|
## 5. 门禁、合并与清理
|
|
48
55
|
|
|
@@ -52,8 +59,8 @@ tower_merge repoRoot=D:\work\repo missionId=M1
|
|
|
52
59
|
tower_teardown repoRoot=D:\work\repo
|
|
53
60
|
```
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
策略为 `review.mode:required` 时,审查前运行 `tower_preflight` 会报告 `no-review`;干净审查之后应为
|
|
63
|
+
`ok:true`。默认 `optional` 时没有审查 blocker。存在其他 blocker 时 `tower_merge` 拒绝合并。
|
|
57
64
|
`tower_teardown` 移除已 merged/abandoned 的 worktree 与分支。
|
|
58
65
|
|
|
59
66
|
```
|
|
@@ -63,9 +70,9 @@ tower_teardown repoRoot=D:\work\repo
|
|
|
63
70
|
## 如果失败
|
|
64
71
|
|
|
65
72
|
阅读 blocker code 并查阅 [blocker 参考](../reference/blockers.md)。最常见的情况:`stale-base`
|
|
66
|
-
(执行 `tower_rebase`)、`no-review`(仅在 `review.
|
|
67
|
-
`merge-hook-failed`(重试,或调大 `timeoutMs`)、`tip-moved
|
|
68
|
-
|
|
73
|
+
(执行 `tower_rebase`)、`no-review`(仅在 `review.mode:required` 时;spawn reviewer)、
|
|
74
|
+
`merge-hook-failed`(重试,或调大 `timeoutMs`)、`tip-moved`(仅在策略为 `required` 时;审查后
|
|
75
|
+
分支已变化,需要重新审查)。
|
|
69
76
|
|
|
70
77
|
工具抛出的错误带 `[tower:<code>]` 前缀;见[错误码](../reference/errors.md)(例如
|
|
71
78
|
`preset-missing` 表示安装 bundle 后需要重启 DSH,`not-initialized` 表示先运行 `tower_init`)。
|
|
@@ -77,7 +84,7 @@ tower_teardown repoRoot=D:\work\repo
|
|
|
77
84
|
|
|
78
85
|
```json
|
|
79
86
|
{
|
|
80
|
-
"review": { "
|
|
87
|
+
"review": { "mode": "required", "maxRoundsPerReviewer": 3 },
|
|
81
88
|
"merge": { "timeoutMs": 1800000 },
|
|
82
89
|
"worktrees": { "root": "D:/tower-worktrees" }
|
|
83
90
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Tower 不是所有多代理模式的替代品。它是**面向 Git 仓库变更的交付协议**:少量边界清晰的 mission、隔离的写入者、可选独立审查、证据与合并门禁。本页解释这些设计取舍、适用场景,以及什么时候 Agent Teams、Ralph 循环、Workflow 编排或普通并行子代理更合适。
|
|
6
6
|
|
|
7
|
-
如果只记一句话:**输出是需要经过受控合并落地的仓库变更时用 Tower
|
|
7
|
+
如果只记一句话:**输出是需要经过受控合并落地的仓库变更时用 Tower;输出是探索、重复尝试或程序化扇出时用其他模式。**如果还需要独立审查,把审查策略设为 `required`;默认为 `optional`。
|
|
8
8
|
|
|
9
9
|
## 1. 设计哲学
|
|
10
10
|
|
|
@@ -26,7 +26,7 @@ mission 不是聊天线程或任务卡,而是绑定到分支与 worktree 的
|
|
|
26
26
|
|
|
27
27
|
worker 永远不合并。控制塔运行 preflight;只有之后 `tower_merge` 才执行 `--no-ff` 合并。门禁重新检查 scope、base 新鲜度、任务、worktree 归属、worker 状态、测试与证据。开启审查时,reviewer 还会审查特定分支 tip,门禁检查审查绑定;职责分离(写代码者不批准、批准者不合并)在审查开启时生效。
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
审查策略是一个三态控件:`off`、`optional`(默认)或 `required`。设为 `required` 才会强制独立审查(此时已完成 mission 必须带有绑定 tip 的 clean/merge 审查)。对敏感仓库建议设为 `required`;策略为 `required` 时仍可用 `reviewPolicy:"none"` + 理由 + `gates.allowReviewExemption:true` 做单个 mission 豁免。`optional` 会记录审查但从不阻塞合并;`off` 是受支持的模式,会移除审查工具。该策略是配置,不是组件行:插件页上只有一个控件,不是三个互斥行。
|
|
30
30
|
|
|
31
31
|
### 1.5 证据优先于断言
|
|
32
32
|
|
|
@@ -127,7 +127,7 @@ Tower 是 Host 插件,只使用本地 Git、本地文件和 DSH subagent 服
|
|
|
127
127
|
| 隔离 | 每 mission 独立 worktree/分支;单写入者 | 共享工作区;靠任务归属协调 | 每轮新 child;无内置分支/合并契约 | 每步 child;无 Git 隔离 | 子会话;可能共享工作区 |
|
|
128
128
|
| 持久状态 | Git 元数据 + JSON state + 活动日志 + 看板 | Team 任务板 + 会话 | 很少;每轮从零开始 | 运行记录/结果;不是合并账本 | 会话/子代理记录 |
|
|
129
129
|
| 集成权限 | 仅控制塔,经 preflight/merge 门禁(可选再加审查) | 人类/teammate 手动合并或编辑 | 通常由父 agent/worker 应用结果 | 脚本应用结果 | 父 agent 应用结果 |
|
|
130
|
-
| 审查/门禁 |
|
|
130
|
+
| 审查/门禁 | 可选独立审查(一个 `review.mode` 控件:off/optional/required)+ preflight/merge 门禁 | 审查是协作约定,不是硬门禁 | 无内置审查门禁 | 无内置审查门禁 | 无内置审查门禁 |
|
|
131
131
|
| 并行度 | 多 mission、互斥 scope、合并串行 | 多 teammate、共享任务板 | 顺序轮次(或外部扇出) | 高扇出,由脚本控制 | 高扇出 |
|
|
132
132
|
| 人的角色 | 拥有模式;可检查证据与发布 | 协作者/协调者 | 重复目标的作者 | 编排脚本作者 | 委派者 |
|
|
133
133
|
| 最适合 | 特性交付、迁移、发布绑定变更 | 设计、研究、横切协作 | 迭代搜索/修复,需要新鲜上下文 | 大规模审计、批量分析、确定性流水线 | 快速探索或独立子任务 |
|
|
@@ -137,7 +137,7 @@ Tower 是 Host 插件,只使用本地 Git、本地文件和 DSH subagent 服
|
|
|
137
137
|
|
|
138
138
|
普通 `subagent`/`subagent_fork` 便宜灵活,适合"并行读五个文件"或"试三种方案"。它们不提供写范围、专用 worktree、持久 mission、独立审查或合并门禁。Tower 用这些契约包装同一个子代理原语,因此每个 child 更贵。
|
|
139
139
|
|
|
140
|
-
只读、短生命周期、或你准备自己集成结果时,用普通子代理;结果必须落到分支并经受控合并时,用 Tower
|
|
140
|
+
只读、短生命周期、或你准备自己集成结果时,用普通子代理;结果必须落到分支并经受控合并时,用 Tower;需要 reviewer 角色把关合并时,再把审查策略设为 `required`。
|
|
141
141
|
|
|
142
142
|
### 4.2 Tower vs Agent Teams
|
|
143
143
|
|
|
@@ -161,13 +161,16 @@ Tower 是**仓库交付协议**,mission 数量少,不是高扇出数据平
|
|
|
161
161
|
|
|
162
162
|
Plan mode 决定做什么;Tower 把已决定的计划执行到仓库。进入 Tower 会清除活跃 plan(`mode.planModePolicy:"refuse"` 时拒绝进入),且 Tower 会话不能使用 goal/todo/team/workflow 工具。先规划,再执行;不要指望 Tower 替你发现计划。
|
|
163
163
|
|
|
164
|
-
### 4.6
|
|
164
|
+
### 4.6 审查策略是一个三态控件
|
|
165
165
|
|
|
166
|
-
`
|
|
167
|
-
|
|
168
|
-
`
|
|
169
|
-
`
|
|
170
|
-
`
|
|
166
|
+
审查策略是一个控件:`off`、`optional`(默认)或 `required`,位于插件页 `dsh-tower` 配置区,
|
|
167
|
+
配置中对应 `review.mode`。它不是组件行,也不是三个互斥行。`optional` 让低风险仓库、临时工作或
|
|
168
|
+
人类逐轮监督的会话可以在没有 reviewer 时合并已完成 mission。`required` 才启用强制独立审查门禁;
|
|
169
|
+
此时检查 `no-review`、`not-clean`、`review-hold`、`review-not-approved`、`tip-moved`、
|
|
170
|
+
`review-mission-mismatch`。`off` 是受支持的模式,不会注册 `tower_review`;`optional` 记录结论但
|
|
171
|
+
从不阻塞合并。只豁免单个 mission 时,在策略为 `required` 的前提下用 `reviewPolicy:"none"` + 理由
|
|
172
|
+
+ `gates.allowReviewExemption:true`。已弃用、保留一个版本的布尔别名把 `true` 映射为 `required`,
|
|
173
|
+
`false` 映射为 `optional`;见[安装、升级与迁移](install-upgrade-migration.md)。
|
|
171
174
|
|
|
172
175
|
### 4.7 各工作流的具体例子
|
|
173
176
|
|
|
@@ -223,7 +226,7 @@ reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查
|
|
|
223
226
|
1. 规划四个 build mission,scope 分别 `src/tokens/**`、`src/email/**`、`src/api/invites/**`、`src/ui/invites/**`;让 API 依赖 token 与 email。
|
|
224
227
|
2. 对独立 mission 启动 worker;API 等依赖完成。
|
|
225
228
|
3. 每个 worker 在自己分支提交,带 checks 完成。
|
|
226
|
-
4.
|
|
229
|
+
4. 若策略为 `review.mode:required`,启动 reviewer 并要求 clean + merge;否则审查可选或关闭。
|
|
227
230
|
5. 逐 mission `tower_preflight` + `tower_merge`,处理 scope/base/review blocker。
|
|
228
231
|
6. `tower_teardown`;`MISSIONS.md` 是人类可读记录。
|
|
229
232
|
|
|
@@ -248,14 +251,17 @@ reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查
|
|
|
248
251
|
|
|
249
252
|
### 场景 E:敏感发布
|
|
250
253
|
|
|
251
|
-
有外部用户的库发布。为变更、迁移指南、release notes 规划 mission
|
|
254
|
+
有外部用户的库发布。为变更、迁移指南、release notes 规划 mission;如发布需要独立审查,把策略设为
|
|
255
|
+
`review.mode:required`;要求测试,并用 `tower_batch` 只有在所有必需检查齐全时才收口发布证据;
|
|
256
|
+
按你的发布流程在 Tower 之外合并/打 tag。
|
|
252
257
|
|
|
253
258
|
## 6. 实践中的选择路径
|
|
254
259
|
|
|
255
260
|
1. **输出是 Git 变更吗?** 否 → 普通 agent、Agent Teams、Workflow 或 Ralph。
|
|
256
261
|
2. **你会为它开 PR 吗?** 否 → Tower 太重,用普通 agent。
|
|
257
262
|
3. **切片有稳定 scope 和已知完成定义吗?** 否 → 先规划/探索,再回到 Tower。
|
|
258
|
-
4. **需要合并门禁吗?** 有集成风险的仓库变更 → Tower
|
|
263
|
+
4. **需要合并门禁吗?** 有集成风险的仓库变更 → Tower;如果还需要独立审查,把审查策略设为
|
|
264
|
+
`required`。两者都不需要时,普通子代理可能足够。
|
|
259
265
|
5. **需要大量并行分析或重复新鲜尝试吗?** 那个阶段用 Workflow/Ralph;把结果编码成 Tower mission。
|
|
260
266
|
6. **需要横切的人类协作吗?** 用 Agent Teams 决定;用 Tower 执行决定的仓库工作。
|
|
261
267
|
|
|
@@ -263,7 +269,9 @@ reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查
|
|
|
263
269
|
|
|
264
270
|
- **每个 mission 有真实开销**:worktree、spawn、完成检查、可选审查轮次、门禁、合并。mission 应有意义(大致 PR 大小),不要一个函数一个 mission。
|
|
265
271
|
- **合并会串行**:重叠 scope 自动加依赖;独立 mission 仍然逐个合入 base。合并密集的工作不要期待线性加速。
|
|
266
|
-
-
|
|
272
|
+
- **审查不是免费的(策略为 required 时)**:每个 mission 需要 reviewer 与 clean 结论;
|
|
273
|
+
`review.mode:optional`(默认)让审查不阻塞,`off` 则移除审查工具;策略为 `required` 时,豁免是
|
|
274
|
+
显式且需要理由。
|
|
267
275
|
- **过细的 mission** 增加协调与合并成本;**过粗的 mission** 失去并行审查收益,scope 冲突概率高。
|
|
268
276
|
- **Tower 不是沙箱**:它是协调协议;Host 权限、仓库 hooks、测试命令仍以 DSH 用户的 OS 权限执行。
|
|
269
277
|
- **不要同时跑两套编排协议**:Tower 模式会拒绝 Team/Workflow/Ralph/subagent 工具并清除 plan mode;请顺序分阶段。
|
|
@@ -274,7 +282,7 @@ reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查
|
|
|
274
282
|
- [ ] 工作会产生值得 PR 式审查的仓库变更。
|
|
275
283
|
- [ ] 我能列出 2–8 个 scope 不重叠、依赖顺序大致的 mission。
|
|
276
284
|
- [ ] 每个 mission 有可测试的完成定义(任务、checks/测试、可选审查)。
|
|
277
|
-
- [ ]
|
|
285
|
+
- [ ] 如果这次变更需要独立审查,审查策略为 `required`(默认为 `optional`)。
|
|
278
286
|
- [ ] 我知道哪些 mission 可并行、哪些必须等待。
|
|
279
287
|
- [ ] 我接受合并门禁开销(以及开启审查时的审查开销),并会检查 `MISSIONS.md`/分支。
|
|
280
288
|
- [ ] 当前没有在同一会话依赖 Team 任务板、Workflow 脚本、Ralph 循环或 plan mode。
|