dev-flow-deepseek 0.8.8 → 0.8.9

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.
@@ -0,0 +1,118 @@
1
+ import { defineTool } from "@deepseek-ai/dsh-tools";
2
+
3
+ import {
4
+ WORKSPACE_COORDINATOR_TOOL,
5
+ authorizeWorkspaceExecution,
6
+ createWorkspaceCoordinator,
7
+ } from "./workspace-coordinator.mjs";
8
+
9
+ export function registerWorkspaceCoordinator(ctx, options) {
10
+ const coordinator = createWorkspaceCoordinator({
11
+ ...options,
12
+ readTask: options?.readTask ?? (async (request) => await readCoreTask(ctx, request)),
13
+ });
14
+ const disposeGuard = ctx.tools.guard((execution) => {
15
+ if (execution?.name !== WORKSPACE_COORDINATOR_TOOL) return undefined;
16
+ try {
17
+ authorizeWorkspaceExecution(execution);
18
+ return undefined;
19
+ } catch (error) {
20
+ return error.message;
21
+ }
22
+ });
23
+ const disposeTool = ctx.tools.register(defineTool({
24
+ name: WORKSPACE_COORDINATOR_TOOL,
25
+ description: "Provision, consume, or separately clean up a user-confirmed isolated Dev Flow worktree launch. Every mutation requires its exact current-turn confirmation.",
26
+ parameters: {
27
+ operation: { type: "string", required: true, enum: ["provision", "consume", "prepare_cleanup", "cleanup_worktree", "cleanup_branch"] },
28
+ request: { type: "string", description: "Exact admitted development request for a new provision operation." },
29
+ profile: { type: "string", description: "Current DSH Profile name." },
30
+ launch_id: { type: "string", description: "Provisioning launch identity returned by provision." },
31
+ task_id: { type: "string", description: "Fresh terminal Core Task identity for cleanup." },
32
+ revision: { type: "integer", description: "Fresh terminal Core Task revision for cleanup." },
33
+ repository_key: { type: "string", description: "Receipt-owned repository selected for cleanup." },
34
+ source_repository_path: { type: "string", description: "Current source checkout used only for separately authorized branch cleanup; never persisted." },
35
+ repositories: {
36
+ type: "array",
37
+ description: "Confirmed repositories in primary-first order.",
38
+ items: {
39
+ type: "object",
40
+ additionalProperties: false,
41
+ properties: {
42
+ repository_key: { type: "string", required: true },
43
+ source_repository_path: { type: "string", required: true },
44
+ remote_name: { type: "string", required: true },
45
+ base_branch: { type: "string", required: true },
46
+ target_branch: { type: "string", required: true },
47
+ },
48
+ },
49
+ },
50
+ },
51
+ output: {
52
+ schema: { type: "json" },
53
+ render(_arguments, value) {
54
+ return [{ type: "text", text: JSON.stringify(value) }];
55
+ },
56
+ },
57
+ timeoutMs: 10 * 60_000,
58
+ async execute(arguments_, execution) {
59
+ authorizeWorkspaceExecution({ ...execution, name: WORKSPACE_COORDINATOR_TOOL, arguments: arguments_ });
60
+ if (arguments_.operation === "provision") {
61
+ return await coordinator.provision({
62
+ request: arguments_.request,
63
+ profile: arguments_.profile,
64
+ repositories: arguments_.repositories,
65
+ signal: execution.signal,
66
+ });
67
+ }
68
+ if (arguments_.operation === "consume") return await coordinator.consume({ launchID: arguments_.launch_id, signal: execution.signal });
69
+ if (arguments_.operation === "prepare_cleanup") {
70
+ return await coordinator.prepareCleanup({
71
+ launchID: arguments_.launch_id, repositoryKey: arguments_.repository_key,
72
+ taskID: arguments_.task_id, revision: arguments_.revision,
73
+ sourceRepositoryPath: arguments_.source_repository_path,
74
+ signal: execution.signal, execution,
75
+ });
76
+ }
77
+ if (arguments_.operation === "cleanup_worktree") {
78
+ const result = await coordinator.cleanupWorktree({
79
+ launchID: arguments_.launch_id, repositoryKey: arguments_.repository_key,
80
+ taskID: arguments_.task_id, revision: arguments_.revision,
81
+ signal: execution.signal, execution,
82
+ });
83
+ execution.concludeTurn();
84
+ return result;
85
+ }
86
+ const result = await coordinator.cleanupBranch({
87
+ launchID: arguments_.launch_id, repositoryKey: arguments_.repository_key,
88
+ taskID: arguments_.task_id, revision: arguments_.revision,
89
+ sourceRepositoryPath: arguments_.source_repository_path,
90
+ signal: execution.signal, execution,
91
+ });
92
+ execution.concludeTurn();
93
+ return result;
94
+ },
95
+ }));
96
+ return () => {
97
+ disposeTool();
98
+ disposeGuard();
99
+ };
100
+ }
101
+
102
+ async function readCoreTask(ctx, { taskID, signal, execution }) {
103
+ const result = await ctx.tools.execute({
104
+ callId: `${execution.callId}:terminal-task`,
105
+ rootCallId: execution.rootCallId ?? execution.callId,
106
+ parent: execution.token,
107
+ name: "mcp__dev_flow__dev_flow_get_task",
108
+ arguments: { host: "deepseek", task_id: taskID },
109
+ agent: execution.agent,
110
+ signal,
111
+ });
112
+ const text = result.content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
113
+ const start = text.indexOf("{");
114
+ if (result.isError || start < 0) throw new Error("terminal Core Task read failed");
115
+ const envelope = JSON.parse(text.slice(start));
116
+ if (envelope?.ok !== true || envelope.result?.task === undefined) throw new Error("terminal Core Task read failed");
117
+ return envelope.result.task;
118
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dev-flow-deepseek",
3
- "version": "0.8.8",
3
+ "version": "0.8.9",
4
4
  "private": false,
5
5
  "description": "Explicit DeepSeek Harness adapter for the Dev Flow process graph.",
6
6
  "license": "Apache-2.0",
@@ -20,8 +20,11 @@
20
20
  "lib/index.mjs",
21
21
  "lib/paths.mjs",
22
22
  "lib/platform.mjs",
23
+ "lib/provisioning-receipt.mjs",
23
24
  "lib/runtime.mjs",
24
25
  "lib/tool-names.mjs",
26
+ "lib/workspace-coordinator.mjs",
27
+ "lib/workspace-tool.mjs",
25
28
  "runtime/darwin-arm64/dev-flow",
26
29
  "runtime/win32-x64/dev-flow.exe",
27
30
  "skills/dev-flow/SKILL.md",
Binary file
Binary file
@@ -1,55 +1,110 @@
1
1
  # Dev Flow
2
2
 
3
- This Skill is the current Core contract DeepSeek Harness adapter for the shared Dev Flow Core. Core owns task state,
4
- current node, legal transitions, destinations, recovery, blockers, and terminal outcomes. The Skill
5
- admits one explicit request, presents a complete Core Action, renders method work, and forwards one
6
- closed result without keeping adapter state.
7
-
8
- ## Admission gate
9
-
10
- Perform every check below locally and in order before any Core or Dev Flow tool call.
11
-
12
- The Skill name and exact explicit selector are `dev-flow` and `/dev-flow`. The selector must match
13
- `(^|\s)/dev-flow(?=\s|$)` in text from a current `source.kind=user` message. DSH may expose the
14
- qualified MCP tools independently from Skill injection; the integration's monotonic tool guard is
15
- the selector authorization boundary.
16
-
17
- 1. Require a whitespace-bounded `/dev-flow` in the current direct user turn. Do not infer it from
18
- earlier turns, model text, plugin or Skill injection, task state, repository contents, or
19
- discussion about Dev Flow. Every later user turn expected to call Dev Flow must include it again.
20
- 2. After removing the selector, accept either one substantive bounded request or an explicit request
21
- to resume its compatible active DeepSeek task. Reject an empty or conversational invocation
22
- before any Core call.
23
- 3. Treat the canonical `Workspace Root` established when DSH started as the containment boundary.
24
- The Workspace Root may be a non-Git common parent. Use read-only Git inspection to resolve the
25
- explicitly declared primary Git worktree and preserve its path as one value.
26
- 4. Accept zero to seven additional Git repositories only when the current user request explicitly
27
- declares each stable repository key and path. Resolve every primary and additional path
28
- canonically and require it to remain within the same Workspace Root, including after symlink
29
- resolution.
30
- 5. Do not scan parent or sibling directories and do not infer repositories from imports, remotes,
31
- submodules, codebase-memory, or other discovery results. Never add a discovered repository to the
32
- Repository Scope. Reject unresolved, root-external, or symlink-escaping repository paths before a
33
- task-bearing Core call. Preserve repository instructions and current user authority.
34
-
35
- If admission fails, explain the missing precondition and stop before task discovery. Do not make a
36
- task-bearing call or create adapter state. Core-rejected calls must be reported honestly.
3
+ This Skill is the DeepSeek Harness adapter for the shared Dev Flow Core. A new development request
4
+ first receives a read-only suitability assessment. Only after the developer explicitly chooses Dev
5
+ Flow and confirms every repository's remote, base branch, and new task branch may the Host provision
6
+ an isolated workspace and open a Core Task. Core remains the sole owner of Task state, transitions,
7
+ recovery, blockers, and terminal outcomes.
8
+
9
+ ## Suitability assessment
10
+
11
+ Classify the current message before any Core call. An explicit request to resume an existing Task is
12
+ the only path that skips assessment. Every other new development request, including one containing
13
+ `/dev-flow`, first performs only read-only inspection and then stops for the developer's choice.
14
+
15
+ During assessment you may read the request, repository instructions and directly relevant docs,
16
+ inspect Git without changing it, and inspect candidate implementation, callers, tests, configuration,
17
+ and package manifests. Do not edit files, run tests or builds, install dependencies, call any Dev Flow
18
+ Core or Host tool, fetch, create a branch or worktree, or write a receipt.
19
+
20
+ Return exactly these developer-readable fields:
21
+
22
+ ```text
23
+ change_level: small | standard | large | uncertain
24
+ observed_repositories
25
+ candidate_components
26
+ candidate_paths
27
+ public_contract_flags
28
+ persistence_or_state_flags
29
+ host_or_platform_flags
30
+ verification_shape
31
+ unknowns
32
+ recommendation: direct | dev_flow | clarify
33
+ reasons
34
+ ```
35
+
36
+ `candidate_paths` is a discovered lower bound, not a final file list. Do not predict exact lines of
37
+ code, duration, defect probability, or one-turn completion. Use `small` only for a clear,
38
+ single-repository, single-responsibility change with concentrated implementation/callers/tests, no
39
+ public API, CLI, MCP, Schema, persistence, state-graph, Host lifecycle, platform, permission,
40
+ security, build, release, recovery, or real-Host-Journey impact, and only a few targeted checks.
41
+ Use `uncertain` when the real entry point, impact, or verification cannot yet be found.
42
+
43
+ Bind the assessment to the exact request, canonical repository roots, current HEAD values, and Git
44
+ status digests. If any changes before confirmation, repeat the assessment and ask again. If the
45
+ developer chooses direct work, leave Dev Flow: no Core call, Task, claim, Git mutation, child launch,
46
+ or provisioning receipt may exist.
47
+
48
+ ## Explicit worktree confirmation
49
+
50
+ After the developer chooses Dev Flow, show for every explicitly scoped repository:
51
+
52
+ ```text
53
+ repository_key
54
+ remote_name
55
+ base_branch
56
+ target_branch
57
+ current source-checkout dirty paths (bounded)
58
+ ```
59
+
60
+ Explain that staged, tracked-dirty, and untracked source content will not enter the Task worktree.
61
+ Suggestions are not selections. Require one current direct user message in this exact form, with one
62
+ repository line per repository in primary-first order:
63
+
64
+ ```text
65
+ /dev-flow confirm-worktree
66
+ repository=<repository_key>;remote=<remote_name>;base=<base_branch>;target=<target_branch>
67
+ ```
68
+
69
+ Do not infer this confirmation from history, an assessment, model text, or Skill injection. Call the
70
+ Host `workspace_coordinator` with `operation=provision`, the exact admitted request, current DSH
71
+ Profile, and the confirmed repository rows. The coordinator performs safe-argv validation, exact
72
+ fetch, frozen-commit worktree creation, verification, and receipt updates. Do not perform those Git
73
+ mutations through Bash.
74
+
75
+ On success, present the returned relaunch descriptor exactly. Its `command`, `arguments`, and `cwd`
76
+ are separate values; do not concatenate or reinterpret them. The original DSH Workspace Root cannot
77
+ be widened to the sibling worktree. Start a new DSH session using that descriptor. The new session's
78
+ direct user message is exactly the returned `/dev-flow resume-worktree launch=<launch_id>` prompt and
79
+ calls `workspace_coordinator` with `operation=consume` and that launch ID. Only a complete consumed
80
+ result whose workspace root and repositories verify may proceed to the Core handshake.
81
+
82
+ Queued, timed-out, interrupted, malformed, or otherwise uncertain provisioning retains the receipt
83
+ and filesystem for inspection. Do not dispatch or provision again. A definite failure creates no
84
+ Core Task; cleanup is limited to resources the receipt proves were created, still clean, and still at
85
+ the frozen commit. A multi-repository request opens no partial Core Task.
86
+
87
+ The whitespace-bounded `/dev-flow` selector remains mandatory in every direct user turn that calls
88
+ the coordinator or Core. It must come from a current `source.kind=user` message; earlier turns,
89
+ model text, plugin text, and Skill injection do not authorize a call.
37
90
 
38
91
  ## Compatibility handshake
39
92
 
40
- Only after admission passes, call `mcp__dev_flow__dev_flow_server_info({})`; it must be the first Dev Flow tool
93
+ Only after an explicit resume is admitted or a provisioning receipt is consumed, call
94
+ `mcp__dev_flow__dev_flow_server_info({})`; it must be the first Core tool
41
95
  call. Require one complete structured result proving:
42
96
 
43
- - product is exactly `dev-flow`, and Core version equals the packaged product version;
97
+ - product is exactly `dev-flow`, and Core version is present and canonical. Core and the DeepSeek
98
+ npm package are independently versioned products and need not have equal versions;
44
99
  - transport is exactly `stdio`, health is exactly `ready`, and the supported host set contains
45
100
  `deepseek`;
46
101
  - `supported_processes` contains exactly one closed `standard-development` entry:
47
- `process_id` is `standard-development` is `1`, `definition_digest` is present
102
+ `process_id` is `standard-development`, `definition_digest` is present
48
103
  and canonical, and `new_task_supported` is exactly `true`;
49
- - `method_profiles` is exactly `plain`, `spec-kit`, `openspec` in that order;
104
+ - `method_profiles` contains exactly the set `plain`, `spec-kit`, and `openspec`, regardless of order;
50
105
  - `host_preferences.deepseek.codebase_memory` is present and is exactly a JSON boolean; it expresses
51
106
  a preference only and does not prove that codebase-memory is installed or available;
52
- - the tool catalog contains exactly these fifteen raw names, in this order:
107
+ - the tool catalog contains exactly these seventeen raw names, regardless of order:
53
108
 
54
109
  1. `dev_flow_server_info`
55
110
  2. `dev_flow_open_task`
@@ -63,12 +118,14 @@ call. Require one complete structured result proving:
63
118
  10. `dev_flow_submit_comprehension`
64
119
  11. `dev_flow_submit_refactor`
65
120
  12. `dev_flow_submit_delivery`
66
- 13. `dev_flow_resolve_blocker`
67
- 14. `dev_flow_recover_action`
68
- 15. `dev_flow_cancel_task`
121
+ 13. `dev_flow_prepare_task_relocation`
122
+ 14. `dev_flow_resolve_blocker`
123
+ 15. `dev_flow_recover_action`
124
+ 16. `dev_flow_cancel_task`
125
+ 17. `dev_flow_abandon_task`
69
126
 
70
127
  Any other schema, unsupported process version, absent process digest, false new-task support,
71
- incomplete method-profile set, missing/additional/reordered tool, or incomplete, truncated, malformed,
128
+ incomplete method-profile set, missing/additional tool, or incomplete, truncated, malformed,
72
129
  or incompatible result fails the handshake. Stop without task discovery or undocumented probing. Do
73
130
  not inspect local source or an installed binary, and do not start a second MCP server to bypass a
74
131
  failed handshake.
@@ -96,35 +153,36 @@ presentation state and must not be written into the Core Task.
96
153
 
97
154
  ## Task discovery
98
155
 
99
- After the handshake, call `mcp__dev_flow__dev_flow_open_task` with `host=deepseek` and the following
100
- Scope rules:
101
-
102
- - For a new request, send `repository_path` for the explicitly declared primary repository,
103
- `primary_repository_key` when supplied, and `additional_repositories` as the user's explicit
104
- closed `{key, repository_path}` declarations. A single-repository request may omit both optional
105
- Scope fields and keeps ordinary repository-relative paths.
106
- - For a resume from any participating repository, send that repository as `repository_path`, omit
107
- the Scope creation fields, and omit `new_task` or send `new_task=null`. Accept the immutable primary
108
- repository, ordered Scope, profile, revision, and current Action returned by Core.
109
-
110
- - For an explicit resume, omit `new_task` or send `new_task=null`. Do not resend a guessed intent or
111
- select another profile; accept the immutable profile returned by Core.
112
- - For a new request, select one profile from explicit current user intent. An explicit `plain`,
113
- `spec-kit`, or `openspec` request selects that exact profile. An explicit request to use Spec Kit
114
- selects `spec-kit`; an explicit request to use OpenSpec selects `openspec`; otherwise use the
115
- conservative `plain` profile.
116
- - Installed tooling does not select or switch a profile. Never change the profile after creation. If
117
- the user explicitly requests conflicting profiles, report the profile conflict and stop.
118
- - Derive the new-task contract only from the admitted user request, repository instructions, known
119
- initial bounds, known acceptance, and granted verification authority. Formal acceptance does not
120
- need to be complete at creation; the current requirements work forms that authority.
121
- - Forward `new_task` with exactly the members `request`, `initial_scope`,
122
- `initial_out_of_scope`, `known_acceptance_criteria`, `verification_budget`, and `method_profile`,
123
- with no additional members. Forward `verification_budget` with exactly `level`,
124
- `max_automatic_commands`, `allow_full_suite`, and `allow_manual_handoff`.
125
- - `request` is a JSON string. `initial_scope`, `initial_out_of_scope`, and
126
- `known_acceptance_criteria` are JSON arrays of strings and may be empty. Never collapse an array
127
- into prose. `verification_budget.level` is exactly `minimal`, `targeted`, or `full`.
156
+ After the handshake, call `mcp__dev_flow__dev_flow_open_task` with `host=deepseek`.
157
+
158
+ For a new request, use only the complete `workspace_coordinator` consume result from this relaunch:
159
+
160
+ - `repository_path` and `workspace_origin` come from its primary repository descriptor;
161
+ - `primary_repository_key` is that descriptor's key;
162
+ - every `additional_repositories` entry contains exactly `key`, `repository_path`, and
163
+ `workspace_origin` from the same launch;
164
+ - every Host-supplied `workspace_origin` contains exactly `mode="dedicated_worktree"`,
165
+ `remote_name`, `base_branch`, `base_commit`, `task_branch`, and
166
+ `provisioning_receipt_id`;
167
+ - never add Core-computed source-group, canonical-root, or worktree-Git-dir members;
168
+ - all repositories from the confirmed launch must be present. Never open a partial Scope or use a
169
+ source checkout after provisioning.
170
+
171
+ For an explicit resume, send the participating original worktree as `repository_path`, omit
172
+ `workspace_origin`, `primary_repository_key`, and `additional_repositories`, and omit `new_task` or
173
+ send `new_task=null`. Do not create a replacement directory, use a same-named branch, resend guessed
174
+ intent, or select another profile. Accept the immutable original worktree instance and profile from
175
+ Core. `WORKSPACE_UNAVAILABLE` requires restoration of that exact instance or an explicit
176
+ `mcp__dev_flow__dev_flow_abandon_task` request; ordinary cancel cannot invent a successful
177
+ observation.
178
+
179
+ For a new request, select one profile from explicit current user intent. `plain`, `spec-kit`, and
180
+ `openspec` select themselves; otherwise use `plain`. Installed tooling does not select or change a
181
+ profile. Derive `new_task` only from the admitted request, repository instructions, known bounds,
182
+ and known acceptance. It contains exactly `request`, `initial_scope`, `initial_out_of_scope`,
183
+ `known_acceptance_criteria`, and `method_profile`. Do not send a creation-time
184
+ `verification_budget`: requirements, design, impact, work breakdown, and the existing test structure
185
+ have not been analyzed yet.
128
186
 
129
187
  Use this exact `new_task` JSON shape, changing only values derived from the admitted request:
130
188
 
@@ -135,20 +193,15 @@ Use this exact `new_task` JSON shape, changing only values derived from the admi
135
193
  "initial_scope": ["Update the endpoint response"],
136
194
  "initial_out_of_scope": ["Change unrelated endpoints"],
137
195
  "known_acceptance_criteria": ["The response contains the requested field"],
138
- "verification_budget": {
139
- "level": "targeted",
140
- "max_automatic_commands": 4,
141
- "allow_full_suite": false,
142
- "allow_manual_handoff": true
143
- },
144
196
  "method_profile": "plain"
145
197
  }
