@deksden-com/dd-flow-cli 0.8.0-beta.135 → 0.9.0-beta.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 +52 -0
- package/README.md +31 -4
- package/dist/build-info.json +10 -10
- package/dist/cli/help.js +15 -63
- package/dist/cli/run-cli.js +55 -26
- package/dist/domain/stage-catalog.js +2 -2
- package/dist/domain/validation.js +1 -1
- package/dist/schemas/agent-profile.schema.json +17 -0
- package/dist/schemas/code-review-decision.schema.json +5 -3
- package/dist/schemas/code-work-batch.schema.json +3 -3
- package/dist/schemas/compatibility.schema.json +32 -0
- package/dist/schemas/flow-contract.schema.json +3 -2
- package/dist/schemas/merge-result.schema.json +15 -0
- package/dist/schemas/protocol-plan.schema.json +1 -1
- package/dist/schemas/stage-start-response.schema.json +4 -2
- package/dist/schemas/status-report.schema.json +76 -0
- package/dist/schemas/vnext-protocol-plan.schema.json +4 -4
- package/dist/services/cli-operation-classifier.js +1 -1
- package/dist/services/code-checks.js +125 -208
- package/dist/services/eval-snapshots.js +10 -1
- package/dist/services/harness-adapter.js +59 -0
- package/dist/services/hooks.js +87 -237
- package/dist/services/ids.js +18 -1
- package/dist/services/lifecycle-command.js +288 -0
- package/dist/services/merge-server.js +124 -0
- package/dist/services/prompts.js +16 -10
- package/dist/services/runs.js +7 -2
- package/dist/services/sessions.js +18 -27
- package/dist/services/stage-pause.js +13 -0
- package/dist/services/vnext-code-review.js +71 -20
- package/dist/services/vnext-code.js +131 -34
- package/dist/services/vnext-execution-profile.js +6 -3
- package/dist/services/vnext-merge.js +330 -0
- package/dist/services/vnext-plan-review.js +2 -2
- package/dist/services/vnext-plan.js +22 -38
- package/dist/services/vnext-specify.js +5 -2
- package/dist/services/vnext-workspace-policy.js +8 -2
- package/dist/services/work-registry.js +85 -34
- package/dist/storage/database.js +66 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# @deksden-com/dd-flow-cli
|
|
2
2
|
|
|
3
|
+
## 0.9.0-beta.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- cef9b99: Add the vNext MERGE stage, project FIFO integration requests, same-session and
|
|
8
|
+
merge-server execution, integrated-tree verification receipts, and explicit
|
|
9
|
+
local delivery and cleanup policies. Upgrade the planned-check contract to
|
|
10
|
+
`code-check-profile@5` and project execution snapshots to
|
|
11
|
+
`project-execution@2`.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 7a97bdf: Use one shell-aware lifecycle parser across every harness hook so quoted
|
|
16
|
+
absolute launchers bind correctly while diagnostic text cannot trigger a
|
|
17
|
+
trusted lifecycle event.
|
|
18
|
+
|
|
19
|
+
## 0.8.0
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- a092c98: Accept controlled OpenCode lifecycle events and cumulative root/child Session usage through the shared harness evidence path.
|
|
24
|
+
- fb2395a: Accept trusted lifecycle events from controlled zcode-acp sessions and retain harness-native root, child, parent, and execution-daemon identities in Session evidence.
|
|
25
|
+
- Promote the accepted SPECIFY-through-CODE-REVIEW runtime as stable 0.8.0 and align its shared compatibility, flow, stage-start and status schemas with Memory Bank 4.0.0.
|
|
26
|
+
|
|
27
|
+
## 0.8.0-beta.138
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Replace CODE and repair file allowlists with optional `planned_write_areas`:
|
|
32
|
+
soft coordination hints that serialize likely concurrent collisions but never
|
|
33
|
+
deny a necessary project-local edit. Record unexpected actual paths as
|
|
34
|
+
`coordination.drift` instead of rejecting the Work.
|
|
35
|
+
- Render the hard RUN workspace boundary separately from required reads,
|
|
36
|
+
discovery hints and planned coordination areas, so a worker can distinguish
|
|
37
|
+
semantic constraints from planning predictions.
|
|
38
|
+
|
|
39
|
+
## 0.8.0-beta.137
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- Transfer a running coordinator Work to a fresh Session at a frozen
|
|
44
|
+
`new_session` stage boundary, while still rejecting a second Session that
|
|
45
|
+
tries to repeat the same stage.
|
|
46
|
+
|
|
47
|
+
## 0.8.0-beta.136
|
|
48
|
+
|
|
49
|
+
### Patch Changes
|
|
50
|
+
|
|
51
|
+
- Serialize the long CODE aggregate gate and reuse complete same-workspace
|
|
52
|
+
receipts after a client loses its command output, preventing a concurrent
|
|
53
|
+
retry from duplicating checks or colliding on receipt identifiers.
|
|
54
|
+
|
|
3
55
|
## 0.8.0-beta.135
|
|
4
56
|
|
|
5
57
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -97,7 +97,7 @@ dd-flow prompt render \
|
|
|
97
97
|
|
|
98
98
|
For a non-plan worker, replace `--plan-item` with `--task-file <path>` pointing to a `dd-flow/worker-task@1` manifest inside the selected RUN home. The manifest embeds one existing plan-item-shaped `task`, so validation and rendered artifacts remain identical to the compatibility route.
|
|
99
99
|
|
|
100
|
-
The selected item must contain `execution_context` and `semantic_spine`. The renderer accepts only registered profiles, validates the active RUN/workspace and source paths, then persists `launch-prompt.md`, `prompt-stack.json` and `render-report.json` in the RUN stage. The stack and render report both retain the validated read/discovery/
|
|
100
|
+
The selected item must contain `execution_context` and `semantic_spine`. The renderer accepts only registered profiles, validates the active RUN/workspace and source paths, then persists `launch-prompt.md`, `prompt-stack.json` and `render-report.json` in the RUN stage. The stack and render report both retain the validated read/discovery/coordination references. It records project sources as paths rather than copying their contents. `required_read` and `discovery_boundary` may use a checked `run://<relative-path>` reference for a source inside the selected RUN home. The RUN workspace is the hard write boundary; `planned_write_areas` are optional soft hints for concurrent-work coordination, never a file allowlist.
|
|
101
101
|
|
|
102
102
|
Human help is available for the operator-facing command groups:
|
|
103
103
|
|
|
@@ -106,8 +106,7 @@ dd-flow --help
|
|
|
106
106
|
dd-flow lane --help
|
|
107
107
|
dd-flow lane workspace --help
|
|
108
108
|
dd-flow lane lock --help
|
|
109
|
-
dd-flow merge
|
|
110
|
-
dd-flow merge-queue wait-next --help
|
|
109
|
+
dd-flow merge --help
|
|
111
110
|
dd-flow cleanup --help
|
|
112
111
|
dd-flow codex home --help
|
|
113
112
|
dd-flow worktree --help
|
|
@@ -189,7 +188,29 @@ When the task stops using the shared checkout:
|
|
|
189
188
|
dd-flow lane lock release --project-root "$PROJECT_ROOT" --lane direct-main --worker-id "$PROTOCOL_ID" --path "$PWD" --lease-token "$TOKEN" --reason done --json
|
|
190
189
|
```
|
|
191
190
|
|
|
192
|
-
##
|
|
191
|
+
## vNext MERGE recipe
|
|
192
|
+
|
|
193
|
+
CODE/CODE-REVIEW closure creates the `MRG-*` request and returns the exact
|
|
194
|
+
standalone stage-start command. Run it unchanged. The accepted packet then
|
|
195
|
+
provides the exact `merge apply` and `stage finish` commands; do not reconstruct
|
|
196
|
+
Git operations or lifecycle arguments manually.
|
|
197
|
+
|
|
198
|
+
For unattended execution, store a validated agent profile under
|
|
199
|
+
`DD_FLOW_HOME/agent-profiles/<id>.json` and run:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
dd-flow merge serve --agent-profile <id> --max-parallel-projects 4 --progress-jsonl
|
|
203
|
+
dd-flow merge server status --json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The server preserves FIFO inside one project and may serve different projects
|
|
207
|
+
concurrently. Same-session and server routes use the same MRG, Work, checks and
|
|
208
|
+
stage report.
|
|
209
|
+
|
|
210
|
+
## Classic merge queue recipe
|
|
211
|
+
|
|
212
|
+
The commands below belong to the classic protocol runtime. The vNext flow does
|
|
213
|
+
not call them or fall back to them.
|
|
193
214
|
|
|
194
215
|
Prompts enqueue protocols only after explicit readiness signals exist:
|
|
195
216
|
|
|
@@ -368,6 +389,12 @@ The installed hook writes invocation markers, forwarded stderr, and the final
|
|
|
368
389
|
exit code to `${DD_FLOW_HOME:-$HOME/.dd-flow}/logs/codex-hook.log`. An absent
|
|
369
390
|
start marker means Codex did not invoke the hook; a start marker without a
|
|
370
391
|
successful finish marker identifies a hook launch or handler failure.
|
|
392
|
+
|
|
393
|
+
All harness event handlers use the same lifecycle shell parser. It recognizes
|
|
394
|
+
`dd-flow` as the actual command word, including a quoted absolute executable,
|
|
395
|
+
and does not treat occurrences in search patterns, JSON, comments or heredoc
|
|
396
|
+
bodies as lifecycle calls. Real lifecycle calls joined to other shell commands
|
|
397
|
+
remain invalid and receive a standalone retry.
|
|
371
398
|
`--project-root` belongs to installer/status commands, not the stored handler.
|
|
372
399
|
|
|
373
400
|
## Verification
|
package/dist/build-info.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"cli_package": "@deksden-com/dd-flow-cli",
|
|
3
|
-
"cli_version": "0.
|
|
4
|
-
"cli_commit": "
|
|
5
|
-
"built_at": "2026-
|
|
3
|
+
"cli_version": "0.9.0-beta.0",
|
|
4
|
+
"cli_commit": "ade3ebb2888bf804bec3879bbf7ed4600ff651fc",
|
|
5
|
+
"built_at": "2026-09-01T20:01:20.985Z",
|
|
6
6
|
"built_with_canon": {
|
|
7
|
-
"version":
|
|
8
|
-
"commit":
|
|
9
|
-
"flow_contract":
|
|
10
|
-
"repo_root":
|
|
11
|
-
"memorybank_root":
|
|
12
|
-
"flow_root":
|
|
13
|
-
"layout":
|
|
7
|
+
"version": "4.0.0",
|
|
8
|
+
"commit": "bd6494ad11bca9544d9b483bd7fe37049e6d00fe",
|
|
9
|
+
"flow_contract": "dd-flow-canonical-2026-08",
|
|
10
|
+
"repo_root": "/Users/deksden/Documents/_Projects/dd-memorybank",
|
|
11
|
+
"memorybank_root": "/Users/deksden/Documents/_Projects/dd-memorybank/.memory-bank",
|
|
12
|
+
"flow_root": "/Users/deksden/Documents/_Projects/dd-memorybank/.memory-bank/dd-flow",
|
|
13
|
+
"layout": "dot_memory_bank"
|
|
14
14
|
}
|
|
15
15
|
}
|
package/dist/cli/help.js
CHANGED
|
@@ -28,9 +28,8 @@ Core commands:
|
|
|
28
28
|
plan status/item/reviews Inspect plans, update SQLite progress, or dispatch vNext grouped reviews.
|
|
29
29
|
prompt render Render one bounded, RUN-local worker launch prompt.
|
|
30
30
|
lane workspace/lock/status Manage shared workspace lanes and leases.
|
|
31
|
-
merge
|
|
32
|
-
merge
|
|
33
|
-
merge-queue status/claim/next Claim, wait for, complete, or fail merge jobs.
|
|
31
|
+
merge request/apply Inspect, route and execute vNext MERGE requests.
|
|
32
|
+
merge serve/status/stop Run or inspect the deterministic vNext merge server.
|
|
34
33
|
session register/status/stop Register flow sessions and stop workers.
|
|
35
34
|
dashboard data/render/open/refresh Render, refresh, open, and inspect project/global dashboards.
|
|
36
35
|
schema validate Validate canonical dd-flow JSON data contracts.
|
|
@@ -60,8 +59,9 @@ Examples:
|
|
|
60
59
|
dd-flow protocol transition PRT-001-demo --to implementation --payload-file transition.json --json
|
|
61
60
|
dd-flow lane workspace set --project-root "$PWD" --lane merge --path "$PWD" --branch main --json
|
|
62
61
|
dd-flow lane lock acquire --project-root "$PWD" --lane merge --worker-id worker-1 --path "$PWD" --ttl 300 --reason "merge worker" --json
|
|
63
|
-
dd-flow merge status --project-root "$PWD" --json
|
|
64
|
-
dd-flow merge
|
|
62
|
+
dd-flow merge request status MRG-001 --project-root "$PWD" --json
|
|
63
|
+
dd-flow merge apply MRG-001 --work WRK-001 --project-root "$PWD" --json --progress-jsonl
|
|
64
|
+
dd-flow merge serve --agent-profile codex-luna-xhigh --progress-jsonl
|
|
65
65
|
|
|
66
66
|
Default output is human-readable. Use --json for hooks, prompts, scripts and other agent automation; JSON mode never mixes human progress text into stdout.
|
|
67
67
|
|
|
@@ -204,9 +204,9 @@ Usage:
|
|
|
204
204
|
dd-flow work show <WORK-ID> --json
|
|
205
205
|
dd-flow work start <WORK-ID> --project-root <root> --json
|
|
206
206
|
dd-flow work finish <WORK-ID> (--result-file <path>|--result-stdin) --project-root <root> --json
|
|
207
|
-
dd-flow work repair add --run <RUN-ID> --from-check <CHECK-ID> --origin-work <WORK-ID>...
|
|
207
|
+
dd-flow work repair add --run <RUN-ID> --from-check <CHECK-ID> --origin-work <WORK-ID>... --task-stdin --project-root <root> --json
|
|
208
208
|
|
|
209
|
-
CODE workers receive their full accepted packet from work start. work finish validates the result and executes the packet's focused checks before completion. A failed aggregate CODE gate returns the exact failed receipt and repair command; repair add creates a new Work from the selected completed origin context plus that failure evidence.
|
|
209
|
+
CODE workers receive their full accepted packet from work start. work finish validates the result and executes the packet's focused checks before completion. A failed aggregate CODE gate returns the exact failed receipt and repair command; repair add creates a new Work from the selected completed origin context plus that failure evidence. Its planned write areas are coordination hints only; the repair may change any necessary project file inside its RUN workspace.`
|
|
210
210
|
],
|
|
211
211
|
[
|
|
212
212
|
"id",
|
|
@@ -363,53 +363,17 @@ The renderer accepts only registered profiles: code_implementation, documentatio
|
|
|
363
363
|
],
|
|
364
364
|
[
|
|
365
365
|
"merge",
|
|
366
|
-
`dd-flow merge -
|
|
366
|
+
`dd-flow merge - deterministic vNext integration queue and executor
|
|
367
367
|
|
|
368
368
|
Usage:
|
|
369
|
-
dd-flow merge status --project-root <root>
|
|
370
|
-
dd-flow merge
|
|
371
|
-
dd-flow merge
|
|
372
|
-
dd-flow merge
|
|
373
|
-
dd-flow merge
|
|
374
|
-
dd-flow merge
|
|
369
|
+
dd-flow merge request status <MRG-ID> --project-root <root> --json
|
|
370
|
+
dd-flow merge request route <MRG-ID> --mode same_session|server --reason <text> --project-root <root> --json
|
|
371
|
+
dd-flow merge apply <MRG-ID> --work <WRK-ID> --project-root <root> --json --progress-jsonl
|
|
372
|
+
dd-flow merge serve --agent-profile <id> [--once] [--poll-seconds <n>] [--max-parallel-projects <n>] --progress-jsonl
|
|
373
|
+
dd-flow merge server status --json
|
|
374
|
+
dd-flow merge server stop <MSV-ID> --json
|
|
375
375
|
|
|
376
|
-
|
|
377
|
-
],
|
|
378
|
-
[
|
|
379
|
-
"merge-worker",
|
|
380
|
-
`dd-flow merge-worker - manage long-lived project merge workers
|
|
381
|
-
|
|
382
|
-
Usage:
|
|
383
|
-
dd-flow merge-worker status --project-root <root> --json
|
|
384
|
-
dd-flow merge-worker start --project-root <root> --worker-id <id> [--path <workspace>] [--branch <branch>] --json
|
|
385
|
-
dd-flow merge-worker stop --project-root <root> [--worker-id <id>] --reason <text> --json
|
|
386
|
-
|
|
387
|
-
start is idempotent: if a worker, claimed job, or active merge lock already exists it returns status instead of creating a duplicate worker. stop is no-op/status when no worker exists, refuses ambiguous multiple workers unless --worker-id is provided, stops idle workers immediately, and marks busy workers as stop-after-current while preserving the claimed job and lock.`
|
|
388
|
-
],
|
|
389
|
-
[
|
|
390
|
-
"merge-queue",
|
|
391
|
-
`dd-flow merge-queue - inspect and process ready-for-merge protocols
|
|
392
|
-
|
|
393
|
-
Usage:
|
|
394
|
-
dd-flow merge-queue status --project-root <root> --json
|
|
395
|
-
dd-flow merge-queue next --project-root <root> --worker-id <id> [--path <workspace>] --json
|
|
396
|
-
dd-flow merge-queue claim <protocol-id> [--project-root <root>] --worker-id <id> [--path <workspace>] --json
|
|
397
|
-
dd-flow merge-queue wait-next --project-root <root> --worker-id <id> [--path <workspace>] --timeout <seconds> --poll-interval <seconds> [--acquire-lock true] --json
|
|
398
|
-
dd-flow merge-queue complete <protocol-id> [--project-root <root>] --worker-id <id> [--path <workspace>] --summary <text> --json
|
|
399
|
-
dd-flow merge-queue note <protocol-id> [--project-root <root>] --worker-id <id> --summary <text> --json
|
|
400
|
-
dd-flow merge-queue fail <protocol-id> [--project-root <root>] --worker-id <id> [--path <workspace>] --reason <text> --requeue true|false --json
|
|
401
|
-
dd-flow merge-queue cancel <protocol-id> [--project-root <root>] --reason <text> [--worker-id <id>] [--path <workspace>] [--force] --json
|
|
402
|
-
|
|
403
|
-
The worker must own the merge lane from the registered merge workspace before claiming, completing, or failing queued protocols. next remains FIFO; claim <protocol-id> atomically claims only that ready/requeued job. Outputs use queue_item/protocol/claim as the primary contract and retain job as a compatibility alias. note updates the final completion summary after post-complete cleanup and does not require a lane lock. --path defaults to the current working directory. Use --worker-id as the owner identity.
|
|
404
|
-
|
|
405
|
-
For branch-level integration prefer:
|
|
406
|
-
dd-flow merge bundle status --project-root "$PWD" --path "$PWD" --json
|
|
407
|
-
dd-flow merge bundle claim --project-root "$PWD" --worker-id merge-worker --path "$PWD" --json
|
|
408
|
-
|
|
409
|
-
Examples:
|
|
410
|
-
dd-flow merge-queue wait-next --project-root "$PWD" --worker-id merge-worker --path "$PWD" --timeout 1200 --poll-interval 10 --acquire-lock true --json
|
|
411
|
-
dd-flow merge-queue complete PRT-123 --project-root "$PWD" --worker-id merge-worker --path "$PWD" --summary "merged locally; cleanup follows" --json
|
|
412
|
-
dd-flow merge-queue note PRT-123 --project-root "$PWD" --worker-id merge-worker --summary "merged, pushed, checked, and cleanup completed" --json`
|
|
376
|
+
CODE or CODE-REVIEW creates one MRG request and child MERGE Work. stage start waits in the shared project FIFO, reports progress, locks the execution target baseline and returns the exact apply/finish commands. merge apply is the only supported initial Git mutation. merge serve is a deterministic dispatcher: it launches a fresh Session through the configured harness adapter but does not perform agent work itself. It preserves FIFO inside each project and may serve different projects concurrently up to the explicit bound.`
|
|
413
377
|
],
|
|
414
378
|
[
|
|
415
379
|
"cleanup",
|
|
@@ -420,18 +384,6 @@ Usage:
|
|
|
420
384
|
dd-flow cleanup apply --project-root <root> --plan-file <file> --reason <text> [--force] --json
|
|
421
385
|
|
|
422
386
|
cleanup scan is read-only and returns deterministic findings plus plan.actions. cleanup apply validates project identity, action kinds, reason, and destructive force requirements before mutating runtime state, then reports requested/applied/changed/skipped action results. Worktree record cleanup marks a checkout removed only when its path is already absent; existing checkouts are kept instead of being silently deleted. Use this for stale queue jobs, missing protocol runtime snapshots, stale sessions, expired locks, and terminal-protocol worktree records.`
|
|
423
|
-
],
|
|
424
|
-
[
|
|
425
|
-
"merge-queue wait-next",
|
|
426
|
-
`dd-flow merge-queue wait-next - wait for the next ready merge protocol
|
|
427
|
-
|
|
428
|
-
Usage:
|
|
429
|
-
dd-flow merge-queue wait-next --project-root <root> --worker-id <id> [--path <workspace>] --timeout <seconds> --poll-interval <seconds> [--acquire-lock true] --json
|
|
430
|
-
|
|
431
|
-
Use this from a shell or supervisor to wait outside model tokens. Live merge workers should prefer long waits, for example --timeout 1200 --poll-interval 10, so the agent sleeps inside the CLI process instead of spending model tokens on frequent polling. If --acquire-lock true is used, wait-next first enters the generic FIFO lane waiter path (lane lock wait-acquire --lane merge), then heartbeats the merge lock while waiting for a ready protocol. A lock acquired by this command is released on timeout. If a protocol is ready, it is claimed atomically. If no protocol appears before the timeout, the command returns outcome: wait_timeout with queue_item: null and legacy job: null.
|
|
432
|
-
|
|
433
|
-
Examples:
|
|
434
|
-
dd-flow merge-queue wait-next --project-root "$PWD" --worker-id supervisor --path "$PWD" --timeout 1200 --poll-interval 10 --acquire-lock true --json`
|
|
435
387
|
],
|
|
436
388
|
[
|
|
437
389
|
"session",
|
package/dist/cli/run-cli.js
CHANGED
|
@@ -17,6 +17,7 @@ import { getProjectConfigStatus, setProjectConfigValue } from "../services/confi
|
|
|
17
17
|
import { getCanonStatus, registerCanonRoot, resolveCanonRoot } from "../services/canon.js";
|
|
18
18
|
import { getRuntimeStatus } from "../services/status.js";
|
|
19
19
|
import { getCliVersionReport } from "../services/build-info.js";
|
|
20
|
+
import { parseCommandArgs } from "../services/lifecycle-command.js";
|
|
20
21
|
import { autoRefreshDashboards, dashboardData, getCmuxStatus, openDashboard, openGlobalDashboard, openProtocolDashboard, refreshAllDashboards, refreshDashboard, refreshGlobalDashboard, renderDashboard, renderGlobalDashboard } from "../services/dashboard.js";
|
|
21
22
|
import { dashboardTargetSummary, preferredDashboardCommand, relatedDashboardCommands, resolveDashboardTarget } from "../services/dashboard-targets.js";
|
|
22
23
|
import { getFlowSessionStatus, registerFlowSession, stopFlowSession, stopMergeWorker, syncFlowSessionUsage } from "../services/sessions.js";
|
|
@@ -38,6 +39,8 @@ import { finishVnextPlan, isVnextPlanRun, startVnextPlan } from "../services/vne
|
|
|
38
39
|
import { dispatchVnextPlanReview, finishVnextPlanReview, isVnextPlanReviewRun, recordVnextPlanReviewCapacity, startVnextPlanReview } from "../services/vnext-plan-review.js";
|
|
39
40
|
import { addVnextCodeRepair, finishVnextCode, startVnextCode } from "../services/vnext-code.js";
|
|
40
41
|
import { addVnextCodeReviewRepair, finishVnextCodeReview, isVnextCodeReviewRun, startVnextCodeReview } from "../services/vnext-code-review.js";
|
|
42
|
+
import { applyVnextMerge, finishVnextMerge, getVnextMergeRequest, isVnextMergeRun, routeVnextMergeRequest, startVnextMerge } from "../services/vnext-merge.js";
|
|
43
|
+
import { mergeServerStatus, serveMergeRequests, stopMergeServer } from "../services/merge-server.js";
|
|
41
44
|
import { getVnextFanoutStatus } from "../services/vnext-fanout.js";
|
|
42
45
|
import { pauseStageForUser, resumeStageAfterUser } from "../services/stage-pause.js";
|
|
43
46
|
import { blockStageForRuntime, unblockStageAfterRuntimeRepair } from "../services/stage-blocker.js";
|
|
@@ -217,7 +220,7 @@ function progressForCommand(args) {
|
|
|
217
220
|
];
|
|
218
221
|
}
|
|
219
222
|
if ((family === "cleanup" && command === "apply") ||
|
|
220
|
-
|
|
223
|
+
family === "merge" ||
|
|
221
224
|
family === "merge-worker" ||
|
|
222
225
|
(family === "protocol" && command === "cancel") ||
|
|
223
226
|
(family === "project" && command === "archive") ||
|
|
@@ -666,7 +669,7 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
|
|
|
666
669
|
projectRoot: requiredScopeProjectRoot(scopeProjectRoot, "work repair add"),
|
|
667
670
|
runId: requiredOption(parsed, "run"),
|
|
668
671
|
findingIds: findings,
|
|
669
|
-
|
|
672
|
+
checkRefsByFinding: Object.fromEntries(findings.map((finding) => [finding, parsed.options.get("check-ref") ?? []])),
|
|
670
673
|
objective: await readStdin(io.stdin)
|
|
671
674
|
});
|
|
672
675
|
if (!hasOption(parsed, "from-check"))
|
|
@@ -678,7 +681,6 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
|
|
|
678
681
|
runId: requiredOption(parsed, "run"),
|
|
679
682
|
checkReceiptId: requiredOption(parsed, "from-check"),
|
|
680
683
|
originWorkIds: origins,
|
|
681
|
-
writeScope: parsed.options.get("write-scope") ?? [],
|
|
682
684
|
objective: await readStdin(io.stdin)
|
|
683
685
|
});
|
|
684
686
|
}
|
|
@@ -783,6 +785,10 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
|
|
|
783
785
|
hookEventId ??= claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
|
|
784
786
|
return attachExternalStageContext(startVnextCodeReview(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }), externalContext);
|
|
785
787
|
}
|
|
788
|
+
if (!bootstrap && stage === "merge" && isVnextMergeRun(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id") })) {
|
|
789
|
+
hookEventId ??= claimVnextStageStart(requiredPosition(parsed, 0, "run-id"));
|
|
790
|
+
return attachExternalStageContext(await startVnextMerge(context, { projectRoot, runId: requiredPosition(parsed, 0, "run-id"), hookEventId, progress: commandProgress(io, output), ...(contextSha256 ? { contextSha256 } : {}), ...(externalContext ? { externalContext } : {}) }), externalContext);
|
|
791
|
+
}
|
|
786
792
|
if (intakeStdin) {
|
|
787
793
|
throw new AppError("usage", "--intake-stdin is only available for vNext SPECIFY", 2);
|
|
788
794
|
}
|
|
@@ -855,6 +861,11 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
|
|
|
855
861
|
throw new AppError("usage", "vNext CODE-REVIEW uses --decision-file", 2);
|
|
856
862
|
return await finishVnextCodeReview(context, { projectRoot, runId, ...(optionalOption(parsed, "decision-file") ? { decisionFile: optionalOption(parsed, "decision-file") } : {}), progress: commandProgress(io, output) });
|
|
857
863
|
}
|
|
864
|
+
if (stage === "merge" && isVnextMergeRun(context, { projectRoot, runId })) {
|
|
865
|
+
if (resultStdin || semanticFile || resultFile || hasOption(parsed, "outcome"))
|
|
866
|
+
throw new AppError("usage", "vNext MERGE uses the Work result path returned by stage start", 2);
|
|
867
|
+
return await finishVnextMerge(context, { projectRoot, runId, requestId: requiredOption(parsed, "request"), workId: requiredOption(parsed, "work"), progress: commandProgress(io, output) });
|
|
868
|
+
}
|
|
858
869
|
if (hasOption(parsed, "outcome") || hasOption(parsed, "result-file") || resultStdin) {
|
|
859
870
|
throw new AppError("usage", "--outcome, --result-file and --result-stdin are only available for vNext SPECIFY", 2);
|
|
860
871
|
}
|
|
@@ -922,7 +933,7 @@ async function dispatch(args, context, io, scopeProjectRoot = null, classificati
|
|
|
922
933
|
return dispatchMergeQueue(context, command, parsed, requiredScopeProjectRootForOptional(scopeProjectRoot, command, parsed));
|
|
923
934
|
}
|
|
924
935
|
if (family === "merge") {
|
|
925
|
-
return dispatchMerge(context, command, parsed);
|
|
936
|
+
return await dispatchMerge(context, command, parsed, commandProgress(io, output));
|
|
926
937
|
}
|
|
927
938
|
if (family === "merge-worker") {
|
|
928
939
|
return dispatchMergeWorker(context, command, parsed);
|
|
@@ -1158,7 +1169,35 @@ function dispatchMergeQueue(context, command, parsed, scopeProjectRoot) {
|
|
|
1158
1169
|
}
|
|
1159
1170
|
throw new AppError("usage", `Unknown merge-queue command: ${command ?? "<empty>"}`, 2);
|
|
1160
1171
|
}
|
|
1161
|
-
function dispatchMerge(context, command, parsed) {
|
|
1172
|
+
async function dispatchMerge(context, command, parsed, progress) {
|
|
1173
|
+
if (command === "serve") {
|
|
1174
|
+
const pollSeconds = optionalPositiveNumber(parsed, "poll-seconds");
|
|
1175
|
+
const maxParallelProjects = optionalPositiveNumber(parsed, "max-parallel-projects", true);
|
|
1176
|
+
return await serveMergeRequests(context, { profileId: requiredOption(parsed, "agent-profile"), once: hasOption(parsed, "once"), ...(pollSeconds ? { pollSeconds } : {}), ...(maxParallelProjects ? { maxParallelProjects } : {}), ...(progress ? { progress } : {}) });
|
|
1177
|
+
}
|
|
1178
|
+
if (command === "server") {
|
|
1179
|
+
const action = requiredPosition(parsed, 0, "server action");
|
|
1180
|
+
if (action === "status")
|
|
1181
|
+
return mergeServerStatus(context);
|
|
1182
|
+
if (action === "stop")
|
|
1183
|
+
return stopMergeServer(context, { serverId: requiredPosition(parsed, 1, "server-id") });
|
|
1184
|
+
throw new AppError("usage", `Unknown merge server action: ${action}`, 2);
|
|
1185
|
+
}
|
|
1186
|
+
if (command === "apply")
|
|
1187
|
+
return applyVnextMerge(context, { projectRoot: requiredOption(parsed, "project-root"), requestId: requiredPosition(parsed, 0, "merge-request-id"), workId: requiredOption(parsed, "work"), ...(progress ? { progress } : {}) });
|
|
1188
|
+
if (command === "request") {
|
|
1189
|
+
const action = requiredPosition(parsed, 0, "request action");
|
|
1190
|
+
const requestId = requiredPosition(parsed, 1, "merge-request-id");
|
|
1191
|
+
if (action === "status")
|
|
1192
|
+
return getVnextMergeRequest(context, { projectRoot: requiredOption(parsed, "project-root"), requestId });
|
|
1193
|
+
if (action === "route") {
|
|
1194
|
+
const mode = requiredOption(parsed, "mode");
|
|
1195
|
+
if (mode !== "same_session" && mode !== "server")
|
|
1196
|
+
throw new AppError("usage", "--mode must be same_session or server", 2);
|
|
1197
|
+
return routeVnextMergeRequest(context, { projectRoot: requiredOption(parsed, "project-root"), requestId, mode, reason: requiredOption(parsed, "reason") });
|
|
1198
|
+
}
|
|
1199
|
+
throw new AppError("usage", `Unknown merge request action: ${action}`, 2);
|
|
1200
|
+
}
|
|
1162
1201
|
if (command === "status") {
|
|
1163
1202
|
return getMergeWorkerStatus(context, { projectRoot: requiredOption(parsed, "project-root"), workspacePath: optionalOption(parsed, "path") });
|
|
1164
1203
|
}
|
|
@@ -1989,26 +2028,7 @@ function parseFlowFlagOverrides(values) {
|
|
|
1989
2028
|
return result;
|
|
1990
2029
|
}
|
|
1991
2030
|
function parseArgs(args) {
|
|
1992
|
-
|
|
1993
|
-
const options = new Map();
|
|
1994
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
1995
|
-
const value = args[index];
|
|
1996
|
-
if (value?.startsWith("--")) {
|
|
1997
|
-
const key = value.slice(2);
|
|
1998
|
-
const next = args[index + 1];
|
|
1999
|
-
if (!next || next.startsWith("--")) {
|
|
2000
|
-
options.set(key, [...(options.get(key) ?? []), flagValue]);
|
|
2001
|
-
}
|
|
2002
|
-
else {
|
|
2003
|
-
options.set(key, [...(options.get(key) ?? []), next]);
|
|
2004
|
-
index += 1;
|
|
2005
|
-
}
|
|
2006
|
-
}
|
|
2007
|
-
else if (value) {
|
|
2008
|
-
positional.push(value);
|
|
2009
|
-
}
|
|
2010
|
-
}
|
|
2011
|
-
return { positional, options };
|
|
2031
|
+
return parseCommandArgs(args);
|
|
2012
2032
|
}
|
|
2013
2033
|
function requiredPosition(parsed, index, label) {
|
|
2014
2034
|
const value = parsed.positional[index];
|
|
@@ -2082,6 +2102,15 @@ function optionalNumber(parsed, key) {
|
|
|
2082
2102
|
}
|
|
2083
2103
|
return parsedNumber;
|
|
2084
2104
|
}
|
|
2105
|
+
function optionalPositiveNumber(parsed, key, integer = false) {
|
|
2106
|
+
const value = optionalNumber(parsed, key);
|
|
2107
|
+
if (typeof value === "undefined")
|
|
2108
|
+
return undefined;
|
|
2109
|
+
if (value <= 0 || (integer && !Number.isInteger(value))) {
|
|
2110
|
+
throw new AppError("validation", `--${key} must be a positive${integer ? " integer" : ""} number`, 2);
|
|
2111
|
+
}
|
|
2112
|
+
return value;
|
|
2113
|
+
}
|
|
2085
2114
|
function requiredWorkerId(parsed) {
|
|
2086
2115
|
return requiredOption(parsed, "worker-id");
|
|
2087
2116
|
}
|
|
@@ -2176,7 +2205,7 @@ function projectRootForMutation(context, args, result, resolvedScope) {
|
|
|
2176
2205
|
if (family === "merge-queue") {
|
|
2177
2206
|
return projectRootForMergeQueueMutation(context, command, parsed);
|
|
2178
2207
|
}
|
|
2179
|
-
if (family === "merge" &&
|
|
2208
|
+
if (family === "merge" && ["one-shot", "apply", "request"].includes(command ?? "")) {
|
|
2180
2209
|
return requiredOption(parsed, "project-root");
|
|
2181
2210
|
}
|
|
2182
2211
|
if (family === "merge-worker" && ["start", "stop"].includes(command ?? "")) {
|
|
@@ -5,8 +5,8 @@ export const vnextStages = [
|
|
|
5
5
|
{ id: "plan", directory: "03-plan", result: "stage-report.json", schema: "dd-flow/stage-report@2", next: ["plan-review", "code"] },
|
|
6
6
|
{ id: "plan-review", directory: "04-plan-review", result: "decision.json", schema: "dd-flow/plan-review-decision@3", next: ["code"] },
|
|
7
7
|
{ id: "code", directory: "05-code", result: "code-verification.json", schema: "dd-flow/code-verification@2", next: ["code-review", "merge"] },
|
|
8
|
-
{ id: "code-review", directory: "06-code-review", result: "decision.json", schema: "dd-flow/code-review-decision@
|
|
9
|
-
{ id: "merge", directory: "07-merge", result: "
|
|
8
|
+
{ id: "code-review", directory: "06-code-review", result: "decision.json", schema: "dd-flow/code-review-decision@3", next: ["merge"] },
|
|
9
|
+
{ id: "merge", directory: "07-merge", result: "stage-report.json", schema: "dd-flow/stage-report@2", next: [] }
|
|
10
10
|
];
|
|
11
11
|
export function vnextStage(id) {
|
|
12
12
|
const stage = vnextStages.find((candidate) => candidate.id === id);
|
|
@@ -113,7 +113,7 @@ function validateExecutionContext(input, itemId) {
|
|
|
113
113
|
prompt_profile: requireString(context.prompt_profile, `Plan item ${itemId} execution_context.prompt_profile`),
|
|
114
114
|
required_read: requireStringArray(context.required_read, `Plan item ${itemId} execution_context.required_read`),
|
|
115
115
|
discovery_boundary: requireStringArray(context.discovery_boundary, `Plan item ${itemId} execution_context.discovery_boundary`),
|
|
116
|
-
|
|
116
|
+
planned_write_areas: requireStringArray(context.planned_write_areas, `Plan item ${itemId} execution_context.planned_write_areas`),
|
|
117
117
|
checks: requireStringArray(context.checks, `Plan item ${itemId} execution_context.checks`)
|
|
118
118
|
};
|
|
119
119
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "dd-flow/agent-profile@1",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schema_id", "id", "harness", "provider", "model", "reasoning", "mode", "permission"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_id": {"const": "dd-flow/agent-profile@1"},
|
|
9
|
+
"id": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$"},
|
|
10
|
+
"harness": {"enum": ["codex", "zcode", "agy", "opencode", "grok"]},
|
|
11
|
+
"provider": {"type": "string", "minLength": 1},
|
|
12
|
+
"model": {"type": "string", "minLength": 1},
|
|
13
|
+
"reasoning": {"type": "string", "minLength": 1},
|
|
14
|
+
"mode": {"type": "string", "minLength": 1},
|
|
15
|
+
"permission": {"enum": ["allow", "deny"]}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "dd-flow/code-review-decision@
|
|
3
|
+
"$id": "dd-flow/code-review-decision@3",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"additionalProperties": false,
|
|
6
6
|
"required": ["schema_id", "summary", "findings"],
|
|
7
7
|
"properties": {
|
|
8
|
-
"schema_id": {"const": "dd-flow/code-review-decision@
|
|
8
|
+
"schema_id": {"const": "dd-flow/code-review-decision@3"},
|
|
9
9
|
"summary": {"type": "string", "minLength": 1},
|
|
10
10
|
"findings": {
|
|
11
11
|
"type": "array",
|
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
"finding_ref": {"type": "string", "pattern": "^WRK-[^/]+/FIND-[0-9]{3}$"},
|
|
18
18
|
"disposition": {"enum": ["fix", "defer", "reject", "duplicate"]},
|
|
19
19
|
"reason": {"type": "string", "minLength": 1},
|
|
20
|
+
"check_refs": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "pattern": "^CHK-[A-Za-z0-9-]+$"}},
|
|
20
21
|
"def_id": {"type": "string", "minLength": 1},
|
|
21
22
|
"duplicate_of": {"type": "string", "minLength": 1}
|
|
22
|
-
}
|
|
23
|
+
},
|
|
24
|
+
"allOf": [{"if": {"properties": {"disposition": {"const": "fix"}}}, "then": {"required": ["check_refs"]}}]
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"$id": "dd-flow/code-work-batch@
|
|
3
|
+
"$id": "dd-flow/code-work-batch@5",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"additionalProperties": false,
|
|
6
6
|
"required": ["schema_id", "sources", "works"],
|
|
7
7
|
"properties": {
|
|
8
|
-
"schema_id": {"const": "dd-flow/code-work-batch@
|
|
8
|
+
"schema_id": {"const": "dd-flow/code-work-batch@5"},
|
|
9
9
|
"sources": {"type": "array", "minItems": 1, "items": {"type": "object", "additionalProperties": false, "required": ["plan_id", "protocol_id", "revision", "sha256"], "properties": {"plan_id": {"type": "string", "minLength": 1}, "protocol_id": {"type": "string", "minLength": 1}, "revision": {"type": "integer", "minimum": 1}, "sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}}}},
|
|
10
10
|
"works": {"type": "array", "minItems": 1, "items": {"$ref": "#/$defs/work"}}
|
|
11
11
|
},
|
|
@@ -19,6 +19,6 @@
|
|
|
19
19
|
"check": {"type": "object", "additionalProperties": false, "required": ["id", "command", "purpose", "run_at", "availability"], "properties": {"id": {"type": "string", "pattern": "^CHK-[A-Za-z0-9-]+$"}, "command": {"type": "string", "minLength": 1}, "purpose": {"type": "string", "minLength": 1}, "run_at": {"enum": ["work", "code", "readiness", "merge", "release", "external"]}, "availability": {"enum": ["available", "planned"]}, "provided_by": {"type": "string", "minLength": 1}, "definition": {"type": "string", "minLength": 1}, "required_artifacts": {"type": "array", "uniqueItems": true, "items": {"type": "string", "minLength": 1}}}, "allOf": [{"if": {"properties": {"availability": {"const": "planned"}}, "required": ["availability"]}, "then": {"required": ["provided_by", "definition"], "properties": {"command": {"pattern": "^@check/"}}}}]},
|
|
20
20
|
"documentUpdate": {"type": "object", "additionalProperties": false, "required": ["path", "action", "owner", "reason", "baseline_sha256"], "properties": {"path": {"type": "string", "minLength": 1}, "action": {"enum": ["create", "update"]}, "owner": {"type": "string", "minLength": 1}, "reason": {"type": "string", "minLength": 1}, "baseline_sha256": {"type": ["string", "null"], "pattern": "^[a-f0-9]{64}$"}}},
|
|
21
21
|
"repair": {"type": "object", "additionalProperties": false, "required": ["origin_work_ids"], "anyOf": [{"required": ["check_receipt_id", "failure_receipt_path"]}, {"required": ["review_finding_ids", "review_evidence_refs"]}], "properties": {"origin_work_ids": {"$ref": "#/$defs/strings"}, "check_receipt_id": {"type": "string", "minLength": 1}, "failure_receipt_path": {"type": "string", "minLength": 1}, "review_finding_ids": {"$ref": "#/$defs/strings"}, "review_evidence_refs": {"$ref": "#/$defs/strings"}}},
|
|
22
|
-
"work": {"type": "object", "additionalProperties": false, "required": ["schema_id", "key", "launch_policy", "source", "task", "semantic_spine", "requirements", "acceptance", "document_updates", "required_read", "discovery_boundary", "
|
|
22
|
+
"work": {"type": "object", "additionalProperties": false, "required": ["schema_id", "key", "launch_policy", "source", "task", "semantic_spine", "requirements", "acceptance", "document_updates", "required_read", "discovery_boundary", "planned_write_areas", "checks", "provides_checks", "stop_conditions", "depends_on", "result_schema"], "properties": {"schema_id": {"const": "dd-flow/code-work-packet@5"}, "key": {"type": "string", "minLength": 1}, "launch_policy": {"const": "fresh_agent_required"}, "source": {"$ref": "#/$defs/source"}, "repair": {"$ref": "#/$defs/repair"}, "task": {"type": "string", "minLength": 1}, "semantic_spine": {"$ref": "#/$defs/spine"}, "requirements": {"type": "array", "minItems": 1, "items": {"$ref": "#/$defs/obligation"}}, "acceptance": {"type": "array", "items": {"$ref": "#/$defs/acceptance"}}, "document_updates": {"type": "array", "items": {"$ref": "#/$defs/documentUpdate"}}, "required_read": {"$ref": "#/$defs/strings", "description": "Mandatory starting sources, not a read allowlist."}, "discovery_boundary": {"$ref": "#/$defs/strings", "description": "Likely discovery areas; additional project-local reads are allowed."}, "planned_write_areas": {"type": "array", "items": {"type": "string", "minLength": 1}, "description": "Soft coordination hints only. A worker may change any necessary project file inside the RUN workspace."}, "checks": {"type": "array", "minItems": 1, "items": {"$ref": "#/$defs/check"}}, "provides_checks": {"type": "array", "items": {"$ref": "#/$defs/check"}}, "stop_conditions": {"$ref": "#/$defs/strings", "description": "Hard semantic or external stop conditions; path prediction drift is not a stop condition."}, "depends_on": {"type": "array", "uniqueItems": true, "items": {"type": "string", "minLength": 1}}, "result_schema": {"const": "dd-flow/code-work-result@2"}}}
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -51,6 +51,38 @@
|
|
|
51
51
|
"status": { "type": "string", "minLength": 1 }
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
|
+
"upgrade_contract": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"additionalProperties": false,
|
|
57
|
+
"required": ["model", "authorization", "storage_mutation", "run_creation", "post_sync_routing", "contexts", "order"],
|
|
58
|
+
"properties": {
|
|
59
|
+
"model": { "const": "dual_context_target_routing" },
|
|
60
|
+
"authorization": { "const": "command_allowlist" },
|
|
61
|
+
"storage_mutation": { "const": "explicit_migration_apply_only" },
|
|
62
|
+
"run_creation": { "const": "after_storage_readiness" },
|
|
63
|
+
"post_sync_routing": { "const": "marker_free_project_current" },
|
|
64
|
+
"contexts": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"const": ["project_current", "upgrade_target", "effective_execution"]
|
|
67
|
+
},
|
|
68
|
+
"order": {
|
|
69
|
+
"type": "array",
|
|
70
|
+
"const": [
|
|
71
|
+
"pin_target_canon",
|
|
72
|
+
"verify_target_router",
|
|
73
|
+
"resolve_contexts",
|
|
74
|
+
"read_only_diagnostics",
|
|
75
|
+
"check_shared_home_activity",
|
|
76
|
+
"verify_backup",
|
|
77
|
+
"plan_adjacent_migration",
|
|
78
|
+
"apply_migration_explicitly",
|
|
79
|
+
"create_upgrade_run",
|
|
80
|
+
"sync_canonical_layer",
|
|
81
|
+
"verify_marker_free_normal_route"
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
54
86
|
"contracts": {
|
|
55
87
|
"type": "object",
|
|
56
88
|
"additionalProperties": false,
|
|
@@ -34,12 +34,13 @@
|
|
|
34
34
|
"specifications": {
|
|
35
35
|
"type": "array",
|
|
36
36
|
"minItems": 3,
|
|
37
|
+
"uniqueItems": true,
|
|
37
38
|
"items": {
|
|
38
39
|
"type": "object",
|
|
39
40
|
"additionalProperties": false,
|
|
40
41
|
"required": ["id", "version", "sha256"],
|
|
41
42
|
"properties": {
|
|
42
|
-
"id": {"enum": ["SPC-004", "SPC-005", "SPC-006"]},
|
|
43
|
+
"id": {"enum": ["SPC-004", "SPC-005", "SPC-006", "SPC-009", "SPC-010", "SPC-011"]},
|
|
43
44
|
"version": {"type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"},
|
|
44
45
|
"sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}
|
|
45
46
|
}
|
|
@@ -180,7 +181,7 @@
|
|
|
180
181
|
"source_of_truth": {"const": "canonical prompts and schemas"},
|
|
181
182
|
"runtime_owner": {"const": "dd-flow-cli"},
|
|
182
183
|
"lint_owner": {"const": "mb-lint"},
|
|
183
|
-
"integrated_gate": {"
|
|
184
|
+
"integrated_gate": {"type": "string", "minLength": 1}
|
|
184
185
|
}
|
|
185
186
|
}
|
|
186
187
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "dd-flow/merge-result@1",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schema_id", "outcome", "summary", "conflict_resolution", "verification_summary", "residual_risks"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_id": {"const": "dd-flow/merge-result@1"},
|
|
9
|
+
"outcome": {"enum": ["completed", "blocked"]},
|
|
10
|
+
"summary": {"type": "string", "minLength": 1},
|
|
11
|
+
"conflict_resolution": {"type": "string"},
|
|
12
|
+
"verification_summary": {"type": "string", "minLength": 1},
|
|
13
|
+
"residual_risks": {"type": "array", "items": {"type": "string", "minLength": 1}}
|
|
14
|
+
}
|
|
15
|
+
}
|