dsh-tower 2.6.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 +82 -0
- package/COMPATIBILITY.md +1 -0
- package/CONTRIBUTING.md +1 -1
- package/README.en.md +2 -1
- package/README.md +6 -1
- 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 +97 -61
- package/app/reviewCheckout.js +133 -0
- package/app/sandbox.js +121 -0
- package/app/sharedCheckout.js +90 -0
- package/app/spawn-prechecks.js +25 -24
- package/app/spawn-support.js +59 -8
- package/app/spawn.js +3 -0
- package/app/teardown.js +119 -2
- package/app/tower.js +29 -1
- package/cordis.patch.yml +50 -0
- package/docs/adr/0006-mission-shapes.md +306 -0
- package/docs/architecture/overview.md +6 -4
- package/docs/guide/install-upgrade-migration.md +26 -0
- package/docs/operations/runbook.md +1 -1
- package/docs/reference/blockers.md +8 -4
- package/docs/reference/component-surface.md +7 -2
- package/docs/reference/config.generated.md +6 -4
- package/docs/reference/config.md +1 -2
- package/docs/reference/doctor.md +7 -7
- package/docs/reference/operations.md +1 -1
- package/docs/reference/shapes.md +123 -0
- package/docs/reference/surface-budget.md +33 -1
- package/docs/reference/testing.md +4 -2
- package/docs/reference/tools.generated.md +5 -5
- package/docs/reference/tools.md +2 -2
- package/docs/zh/reference/blockers.md +2 -2
- package/docs/zh/reference/config.md +1 -2
- package/docs/zh/reference/testing.md +3 -2
- package/domain/batch.js +75 -105
- package/domain/collab/batch.js +30 -10
- package/domain/collab/spawn.js +53 -16
- package/domain/config/schema.js +47 -17
- package/domain/contracts/outputs.js +0 -1
- package/domain/contracts/tool-inputs/missions.js +9 -1
- package/domain/evidence.js +283 -0
- package/domain/gate.js +11 -31
- 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/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/doctor.js +2 -1
- package/host/preset-survey-sandbox.js +19 -0
- package/host/preset-survey.js +18 -0
- package/host/presets.js +8 -3
- package/host/tool-registry.js +14 -12
- 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 +13 -2
- package/ports/state.js +8 -1
- package/scripts/architecture-waivers.json +3 -3
- package/scripts/check-docs.mjs +1 -1
- package/scripts/check-pack.mjs +2 -0
- package/scripts/component-surface.json +68 -20
- 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 +21 -0
- package/scripts/shape-audit.mjs +361 -0
- package/scripts/surface-baseline.json +68 -4
- 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/spawn.js +47 -49
- package/tools/test.js +2 -1
- package/types/index.d.ts +66 -5
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Tower survey preset declaration (#148 D7): the read-only survey preset's own
|
|
2
|
+
// Plugins-page label. This is the survey twin of `host/preset-worker.js`: the row
|
|
3
|
+
// config stays in `cordis.patch.yml` and this module forwards it to the injected
|
|
4
|
+
// `agentPresets` service, which owns mount/unmount. A Tower-owned specifier gives
|
|
5
|
+
// the row a distinct locale (`dsh-tower/preset-survey/locale/<lang>.json`).
|
|
6
|
+
export const name = 'dsh-tower/preset-survey'
|
|
7
|
+
|
|
8
|
+
export const inject = ['agentPresets']
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Register the survey preset with the profile's preset registry.
|
|
12
|
+
* @param {{ agentPresets: { register: (config: any) => Promise<() => Promise<void> | void> } }} ctx
|
|
13
|
+
* @param {any} config the `cordis.patch.yml` row config (id/name/description/order/plugins)
|
|
14
|
+
* @returns {Promise<() => Promise<void> | void>} the registry's unregister disposer
|
|
15
|
+
*/
|
|
16
|
+
export async function apply(ctx, config) {
|
|
17
|
+
return ctx.agentPresets.register(config)
|
|
18
|
+
}
|
package/host/presets.js
CHANGED
|
@@ -20,13 +20,18 @@
|
|
|
20
20
|
// contradiction is refused up front instead.
|
|
21
21
|
import { TowerToolError } from '../domain/errors.js'
|
|
22
22
|
import { reviewRequired } from '../domain/integration/review.js'
|
|
23
|
+
import { ROLES, rolePresetConfig } from '../domain/roles.js'
|
|
23
24
|
import { componentEnabled, disabledReason } from './capability-registry.js'
|
|
24
25
|
|
|
25
26
|
export function presetIds(config = {}) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
const ids = {}
|
|
28
|
+
const spawn = config.spawn ?? {}
|
|
29
|
+
for (const role of ROLES) {
|
|
30
|
+
const spec = rolePresetConfig(role)
|
|
31
|
+
if (!spec) continue
|
|
32
|
+
ids[role] = String(spawn[spec.slot] ?? spec.fallback)
|
|
29
33
|
}
|
|
34
|
+
return ids
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
function rowId(preset) {
|
package/host/tool-registry.js
CHANGED
|
@@ -54,7 +54,7 @@ import { registerFindingsTool } from '../tools/findings.js'
|
|
|
54
54
|
import { readDiscoveryConfig, normalizeDiscovery, runDiscovery } from '../adapters/tests.js'
|
|
55
55
|
import { summarize as summarizeBatch } from '../domain/batch.js'
|
|
56
56
|
import { assertPorts } from '../ports/index.js'
|
|
57
|
-
import { COMPONENT_TOOLS, componentEnabled, componentReport, holdComponent, disabledReason } from './capability-registry.js'
|
|
57
|
+
import { COMPONENT_TOOLS, componentEnabled, componentReport, holdComponent, disabledReason, presetAvailable, PRESET_ROW_COMPONENTS } from './capability-registry.js'
|
|
58
58
|
import path from 'node:path'
|
|
59
59
|
import { fsp } from '../adapters/store-fs.js'
|
|
60
60
|
import { createDefaultDeps } from '../adapters/default.js'
|
|
@@ -511,16 +511,9 @@ async function runMissionDiscovery(tower, mission) {
|
|
|
511
511
|
diagnosticsDir: path.join(tower.paths.dir, 'test-runs', `${mission.id}-${Date.now()}`),
|
|
512
512
|
})
|
|
513
513
|
const stored = await tower.recordTestRun({ missionId: mission.id, receipt })
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
command: commands.map((command) => `${command.id}: ${command.command}`).join('; ') || 'tower.testDiscovery',
|
|
518
|
-
exitCode: commands.every((command) => command.exitCode === 0) ? 0 : (commands.find((command) => command.exitCode !== 0)?.exitCode ?? 1),
|
|
519
|
-
evidence: stored.ok
|
|
520
|
-
? `${stored.tests?.length ?? 0} test(s) passed at ${String(stored.treeTip ?? '').slice(0, 12)}; receipt ${stored.receiptPath ?? stored.diagnosticsPath}`
|
|
521
|
-
: `test discovery failed: ${String(stored.error ?? 'unknown').slice(0, 300)}`,
|
|
522
|
-
}
|
|
523
|
-
return { configured: true, receipt: stored, check }
|
|
514
|
+
// #149 W4: the recorded receipt is the only evidence shape. Consumers read it
|
|
515
|
+
// through domain/evidence.js; there is no separate `check` projection.
|
|
516
|
+
return { configured: true, receipt: stored }
|
|
524
517
|
}
|
|
525
518
|
|
|
526
519
|
async function observeActivity(ctx, tower) {
|
|
@@ -580,6 +573,15 @@ export function registerCoreTowerTools(ctx, options = {}) {
|
|
|
580
573
|
components: {
|
|
581
574
|
enabled: (id) => componentEnabled(id),
|
|
582
575
|
reason: (id) => disabledReason(id),
|
|
576
|
+
// Preset rows are declarative and invisible to the code registry, so the
|
|
577
|
+
// synchronous `enabled` probe cannot answer for them. Callers that gate a
|
|
578
|
+
// shape read this async probe, which returns null when `agentPresets` is
|
|
579
|
+
// absent (unknown, not disabled).
|
|
580
|
+
available: async (id) => {
|
|
581
|
+
const presetId = PRESET_ROW_COMPONENTS[id]
|
|
582
|
+
if (presetId) return presetAvailable(ctx, presetId)
|
|
583
|
+
return componentEnabled(id)
|
|
584
|
+
},
|
|
583
585
|
},
|
|
584
586
|
events: {
|
|
585
587
|
emit(name, payload) {
|
|
@@ -639,7 +641,7 @@ export function registerCoreTowerTools(ctx, options = {}) {
|
|
|
639
641
|
|
|
640
642
|
registerInterruptTool(ctx, { openTower, define, actorFor, requireTowerActor, interruptRosterAgent })
|
|
641
643
|
|
|
642
|
-
registerDiffTool(ctx, { openTower, define })
|
|
644
|
+
registerDiffTool(ctx, { openTower, define, actorFor })
|
|
643
645
|
|
|
644
646
|
registerAdoptTool(ctx, { openTower, define, actorFor, requireTowerActor })
|
|
645
647
|
|
package/locale/en.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Tower",
|
|
4
|
-
"description": "Plan and track missions, isolate each one in its own worktree, hand the work to worker and reviewer agents, and merge after review when review before merging is required. Off equals uninstalling Tower: no tools, presets or skills remain."
|
|
4
|
+
"description": "Plan and track missions, isolate each one in its own worktree, hand the work to worker and reviewer agents, and merge after review when review before merging is required. Off equals uninstalling Tower: no tools, presets or skills remain. Turning off the survey capability removes both survey presets: surveys cannot be planned (planning one is refused with an actionable code) and no survey agent can be dispatched. Build missions and every other capability keep working."
|
|
5
5
|
},
|
|
6
6
|
"components": {
|
|
7
7
|
"tower": {
|
|
@@ -59,6 +59,21 @@
|
|
|
59
59
|
"summary": "The independent Tower Reviewer preset: a read-only reviewer agent that reads the mission diff, checks scope and acceptance, and returns a verdict. Usable while review before merging is optional; a precondition for merging once review before merging is required.",
|
|
60
60
|
"disables": "The reviewer cannot be started. That is supported while review before merging is optional; once review before merging is required, planning and entering Tower mode are refused with an explanation."
|
|
61
61
|
},
|
|
62
|
+
"tower-survey": {
|
|
63
|
+
"title": "Tower Survey",
|
|
64
|
+
"summary": "Inspect one recorded commit either read-only in the shared checkout or in a disposable detached sandbox that may write and run commands inside it. A survey has no branch, no commit of its own, and never merges; the sandbox is removed when the survey completes.",
|
|
65
|
+
"disables": "Turning off the survey capability removes both survey presets: surveys cannot be planned (planning one is refused with an actionable code) and no survey agent can be dispatched. Build missions and every other capability keep working."
|
|
66
|
+
},
|
|
67
|
+
"preset-tower-survey": {
|
|
68
|
+
"title": "Tower Survey preset",
|
|
69
|
+
"summary": "The shared-checkout survey dependency: read, glob, grep, skill, and the Tower mission/status/finding/inbox/complete tools, with no write, edit, or shell tool.",
|
|
70
|
+
"disables": "A shared survey cannot be dispatched; build missions and every other capability keep working."
|
|
71
|
+
},
|
|
72
|
+
"preset-tower-survey-sandbox": {
|
|
73
|
+
"title": "Tower Survey Sandbox preset",
|
|
74
|
+
"summary": "The detached-survey dependency: a disposable sandbox that may write and run commands inside its checkout while reading one recorded commit, with no branch and no commit of its own.",
|
|
75
|
+
"disables": "A detached survey cannot be dispatched; shared surveys and build missions keep working."
|
|
76
|
+
},
|
|
62
77
|
"tower-ui": {
|
|
63
78
|
"title": "Tower UI",
|
|
64
79
|
"summary": "Adds Tower cards for tool results, a compact status summary above the message box, and a short status strip, in the web client.",
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "Tower Survey preset",
|
|
4
|
+
"description": "The shared-checkout survey dependency: read, glob, grep, skill, and the Tower mission/status/finding/inbox/complete tools, with no write, edit, or shell tool. Mandatory dependency, not a switch: A shared survey cannot be dispatched; build missions and every other capability keep working."
|
|
5
|
+
}
|
|
6
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "Tower Survey Sandbox preset",
|
|
4
|
+
"description": "The detached-survey dependency: a disposable sandbox that may write and run commands inside its checkout while reading one recorded commit, with no branch and no commit of its own. Mandatory dependency, not a switch: A detached survey cannot be dispatched; shared surveys and build missions keep working."
|
|
5
|
+
}
|
|
6
|
+
}
|
package/locale/zh.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Tower",
|
|
4
|
-
"description": "规划并跟踪任务线,让每条任务线在独立工作树中完成,交给执行代理与审查代理,并且在把合并前审查设为必须时,审查通过后再合并。关闭这一项等同于卸载 Tower
|
|
4
|
+
"description": "规划并跟踪任务线,让每条任务线在独立工作树中完成,交给执行代理与审查代理,并且在把合并前审查设为必须时,审查通过后再合并。关闭这一项等同于卸载 Tower:不再保留任何工具、预设或技能。关闭勘察能力会移除两个勘察预设:无法规划勘察任务(规划勘察会被可操作的错误码拒绝),也无法派发勘察代理。普通构建任务线与其他能力继续工作。"
|
|
5
5
|
},
|
|
6
6
|
"components": {
|
|
7
7
|
"tower": {
|
|
@@ -59,6 +59,21 @@
|
|
|
59
59
|
"summary": "独立的 Tower Reviewer 审查代理预设:一个只读代理,阅读任务线差异、核对范围与验收,并给出结论。在合并前审查仍为可选时可以使用;一旦把合并前审查设为必须,它就是合并的前置条件。",
|
|
60
60
|
"disables": "无法启动审查代理。在合并前审查仍为可选时,允许关闭这一项;一旦要求合并前必须审查,规划或进入 Tower 模式会被拒绝并给出解释。"
|
|
61
61
|
},
|
|
62
|
+
"tower-survey": {
|
|
63
|
+
"title": "Tower 勘察",
|
|
64
|
+
"summary": "勘察一个已记录的提交:可在共享检出中只读查看,也可在一次性分离沙箱中写入并运行命令。勘察没有分支、没有自己的提交,也从不合并;勘察完成时沙箱会被移除。",
|
|
65
|
+
"disables": "关闭勘察能力会移除两个勘察预设:无法规划勘察任务(规划勘察会被可操作的错误码拒绝),也无法派发勘察代理。普通构建任务线与其他能力继续工作。"
|
|
66
|
+
},
|
|
67
|
+
"preset-tower-survey": {
|
|
68
|
+
"title": "Tower Survey 预设",
|
|
69
|
+
"summary": "共享检出勘察的依赖项:read、glob、grep、skill,以及 Tower 的任务线、状态、发现、收件箱与完成工具,不包含写入、编辑或命令行工具。",
|
|
70
|
+
"disables": "无法派发共享检出勘察;普通构建任务线与其他能力继续工作。"
|
|
71
|
+
},
|
|
72
|
+
"preset-tower-survey-sandbox": {
|
|
73
|
+
"title": "Tower Survey Sandbox 预设",
|
|
74
|
+
"summary": "分离勘察的依赖项:一个一次性沙箱,可在读取一个已记录提交时于检出中写入并运行命令,没有分支,也没有自己的提交。",
|
|
75
|
+
"disables": "无法派发分离勘察;共享检出勘察与普通构建任务线继续工作。"
|
|
76
|
+
},
|
|
62
77
|
"tower-ui": {
|
|
63
78
|
"title": "Tower 界面",
|
|
64
79
|
"summary": "在 Web 客户端中显示 Tower 工具结果卡片、输入框上方的简要状态摘要,以及简短的状态提示条。",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-tower",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DSH-native Tower: mission planning, worktree isolation, review-gated merges, and a human-owned Tower mode.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
"./client": "./client.js",
|
|
32
32
|
"./worker": "./worker.js",
|
|
33
33
|
"./reviewer": "./reviewer.js",
|
|
34
|
+
"./survey": "./survey.js",
|
|
35
|
+
"./survey-sandbox": "./survey-sandbox.js",
|
|
34
36
|
"./skills": "./skills.js",
|
|
35
37
|
"./batch": "./host/capability-batch.js",
|
|
36
38
|
"./import": "./host/capability-import.js",
|
|
@@ -41,6 +43,8 @@
|
|
|
41
43
|
"./hmr": "./host/capability-hmr.js",
|
|
42
44
|
"./preset-worker": "./host/preset-worker.js",
|
|
43
45
|
"./preset-reviewer": "./host/preset-reviewer.js",
|
|
46
|
+
"./preset-survey": "./host/preset-survey.js",
|
|
47
|
+
"./preset-survey-sandbox": "./host/preset-survey-sandbox.js",
|
|
44
48
|
"./skills/locale/*.json": "./locale/skills/*.json",
|
|
45
49
|
"./batch/locale/*.json": "./locale/batch/*.json",
|
|
46
50
|
"./import/locale/*.json": "./locale/import/*.json",
|
|
@@ -51,6 +55,8 @@
|
|
|
51
55
|
"./hmr/locale/*.json": "./locale/hmr/*.json",
|
|
52
56
|
"./preset-worker/locale/*.json": "./locale/preset-worker/*.json",
|
|
53
57
|
"./preset-reviewer/locale/*.json": "./locale/preset-reviewer/*.json",
|
|
58
|
+
"./preset-survey/locale/*.json": "./locale/preset-survey/*.json",
|
|
59
|
+
"./preset-survey-sandbox/locale/*.json": "./locale/preset-survey-sandbox/*.json",
|
|
54
60
|
"./locale/*.json": "./locale/*.json",
|
|
55
61
|
"./icon": "./icon.svg",
|
|
56
62
|
"./package.json": "./package.json"
|
|
@@ -60,6 +66,8 @@
|
|
|
60
66
|
"index.js",
|
|
61
67
|
"worker.js",
|
|
62
68
|
"reviewer.js",
|
|
69
|
+
"survey.js",
|
|
70
|
+
"survey-sandbox.js",
|
|
63
71
|
"skills.js",
|
|
64
72
|
"skills/",
|
|
65
73
|
"host/*.js",
|
|
@@ -125,6 +133,9 @@
|
|
|
125
133
|
"docs:check:generated:components": "node scripts/generate-component-surface.mjs --check",
|
|
126
134
|
"docs:generate:locale": "node scripts/generate-capability-locale.mjs",
|
|
127
135
|
"docs:check:generated:locale": "node scripts/generate-capability-locale.mjs --check",
|
|
136
|
+
"docs:generate:shapes": "node scripts/generate-shapes-reference.mjs",
|
|
137
|
+
"docs:check:generated:shapes": "node scripts/generate-shapes-reference.mjs --check",
|
|
138
|
+
"shape:audit": "node scripts/shape-audit.mjs",
|
|
128
139
|
"docs:check:components": "node scripts/check-components.mjs",
|
|
129
140
|
"pack:check": "node scripts/check-pack.mjs",
|
|
130
141
|
"architecture:check": "node scripts/architecture.mjs",
|
|
@@ -132,7 +143,7 @@
|
|
|
132
143
|
"types:coverage": "node scripts/types-coverage.mjs",
|
|
133
144
|
"types:strict:check": "node scripts/types-strict.mjs",
|
|
134
145
|
"types:strict:write": "node scripts/types-strict.mjs --write",
|
|
135
|
-
"check": "npm test && npm run test:property && npm run docs:check && npm run docs:check:philosophy && npm run docs:check:generated && npm run docs:check:generated:tools && npm run docs:check:generated:config && npm run docs:check:generated:events && npm run docs:check:generated:types && npm run docs:check:generated:components && npm run docs:check:generated:locale && npm run docs:check:components && npm run surface:check && npm run pack:check && npm run architecture:check && npm run types:coverage && npm run types:strict:check && npm run types:check && npm run domain:check",
|
|
146
|
+
"check": "npm test && npm run test:property && npm run docs:check && npm run docs:check:philosophy && npm run docs:check:generated && npm run docs:check:generated:tools && npm run docs:check:generated:config && npm run docs:check:generated:events && npm run docs:check:generated:types && npm run docs:check:generated:components && npm run docs:check:generated:locale && npm run docs:check:generated:shapes && npm run shape:audit && npm run docs:check:components && npm run surface:check && npm run pack:check && npm run architecture:check && npm run types:coverage && npm run types:strict:check && npm run types:check && npm run domain:check",
|
|
136
147
|
"domain:metrics": "node scripts/domain-metrics.mjs",
|
|
137
148
|
"domain:check": "node scripts/domain-metrics.mjs --check"
|
|
138
149
|
},
|
package/ports/state.js
CHANGED
|
@@ -5,7 +5,14 @@ import { assertPort, definePort } from './contract.js'
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @typedef {object} StatePort
|
|
8
|
-
* @property {(input: {
|
|
8
|
+
* @property {(input: {
|
|
9
|
+
* store: unknown,
|
|
10
|
+
* paths: unknown,
|
|
11
|
+
* now?: number,
|
|
12
|
+
* persist?: boolean,
|
|
13
|
+
* migrations?: readonly unknown[],
|
|
14
|
+
* resolveLegacySurvey?: (rawState: Record<string, any>) => Promise<{ readCommit: string, readDirty: string[] } | null>,
|
|
15
|
+
* }) => Promise<any>} loadStateFile
|
|
9
16
|
*/
|
|
10
17
|
|
|
11
18
|
export const STATE_PORT = definePort('StatePort', ['loadStateFile'])
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "Justified architecture-gate exemptions (#80). Every entry needs rule, path, reason, and owner or ref. Scripts/architecture.mjs fails with waiver-contract when an entry is not justified. domain-pure, host-scope and no-lib-from-core cannot be waived at all, and domain/** accepts no waiver. Since #70 the retired lib/ layer has no waivers: host/** owns ambient state by rule, and only the two I/O adapters below are exempt.",
|
|
3
|
-
"waivers": [
|
|
4
|
-
{
|
|
3
|
+
"waivers": [ {
|
|
5
4
|
"rule": "child-process-surface",
|
|
6
5
|
"path": "adapters/vcs-git.js",
|
|
7
6
|
"reason": "The git adapter is the single process-spawning boundary; no other module implements VcsPort with a child process.",
|
|
@@ -15,5 +14,6 @@
|
|
|
15
14
|
"owner": "louifinn",
|
|
16
15
|
"ref": "#50"
|
|
17
16
|
}
|
|
18
|
-
]
|
|
17
|
+
],
|
|
18
|
+
"shapeWaivers": []
|
|
19
19
|
}
|
package/scripts/check-docs.mjs
CHANGED
package/scripts/check-pack.mjs
CHANGED
|
@@ -90,6 +90,24 @@
|
|
|
90
90
|
"kind": "row",
|
|
91
91
|
"fallback": "Declared by dsh-tower/preset-reviewer: the reviewer cannot be dispatched. Supported while review.mode is off or optional (merge is unaffected; off does not use the preset at all); with review.mode required, planning/mode entry is locked with an explanatory error."
|
|
92
92
|
},
|
|
93
|
+
{
|
|
94
|
+
"id": "tower-survey",
|
|
95
|
+
"scope": "visible",
|
|
96
|
+
"kind": "group",
|
|
97
|
+
"fallback": "Declared by the tower-survey group: surveys cannot be planned (planning one is refused with an actionable code) and no survey agent is dispatched, because both the read-only and the sandbox preset are nested dependencies of this row. Build missions and every existing capability are unaffected. survey.sandbox stays tuning: it chooses shared vs detached placement, never whether surveys exist."
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "preset-tower-survey",
|
|
101
|
+
"scope": "internal",
|
|
102
|
+
"kind": "row",
|
|
103
|
+
"fallback": "Declared by dsh-tower/preset-survey: the shared-checkout survey preset is a dependency of the tower-survey group, never its own switch. With the group off, a shared survey cannot be dispatched."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "preset-tower-survey-sandbox",
|
|
107
|
+
"scope": "internal",
|
|
108
|
+
"kind": "row",
|
|
109
|
+
"fallback": "Declared by dsh-tower/preset-survey-sandbox: the detached-sandbox survey preset is a dependency of the tower-survey group, never its own switch. It is selected only when survey.sandbox is detached; with the group off, a detached survey cannot be dispatched."
|
|
110
|
+
},
|
|
93
111
|
{
|
|
94
112
|
"id": "tower-ui",
|
|
95
113
|
"scope": "visible",
|
|
@@ -287,6 +305,16 @@
|
|
|
287
305
|
"class": "optional-config",
|
|
288
306
|
"note": "Optional independent model route for reviewers."
|
|
289
307
|
},
|
|
308
|
+
{
|
|
309
|
+
"name": "spawn.surveyModel",
|
|
310
|
+
"class": "optional-config",
|
|
311
|
+
"note": "Optional model route for survey workers."
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"name": "survey.sandbox",
|
|
315
|
+
"class": "optional-config",
|
|
316
|
+
"note": "Tuning, not a capability: shared (read-only in the shared checkout) or detached (a disposable detached sandbox that may write and run commands). The tower-survey row is still the switch."
|
|
317
|
+
},
|
|
290
318
|
{
|
|
291
319
|
"name": "spawn.maxLiveWorkers",
|
|
292
320
|
"class": "core",
|
|
@@ -350,17 +378,6 @@
|
|
|
350
378
|
"class": "optional-config",
|
|
351
379
|
"note": "Captured discovery output cap."
|
|
352
380
|
},
|
|
353
|
-
{
|
|
354
|
-
"name": "tests.autoChecks",
|
|
355
|
-
"class": "optional-config",
|
|
356
|
-
"note": "Attaches a tests check to completion when discovery runs.",
|
|
357
|
-
"exemption": {
|
|
358
|
-
"date": "2026-11-03",
|
|
359
|
-
"ref": "docs/adr/0005-component-surface.md",
|
|
360
|
-
"issue": "#138",
|
|
361
|
-
"reason": "Tuning the default receipt policy inside the optional tower-tests row, which still owns whether any test tooling exists."
|
|
362
|
-
}
|
|
363
|
-
},
|
|
364
381
|
{
|
|
365
382
|
"name": "tests.allowPackageDiscovery",
|
|
366
383
|
"class": "core",
|
|
@@ -381,6 +398,11 @@
|
|
|
381
398
|
"class": "forbidden-to-disable",
|
|
382
399
|
"note": "The review-exemption path is part of the review and merge contract."
|
|
383
400
|
},
|
|
401
|
+
{
|
|
402
|
+
"name": "gates.requireFreshSurvey",
|
|
403
|
+
"class": "forbidden-to-disable",
|
|
404
|
+
"note": "Promotes the survey-stale dependency warning to a merge blocker; the gate itself is part of the merge contract and defaults to advisory."
|
|
405
|
+
},
|
|
384
406
|
{
|
|
385
407
|
"name": "gates.maxReportBytes",
|
|
386
408
|
"class": "forbidden-to-disable",
|
|
@@ -423,21 +445,31 @@
|
|
|
423
445
|
"capability": "the Tower host",
|
|
424
446
|
"reason": "Without the host the plugin registers nothing; there is no off state that leaves the rest working, and no config boolean may remove it. The visible `tower` anchor is the all-off boundary, and the host section nested under it may never become its own switch.",
|
|
425
447
|
"tools": [],
|
|
426
|
-
"rowIds": [
|
|
448
|
+
"rowIds": [
|
|
449
|
+
"tower-host"
|
|
450
|
+
]
|
|
427
451
|
},
|
|
428
452
|
{
|
|
429
453
|
"id": "health",
|
|
430
454
|
"capability": "tower_doctor (read-only health contract)",
|
|
431
455
|
"reason": "Diagnosis must always exist so a failure message can point at it. #122 removed exposeDoctor and the exposeOperational master switch; the tool is registered for every configuration.",
|
|
432
|
-
"tools": [
|
|
433
|
-
|
|
456
|
+
"tools": [
|
|
457
|
+
"tower_doctor"
|
|
458
|
+
],
|
|
459
|
+
"rowIds": [
|
|
460
|
+
"tower-doctor"
|
|
461
|
+
]
|
|
434
462
|
},
|
|
435
463
|
{
|
|
436
464
|
"id": "recovery",
|
|
437
465
|
"capability": "tower_recover (stale state-lock escape)",
|
|
438
466
|
"reason": "The escape hatch must exist whenever the lock it repairs can be left behind. #122 removed exposeRecovery and the exposeOperational master switch; the tool is registered for every configuration.",
|
|
439
|
-
"tools": [
|
|
440
|
-
|
|
467
|
+
"tools": [
|
|
468
|
+
"tower_recover"
|
|
469
|
+
],
|
|
470
|
+
"rowIds": [
|
|
471
|
+
"tower-recover"
|
|
472
|
+
]
|
|
441
473
|
},
|
|
442
474
|
{
|
|
443
475
|
"id": "review",
|
|
@@ -445,15 +477,31 @@
|
|
|
445
477
|
"reason": "The policy is one tri-state configuration control on the plugin-page form, not a component row: review.mode is off, optional (default) or required, and off is a documented mode that removes tower_review and makes the merge gate ignore review. What no group, row or boolean key may switch off is the gate once the mode is required: a completed mission still needs a clean review bound to the branch tip, and the exemption path stays explicit. review.requireReview is a deprecated one-release alias, not a switch. The reviewer preset row remains a capability the policy may leave unused, never a way to weaken required mode.",
|
|
446
478
|
"tools": [],
|
|
447
479
|
"rowIds": [],
|
|
448
|
-
"gatedBy": [
|
|
480
|
+
"gatedBy": [
|
|
481
|
+
"review.mode",
|
|
482
|
+
"review.maxRoundsPerReviewer",
|
|
483
|
+
"gates.allowReviewExemption"
|
|
484
|
+
]
|
|
449
485
|
},
|
|
450
486
|
{
|
|
451
487
|
"id": "merge-gates",
|
|
452
488
|
"capability": "the merge gates",
|
|
453
489
|
"reason": "gates.* decides delivery; a component may not bypass it.",
|
|
454
|
-
"tools": [
|
|
455
|
-
|
|
456
|
-
|
|
490
|
+
"tools": [
|
|
491
|
+
"tower_complete",
|
|
492
|
+
"tower_merge"
|
|
493
|
+
],
|
|
494
|
+
"rowIds": [
|
|
495
|
+
"tower-gates",
|
|
496
|
+
"tower-merge-gates"
|
|
497
|
+
],
|
|
498
|
+
"gatedBy": [
|
|
499
|
+
"gates.requireChecks",
|
|
500
|
+
"gates.requireTests",
|
|
501
|
+
"gates.allowReviewExemption",
|
|
502
|
+
"gates.requireFreshSurvey",
|
|
503
|
+
"gates.maxReportBytes"
|
|
504
|
+
]
|
|
457
505
|
}
|
|
458
506
|
]
|
|
459
507
|
}
|
|
@@ -63,6 +63,11 @@ export const CAPABILITY_LOCALES = [
|
|
|
63
63
|
export const PRESET_LOCALES = [
|
|
64
64
|
{ specifier: 'preset-worker', component: 'preset-tower-worker', mandatory: true },
|
|
65
65
|
{ specifier: 'preset-reviewer', component: 'preset-tower-reviewer', mandatory: false },
|
|
66
|
+
// #148 W2: the survey capability row is a group; its two preset children are
|
|
67
|
+
// internal dependencies (never individual switches), so both are labelled with
|
|
68
|
+
// the mandatory-dependency marker.
|
|
69
|
+
{ specifier: 'preset-survey', component: 'preset-tower-survey', mandatory: true },
|
|
70
|
+
{ specifier: 'preset-survey-sandbox', component: 'preset-tower-survey-sandbox', mandatory: true },
|
|
66
71
|
]
|
|
67
72
|
|
|
68
73
|
/** Every row that ships a generated subpath locale resource. */
|