146
198
  ```
147
199
  <!-- new-task-example:end -->
148
200
 
149
- Ask before opening only when a material request, initial-bound, verification, or profile choice
150
- cannot be derived without changing user intent. Let Core decide whether a compatible intent creates
151
- or resumes a task. Report an ownership or contract conflict unchanged in meaning and stop.
201
+ The Core call occurs only after all repository descriptors were consumed and verified. A new Task
202
+ opened without a dedicated-worktree origin is a contract defect, not permission to fall back to the
203
+ source checkout. Report ownership, provisioning, workspace, or contract conflicts unchanged in
204
+ meaning and stop.
152
205
 
153
206
  ## Governed action loop
154
207
 
@@ -156,16 +209,18 @@ The inseparable Action fields are exactly `task_id`, `revision`, `action_id`, `a
156
209
  `process_id`, `process_definition_digest`, `current_node`, `node_purpose`,
157
210
  `entry_conditions`, `completion_conditions`, `allowed_effects`, `required_evidence`,
158
211
  `method_profile`, `method_steps`, `available_transitions`, `payload_contract`, `guidance`,
159
- `repository_binding_digest`, and `issued_at`.
212
+ `repository_binding_digest`, `issuance_identity_digest`, `issuance_history_digest`,
213
+ `issuance_content_digest`, and `issued_at`.
160
214
 
