ultra-builder-pro-cli 0.22.0 → 0.23.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 +38 -0
- package/README.md +55 -25
- package/adapters/_shared/codex-assets.cjs +8 -3
- package/adapters/_shared/interaction-contract.cjs +13 -6
- package/adapters/_shared/runtime-assets.cjs +1 -1
- package/adapters/claude.js +1 -1
- package/adapters/kimi.js +1 -1
- package/adapters/opencode.js +1 -1
- package/docs/AGENT-CONTEXT.md +38 -40
- package/docs/ARCHITECTURE.md +29 -33
- package/docs/ARTIFACT-AUTHORITY.md +15 -16
- package/docs/ROADMAP.md +2 -2
- package/docs/RUNTIME-COMPAT-MATRIX.md +7 -6
- package/docs/STATE-DB-ACCESS-POLICY.md +14 -14
- package/docs/WORKFLOW-LIFECYCLE.md +39 -33
- package/mcp-server/lib/artifact-registry.cjs +25 -1
- package/mcp-server/lib/change-workflow.cjs +42 -6
- package/mcp-server/lib/ultra-facade.cjs +646 -0
- package/mcp-server/lib/workflow-state.cjs +166 -2
- package/mcp-server/server.cjs +73 -21
- package/package.json +1 -1
- package/skills/ultra-change/SKILL.md +38 -98
- package/skills/ultra-deliver/SKILL.md +42 -65
- package/skills/ultra-dev/SKILL.md +34 -88
- package/skills/ultra-doctor/SKILL.md +35 -57
- package/skills/ultra-init/SKILL.md +37 -78
- package/skills/ultra-plan/SKILL.md +52 -132
- package/skills/ultra-research/SKILL.md +41 -100
- package/skills/ultra-review/SKILL.md +25 -46
- package/skills/ultra-status/SKILL.md +21 -44
- package/skills/ultra-test/SKILL.md +25 -61
- package/skills/ultra-think/SKILL.md +29 -48
- package/skills/ultra-think/references/decision-dialogue.md +6 -4
- package/spec/cli-protocol.md +12 -0
- package/spec/mcp-tools.yaml +159 -0
- package/spec/schemas/mcp-tools.schema.json +1 -1
|
@@ -59,14 +59,12 @@ inspect -> suggest -> host-native ask -> normalize -> persist -> apply -> read b
|
|
|
59
59
|
The host-native ask is conditional. An explicit owner instruction can already resolve
|
|
60
60
|
a choice, so the model must not ask
|
|
61
61
|
again merely to manufacture proof. When interaction is needed, the adapter uses the
|
|
62
|
-
host-native question surface. Once the model
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
raw prompt, or transcript.
|
|
62
|
+
host-native question surface. Once the model batches the normalized result through
|
|
63
|
+
`ultra.record`, the DB treats that result as current cross-session intent authority. It
|
|
64
|
+
does not store or verify a UI receipt, raw prompt, or transcript.
|
|
66
65
|
|
|
67
66
|
If the accepted decision changes another Ultra authority, the model applies that change
|
|
68
|
-
through
|
|
69
|
-
typed `applied_refs` to `decision.complete`. A decision whose normalized record is
|
|
67
|
+
through `ultra.record` or a digest-bound artifact and reads the result back. A decision whose normalized record is
|
|
70
68
|
itself the complete authority may have no applied reference. Breadcrumb and decision
|
|
71
69
|
read paths recall accepted intent only after the dialogue thread is completed or
|
|
72
70
|
confirmed. A row-backed applied reference names an exact field and canonical value,
|
|
@@ -77,7 +75,7 @@ the exact file digest. Row existence alone never proves that intent was applied.
|
|
|
77
75
|
|
|
78
76
|
Working material becomes durable only when all applicable conditions hold:
|
|
79
77
|
|
|
80
|
-
1. the
|
|
78
|
+
1. the current Change and owner authority permit the write;
|
|
81
79
|
2. consequential claims are verified against the checkout, runtime, test result, or
|
|
82
80
|
primary source;
|
|
83
81
|
3. the model writes through the owning MCP operation or immutable artifact path;
|
|
@@ -122,9 +120,9 @@ as delivered.
|
|
|
122
120
|
|
|
123
121
|
## Context and plan authority
|
|
124
122
|
|
|
125
|
-
|
|
126
|
-
and provider-reference authority and writes one immutable manifest plus its
|
|
127
|
-
row. It never updates provider references or semantic Change fields. Each snapshot is
|
|
123
|
+
The Context compiler used by `ultra.checkpoint` reads accepted Change, task, baseline,
|
|
124
|
+
checkout, and provider-reference authority and writes one immutable manifest plus its
|
|
125
|
+
DB snapshot row. It never updates provider references or semantic Change fields. Each snapshot is
|
|
128
126
|
identified exactly by `change_id`, nullable `task_id`, `role`, and `gate`; consumers
|
|
129
127
|
must not substitute a newer snapshot from a different tuple.
|
|
130
128
|
|
|
@@ -141,8 +139,8 @@ A current plan is a Change-owned pair:
|
|
|
141
139
|
- `<artifact_root>/plan.md` is the deterministic human projection of the same plan and
|
|
142
140
|
task contracts.
|
|
143
141
|
|
|
144
|
-
|
|
145
|
-
path.
|
|
142
|
+
The Plan checkpoint selects both paths from the owning Change and accepts no arbitrary
|
|
143
|
+
output path. It binds the JSON digest and the preceding `plan/planning` snapshot;
|
|
146
144
|
the artifact registry records both plan files with that context provenance. Publication
|
|
147
145
|
preflights both path authorities and prior digests, rejects symlinked ancestors or
|
|
148
146
|
targets, and journals the two file replacements so a registry or event failure restores
|
|
@@ -152,7 +150,7 @@ never current write or dispatch authority.
|
|
|
152
150
|
|
|
153
151
|
## Registry contract
|
|
154
152
|
|
|
155
|
-
`
|
|
153
|
+
`ultra.record` is the public writer for a semantic or evidence file that is not
|
|
156
154
|
already registered by its owning workflow operation. Every managed registry row has:
|
|
157
155
|
|
|
158
156
|
- a typed `owner_type` and `owner_id`;
|
|
@@ -190,7 +188,7 @@ pretending that an old row satisfies the current registry contract.
|
|
|
190
188
|
|
|
191
189
|
## Dependency and orphan diagnosis
|
|
192
190
|
|
|
193
|
-
`
|
|
191
|
+
`ultra.doctor` compares the registry, dependency graph, filesystem, and owner
|
|
194
192
|
tables. It reports:
|
|
195
193
|
|
|
196
194
|
- unregistered semantic or evidence files;
|
|
@@ -235,7 +233,7 @@ Change creation or update, plan acceptance, durable task-contract or status chan
|
|
|
235
233
|
task expansion or deletion, and Change convergence or archive. A direct edit is
|
|
236
234
|
rejected by host hooks and fails digest validation even without hooks.
|
|
237
235
|
|
|
238
|
-
`
|
|
236
|
+
`ultra.sync { action: import }` validates schema, full and per-record digests, bounded ancestry,
|
|
239
237
|
Change ownership, task parents, and local active sessions. A clean record fast-forwards.
|
|
240
238
|
A record changed on both sides, a non-descendant checkpoint, or a remote update to a
|
|
241
239
|
locally active task stops with a typed conflict. Re-importing the same checkpoint
|
|
@@ -245,7 +243,8 @@ HEAD, scope bytes, verification, or accepted dirty state. Publication remains bl
|
|
|
245
243
|
until that local baseline converges, preventing one unvalidated checkout from
|
|
246
244
|
downgrading team authority.
|
|
247
245
|
|
|
248
|
-
Legacy v4.4/v4.5 projections are replaced only through
|
|
246
|
+
Legacy v4.4/v4.5 projections are replaced only through
|
|
247
|
+
`ultra.sync { action: publish }`. The
|
|
249
248
|
publisher first compares every available durable field with SQLite, writes the exact
|
|
250
249
|
legacy bytes to `.ultra/.runtime/backups/task-ledger/`, and refuses any mismatch.
|
|
251
250
|
Doctor diagnoses this state but never performs the semantic replacement.
|
package/docs/ROADMAP.md
CHANGED
|
@@ -57,14 +57,14 @@ sharing one authoritative workflow store.
|
|
|
57
57
|
|
|
58
58
|
```
|
|
59
59
|
spec/ ← Phase 1 single source of truth
|
|
60
|
-
├── mcp-tools.yaml (
|
|
60
|
+
├── mcp-tools.yaml (7 public kernel tools + 60 hidden compatibility operations)
|
|
61
61
|
├── cli-protocol.md (CLI ↔ MCP mapping table)
|
|
62
62
|
├── schemas/ (state-db.sql + 4 JSON schemas)
|
|
63
63
|
├── fixtures/{valid,invalid}/ (+ v4.4-project for migration)
|
|
64
64
|
└── scripts/test-all.cjs (npm run test:spec — 7 validation stages)
|
|
65
65
|
|
|
66
66
|
mcp-server/ ← Phase 2 authoritative state layer
|
|
67
|
-
├── server.cjs (stdio MCP server
|
|
67
|
+
├── server.cjs (stdio MCP server with a 7-tool public façade)
|
|
68
68
|
├── lib/
|
|
69
69
|
│ ├── state-db.cjs (SQLite + WAL + pragmas)
|
|
70
70
|
│ ├── state-ops.cjs (full write API, status state machine)
|
|
@@ -46,7 +46,7 @@ not presented as nonexistent custom agents.
|
|
|
46
46
|
|
|
47
47
|
| Lifecycle | Claude Code | OpenCode | Codex | Kimi Code 0.26+ |
|
|
48
48
|
|---|---|---|---|---|
|
|
49
|
-
| Session context/health | FULL, active-workflow breadcrumb on native `SessionStart` | FULL, native JS plugin injects only an active-workflow breadcrumb; health via `
|
|
49
|
+
| Session context/health | FULL, active-workflow breadcrumb on native `SessionStart` | FULL, native JS plugin injects only an active-workflow breadcrumb; health via `ultra.doctor` | FULL, active-workflow breadcrumb on native `SessionStart` | FULL, active-workflow breadcrumb via native hooks |
|
|
50
50
|
| Active edit boundary | FULL, `PreToolUse Edit|Write` | FULL, `tool.execute.before` rejects managed checkpoint/projection writes | FULL, `PreToolUse Edit|Write|apply_patch` | FULL, native `PreToolUse Edit|Write` deny contract |
|
|
51
51
|
| Pre-compact checkpoint | FULL | FULL | FULL | FULL, native `PreCompact` |
|
|
52
52
|
| Post-compact context injection | FULL | FULL, native compacting context | FULL, native `PostCompact` restore | DEGRADED; checkpoint restoration runs, but Kimi 0.26/0.27 does not reinject fire-and-forget hook text |
|
|
@@ -68,7 +68,8 @@ they do not deny edits or stop active incident work.
|
|
|
68
68
|
| Capability | Claude Code | OpenCode | Codex | Kimi Code 0.26+ |
|
|
69
69
|
|---|---|---|---|---|
|
|
70
70
|
| stdio MCP registration | plugin `.mcp.json` | `opencode.json` local MCP entry | plugin `.mcp.json` | plugin `mcpServers` entry |
|
|
71
|
-
|
|
|
71
|
+
| Public discovered MCP tools | 7 | 7 | 7 | 7 |
|
|
72
|
+
| Hidden 0.22 compatibility operations | 60 | 60 | 60 | 60 |
|
|
72
73
|
| Structured user alignment | `AskUserQuestion` in interactive sessions | `question` when permission is not denied | `request_user_input` when the current mode exposes it | `AskUserQuestion` outside auto mode |
|
|
73
74
|
| Greenfield/brownfield baseline adoption | FULL | FULL | FULL | FULL |
|
|
74
75
|
| Context Manifest v3 / breadcrumb | FULL | FULL, same bundled read-only DB reader as every hook | FULL | FULL |
|
|
@@ -79,10 +80,10 @@ they do not deny edits or stop active incident work.
|
|
|
79
80
|
| Git team checkpoint | `.ultra/tasks/tasks.json` | `.ultra/tasks/tasks.json` | `.ultra/tasks/tasks.json` | `.ultra/tasks/tasks.json` |
|
|
80
81
|
| General memory-provider API | N/A | N/A | N/A | N/A |
|
|
81
82
|
|
|
82
|
-
All
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
All hosts discover the seven `ultra.*` persistence and safety tools. The sixty
|
|
84
|
+
fine-grained 0.22 operations remain callable but undiscoverable for one compatibility
|
|
85
|
+
release; new Skills do not call them. Review, impact discovery, skill loading, model
|
|
86
|
+
reasoning, and user interaction remain host-native surfaces.
|
|
86
87
|
|
|
87
88
|
When a native structured question surface is unavailable, the shared interaction
|
|
88
89
|
contract permits one concise direct question only if ordinary conversation is still
|
|
@@ -26,7 +26,7 @@ bugs.
|
|
|
26
26
|
but never `UPDATE` / `DELETE`.
|
|
27
27
|
|
|
28
28
|
The CLI may indirectly mutate ordinary workflow tables by spawning the MCP server over
|
|
29
|
-
stdio and calling
|
|
29
|
+
stdio and calling the public `ultra.*` kernel — but the actual
|
|
30
30
|
SQLite write is performed by the MCP server's writer connection. The documented
|
|
31
31
|
exceptions are initial schema/baseline creation, migration, and explicitly
|
|
32
32
|
authorized backup-first doctor recovery. The CLI never provides a parallel raw
|
|
@@ -36,8 +36,8 @@ The append-only carve-out for `events` exists because `events.id INTEGER
|
|
|
36
36
|
PRIMARY KEY AUTOINCREMENT` makes concurrent inserts collision-free under
|
|
37
37
|
WAL + `busy_timeout`. This lets hooks and short-lived CLI invocations
|
|
38
38
|
record audit observations without paying the cost of a full MCP round trip.
|
|
39
|
-
It does not grant lifecycle authority: external writers
|
|
40
|
-
|
|
39
|
+
It does not grant lifecycle authority: external writers use the published observation
|
|
40
|
+
allowlist, while lifecycle event
|
|
41
41
|
names are emitted only inside the mutation that owns the corresponding state change.
|
|
42
42
|
Consumers must verify mutable rows rather than infer success from an event name.
|
|
43
43
|
|
|
@@ -74,16 +74,16 @@ resolve the mount/runtime constraint before retrying.
|
|
|
74
74
|
|
|
75
75
|
| Table | Writer of record |
|
|
76
76
|
|--------------------|--------------------------------------------------------|
|
|
77
|
-
| `baselines` | MCP server
|
|
78
|
-
| `tasks` | MCP server
|
|
79
|
-
| `changes` | MCP server
|
|
80
|
-
| `decision_threads`, `decision_items` | MCP server
|
|
81
|
-
| `workflow_runs`, `workflow_steps` | MCP server
|
|
82
|
-
| `artifacts`, `artifact_edges` | MCP server
|
|
83
|
-
| `context_snapshots`, `spec_learning_candidates`, `trace_links` | MCP server through
|
|
77
|
+
| `baselines` | MCP server through `ultra.record`, `ultra.checkpoint`, and `ultra.archive`; initialization and legacy migration may create only the first draft or compatibility row |
|
|
78
|
+
| `tasks` | MCP server through `ultra.record`, `ultra.checkpoint`, and `ultra.sync` |
|
|
79
|
+
| `changes` | MCP server through `ultra.record`, `ultra.checkpoint`, and `ultra.archive` |
|
|
80
|
+
| `decision_threads`, `decision_items` | MCP server through `ultra.record`; normalized accepted intent and applied references are stored, never UI receipts, prompts, or transcripts |
|
|
81
|
+
| `workflow_runs`, `workflow_steps` | MCP server internally through `ultra.checkpoint`; Skills supply semantic evidence but never drive individual rows |
|
|
82
|
+
| `artifacts`, `artifact_edges` | MCP server through `ultra.record` and checkpoint-owned registration |
|
|
83
|
+
| `context_snapshots`, `spec_learning_candidates`, `trace_links` | MCP server through `ultra.record` and `ultra.checkpoint` |
|
|
84
84
|
| `incidents`, `projection_jobs`, `event_consumers`, `circuit_breaker` | MCP server; backup-first doctor recovery may perform only documented mechanical transitions |
|
|
85
|
-
| `events` | MCP server for lifecycle events; approved processes and `
|
|
86
|
-
| `sessions` | MCP server
|
|
85
|
+
| `events` | MCP server for lifecycle events; approved processes and `ultra.record` for allowlisted append-only observations |
|
|
86
|
+
| `sessions` | MCP server through `ultra.session`; orchestrator may write status transitions |
|
|
87
87
|
| `telemetry` | MCP server (collected from tool-call wrappers); orchestrator may dump bulk samples |
|
|
88
88
|
| `specs_refs` | MCP server (rebuilt on `spec_changed` event); orchestrator may rebuild |
|
|
89
89
|
| `migration_history`| schema initializer and `ultra-tools migrate` or doctor repair |
|
|
@@ -91,8 +91,8 @@ resolve the mount/runtime constraint before retrying.
|
|
|
91
91
|
|
|
92
92
|
## 5. Git team checkpoint
|
|
93
93
|
|
|
94
|
-
Only `
|
|
95
|
-
`
|
|
94
|
+
Only `ultra.sync { action: publish }` may derive `.ultra/tasks/tasks.json` from SQLite,
|
|
95
|
+
and only `ultra.sync { action: import }` may merge it into SQLite. Server startup performs one import after
|
|
96
96
|
opening project authority; later pulls in a long-running process require an explicit
|
|
97
97
|
import. The same checkpoint is idempotent and must not append an event again.
|
|
98
98
|
|
|
@@ -11,7 +11,7 @@ host and project owner. It is the operational companion to
|
|
|
11
11
|
|---|---|---|
|
|
12
12
|
| Active host and owner | Product judgment, research content, implementation, review findings, and authorization for destructive or external effects | Durable workflow status or fabricated evidence digests |
|
|
13
13
|
| Skill | One reusable procedure and its evidence requirements | Project state, static product doctrine, host-specific tool fiction |
|
|
14
|
-
| MCP |
|
|
14
|
+
| MCP | Durable checkpoints, task contracts, evidence references, output hashes, team sync, leases, archives, and mechanical recovery | Semantic route selection, research prose, code generation, general memory-provider payloads, or model calls |
|
|
15
15
|
| `.ultra/.runtime/state.db` | Checkout-local lifecycle, index, transition, freshness, and coordination authority for baseline, change, decision, task, workflow, session, event, incident, projection, and evidence references | Prompts, transcripts, general external-memory payloads, semantic prose, or code-graph payloads |
|
|
16
16
|
| `.ultra/tasks/tasks.json` | MCP-published Git checkpoint for portable baseline, Change, task-contract, dependency, and durable status records | Live sessions, leases, `in_progress` ownership, completion hashes, or a parallel write API |
|
|
17
17
|
| Digest-bound artifacts | Registered specification, research, Change, context, test, review, delivery, and verification bodies | Independent lifecycle state or content whose digest no longer matches |
|
|
@@ -22,19 +22,22 @@ Together, `.ultra/` is project-local cross-session workflow memory. The detailed
|
|
|
22
22
|
artifact classes and promotion rules live in
|
|
23
23
|
[`ARTIFACT-AUTHORITY.md`](./ARTIFACT-AUTHORITY.md).
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
as MCP authority.
|
|
25
|
+
Model input can supply facts, content paths, reasons, owner decisions, and evidence
|
|
26
|
+
references. `ultra.record` stores mutable typed drafts and `ultra.checkpoint` attempts
|
|
27
|
+
one durable semantic commit. A semantic rejection returns diagnostics and keeps the
|
|
28
|
+
draft editable. Model input cannot override a task's public seam, evidence digest, or
|
|
29
|
+
accepted checkpoint. A host recommendation is never stored as MCP authority.
|
|
31
30
|
|
|
32
|
-
Load-bearing owner choices are normalized through `
|
|
33
|
-
durable authority. The host acquires observable facts autonomously, exposes one
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
Load-bearing owner choices are normalized through `ultra.record`; prompt prose is not
|
|
32
|
+
durable authority. The host acquires observable facts autonomously, exposes one current
|
|
33
|
+
question, and stops. Unanswered material choices remain warnings or checkpoint
|
|
34
|
+
diagnostics until a capability truly needs their result. A normalized answer alone
|
|
35
|
+
does not require a ceremonial checkpoint.
|
|
36
|
+
|
|
37
|
+
Every host discovers seven public MCP tools: `ultra.context`, `ultra.record`,
|
|
38
|
+
`ultra.checkpoint`, `ultra.sync`, `ultra.session`, `ultra.archive`, and
|
|
39
|
+
`ultra.doctor`. The 0.22 fine-grained operations documented below remain hidden
|
|
40
|
+
compatibility internals for one release. Skills must not drive them one call at a time.
|
|
38
41
|
|
|
39
42
|
Every change-bound research, plan, dev, test, review, and deliver run inherits
|
|
40
43
|
the baseline id from the owning change workflow. A Prompt cannot switch that
|
|
@@ -190,8 +193,10 @@ execution failure.
|
|
|
190
193
|
### Workflow run and step
|
|
191
194
|
|
|
192
195
|
```text
|
|
193
|
-
|
|
194
|
-
|
|
196
|
+
draft: active <-> blocked <-> ready
|
|
197
|
+
| | |
|
|
198
|
+
+----------+---------+----> cancelled
|
|
199
|
+
\----> completed (accepted, immutable)
|
|
195
200
|
|
|
196
201
|
step: pending -> in_progress -> completed
|
|
197
202
|
| |
|
|
@@ -199,10 +204,10 @@ step: pending -> in_progress -> completed
|
|
|
199
204
|
blocked ------> in_progress/completed
|
|
200
205
|
```
|
|
201
206
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
207
|
+
Fine-grained steps are internal evidence bookkeeping. `ultra.checkpoint` records and
|
|
208
|
+
validates them in one public call. A missing output returns mutable diagnostics. Draft
|
|
209
|
+
artifact changes reopen `ready` to `active`; only an accepted `completed` revision is
|
|
210
|
+
immutable.
|
|
206
211
|
|
|
207
212
|
### Decision thread and item
|
|
208
213
|
|
|
@@ -315,7 +320,8 @@ opens one replacement.
|
|
|
315
320
|
|
|
316
321
|
## 6. Context and prompt follow-through
|
|
317
322
|
|
|
318
|
-
|
|
323
|
+
The Context compiler used internally by `ultra.checkpoint` creates an immutable
|
|
324
|
+
Context Manifest v3 snapshot. It combines:
|
|
319
325
|
|
|
320
326
|
- the bound baseline/change/task identity;
|
|
321
327
|
- a role and lifecycle gate;
|
|
@@ -328,11 +334,10 @@ opens one replacement.
|
|
|
328
334
|
- optional metadata-only external memory or graph references;
|
|
329
335
|
- advisory file/token/context-share budgets, including inline Change/task authority;
|
|
330
336
|
- the current Change and task authority digests;
|
|
331
|
-
- readiness
|
|
332
|
-
unique hard-recovery path.
|
|
337
|
+
- readiness warnings and hard mechanical blockers without a semantic route command.
|
|
333
338
|
|
|
334
339
|
Compilation is pure with respect to accepted Change authority. Provider references are
|
|
335
|
-
|
|
340
|
+
recorded through `ultra.record`; they cannot be smuggled into a checkpoint context.
|
|
336
341
|
Context references retain `expected_digest`, `anchor`, `scope`, and
|
|
337
342
|
`freshness_policy`. `digest` requires byte-current content, `existence` allows an
|
|
338
343
|
implementation target to change while remaining present, and `advisory` reports drift
|
|
@@ -349,9 +354,9 @@ Critical stage workflows bind a matching snapshot as a durable output:
|
|
|
349
354
|
| `deliver` | `check` | `convergence` |
|
|
350
355
|
|
|
351
356
|
Every lookup is exact on `change_id + task_id + role + gate`. The snapshot path and
|
|
352
|
-
digest are carried into plan, test, review, and delivery artifacts.
|
|
353
|
-
writes
|
|
354
|
-
exact planning snapshot and digest to
|
|
357
|
+
digest are carried into plan, test, review, and delivery artifacts. The Plan
|
|
358
|
+
`ultra.checkpoint` writes the owning Change's `plan.json` and deterministic `plan.md`
|
|
359
|
+
once, and binds the exact planning snapshot and digest to the artifact registry.
|
|
355
360
|
The legacy global `.ultra/execution-plan.json` is read-only migration compatibility,
|
|
356
361
|
not current authority. These rules prevent a later Prompt or a different role packet
|
|
357
362
|
from claiming evidence gathered under another context. Referenced file content remains
|
|
@@ -389,9 +394,9 @@ evidence do block.
|
|
|
389
394
|
fast-forward or conflict handling.
|
|
390
395
|
- A changed checkpoint artifact digest or superseded decision invalidates the linked
|
|
391
396
|
decision checkpoint and blocks matching workflow advancement until reconfirmed.
|
|
392
|
-
-
|
|
393
|
-
|
|
394
|
-
|
|
397
|
+
- A rejected draft is repaired in place or explicitly abandoned. A new accepted
|
|
398
|
+
revision preserves prior accepted history and invalidates only true transitive
|
|
399
|
+
registered consumers.
|
|
395
400
|
|
|
396
401
|
## 8. Entry flows
|
|
397
402
|
|
|
@@ -459,13 +464,14 @@ evidence rather than bypassing them.
|
|
|
459
464
|
| `ultra-doctor` | read-only diagnosis and authorized mechanical recovery | required recovery only when unique; otherwise safe alternatives |
|
|
460
465
|
|
|
461
466
|
Every row permits `ultra-think` when material owner authority is missing and permits
|
|
462
|
-
`ultra-doctor` when state or installed-runtime authority is unhealthy.
|
|
463
|
-
|
|
464
|
-
|
|
467
|
+
`ultra-doctor` when state or installed-runtime authority is unhealthy. The host model
|
|
468
|
+
recommends either from current evidence; hard MCP blockers remain limited to the
|
|
469
|
+
mechanical safety boundary. Neither capability creates a parallel workflow or
|
|
470
|
+
substitutes a prompt summary for DB state.
|
|
465
471
|
|
|
466
472
|
## 9. Recovery and diagnosis
|
|
467
473
|
|
|
468
|
-
Use `
|
|
474
|
+
Use `ultra.doctor` for project authority and
|
|
469
475
|
`ubp --all --global --doctor` for installed host assets. Both are read-only
|
|
470
476
|
unless an explicit project repair command is chosen.
|
|
471
477
|
|
|
@@ -505,10 +505,34 @@ function invalidateConsumersFromEndpointInTx(db, start, {
|
|
|
505
505
|
}
|
|
506
506
|
if (endpoint.type === 'workflow') {
|
|
507
507
|
const row = db.prepare(
|
|
508
|
-
'SELECT metadata_json, change_id, task_id FROM workflow_runs WHERE id = ?',
|
|
508
|
+
'SELECT status, metadata_json, change_id, task_id FROM workflow_runs WHERE id = ?',
|
|
509
509
|
).get(endpoint.id);
|
|
510
510
|
if (row) {
|
|
511
511
|
const metadata = parseJson(row.metadata_json, {});
|
|
512
|
+
if (['active', 'blocked', 'ready'].includes(row.status)) {
|
|
513
|
+
delete metadata.authority_invalidation;
|
|
514
|
+
metadata.draft_dirty = true;
|
|
515
|
+
db.prepare(
|
|
516
|
+
`UPDATE workflow_runs
|
|
517
|
+
SET status = CASE WHEN status = 'ready' THEN 'active' ELSE status END,
|
|
518
|
+
metadata_json = ?,
|
|
519
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
520
|
+
WHERE id = ?`,
|
|
521
|
+
).run(JSON.stringify(metadata), endpoint.id);
|
|
522
|
+
ops.appendEventInTx(db, {
|
|
523
|
+
type: 'workflow_draft_changed',
|
|
524
|
+
change_id: row.change_id,
|
|
525
|
+
task_id: row.task_id,
|
|
526
|
+
payload: {
|
|
527
|
+
workflow_id: endpoint.id,
|
|
528
|
+
source_type: start.type,
|
|
529
|
+
source_id: start.id,
|
|
530
|
+
reason,
|
|
531
|
+
},
|
|
532
|
+
});
|
|
533
|
+
queue.push(...outgoingEdges(db, endpoint));
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
512
536
|
if (metadata.authority_invalidation?.invalidated !== true) {
|
|
513
537
|
metadata.authority_invalidation = {
|
|
514
538
|
invalidated: true,
|
|
@@ -39,7 +39,7 @@ const SEMANTIC_AUTHORITY_FIELDS = new Set([
|
|
|
39
39
|
const CHANGE_TRANSITIONS = Object.freeze({
|
|
40
40
|
active: new Set(['active', 'blocked', 'cancelled']),
|
|
41
41
|
blocked: new Set(['active', 'blocked', 'cancelled']),
|
|
42
|
-
ready: new Set(['ready']),
|
|
42
|
+
ready: new Set(['active', 'ready', 'cancelled']),
|
|
43
43
|
archived: new Set(),
|
|
44
44
|
cancelled: new Set(),
|
|
45
45
|
});
|
|
@@ -702,11 +702,8 @@ function compileContext(db, input, { rootDir = process.cwd() } = {}) {
|
|
|
702
702
|
const recommendation = spine.recommendation;
|
|
703
703
|
const durableSpine = { ...spine };
|
|
704
704
|
delete durableSpine.recommendation;
|
|
705
|
-
const
|
|
706
|
-
const manifest = {
|
|
705
|
+
const semanticManifest = {
|
|
707
706
|
schema_version: '3.0',
|
|
708
|
-
snapshot_id: snapshotId,
|
|
709
|
-
generated_at: nowIso(),
|
|
710
707
|
change: {
|
|
711
708
|
id: change.id, title: change.title, kind: change.kind, status: change.status,
|
|
712
709
|
intent: change.intent, docs_impact: change.docs_impact, base_commit: change.base_commit,
|
|
@@ -734,6 +731,43 @@ function compileContext(db, input, { rootDir = process.cwd() } = {}) {
|
|
|
734
731
|
providers,
|
|
735
732
|
provider_boundary: 'metadata references only; memory and code graph content remain external',
|
|
736
733
|
};
|
|
734
|
+
const identityHash = crypto.createHash('sha256')
|
|
735
|
+
.update(JSON.stringify(semanticManifest))
|
|
736
|
+
.digest('hex');
|
|
737
|
+
const snapshotId = `ctx-${identityHash.slice(0, 12)}`;
|
|
738
|
+
const existing = db.prepare(
|
|
739
|
+
`SELECT manifest_path, manifest_hash
|
|
740
|
+
FROM context_snapshots WHERE id = ?`,
|
|
741
|
+
).get(snapshotId);
|
|
742
|
+
if (existing) {
|
|
743
|
+
const existingPath = path.resolve(rootDir, existing.manifest_path);
|
|
744
|
+
if (!fs.existsSync(existingPath)) {
|
|
745
|
+
throw new ChangeWorkflowError(
|
|
746
|
+
'CONTEXT_SNAPSHOT_CORRUPT',
|
|
747
|
+
`content-addressed Context snapshot is missing: ${existing.manifest_path}`,
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
const bytes = fs.readFileSync(existingPath);
|
|
751
|
+
const existingHash = crypto.createHash('sha256').update(bytes).digest('hex');
|
|
752
|
+
if (existingHash !== existing.manifest_hash) {
|
|
753
|
+
throw new ChangeWorkflowError(
|
|
754
|
+
'CONTEXT_SNAPSHOT_CORRUPT',
|
|
755
|
+
`content-addressed Context snapshot digest changed: ${existing.manifest_path}`,
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
return {
|
|
759
|
+
manifest: JSON.parse(bytes.toString('utf8')),
|
|
760
|
+
recommendation,
|
|
761
|
+
context_manifest_path: existingPath,
|
|
762
|
+
manifest_hash: existingHash,
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
const manifest = {
|
|
766
|
+
schema_version: semanticManifest.schema_version,
|
|
767
|
+
snapshot_id: snapshotId,
|
|
768
|
+
generated_at: nowIso(),
|
|
769
|
+
...Object.fromEntries(Object.entries(semanticManifest).filter(([key]) => key !== 'schema_version')),
|
|
770
|
+
};
|
|
737
771
|
const artifactDir = path.resolve(rootDir, change.artifact_root);
|
|
738
772
|
fs.mkdirSync(artifactDir, { recursive: true });
|
|
739
773
|
const manifestPath = path.join(artifactDir, 'contexts', `${snapshotId}.json`);
|
|
@@ -1005,7 +1039,7 @@ function assertTaskCreationAllowed(db, input = {}, { rootDir = process.cwd() } =
|
|
|
1005
1039
|
function updateChange(db, id, patch = {}, { rootDir = process.cwd() } = {}) {
|
|
1006
1040
|
const current = readChange(db, id);
|
|
1007
1041
|
if (!current) throw new ChangeWorkflowError('CHANGE_NOT_FOUND', `change ${id} not found`);
|
|
1008
|
-
if (['
|
|
1042
|
+
if (['archived', 'cancelled'].includes(current.status)) {
|
|
1009
1043
|
throw new ChangeWorkflowError('CHANGE_NOT_MUTABLE', `change ${id} is ${current.status}`);
|
|
1010
1044
|
}
|
|
1011
1045
|
for (const field of Object.keys(patch)) {
|
|
@@ -1059,6 +1093,8 @@ function updateChange(db, id, patch = {}, { rootDir = process.cwd() } = {}) {
|
|
|
1059
1093
|
);
|
|
1060
1094
|
}
|
|
1061
1095
|
sets.push('status = ?'); values.push(patch.status);
|
|
1096
|
+
} else if (current.status === 'ready' && Object.keys(patch).length > 0) {
|
|
1097
|
+
sets.push('status = ?'); values.push('active');
|
|
1062
1098
|
}
|
|
1063
1099
|
if (sets.length === 0) return current;
|
|
1064
1100
|
sets.push('updated_at = ?'); values.push(nowIso(), id);
|