ultra-builder-pro-cli 0.16.0 → 0.17.1
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/.ultra-template/reports/templates/delivery-report.json +17 -0
- package/.ultra-template/reports/templates/test-report.json +18 -0
- package/.ultra-template/specs/research-distillate.md +4 -3
- package/CHANGELOG.md +95 -0
- package/README.md +54 -24
- package/adapters/_shared/codex-assets.cjs +10 -5
- package/adapters/_shared/handbook.cjs +1 -1
- package/adapters/_shared/interaction-contract.cjs +61 -0
- package/adapters/claude.js +1 -1
- package/adapters/opencode.js +1 -1
- package/bin/orchestrator.js +175 -19
- package/commands/ultra-change.md +1 -1
- package/commands/ultra-deliver.md +3 -3
- package/commands/ultra-init.md +1 -1
- package/commands/ultra-plan.md +1 -1
- package/commands/ultra-research.md +2 -2
- package/commands/ultra-review.md +10 -0
- package/commands/ultra-status.md +1 -1
- package/commands/ultra-test.md +1 -1
- package/docs/AGENT-CONTEXT.md +11 -8
- package/docs/ARCHITECTURE.md +67 -9
- package/docs/LEGACY-CLI-CROSSWALK.md +163 -0
- package/docs/PLAN.zh-CN.md +19 -13
- package/docs/RUNTIME-COMPAT-MATRIX.md +2 -2
- package/docs/WORKFLOW-LIFECYCLE.md +123 -59
- package/hooks/pre_stop_check.py +3 -2
- package/mcp-server/lib/baseline-workflow.cjs +84 -16
- package/mcp-server/lib/change-workflow.cjs +55 -35
- package/mcp-server/lib/context-spine.cjs +171 -105
- package/mcp-server/lib/git-bootstrap.cjs +240 -0
- package/mcp-server/lib/init-project.cjs +178 -41
- package/mcp-server/lib/project-breadcrumb.cjs +14 -14
- package/mcp-server/lib/state-db.cjs +257 -10
- package/mcp-server/lib/state-ops.cjs +64 -1
- package/mcp-server/lib/workflow-state.cjs +300 -205
- package/mcp-server/server.cjs +58 -34
- package/orchestrator/auto-merge.cjs +19 -0
- package/orchestrator/daemon.cjs +104 -0
- package/orchestrator/parallel-orchestrator.cjs +371 -49
- package/orchestrator/session-runner.cjs +354 -25
- package/package.json +2 -1
- package/skills/ultra-change/SKILL.md +69 -94
- package/skills/ultra-deliver/SKILL.md +37 -65
- package/skills/ultra-dev/SKILL.md +50 -52
- package/skills/ultra-doctor/SKILL.md +34 -49
- package/skills/ultra-init/SKILL.md +78 -105
- package/skills/ultra-plan/SKILL.md +78 -99
- package/skills/ultra-research/SKILL.md +99 -113
- package/skills/ultra-review/SKILL.md +38 -53
- package/skills/ultra-review/references/review-modes.md +5 -3
- package/skills/ultra-review/references/unified-schema.md +26 -6
- package/skills/ultra-review/scripts/review_wait.py +12 -0
- package/skills/ultra-status/SKILL.md +34 -44
- package/skills/ultra-test/SKILL.md +61 -54
- package/skills/ultra-think/SKILL.md +37 -51
- package/skills/ultra-think/references/decision-dialogue.md +87 -111
- package/spec/cli-protocol.md +35 -0
- package/spec/mcp-tools.yaml +145 -28
- package/spec/schemas/delivery-report.v1.schema.json +1 -46
- package/spec/schemas/state-db.sql +8 -2
- package/spec/schemas/test-report.v1.schema.json +45 -14
- package/ultra-tools/cli.cjs +1 -1
- package/ultra-tools/commands/session.cjs +10 -3
- package/ultra-tools/commands/status.cjs +19 -14
- package/ultra-tools/commands/system.cjs +2 -2
- package/ultra-tools/commands/task.cjs +3 -0
package/bin/orchestrator.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* ubp-orchestrator — Phase 5.4 daemon CLI.
|
|
5
5
|
*
|
|
6
6
|
* Subcommands:
|
|
7
|
+
* execute-plan resume the current plan through the first unfinished dependency wave.
|
|
7
8
|
* run foreground daemon (debug / test).
|
|
8
9
|
* start detached background daemon, writes .ultra/orchestrator.pid.
|
|
9
10
|
* stop reads pidfile, SIGTERM the process, deletes pidfile.
|
|
@@ -12,9 +13,8 @@
|
|
|
12
13
|
* Opt-in gate: `start` and `run` require settings.json
|
|
13
14
|
* `orchestrator.auto_dispatch: true` — default off per PLAN Phase 5.4 AC.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* the worktree out-of-band. command/args can be passed via env for testing.
|
|
16
|
+
* Dispatch requires both explicit opt-in and an explicit executable command.
|
|
17
|
+
* A daemon may never reserve a session/worktree without a real worker process.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
'use strict';
|
|
@@ -56,6 +56,124 @@ function parseRuntimes() {
|
|
|
56
56
|
return runtimes;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
function commandConfigError(code, message) {
|
|
60
|
+
const error = new Error(message);
|
|
61
|
+
error.code = code;
|
|
62
|
+
return error;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resolveDispatchCommand(settings, env = process.env) {
|
|
66
|
+
const configured = settings?.orchestrator || {};
|
|
67
|
+
const fromEnvironment = typeof env.UBP_ORCH_COMMAND === 'string'
|
|
68
|
+
&& env.UBP_ORCH_COMMAND.trim() !== '';
|
|
69
|
+
const command = fromEnvironment
|
|
70
|
+
? env.UBP_ORCH_COMMAND.trim()
|
|
71
|
+
: (typeof configured.command === 'string' ? configured.command.trim() : '');
|
|
72
|
+
if (!command) {
|
|
73
|
+
throw commandConfigError(
|
|
74
|
+
'ORCHESTRATOR_COMMAND_REQUIRED',
|
|
75
|
+
'orchestrator dispatch requires orchestrator.command or UBP_ORCH_COMMAND',
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
if (/\s/.test(command) && !fs.existsSync(command)) {
|
|
79
|
+
throw commandConfigError(
|
|
80
|
+
'ORCHESTRATOR_COMMAND_INVALID',
|
|
81
|
+
'orchestrator.command must contain only the executable; put arguments in command_args',
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let commandArgs;
|
|
86
|
+
if (fromEnvironment && env.UBP_ORCH_ARGS_JSON !== undefined) {
|
|
87
|
+
try {
|
|
88
|
+
commandArgs = JSON.parse(env.UBP_ORCH_ARGS_JSON);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
throw commandConfigError(
|
|
91
|
+
'ORCHESTRATOR_COMMAND_INVALID',
|
|
92
|
+
`UBP_ORCH_ARGS_JSON must be a JSON array: ${error.message}`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
commandArgs = configured.command_args === undefined ? [] : configured.command_args;
|
|
97
|
+
}
|
|
98
|
+
if (!Array.isArray(commandArgs) || commandArgs.some((arg) => typeof arg !== 'string')) {
|
|
99
|
+
throw commandConfigError(
|
|
100
|
+
'ORCHESTRATOR_COMMAND_INVALID',
|
|
101
|
+
'orchestrator command arguments must be an array of strings',
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
command,
|
|
106
|
+
commandArgs: commandArgs.slice(),
|
|
107
|
+
source: fromEnvironment ? 'environment' : 'settings',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function parseExecutePlanArgs(argv = []) {
|
|
112
|
+
const options = {
|
|
113
|
+
planPath: null,
|
|
114
|
+
autoMerge: false,
|
|
115
|
+
mergeBaseBranch: 'main',
|
|
116
|
+
};
|
|
117
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
118
|
+
const arg = argv[index];
|
|
119
|
+
if (arg === '--auto-merge') {
|
|
120
|
+
options.autoMerge = true;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (arg === '--plan' || arg === '--base-branch') {
|
|
124
|
+
const value = argv[index + 1];
|
|
125
|
+
if (!value || value.startsWith('--')) {
|
|
126
|
+
throw commandConfigError(
|
|
127
|
+
'ORCHESTRATOR_ARGUMENT_INVALID',
|
|
128
|
+
`${arg} requires a value`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (arg === '--plan') options.planPath = value;
|
|
132
|
+
else options.mergeBaseBranch = value;
|
|
133
|
+
index += 1;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
throw commandConfigError(
|
|
137
|
+
'ORCHESTRATOR_ARGUMENT_INVALID',
|
|
138
|
+
`unknown execute-plan option: ${arg}`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
return options;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function cmdExecutePlan(argv = []) {
|
|
145
|
+
const settings = readSettings();
|
|
146
|
+
const dispatch = resolveDispatchCommand(settings);
|
|
147
|
+
const options = parseExecutePlanArgs(argv);
|
|
148
|
+
const { initStateDb, closeStateDb } = require('../mcp-server/lib/state-db.cjs');
|
|
149
|
+
const parallelOrchestrator = require('../orchestrator/parallel-orchestrator.cjs');
|
|
150
|
+
const { db } = initStateDb(path.join(REPO_ROOT, '.ultra', 'state.db'));
|
|
151
|
+
try {
|
|
152
|
+
const result = await parallelOrchestrator.runPlan({
|
|
153
|
+
db,
|
|
154
|
+
repoRoot: REPO_ROOT,
|
|
155
|
+
planPath: options.planPath ? path.resolve(REPO_ROOT, options.planPath) : undefined,
|
|
156
|
+
runtimes: parseRuntimes(),
|
|
157
|
+
command: dispatch.command,
|
|
158
|
+
commandArgs: dispatch.commandArgs,
|
|
159
|
+
autoMerge: options.autoMerge,
|
|
160
|
+
mergeBaseBranch: options.mergeBaseBranch,
|
|
161
|
+
onError: (error) => process.stderr.write(`orchestrator error: ${error.message}\n`),
|
|
162
|
+
});
|
|
163
|
+
process.stdout.write(`${JSON.stringify({
|
|
164
|
+
ok: true,
|
|
165
|
+
data: {
|
|
166
|
+
...result,
|
|
167
|
+
auto_merge: options.autoMerge,
|
|
168
|
+
merge_base_branch: options.mergeBaseBranch,
|
|
169
|
+
},
|
|
170
|
+
})}\n`);
|
|
171
|
+
return result;
|
|
172
|
+
} finally {
|
|
173
|
+
closeStateDb(db);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
59
177
|
function cmdRun(opts = {}) {
|
|
60
178
|
const settings = readSettings();
|
|
61
179
|
if (!opts.skipOptIn && !optInAllowed(settings)) {
|
|
@@ -68,11 +186,14 @@ function cmdRun(opts = {}) {
|
|
|
68
186
|
const { initStateDb } = require('../mcp-server/lib/state-db.cjs');
|
|
69
187
|
const { runDaemon } = require('../orchestrator/daemon.cjs');
|
|
70
188
|
const runtimes = parseRuntimes();
|
|
189
|
+
const dispatch = resolveDispatchCommand(settings);
|
|
71
190
|
const { db } = initStateDb(path.join(REPO_ROOT, '.ultra', 'state.db'));
|
|
72
191
|
const handle = runDaemon({
|
|
73
192
|
db,
|
|
74
193
|
repoRoot: REPO_ROOT,
|
|
75
194
|
runtimes,
|
|
195
|
+
command: dispatch.command,
|
|
196
|
+
commandArgs: dispatch.commandArgs,
|
|
76
197
|
pollMs: Number(process.env.UBP_ORCH_POLL_MS || 1000),
|
|
77
198
|
onError: (err) => process.stderr.write(`orchestrator error: ${err.message}\n`),
|
|
78
199
|
});
|
|
@@ -85,7 +206,10 @@ function cmdRun(opts = {}) {
|
|
|
85
206
|
};
|
|
86
207
|
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
87
208
|
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
88
|
-
process.stderr.write(
|
|
209
|
+
process.stderr.write(
|
|
210
|
+
`orchestrator running (pollMs=${Number(process.env.UBP_ORCH_POLL_MS || 1000)}, ` +
|
|
211
|
+
`runtimes=${runtimes.join(',')}, worker=${dispatch.command}, source=${dispatch.source})\n`,
|
|
212
|
+
);
|
|
89
213
|
// Keep process alive while the setInterval is unref'd.
|
|
90
214
|
setInterval(() => {}, 60000);
|
|
91
215
|
}
|
|
@@ -96,6 +220,7 @@ function cmdStart() {
|
|
|
96
220
|
process.stderr.write('orchestrator.auto_dispatch is not enabled; refusing to start.\n');
|
|
97
221
|
process.exit(2);
|
|
98
222
|
}
|
|
223
|
+
resolveDispatchCommand(settings);
|
|
99
224
|
if (fs.existsSync(PIDFILE)) {
|
|
100
225
|
const existing = Number(fs.readFileSync(PIDFILE, 'utf8'));
|
|
101
226
|
try { process.kill(existing, 0); }
|
|
@@ -170,8 +295,9 @@ function cmdStatus() {
|
|
|
170
295
|
|
|
171
296
|
function usage() {
|
|
172
297
|
process.stderr.write(
|
|
173
|
-
'usage: ubp-orchestrator <run|start|stop|status>\n' +
|
|
298
|
+
'usage: ubp-orchestrator <execute-plan|run|start|stop|status>\n' +
|
|
174
299
|
'\n' +
|
|
300
|
+
' execute-plan resume the first unfinished dependency wave [--plan <path>] [--auto-merge] [--base-branch <name>]\n' +
|
|
175
301
|
' run foreground daemon (requires opt-in)\n' +
|
|
176
302
|
' start detached background daemon (requires opt-in)\n' +
|
|
177
303
|
' stop terminate running daemon\n' +
|
|
@@ -179,18 +305,48 @@ function usage() {
|
|
|
179
305
|
);
|
|
180
306
|
}
|
|
181
307
|
|
|
182
|
-
|
|
183
|
-
const subcommand = argv[0];
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
308
|
+
async function main(argv = process.argv.slice(2)) {
|
|
309
|
+
const subcommand = argv[0];
|
|
310
|
+
try {
|
|
311
|
+
switch (subcommand) {
|
|
312
|
+
case 'execute-plan': await cmdExecutePlan(argv.slice(1)); break;
|
|
313
|
+
case 'run': cmdRun(); break;
|
|
314
|
+
case 'start': cmdStart(); break;
|
|
315
|
+
case 'stop': cmdStop(); break;
|
|
316
|
+
case 'status': cmdStatus(); break;
|
|
317
|
+
case '-h':
|
|
318
|
+
case '--help':
|
|
319
|
+
case 'help':
|
|
320
|
+
usage(); process.exit(0);
|
|
321
|
+
break;
|
|
322
|
+
default:
|
|
323
|
+
usage(); process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
} catch (error) {
|
|
326
|
+
process.stderr.write(
|
|
327
|
+
`orchestrator configuration error${error.code ? ` [${error.code}]` : ''}: ${error.message}\n`,
|
|
328
|
+
);
|
|
329
|
+
process.exit(2);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (require.main === module) {
|
|
334
|
+
main().catch((error) => {
|
|
335
|
+
process.stderr.write(`orchestrator fatal error: ${error.message}\n`);
|
|
336
|
+
process.exit(2);
|
|
337
|
+
});
|
|
196
338
|
}
|
|
339
|
+
|
|
340
|
+
module.exports = {
|
|
341
|
+
readSettings,
|
|
342
|
+
optInAllowed,
|
|
343
|
+
parseRuntimes,
|
|
344
|
+
parseExecutePlanArgs,
|
|
345
|
+
resolveDispatchCommand,
|
|
346
|
+
cmdExecutePlan,
|
|
347
|
+
cmdRun,
|
|
348
|
+
cmdStart,
|
|
349
|
+
cmdStop,
|
|
350
|
+
cmdStatus,
|
|
351
|
+
main,
|
|
352
|
+
};
|
package/commands/ultra-change.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Capture or revise one bounded Change Contract without starting downstream workflows
|
|
3
3
|
argument-hint: "[change-id-or-title] [quick|standard|major|incident]"
|
|
4
4
|
workflow-ref: "@skills/ultra-change/SKILL.md"
|
|
5
5
|
---
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Converge current evidence and
|
|
3
|
-
argument-hint: "[
|
|
2
|
+
description: Converge current evidence and archive local Ultra authority without external release effects
|
|
3
|
+
argument-hint: "[change-id]"
|
|
4
4
|
workflow-ref: "@skills/ultra-deliver/SKILL.md"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Converge and deliver
|
|
8
8
|
|
|
9
|
-
Read and follow `@skills/ultra-deliver/SKILL.md`, using `$ARGUMENTS` only
|
|
9
|
+
Read and follow `@skills/ultra-deliver/SKILL.md`, using `$ARGUMENTS` only to select the change.
|
|
10
10
|
Treat the referenced skill as the only workflow definition.
|
package/commands/ultra-init.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Create or recover Ultra project authority without implicitly starting research
|
|
3
3
|
argument-hint: "[name] [type] [stack] [auto|greenfield|brownfield] [--scope <path>]"
|
|
4
4
|
workflow-ref: "@skills/ultra-init/SKILL.md"
|
|
5
5
|
---
|
package/commands/ultra-plan.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Persist dependency-valid vertical task contracts from an accepted Change Contract
|
|
3
3
|
argument-hint: "[scope]"
|
|
4
4
|
workflow-ref: "@skills/ultra-plan/SKILL.md"
|
|
5
5
|
---
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Build
|
|
2
|
+
description: Build evidence with model-selected semantic coverage and adaptive user alignment
|
|
3
3
|
argument-hint: "[scope-or-question]"
|
|
4
4
|
workflow-ref: "@skills/ultra-research/SKILL.md"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Research
|
|
7
|
+
# Research one bounded question or baseline
|
|
8
8
|
|
|
9
9
|
Read and follow `@skills/ultra-research/SKILL.md`, using `$ARGUMENTS` to bound the research scope.
|
|
10
10
|
Treat the referenced skill as the only workflow definition.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Review one plan, task diff, or aggregate change on independent specification and engineering axes
|
|
3
|
+
argument-hint: "[plan|task|change] [id]"
|
|
4
|
+
workflow-ref: "@skills/ultra-review/SKILL.md"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Review one bounded Ultra scope
|
|
8
|
+
|
|
9
|
+
Read and follow `@skills/ultra-review/SKILL.md`, using `$ARGUMENTS` to select the review mode and authority.
|
|
10
|
+
Treat the referenced skill as the only workflow definition.
|
package/commands/ultra-status.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Report authoritative Ultra health,
|
|
2
|
+
description: Report authoritative Ultra health, evidence freshness, and valid capability transitions
|
|
3
3
|
argument-hint: "[task-or-change-id]"
|
|
4
4
|
workflow-ref: "@skills/ultra-status/SKILL.md"
|
|
5
5
|
---
|
package/commands/ultra-test.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Run
|
|
2
|
+
description: Run independent, risk-selected verification and record current acceptance evidence
|
|
3
3
|
argument-hint: "[scope]"
|
|
4
4
|
workflow-ref: "@skills/ultra-test/SKILL.md"
|
|
5
5
|
---
|
package/docs/AGENT-CONTEXT.md
CHANGED
|
@@ -80,23 +80,26 @@ review, and deliver route back to the same thread instead of deciding for the ow
|
|
|
80
80
|
One partial unique index permits only one open item per thread. `decision.resolve`,
|
|
81
81
|
`decision.delegate`, and `decision.defer` preserve the source of authority;
|
|
82
82
|
`decision.supersede` preserves history when evidence or intent changes. Prepare and
|
|
83
|
-
confirm checkpointing bind
|
|
84
|
-
|
|
85
|
-
and
|
|
83
|
+
confirm checkpointing bind a material accepted cluster to current artifact digests
|
|
84
|
+
when interruption recovery needs that boundary. Status and breadcrumb return only the
|
|
85
|
+
current question plus allowed and mechanically required transitions, so recovery does
|
|
86
|
+
not require replaying conversation history.
|
|
86
87
|
|
|
87
88
|
## 5. Context Spine contract
|
|
88
89
|
|
|
89
|
-
Context Manifest
|
|
90
|
+
Context Manifest v3 is an immutable DB-backed role handoff, not a static codebase summary.
|
|
90
91
|
`change.context` compiles required references, digests, readiness, context budget,
|
|
91
|
-
public seam, exact verification command,
|
|
92
|
-
`implement`, `check`, or `review`. The default 12-file,
|
|
92
|
+
public seam, exact verification command, Change/task authority digests, and valid
|
|
93
|
+
transitions for `plan`, `implement`, `check`, or `review`. The default 12-file,
|
|
94
|
+
about 12k-token, and 40%
|
|
93
95
|
fresh-context values are attention guidance. Overflow produces warnings; it does
|
|
94
96
|
not block work or require raising a threshold. Prefer direct reads, bounded
|
|
95
97
|
excerpts, or a smaller slice when they preserve correctness, and retain all
|
|
96
98
|
necessary context when they do not.
|
|
97
99
|
|
|
98
100
|
`change.breadcrumb` is the only compact router. Hooks may inject its change/task,
|
|
99
|
-
role, gate, readiness, blockers, and
|
|
101
|
+
role, gate, readiness, blockers, `allowed_transitions`, and `required_transition`.
|
|
102
|
+
They must not inject intent
|
|
100
103
|
bodies, transcripts, external memory, or graph payloads. Missing references,
|
|
101
104
|
digest drift, HEAD drift, or a missing execution seam blocks readiness. Context
|
|
102
105
|
size and baseline drift are advisory for a change that is already active. New ordinary
|
|
@@ -176,7 +179,7 @@ Archive before prune; the confirmation token is intentionally required.
|
|
|
176
179
|
├── runtime/
|
|
177
180
|
│ └── checkpoint.json # advisory breadcrumb recovery projection
|
|
178
181
|
├── changes/
|
|
179
|
-
│ ├── active/<id>/ # intent, delta, plan, context
|
|
182
|
+
│ ├── active/<id>/ # intent, delta, plan, context v3, learning, verification
|
|
180
183
|
│ └── archive/ # converged packets after baseline reconciliation
|
|
181
184
|
├── tasks/ # projections and task contexts
|
|
182
185
|
├── specs/ # research/product/architecture artifacts
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -74,7 +74,7 @@ covers twenty-one tables:
|
|
|
74
74
|
|
|
75
75
|
| Table | Holds | Phase |
|
|
76
76
|
|--------------------|---------------------------------------------------|-------|
|
|
77
|
-
| `baselines` | repository classification, greenfield/brownfield adoption,
|
|
77
|
+
| `baselines` | repository classification, greenfield/brownfield adoption, explicit unborn/clean/dirty Git snapshot, specs, evidence, verification, gap ledger, persisted known-red acceptance, and approval | 12→17 |
|
|
78
78
|
| `tasks` | task rows — id, status, deps, files_modified, … | 2 |
|
|
79
79
|
| `events` | append-only event stream; `id` is subscription cursor (D31) | 2 |
|
|
80
80
|
| `sessions` | execution sessions, **including lease + heartbeat fields** (D32) | 4.5 |
|
|
@@ -141,6 +141,19 @@ scripts, and monorepo markers. It detects `greenfield` or `brownfield`, records
|
|
|
141
141
|
bounded classification evidence and selected repository scope, and creates the
|
|
142
142
|
same authoritative state shape without rewriting application code.
|
|
143
143
|
|
|
144
|
+
Initialization completes after local authority, classification, Git/scaffold setup,
|
|
145
|
+
and read-back verification. It does not start or complete research. An explicit
|
|
146
|
+
`ultra-research` invocation then records a disposition for each of the seventeen
|
|
147
|
+
coverage areas and executes, verifies, or reuses only the evidence needed to converge
|
|
148
|
+
the baseline.
|
|
149
|
+
|
|
150
|
+
Auto initialization preserves an existing Git repository and HEAD. When Git is absent,
|
|
151
|
+
it initializes `main`, adds the symlink-safe `.ultra` rule to `.gitignore`, and persists
|
|
152
|
+
the resulting `unborn` snapshot. Existing repositories keep their tracked ignore file
|
|
153
|
+
unchanged. It never creates a commit, remote, tag, or push. An initialized
|
|
154
|
+
repository cannot use a non-Git workspace hash: research must obtain approval for a
|
|
155
|
+
local checkpoint commit before `baseline.record`.
|
|
156
|
+
|
|
144
157
|
Projection-only v4.4 and v4.5 projects use `ultra-tools migrate` to preserve the
|
|
145
158
|
entire `.ultra` tree, import tasks and events, and create a `migrated/adopting`
|
|
146
159
|
compatibility row. Schema upgrades use `ultra-tools system doctor --repair` and
|
|
@@ -212,7 +225,7 @@ impact, and no open incident. Memory and graph payloads never enter Ultra;
|
|
|
212
225
|
|
|
213
226
|
### Context Spine
|
|
214
227
|
|
|
215
|
-
Context Manifest
|
|
228
|
+
Context Manifest v3 is the immutable handoff contract between planning,
|
|
216
229
|
implementation, checking, review, convergence, and recovery. Each snapshot records:
|
|
217
230
|
|
|
218
231
|
- one role (`plan`, `implement`, `check`, or `review`) and lifecycle gate;
|
|
@@ -221,19 +234,24 @@ implementation, checking, review, convergence, and recovery. Each snapshot recor
|
|
|
221
234
|
execution contract;
|
|
222
235
|
- advisory attention budgets (12 files / about 12k tokens / 40% by default);
|
|
223
236
|
- a DB-derived execution contract (`slice_kind`, public seam, exact verification command);
|
|
224
|
-
-
|
|
237
|
+
- mechanically valid `allowed_transitions` and a `required_transition` only when a
|
|
238
|
+
hard invariant leaves one recovery route;
|
|
239
|
+
- a digest of the accepted Change authority so semantic updates invalidate the
|
|
240
|
+
snapshot.
|
|
225
241
|
|
|
226
242
|
Prompt input may identify the intended role/gate, add bounded reference candidates,
|
|
227
243
|
and lower advisory budgets. It cannot supply or override the task seam, verification
|
|
228
244
|
command, task context references, evidence digest, gate verdict, workflow summary, or
|
|
229
|
-
|
|
245
|
+
machine transitions. A host may attach a clearly non-authoritative recommendation.
|
|
246
|
+
Critical dev/test/review/deliver workflow steps record the matching
|
|
230
247
|
snapshot as an output; test, review, and delivery reports carry its digest forward.
|
|
231
248
|
|
|
232
249
|
`change.breadcrumb` derives the compact current position from state.db. Session,
|
|
233
250
|
edit, resume, and OpenCode lifecycle hooks invoke one bundled read-only reader
|
|
234
251
|
and inject only this breadcrumb, never the intent body,
|
|
235
|
-
provider content, or a conversation summary. A changed
|
|
236
|
-
snapshot stale and
|
|
252
|
+
provider content, or a conversation summary. A changed Git HEAD, task contract, or
|
|
253
|
+
Change semantic authority marks the snapshot stale and permits recompilation through
|
|
254
|
+
`change.context`.
|
|
237
255
|
|
|
238
256
|
PRD decomposition and complex-task subdivision use the active host model. The
|
|
239
257
|
MCP accepts the resulting structured tasks, validates schema, topology,
|
|
@@ -275,10 +293,13 @@ authority and the legacy task projection before creating a new brownfield adopti
|
|
|
275
293
|
A **session** is the standard unit of execution across all four runtimes
|
|
276
294
|
(D20). One session =
|
|
277
295
|
|
|
278
|
-
-
|
|
279
|
-
- an isolated `git worktree`,
|
|
296
|
+
- one authoritative task/runtime lease;
|
|
297
|
+
- an isolated `git worktree` created by `session.spawn`,
|
|
298
|
+
- an ignored `.ultra` link from that checkout to the one central authority,
|
|
280
299
|
- a lease + heartbeat row in `sessions` (D32),
|
|
281
|
-
- an `artifact_dir` under `.ultra/sessions/<sid>/` for logs and scratch
|
|
300
|
+
- an `artifact_dir` under `.ultra/sessions/<sid>/` for logs and scratch;
|
|
301
|
+
- either the active host operating in that exact worktree or an explicitly configured
|
|
302
|
+
worker process.
|
|
282
303
|
|
|
283
304
|
Spawning a new session for a task is gated by `session.admission_check`
|
|
284
305
|
(D33). If another session already owns an active lease on the same task,
|
|
@@ -292,6 +313,43 @@ This admission gate is the smallest piece that prevents two agents from
|
|
|
292
313
|
silently double-writing the same task — it is part of the v0.1 minimum
|
|
293
314
|
execution layer, not deferred to Phase 5.
|
|
294
315
|
|
|
316
|
+
Process status is not task status. Exit zero closes transport evidence but leaves the
|
|
317
|
+
task `in_progress` until workflow gates pass; failure blocks the task and records
|
|
318
|
+
circuit evidence. `session.close` preserves its worktree by default. Explicit cleanup
|
|
319
|
+
is allowed only when the worktree is clean and its commit is an ancestor of the
|
|
320
|
+
current checkout.
|
|
321
|
+
|
|
322
|
+
The optional `ubp-orchestrator` daemon requires both `auto_dispatch: true` and an
|
|
323
|
+
explicit executable plus argument array. It refuses to create a session when no real
|
|
324
|
+
worker can consume it. Before launch, the runner verifies that Git ignores the
|
|
325
|
+
symlink itself. When a legacy repository has only the directory-specific `.ultra/`
|
|
326
|
+
rule, the runner adds `.ultra` to the repository-local `info/exclude` file without
|
|
327
|
+
changing a tracked file. It then binds the checkout to the central `.ultra` and rolls
|
|
328
|
+
the worktree back if the ignore rule or binding cannot be established safely. The
|
|
329
|
+
executable is launched without a shell and receives
|
|
330
|
+
the session, task, runtime, worktree, artifact, central DB, checkout root, and
|
|
331
|
+
authority-root paths through reserved `UBP_*` environment variables that caller
|
|
332
|
+
configuration cannot override.
|
|
333
|
+
Pending tasks are skipped while stale, dependency-blocked, circuit-broken, leased, or
|
|
334
|
+
overlapping the declared files of an active task.
|
|
335
|
+
|
|
336
|
+
`execute-plan` is a resumable dispatcher, not a second workflow authority. It runs
|
|
337
|
+
only the exact current DB task graph whose change-bound `plan` workflow is completed,
|
|
338
|
+
healthy, and current. Empty, cyclic, duplicate-task, cross-change, stale, and merely
|
|
339
|
+
exported plans fail before session creation. Owner approval is present only when a
|
|
340
|
+
material planning choice required it. The dispatcher then runs only pending tasks whose
|
|
341
|
+
dependencies are DB-terminal and re-reads task state. If a
|
|
342
|
+
worker exits before the task converges, the current wave and plan become `paused`;
|
|
343
|
+
later waves remain pending. Re-running the command skips completed waves and resumes
|
|
344
|
+
the first unfinished one. `wave_completed` and `plan_completed` therefore describe
|
|
345
|
+
Ultra task convergence, while `wave_paused` and `plan_paused` preserve unfinished
|
|
346
|
+
gate state. Even with explicit auto-merge, integration is attempted only when the
|
|
347
|
+
change task is `completed`, its completion commit matches the session HEAD, its dev
|
|
348
|
+
workflow is ready, and its task review is current; process exit zero is insufficient.
|
|
349
|
+
If task or plan authority changes after wave selection but before worktree creation,
|
|
350
|
+
dispatch reports an authority pause without recording a worker failure or incrementing
|
|
351
|
+
the circuit breaker.
|
|
352
|
+
|
|
295
353
|
## 6. Compaction recovery — checkpoint as a validated consumer
|
|
296
354
|
|
|
297
355
|
`workflow_checkpoint.py` validates the current non-terminal workflow and writes
|