161
215
  For an active task, perform each iteration in this order:
162
216
 
163
217
  1. Obtain one complete fresh Action from the open result or `mcp__dev_flow__dev_flow_get_next_action`, and bind it as
164
218
  `fresh_action` from `result.task.current_action` or `result.action` respectively.
165
- 2. Treat its task ID, revision, action ID, action kind, process ID, process version,
219
+ 2. Treat its task ID, revision, action ID, action kind, process ID,
166
220
  process-definition digest, current node, node purpose, entry conditions, completion conditions,
167
221
  allowed effects, required evidence, method profile, method steps, available transitions, payload
168
- schema/contract, guidance, repository-binding digest, and issued time as one inseparable Core
222
+ schema/contract, guidance, repository-binding and issuance identity/history/content digests, and
223
+ issued time as one inseparable Core
169
224
  result. Stop if any field is absent, malformed, or truncated.
170
225
  3. Present the current node, purpose, entry and completion conditions, allowed effects, required
171
226
  evidence, immutable method profile, every method step, and all `available_transitions`. For every
@@ -180,10 +235,8 @@ For an active task, perform each iteration in this order:
180
235
  instructions, verification budget, and current user authority.
181
236
  7. Select only a Core-returned transition and build the closed input of
182
237
  `fresh_action.submission_tool` from the actual typed node facts.
183
- `changed_paths` contains only repository paths newly changed while performing this current Action,
184
- relative to its issuance binding. Do not repeat paths changed by an earlier node. When the current
185
- Action only reads files or runs verification commands, submit `changed_paths=[]` and
186
- `no_file_changes=true`, even when the Task's implementation already has uncommitted paths.
238
+ File effects are not Host payload fields. Core re-observes the dedicated worktree and computes the
239
+ Action delta and complete current Task surface.
187
240
  8. Submit exactly one call to that qualified tool with `host`, `task_id`, `action_id`, the selected
188
241
  transition, result text, artifact slots, method results and the exact node result. Core fills and
189
242
  retains the complete Action identity and payload envelope.
@@ -218,8 +271,8 @@ reuse an `allow_once` decision for a different write, expand Repository Scope, o
218
271
  path.
219
272
 
220
273
  The gate covers the structured tools above; it is not a filesystem or shell sandbox. Bash, external
221
- processes, and other tool paths may write before Core observes them. Implementation, Refactor and
222
- Delivery submissions must therefore use the exact current changed surface and obey Core's final
274
+ processes, and other tool paths may write before Core observes them. Core derives the complete Task
275
+ surface from the frozen base, commits, index, worktree, and untracked entries, and applies the final
223
276
  scope guard. If the gate is unavailable, stop the supported write rather than describing prompt
224
277
  compliance as interception.
225
278
 
@@ -430,26 +483,141 @@ recovery-before-retry contract.
430
483
 
431
484
  ## Evidence and verification budget
432
485
 
433
- - Count verification commands exactly against Core's immutable budget.
434
- - Do not run a prohibited full suite. When automatic capacity is exhausted, report the remaining
435
- permitted work as manual handoff without claiming it ran.
436
- - Preserve repository instructions and explicit user authority.
437
- - Keep static inspection, simulated Core execution, user-performed evidence, and native automated
438
- evidence distinctly labelled.
439
- - Submit actual sources and outcomes. Never relabel failed, skipped, or unavailable work as passed.
440
- - `source=automated` uses `command_count` 1 to 20 and may set `full_suite` when the budget allows it.
441
- - `source=user`, `source=static`, and `source=host_observed` use `command_count=0` and
442
- `full_suite=false`. Shell commands a person ran by hand belong in that check's `summary`; they
443
- never consume the automatic command budget.
444
- - A verification the user already completed belongs in `checks` with `source=user`. Remove it from
445
- `manual_handoff_items`; that list keeps only work nobody has executed yet.
486
+ At TASKS, after reading the current requirements and design, decomposing the work, identifying its
487
+ expected paths and causal impact, and inspecting the existing tests, create the initial
488
+ `verification_plan`. Record the intended checks, a concrete rationale for each, the expected
489
+ automatic-command budget, whether a full suite is expected, and whether test-code changes are
490
+ expected. Use the smallest level and command count that cover the analyzed change. Task creation has
491
+ no final verification budget.
492
+
493
+ Before each automatic check, compare it with the current plan, current diff, causal impact,
494
+ acceptance criteria, an observed failure, or a real regression. A small local change uses the closest
495
+ targeted check first. Remaining capacity does not justify widening to package, module, or repository
496
+ scope, and verification stops when the current acceptance and actual impact are sufficiently checked.
497
+
498
+ If capacity is insufficient, do not stop merely because it is exhausted and do not run the extra
499
+ command first. Re-read the Task and TEST Action, then submit the returned
500
+ `verification_budget_increased` transition with one closed basis (`new_impact`, `new_risk`,
501
+ `verification_failure`, or `verification_gap`), newly needed checks and rationales, only the extra
502
+ commands or permissions required now, and a concrete reason. Core stays in TEST and returns a new
503
+ Action. “For completeness”, “increase confidence”, “to be safe”, or the existence of remaining
504
+ budget are not specific reasons and cannot authorize an increase.
505
+
506
+ Before every full-suite command, including a rerun after a small fix, freshly decide whether the
507
+ change has broad causal impact, why targeted or package checks are insufficient, which concrete risk
508
+ the suite covers, and whether repository instructions require it at this checkpoint. Budget
509
+ permission alone is never a reason. Run the closest targeted check when those facts do not justify a
510
+ suite. Otherwise send the fresh explanation as `full_suite_reason`; never automatically reuse an
511
+ earlier reason after another edit.
512
+
513
+ Before adding or changing test code, require lasting value: stable product behavior, a public
514
+ contract, an important failure path, or an observed regression. Prefer an existing test location
515
+ with the matching responsibility; create a new file only for a genuinely independent test
516
+ responsibility. A one-time edit or transient prose requirement normally gets a one-time check. For
517
+ example, a forbidden README word is checked with one text search and creates no permanent test file
518
+ or full-suite run.
519
+
520
+ Count and submit actual outcomes. Keep static inspection, simulated execution, user evidence, and
521
+ native automation distinct. `source=automated` uses `command_count` 1 to 20. Non-full checks send an
522
+ empty `full_suite_reason`; full suites send the fresh concrete reason. `source=user`, `source=static`,
523
+ and `source=host_observed` use `command_count=0`, `full_suite=false`, and an empty
524
+ `full_suite_reason`. Put only work nobody has run in `manual_handoff_items`.
525
+
526
+ ## Bounded post-change review
527
+
528
+ For ordinary implementation work, review only the current diff, callers, dependencies and runtime
529
+ paths directly or indirectly affected by it, plus material required for current acceptance. Do not
530
+ restart a repository-wide audit after each edit. Any added review area needs a stated causal path
531
+ from the current change.
532
+
533
+ Fix only defects introduced by the current change or caused in another location by that change.
534
+ Unrelated historical problems are not repaired, tested, or added to this Task; mention them
535
+ separately at delivery and suggest another Task when useful.
536
+
537
+ After fixing a review finding, re-check only the original finding, related regressions, affected
538
+ acceptance criteria, and matching targeted checks. Never restart a broad audit because one finding
539
+ was fixed. End when current acceptance, planned checks, justified increases, and the bounded review
540
+ are complete, with unrun checks and current-design risks reported honestly.
541
+
542
+ An explicit code review, code audit, or repository-wide audit is read-only. Complete that requested
543
+ scope, report all findings and their impact, then stop for a later explicit repair request. Do not
544
+ edit, format, create a patch, or move from review into repair automatically.
545
+
546
+ ## Relocation and unavailable workspaces
547
+
548
+ Relocation keeps one Core Task. After explicit developer authority, call
549
+ `mcp__dev_flow__dev_flow_prepare_task_relocation` with exactly `host`, `task_id`, and `revision` from
550
+ the fresh Task before changing the Host workspace. Core enters `BLOCKED` and returns the relocation
551
+ ID and retained source facts. Then
552
+ perform only the same-machine DSH relaunch or supported Host handoff. Resolve the relocation blocker
553
+ only after the target workspace is available, using `mcp__dev_flow__dev_flow_resolve_blocker` with
554
+ the normal blocked Action identity plus `relocation_id` and
555
+ `relocation_destinations=[{key,repository_path}]` for every repository. Core verifies the same Git
556
+ group, base, content, Task surface, and claim availability and atomically replaces bindings and
557
+ claims. A failure retains the old claim. An uncertain Host response
558
+ requires reading the retained relocation operation and actual Host state; never repeat the handoff
559
+ blindly.
560
+
561
+ `WORKSPACE_UNAVAILABLE` cannot be bypassed by creating a directory at the old path or selecting a
562
+ same-named branch. Restore the exact worktree instance or, after explicit current-turn authority,
563
+ call `mcp__dev_flow__dev_flow_abandon_task` with exact host, Task ID, revision, and a non-empty reason.
564
+ Abandon records the last known binding, releases claims, and ends at `CANCELLED`; it does not inspect
565
+ or delete Git resources.
566
+
567
+ For a prepared workspace-history blocker, use only
568
+ `history_resolution={choice:"accept_current_history",reason:<non-empty>}` after explicit review and
569
+ authorization. Do not mix history, relocation, and file-scope decision members.
446
570
 
447
571
  ## Blocked and terminal behavior
448
572
 
449
573
  Stop repository work when Core returns authoritative `BLOCKED`, `DONE`, `CANCELLED`, an ownership or
450
574
  contract conflict, or another safe-stop. Report Core's blocker and condition, terminal outcome,
451
575
  evidence summary, cancellation, or conflict without replacing or merging a task. Use
452
- `mcp__dev_flow__dev_flow_cancel_task` only after explicit user authority and a fresh current Core identity.
576
+ `mcp__dev_flow__dev_flow_cancel_task` only after explicit user authority, a fresh current Core
577
+ identity, and a successful workspace observation. Use abandon only for a genuinely unavailable
578
+ worktree.
579
+
580
+ Terminal state releases Core claims but never means commit, push, merge, PR, handoff, worktree
581
+ removal, or branch removal. Show the remote/base/frozen commit, task branch/current HEAD, worktree
582
+ path, clean state, current changed paths, and completed verification. Keep, review, handoff,
583
+ worktree cleanup, and branch cleanup are distinct choices. Never automatically remove an active,
584
+ dirty, unpushed, uncertain, or unknown-origin worktree; worktree and branch deletion require separate
585
+ current user authorization and may touch only resources owned by the retained provisioning receipt.
586
+
587
+ Cleanup never deletes the DSH process's current Workspace Root in place. First choose a surviving
588
+ source checkout in the same Git group and require:
589
+
590
+ ```text
591
+ /dev-flow prepare-cleanup launch=<launch_id> repository=<repository_key> task=<task_id> revision=<revision>
592
+ ```
593
+
594
+ Call `workspace_coordinator` with `operation=prepare_cleanup`, those identities, and the transient
595
+ `source_repository_path`. It verifies the terminal Core Task and receipt, does not persist the source
596
+ path, and returns a `command`/`arguments`/`cwd` relaunch descriptor. Relaunch DSH from that source
597
+ checkout. The relaunch turn deletes nothing and asks for the separate worktree decision below.
598
+
599
+ For worktree removal, require the exact current message returned by the Adapter:
600
+
601
+ ```text
602
+ /dev-flow cleanup-worktree launch=<launch_id> repository=<repository_key> task=<task_id> revision=<revision>
603
+ ```
604
+
605
+ Then call `workspace_coordinator` with `operation=cleanup_worktree` and those exact values. The
606
+ Coordinator performs a nested fresh Core read and removes only a terminal receipt-owned worktree
607
+ whose branch and HEAD match Core, whose tracked/index/worktree/submodule state is clean, and whose
608
+ remote task branch equals the terminal HEAD. It never uses force. The task branch remains.
609
+
610
+ Branch deletion is a second decision in a later current user message:
611
+
612
+ ```text
613
+ /dev-flow cleanup-branch launch=<launch_id> repository=<repository_key> task=<task_id> revision=<revision>
614
+ ```
615
+
616
+ Call `workspace_coordinator` with `operation=cleanup_branch`, the same identities, and a current
617
+ source checkout path. The Coordinator does not persist that source path. It verifies the same Git
618
+ group, terminal Core HEAD, exact remote branch, and that no worktree uses the task branch, then uses
619
+ non-force branch deletion. If the branch is not merged, Git refuses and the branch remains. A failed
620
+ or uncertain safety check preserves the resource.
453
621
 
454
622
  Adapter belief that work is complete does not override Core, and a blocker is not success.
455
623