ultra-builder-pro-cli 0.26.0 → 0.26.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/changes/abandoned/.gitkeep +0 -0
- package/.ultra-template/contexts/TEMPLATE.md +7 -0
- package/CHANGELOG.md +67 -1
- package/README.md +1 -1
- package/bin/delegate-worker.cjs +5 -0
- package/bin/delegate.cjs +7 -0
- package/docs/ARCHITECTURE.md +4 -1
- package/docs/DECISIONS.md +4 -2
- package/docs/PHILOSOPHY.md +36 -5
- package/docs/PLUGIN-ISOLATION-CONTRACT.md +6 -3
- package/docs/RUNTIME-COMPAT-MATRIX.md +43 -1
- package/docs/WORKFLOW-LIFECYCLE.md +4 -0
- package/hooks/README.md +5 -3
- package/hooks/block_dangerous_commands.py +116 -10
- package/package.json +1 -1
- package/skills/ultra-change/SKILL.md +25 -7
- package/skills/ultra-change/references/change-contract.md +28 -2
- package/skills/ultra-delegate/SKILL.md +7 -0
- package/skills/ultra-delegate/references/delegation-contract.md +10 -2
- package/skills/ultra-deliver/SKILL.md +40 -3
- package/skills/ultra-dev/SKILL.md +25 -6
- package/skills/ultra-grilling/SKILL.md +58 -19
- package/skills/ultra-grilling/references/reframing.md +72 -0
- package/skills/ultra-init/SKILL.md +12 -4
- package/skills/ultra-plan/SKILL.md +19 -6
- package/skills/ultra-research/SKILL.md +6 -0
- package/skills/ultra-review/SKILL.md +27 -2
- package/skills/ultra-test/SKILL.md +5 -0
|
File without changes
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
<!-- The verifiable definition of done. Read by mid_workflow_recall and session_context, and
|
|
33
33
|
injected into agent context — keep every line testable and keep noise out. -->
|
|
34
34
|
|
|
35
|
+
**Change Acceptance IDs**: [`AC-1`, `AC-3`, or `none` for task-local-only work]
|
|
36
|
+
|
|
35
37
|
- [ ] `exact test command`
|
|
36
38
|
- [ ] Pass: [scenario 1]
|
|
37
39
|
- [ ] Pass: [scenario 2]
|
|
@@ -51,6 +53,11 @@
|
|
|
51
53
|
|
|
52
54
|
**Source**: `.ultra/specs/product.md#section-id`
|
|
53
55
|
|
|
56
|
+
**Hard Constraints**: [`HC-1`, `HC-3`, or `none` — the north-star constraints this
|
|
57
|
+
task could plausibly violate. Read them before the first edit and again before
|
|
58
|
+
marking complete. Crossing one stops the work and goes to the owner, however good
|
|
59
|
+
the argument.]
|
|
60
|
+
|
|
54
61
|
**Decisions**: [relevant `.ultra/decisions/<id>.md` entries, or `none`]
|
|
55
62
|
|
|
56
63
|
## Change Log
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.26.1] — 2026-08-03
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Added reframing to `ultra-grilling`, five bounded framing questions, and checkable
|
|
15
|
+
resolved, stalled, and unavailable exits so a literal request can be translated
|
|
16
|
+
into the role and outcome the owner actually means.
|
|
17
|
+
- Added `HC-<n>` hard-constraint identifiers, task-level constraint mapping,
|
|
18
|
+
executable Change verification, and a supported `changes/abandoned/` exit.
|
|
19
|
+
- Added owner-authorized cross-model-family review for major or security-relevant
|
|
20
|
+
Changes, plus optional native fan-out inside independent research and test regions.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Made `ultra-dev` converge on each task's mapped Change acceptance IDs, track the
|
|
25
|
+
best-ever passing set, and stop after two no-progress rounds or three repair rounds.
|
|
26
|
+
- Expanded delivery reconciliation to every repository document and kept its wiring
|
|
27
|
+
gate local to an explicitly invoked `ultra-deliver`; ordinary npm lifecycle commands
|
|
28
|
+
never depend on project `.ultra/` evidence.
|
|
29
|
+
- Made `ultra-change` read relevant archive history before opening intent, preferring
|
|
30
|
+
`delivery.md` while supporting legacy archive summaries and verification records.
|
|
31
|
+
- Made all six review lenses the default and required every skipped lens to preserve
|
|
32
|
+
its reason in the aggregate result.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- Prevented delegated workers from modifying `.ultra/`, including when `.` grants the
|
|
37
|
+
rest of an isolated checkout.
|
|
38
|
+
- Made dangerous-command authorization reachable by hashing the protected effect
|
|
39
|
+
independently of its retry spelling.
|
|
40
|
+
- Kept additive protected-branch publication on the host's native authority path instead
|
|
41
|
+
of hard-blocking an already owner-authorized release, retained exact-digest guards for
|
|
42
|
+
history rewrites and branch deletion, and stopped treating inert searches as effects.
|
|
43
|
+
- Kept expandable interpreter heredocs inside dangerous-effect inspection while
|
|
44
|
+
continuing to treat quoted commit-message heredocs as data.
|
|
45
|
+
- Required explicit owner authority before `ultra-review` can launch a cross-host
|
|
46
|
+
model-family recheck.
|
|
47
|
+
- Bound `ultra-dev` convergence to the active Change acceptance IDs, with explicit
|
|
48
|
+
stalled and unreachable exits instead of an open-ended repair loop.
|
|
49
|
+
- Made `ultra-change` recover archived intent from legacy archive evidence when the
|
|
50
|
+
preferred delivery record is absent.
|
|
51
|
+
- Kept the `ultra-deliver` wiring gate local to an owner-invoked delivery workflow;
|
|
52
|
+
ordinary package commands remain independent of project `.ultra/` state.
|
|
53
|
+
- Added the missing `changes/abandoned/` template directory and migrated completed WIP
|
|
54
|
+
evidence links to their canonical runtime document.
|
|
55
|
+
|
|
56
|
+
### Verified
|
|
57
|
+
|
|
58
|
+
- Completed an authenticated Claude-to-Codex continuation on one isolated
|
|
59
|
+
file-first task: Claude banked the failing test and Resume Note without changing
|
|
60
|
+
implementation, and Codex resumed from Git plus `.ultra/`, reached green, and
|
|
61
|
+
closed the ledger and canonical evidence without conversation transfer.
|
|
62
|
+
- Verified the release candidate with 111 Node tests, 10 Hook tests, 14 Skill Creator
|
|
63
|
+
validations, five healthy host Doctor reports, and zero audit vulnerabilities.
|
|
64
|
+
|
|
10
65
|
## [0.26.0] — 2026-08-01
|
|
11
66
|
|
|
12
67
|
### Added
|
|
@@ -1167,7 +1222,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1167
1222
|
skill manifest, CLI protocol + mapping table; 5 spec validators.
|
|
1168
1223
|
- **Phase 0 — skeleton**: multi-runtime installer scaffolding.
|
|
1169
1224
|
|
|
1170
|
-
[Unreleased]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.
|
|
1225
|
+
[Unreleased]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.26.1...HEAD
|
|
1226
|
+
[0.26.1]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.26.0...v0.26.1
|
|
1227
|
+
[0.26.0]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.25.1...v0.26.0
|
|
1228
|
+
[0.25.1]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.25.0...v0.25.1
|
|
1229
|
+
[0.25.0]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.24.2...v0.25.0
|
|
1230
|
+
[0.24.2]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.24.1...v0.24.2
|
|
1231
|
+
[0.24.1]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.24.0...v0.24.1
|
|
1232
|
+
[0.24.0]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.23.0...v0.24.0
|
|
1233
|
+
[0.23.0]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.22.0...v0.23.0
|
|
1234
|
+
[0.22.0]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.21.1...v0.22.0
|
|
1235
|
+
[0.21.1]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.21.0...v0.21.1
|
|
1236
|
+
[0.21.0]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.20.0...v0.21.0
|
|
1171
1237
|
[0.20.0]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.19.1...v0.20.0
|
|
1172
1238
|
[0.19.1]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.19.0...v0.19.1
|
|
1173
1239
|
[0.19.0]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.18.0...v0.19.0
|
package/README.md
CHANGED
|
@@ -219,7 +219,7 @@ Five optional hooks accelerate file reading and protect a narrow effect boundary
|
|
|
219
219
|
| `mid_workflow_recall.py` | Restate acceptance before relevant source operations |
|
|
220
220
|
| `compact_context.py` | Save and restore a disposable Git/file snapshot |
|
|
221
221
|
| `post_edit_guard.py` | Record mechanical evidence observations after edits |
|
|
222
|
-
| `block_dangerous_commands.py` |
|
|
222
|
+
| `block_dangerous_commands.py` | Advise on additive protected-branch publication; deny history rewrites and named destructive shell effects until the exact command is authorized |
|
|
223
223
|
|
|
224
224
|
All five exit silently when `.ultra/` is absent. Details are in
|
|
225
225
|
[Plugin Isolation](docs/PLUGIN-ISOLATION-CONTRACT.md).
|
package/bin/delegate-worker.cjs
CHANGED
|
@@ -7,6 +7,7 @@ const path = require('node:path');
|
|
|
7
7
|
const { execFileSync, spawn } = require('node:child_process');
|
|
8
8
|
|
|
9
9
|
const RESULT_SCHEMA = 'ultra-delegation-result-v1';
|
|
10
|
+
const PROTECTED_ROOT = '.ultra';
|
|
10
11
|
const MODEL_FIELDS = new Set([
|
|
11
12
|
'$schema', 'status', 'summary', 'changed_files', 'checks', 'evidence',
|
|
12
13
|
'questions', 'residual_risks',
|
|
@@ -148,7 +149,11 @@ function validateModelResult(payload) {
|
|
|
148
149
|
return null;
|
|
149
150
|
}
|
|
150
151
|
|
|
152
|
+
// The project's memory has exactly one writer: the primary host. A worker that edits
|
|
153
|
+
// `.ultra` in its own worktree collides in the files every later session reads to
|
|
154
|
+
// resume, so no permission grants it — not even `writable_roots: ["."]`.
|
|
151
155
|
function authorized(spec, file) {
|
|
156
|
+
if (file === PROTECTED_ROOT || file.startsWith(`${PROTECTED_ROOT}/`)) return false;
|
|
152
157
|
return spec.writable_roots.some((root) => (
|
|
153
158
|
root === '.' || file === root || file.startsWith(`${root}/`)
|
|
154
159
|
));
|
package/bin/delegate.cjs
CHANGED
|
@@ -12,6 +12,7 @@ const PERMISSION_SCHEMA = 'ultra-delegation-permission-v1';
|
|
|
12
12
|
const RECEIPT_SCHEMA = 'ultra-delegation-receipt-v1';
|
|
13
13
|
const RESULT_SCHEMA = 'ultra-delegation-result-v1';
|
|
14
14
|
const PERMISSION_FIELDS = new Set(['$schema', 'writable_roots', 'external_effects']);
|
|
15
|
+
const PROTECTED_ROOT = '.ultra';
|
|
15
16
|
const RESULT_JSON_SCHEMA = Object.freeze({
|
|
16
17
|
type: 'object',
|
|
17
18
|
additionalProperties: false,
|
|
@@ -149,6 +150,12 @@ function readPermission(file, worktree) {
|
|
|
149
150
|
throw new Error('permission writable_roots must not escape through symlinks');
|
|
150
151
|
}
|
|
151
152
|
const normalized = path.relative(worktree, real).split(path.sep).join('/') || '.';
|
|
153
|
+
// `.ultra` is the project's memory and has exactly one writer: the primary host.
|
|
154
|
+
// Rejected here so the delegation never starts, and again against the actual diff
|
|
155
|
+
// in the worker, which also covers the `.` grant.
|
|
156
|
+
if (normalized === PROTECTED_ROOT || normalized.startsWith(`${PROTECTED_ROOT}/`)) {
|
|
157
|
+
throw new Error(`permission writable_roots must not include ${PROTECTED_ROOT}; the primary host is its only writer`);
|
|
158
|
+
}
|
|
152
159
|
if (!writableRoots.includes(normalized)) {
|
|
153
160
|
writableRoots.push(normalized);
|
|
154
161
|
writableRootPaths.push(real);
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -87,7 +87,10 @@ the parent model runs the same references sequentially.
|
|
|
87
87
|
Five hooks read canonical files and emit bounded context or observations. Their output
|
|
88
88
|
under `.ultra/.runtime/`, `.ultra/progress/`, or `.ultra/reviews/` is derived and
|
|
89
89
|
disposable. The dangerous-command hook is the only hard effect guard; it classifies a
|
|
90
|
-
small named set
|
|
90
|
+
small named destructive set and provides an exact-command authorization repair.
|
|
91
|
+
Additive protected-branch publication remains advisory when portable host wiring cannot
|
|
92
|
+
project a trusted owner-approval receipt; history rewrites and branch deletion remain
|
|
93
|
+
guarded.
|
|
91
94
|
|
|
92
95
|
## Completion and recovery
|
|
93
96
|
|
package/docs/DECISIONS.md
CHANGED
|
@@ -52,8 +52,10 @@ No single sensor is promoted into a semantic completion gate.
|
|
|
52
52
|
|
|
53
53
|
The hook surface is session context, mid-workflow acceptance recall, compact snapshot,
|
|
54
54
|
post-edit evidence observation, and dangerous-command protection. Every hook is silent
|
|
55
|
-
without `.ultra/`.
|
|
56
|
-
|
|
55
|
+
without `.ultra/`. Additive protected-branch publication is advisory because the
|
|
56
|
+
portable hook cannot receive every host's trusted owner-approval receipt. History
|
|
57
|
+
rewrites, branch deletion, and the narrower named destructive effects can be denied;
|
|
58
|
+
their repair is authorization scoped to the exact command digest.
|
|
57
59
|
|
|
58
60
|
## Delegation is a process boundary
|
|
59
61
|
|
package/docs/PHILOSOPHY.md
CHANGED
|
@@ -61,16 +61,20 @@ agents to find loopholes (rename `mock` to `stub`, etc.). The cheaper path must
|
|
|
61
61
|
|
|
62
62
|
### C3 — Sensors not Blockers
|
|
63
63
|
|
|
64
|
-
Hooks emit signal; agents and users decide. Block only the **truly irreversible
|
|
64
|
+
Hooks emit signal; agents and users decide. Block only the **truly irreversible or
|
|
65
|
+
privileged destructive** effects for which the hook has an exact repair:
|
|
65
66
|
|
|
66
|
-
- `git push` to protected branches
|
|
67
67
|
- Funds transfer / on-chain transactions
|
|
68
|
-
-
|
|
68
|
+
- Protected-branch history rewrite or deletion
|
|
69
|
+
- `DROP` / `TRUNCATE`
|
|
69
70
|
- Hardcoded secret commit
|
|
70
71
|
- Arbitrary code execution driven by user input
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
Additive protected-branch publication and database migrations are advisory: the former
|
|
74
|
+
remains recoverable through Git and the portable hook cannot receive every host's
|
|
75
|
+
trusted approval receipt; the latter is not mechanically classifiable as reversible or
|
|
76
|
+
irreversible. The work stands, the signal is delivered, and the agent proceeds inside
|
|
77
|
+
the owner's authorized frame.
|
|
74
78
|
|
|
75
79
|
> **Why this is absolute**: hard final gates and hard pre-commit gates each produced the same
|
|
76
80
|
> over-correction loop in v7 — the agent weakened tests to escape the gate and drifted from the
|
|
@@ -102,6 +106,27 @@ boundary surfaces to the user.
|
|
|
102
106
|
feature flags, in-memory replacing real persistence, scope reduction, external or irreversible
|
|
103
107
|
effects
|
|
104
108
|
|
|
109
|
+
**Which decisions reach the owner.** Inside/Crossing above sorts actions. Read from the owner's
|
|
110
|
+
side, the same boundary sorts decisions into three:
|
|
111
|
+
|
|
112
|
+
| Type | Definition | Handling |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| taste | no objectively correct answer; only the owner's preference settles it | always ask |
|
|
115
|
+
| crossing | objectively decidable, but the consequence is irreversible | always ask |
|
|
116
|
+
| everything else | has an objective answer, or is cheap to reverse | decide and proceed; asking is the error |
|
|
117
|
+
|
|
118
|
+
How much lands in the third row is a function of how sharp the north star is. With constraints
|
|
119
|
+
that can veto a concrete decision, most execution-time questions are answered by reading them.
|
|
120
|
+
With vague ones, "does this cross a boundary?" cannot be decided at all, so every question
|
|
121
|
+
degrades into taste and reaches the owner. **Interrupt frequency measures the north star, not
|
|
122
|
+
the work.** Frequent interruptions mean going back to sharpen constraints, not asking faster.
|
|
123
|
+
|
|
124
|
+
**Boundaries grow; they do not change.** Adding a hard constraint or a non-goal mid-flight is
|
|
125
|
+
routine and needs no permission — the frame got sharper and no prior promise broke. Editing or
|
|
126
|
+
deleting one is a REDUCTION under the test below. This is what makes iteration five cheaper than
|
|
127
|
+
iteration one: the frame accumulates, and the share of decisions the model settles alone rises
|
|
128
|
+
with it.
|
|
129
|
+
|
|
105
130
|
**Operational test for spec changes.** When implementation and spec disagree, classify the change
|
|
106
131
|
before touching the spec. Do not classify by intent — classify by asking one question that can be
|
|
107
132
|
checked against the file:
|
|
@@ -119,6 +144,12 @@ not convert a REDUCTION into a CORRECTION; the rationale goes into the question
|
|
|
119
144
|
This is the mechanism by which specs shrink silently, so it is the one place the model must not
|
|
120
145
|
be allowed to self-certify.
|
|
121
146
|
|
|
147
|
+
**Not to be confused with Planning Posture.** A Change's `## Planning Posture` uses
|
|
148
|
+
EXPAND / SELECTIVE / HOLD / REDUCE to say how much work to plan right now. That is a scope
|
|
149
|
+
decision about the future and is freely reversible. The classification above is about the past:
|
|
150
|
+
whether a promise already made still holds. `REDUCE` the plan is routine; a `REDUCTION` of
|
|
151
|
+
commitments stops the work and goes to the owner.
|
|
152
|
+
|
|
122
153
|
> **Test**: any boundary-crossing action must trigger an owner question, an active task
|
|
123
154
|
> `## Change Log` entry, or an accepted `.ultra/decisions/<id>.md`.
|
|
124
155
|
|
|
@@ -70,9 +70,12 @@ Every hook resolves the current project and checks for `.ultra/` before reading,
|
|
|
70
70
|
writing, injecting context, or denying an effect. Without `.ultra/`, it emits no stdout,
|
|
71
71
|
exits zero, and leaves the project untouched.
|
|
72
72
|
|
|
73
|
-
The only hook denial is a named
|
|
74
|
-
denial identifies the protected effect and supplies an exact-command SHA-256
|
|
75
|
-
authorization path.
|
|
73
|
+
The only hook denial is a named destructive shell effect in an active Ultra project.
|
|
74
|
+
The denial identifies the protected effect and supplies an exact-command SHA-256
|
|
75
|
+
authorization path. Additive protected-branch publication is an advisory observation
|
|
76
|
+
because a portable hook cannot consume every host's trusted owner-approval receipt;
|
|
77
|
+
history rewrites and branch deletion remain guarded. All other hook failures are
|
|
78
|
+
fail-open diagnostics.
|
|
76
79
|
|
|
77
80
|
## Project data boundary
|
|
78
81
|
|
|
@@ -60,7 +60,7 @@ host feature OpenCode does not expose.
|
|
|
60
60
|
| mid-workflow recall | yes | handles `apply_patch` | native bridge | normalized | executed |
|
|
61
61
|
| compact context | pre/start | pre/post | native compact event | pre/post | pre-compact |
|
|
62
62
|
| post-edit observation | Write/Edit | Write/Edit/`apply_patch` | write/edit/patch | Write/Edit | Write/Edit/patch |
|
|
63
|
-
| dangerous command guard | Bash | Bash | bash | Bash | Bash deny mapping |
|
|
63
|
+
| dangerous command guard | Bash advisory/deny | Bash advisory/deny | bash advisory/deny | Bash advisory/deny | Bash allow/deny mapping |
|
|
64
64
|
|
|
65
65
|
All hooks share the same `.ultra/` idle guard. Wire adapters normalize payload and
|
|
66
66
|
output fields only; they do not change semantic policy. Codex installation health and
|
|
@@ -99,3 +99,45 @@ inherits the same isolated `HOME` and `CODEX_HOME`. Grok native registration is
|
|
|
99
99
|
only in explicit isolated test mode. Lifecycle tests also require the isolated config
|
|
100
100
|
and fake HOME to contain zero children after uninstall, while separate ownership tests
|
|
101
101
|
prove that pre-existing empty Codex and Kimi registries survive.
|
|
102
|
+
|
|
103
|
+
## Authenticated cross-host continuation evidence
|
|
104
|
+
|
|
105
|
+
On 2026-08-03, one deliberately narrow task was run in an isolated Git repository to
|
|
106
|
+
test the product's central recovery claim with real authenticated models. This was a
|
|
107
|
+
continuation drill, not a full project workflow or a delegation receipt test.
|
|
108
|
+
|
|
109
|
+
Both hosts used globally installed artifacts from the same clean source candidate:
|
|
110
|
+
|
|
111
|
+
- source commit: `c473a248bde2afce77591f2ba382246d420b5c72`;
|
|
112
|
+
- worktree digest: `e83bdcbe2905cf02cb06cb0219127f6ce0400484331a6e9fc95622bbe24b44bd`;
|
|
113
|
+
- Doctor: Claude healthy with 83 assets and zero issues; Codex healthy with 99 assets
|
|
114
|
+
and zero issues, with optional hooks still `user_review_required`.
|
|
115
|
+
|
|
116
|
+
The seed repository had one passing smoke test, one pending task, one mapped Change
|
|
117
|
+
acceptance ID, and seed HEAD `cf27d62aeeae353e0650413de6d9a118b89a0406`.
|
|
118
|
+
|
|
119
|
+
| Phase | Execution boundary | Observed result |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| Claude | One print-mode call, `acceptEdits`, no persistent session, empty MCP config, explicit file and local-test tools, USD 1.00 cap | Exit 0 at USD 0.741367 with zero web requests. It changed only the task ledger/context, added `test/slug.test.cjs`, and allowed the hook to write disposable progress. `src/slug.cjs` and completion evidence remained untouched. The task test exited 1 with actual `hello,-world!` versus expected `hello-world`; both task surfaces read `in_progress`, and the Resume Note named the exact next action. |
|
|
122
|
+
| Codex | One ephemeral `workspace-write` call with sandbox network disabled and no conversation from Claude | Exit 0. It found and read the installed `ultra-dev` Skill, recovered the single task from Git and `.ultra/`, reproduced the same red, changed only the intended implementation, then passed the task test 1/1 and `npm test` 2/2. It wrote the three-command canonical evidence record and logs, completed both task status surfaces, and filled Completion and the final Resume Note. |
|
|
123
|
+
| Independent check | Local commands after both model calls | `node --test test/slug.test.cjs` passed 1/1, `npm test` passed 2/2, `git diff --check` passed, and a structural check confirmed one completed task, six evidence dimensions, three existing command-log references, and matching ledger/context state. |
|
|
124
|
+
|
|
125
|
+
The Codex process emitted non-blocking diagnostics for an older local model-cache
|
|
126
|
+
schema and an unauthenticated user-config MCP startup. No MCP result was consumed and
|
|
127
|
+
no external effect occurred; all task actions used local file and shell tools. This
|
|
128
|
+
means the drill proves file-backed Claude-to-Codex continuation even while Codex hooks
|
|
129
|
+
remain untrusted, but it does not claim that arbitrary user configuration starts
|
|
130
|
+
without unrelated host diagnostics.
|
|
131
|
+
|
|
132
|
+
The result establishes one real end-to-end example of cross-host resume without a
|
|
133
|
+
shared conversation, database, MCP authority, daemon, or generated prompt projection.
|
|
134
|
+
It does not establish output quality for every model, host, repository, or task shape.
|
|
135
|
+
Task-level `ultra-review` and commits were intentionally excluded from the drill so the
|
|
136
|
+
two host calls tested only the handoff boundary.
|
|
137
|
+
|
|
138
|
+
Two older `.ultra` evidence snapshots originally named the completed WIP by its former
|
|
139
|
+
path. The current-path artifact contract requires every reference to resolve in the
|
|
140
|
+
checkout, so those two references now point here while their 2026-08-01 status and
|
|
141
|
+
limitations remain explicitly historical. The original WIP is still recoverable from
|
|
142
|
+
their pinned source commit `3f99189bc68697262cd90444685ac2d4857139c4` with
|
|
143
|
+
`git show`; the live `docs/wip/` directory contains no unfinished document.
|
|
@@ -132,3 +132,7 @@ the common entry contract and compares the working tree with those claims.
|
|
|
132
132
|
|
|
133
133
|
This path remains valid when hooks and `ubp` are disabled. A compact snapshot may be
|
|
134
134
|
used as a hint, then checked against canonical files and Git.
|
|
135
|
+
|
|
136
|
+
An authenticated Claude-to-Codex continuation using this path passed on 2026-08-03;
|
|
137
|
+
the exact scope, provenance, results, and limitations are recorded in the
|
|
138
|
+
[runtime compatibility matrix](RUNTIME-COMPAT-MATRIX.md#authenticated-cross-host-continuation-evidence).
|
package/hooks/README.md
CHANGED
|
@@ -9,7 +9,7 @@ directory and exits silently when the workflow is not active.
|
|
|
9
9
|
| `mid_workflow_recall.py` | Before source reads or edits | Restate current acceptance only |
|
|
10
10
|
| `compact_context.py` | Before/after compaction | Save and restore a disposable snapshot derived from files and Git |
|
|
11
11
|
| `post_edit_guard.py` | After edits | Record mechanical evidence observations without deciding completion |
|
|
12
|
-
| `block_dangerous_commands.py` | Before shell execution |
|
|
12
|
+
| `block_dangerous_commands.py` | Before shell execution | Advise on additive protected-branch publication; block history rewrites and a narrow destructive set until the exact command is owner-authorized |
|
|
13
13
|
|
|
14
14
|
`_common.py` is a shared library, not a lifecycle registration. Compact snapshots and
|
|
15
15
|
progress observations live under ignored `.ultra/.runtime/` or `.ultra/progress/`; the
|
|
@@ -18,5 +18,7 @@ canonical semantic facts remain the owner-readable files and Git.
|
|
|
18
18
|
Claude Code runs the hooks directly. Codex, Kimi Code, and Grok Build use the small
|
|
19
19
|
wire adapters under `hooks/adapters/`. OpenCode calls the same scripts from its native
|
|
20
20
|
JavaScript plugin. A hook failure is advisory except for the explicitly classified
|
|
21
|
-
|
|
22
|
-
SHA-256-scoped authorization path.
|
|
21
|
+
destructive effects in `block_dangerous_commands.py`, whose denial includes a reachable
|
|
22
|
+
SHA-256-scoped authorization path. Additive protected-branch publication stays advisory
|
|
23
|
+
because portable hooks cannot consume every host's trusted owner-approval receipt;
|
|
24
|
+
history rewrites and branch deletion remain guarded.
|
|
@@ -7,11 +7,88 @@ import hashlib
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
9
|
import re
|
|
10
|
+
import shlex
|
|
10
11
|
import subprocess
|
|
11
12
|
|
|
12
13
|
from _common import emit_context, project_root, read_payload
|
|
13
14
|
|
|
14
15
|
|
|
16
|
+
APPROVAL_VAR = "UBP_DANGEROUS_COMMAND_APPROVED"
|
|
17
|
+
APPROVAL_PREFIX = re.compile(rf"^\s*{APPROVAL_VAR}=\S*\s+")
|
|
18
|
+
|
|
19
|
+
HEREDOC = re.compile(
|
|
20
|
+
r"<<-?\s*(['\"]?)(?P<tag>[A-Za-z_]\w*)\1(?P<rest>[^\n]*)\n(?P<body>.*?)^\s*(?P=tag)\s*$",
|
|
21
|
+
re.DOTALL | re.MULTILINE,
|
|
22
|
+
)
|
|
23
|
+
# Commands whose heredoc is a payload rather than a script. Deliberately short: an
|
|
24
|
+
# unlisted sink keeps its body in scope, so the cost of an omission is a false positive,
|
|
25
|
+
# never a missed effect.
|
|
26
|
+
DATA_SINK = re.compile(r"\bgit\s+(?:commit|tag|notes)\b", re.IGNORECASE)
|
|
27
|
+
SEARCH_COMMANDS = {"egrep", "fgrep", "grep", "rg"}
|
|
28
|
+
SHELL_CONTROL = {";", ";;", "&", "&&", "|", "||", "(", ")", "\n"}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def strip_data_heredocs(command: str) -> str:
|
|
32
|
+
"""Drop heredoc bodies that are data for a known sink.
|
|
33
|
+
|
|
34
|
+
Describing an effect inside a commit message is not performing it, and a message
|
|
35
|
+
that mentions one used to be blocked as though it did.
|
|
36
|
+
|
|
37
|
+
Bodies are kept whenever they might be executed: an interpreter reading a heredoc
|
|
38
|
+
runs it, so stripping there would make quoting style a way around this gate. The
|
|
39
|
+
body survives unless the delimiter is quoted, the segment introducing it is a
|
|
40
|
+
listed data sink, and nothing on the heredoc's own line pipes it somewhere else.
|
|
41
|
+
An unquoted delimiter performs parameter, command and arithmetic expansion before
|
|
42
|
+
the sink receives the data, so its body remains executable shell input.
|
|
43
|
+
"""
|
|
44
|
+
def resolve(match: re.Match) -> str:
|
|
45
|
+
segment = re.split(r"\|\||&&|[;&|\n]", command[:match.start()])[-1]
|
|
46
|
+
if (
|
|
47
|
+
not match.group(1)
|
|
48
|
+
or "|" in match.group("rest")
|
|
49
|
+
or not DATA_SINK.search(segment)
|
|
50
|
+
):
|
|
51
|
+
return match.group(0)
|
|
52
|
+
tag = match.group("tag")
|
|
53
|
+
return f"<<{tag}\n{tag}"
|
|
54
|
+
|
|
55
|
+
return HEREDOC.sub(resolve, command)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def effect_of(command: str) -> str:
|
|
59
|
+
"""The command reduced to what it actually does.
|
|
60
|
+
|
|
61
|
+
Strips an inline approval assignment, then any heredoc body that is data for a
|
|
62
|
+
known sink. What remains is the effect: the part worth classifying and hashing.
|
|
63
|
+
|
|
64
|
+
The digest must identify the *effect*, not the spelling of the retry. Without this,
|
|
65
|
+
prepending the variable changes the command text, which changes the digest, which
|
|
66
|
+
means the quoted digest is never the one that matches -- the repair path is a loop.
|
|
67
|
+
|
|
68
|
+
The assigned value is discarded on purpose. Only the process environment authorizes,
|
|
69
|
+
because the command string is composed by the model and honouring an inline value
|
|
70
|
+
would let it approve itself.
|
|
71
|
+
"""
|
|
72
|
+
return strip_data_heredocs(APPROVAL_PREFIX.sub("", command, count=1))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def is_inert_search(command: str) -> bool:
|
|
76
|
+
"""Return true when a search query is data, not executable shell input."""
|
|
77
|
+
if any(marker in command for marker in ("$(", "<(", ">(", "`")):
|
|
78
|
+
return False
|
|
79
|
+
try:
|
|
80
|
+
lexer = shlex.shlex(command, posix=True, punctuation_chars=";&|()\n")
|
|
81
|
+
lexer.whitespace = " \t\r"
|
|
82
|
+
lexer.whitespace_split = True
|
|
83
|
+
lexer.commenters = ""
|
|
84
|
+
tokens = list(lexer)
|
|
85
|
+
except ValueError:
|
|
86
|
+
return False
|
|
87
|
+
if not tokens or any(token in SHELL_CONTROL for token in tokens):
|
|
88
|
+
return False
|
|
89
|
+
return os.path.basename(tokens[0]) in SEARCH_COMMANDS
|
|
90
|
+
|
|
91
|
+
|
|
15
92
|
def protected_push(command: str, root) -> bool:
|
|
16
93
|
if not re.search(r"\bgit\s+push\b", command, re.IGNORECASE):
|
|
17
94
|
return False
|
|
@@ -24,9 +101,26 @@ def protected_push(command: str, root) -> bool:
|
|
|
24
101
|
return result.stdout.strip() in {"main", "master", "production", "prod"}
|
|
25
102
|
|
|
26
103
|
|
|
104
|
+
def destructive_protected_push(command: str, root) -> bool:
|
|
105
|
+
"""Detect history rewrites or deletion, not ordinary additive publication."""
|
|
106
|
+
if not protected_push(command, root):
|
|
107
|
+
return False
|
|
108
|
+
match = re.search(r"\bgit\s+push\b", command, re.IGNORECASE)
|
|
109
|
+
if match is None:
|
|
110
|
+
return False
|
|
111
|
+
segment = re.split(r"\|\||&&|[;&|\n]", command[match.end():], maxsplit=1)[0]
|
|
112
|
+
force_or_delete = re.search(
|
|
113
|
+
r"(?:^|\s)(?:-f|--force(?:-with-lease(?:=\S+)?|-if-includes)?|--delete)(?=\s|$)",
|
|
114
|
+
segment,
|
|
115
|
+
re.IGNORECASE,
|
|
116
|
+
)
|
|
117
|
+
forced_refspec = re.search(r"(?:^|\s)(?:\+\S+|:\S+)(?=\s|$)", segment)
|
|
118
|
+
return force_or_delete is not None or forced_refspec is not None
|
|
119
|
+
|
|
120
|
+
|
|
27
121
|
def classify(command: str, root) -> str | None:
|
|
28
|
-
if
|
|
29
|
-
return "protected branch
|
|
122
|
+
if destructive_protected_push(command, root):
|
|
123
|
+
return "protected branch history rewrite or deletion"
|
|
30
124
|
if re.search(r"\b(?:drop\s+(?:table|database|schema)|truncate\s+(?:table\s+)?)\b", command, re.IGNORECASE):
|
|
31
125
|
return "destructive database operation"
|
|
32
126
|
if re.search(r"\b(?:cast\s+send|solana\s+transfer|bitcoin-cli\s+send|near\s+send|aptos\s+move\s+run)\b", command, re.IGNORECASE):
|
|
@@ -42,7 +136,14 @@ def classify(command: str, root) -> str | None:
|
|
|
42
136
|
return None
|
|
43
137
|
|
|
44
138
|
|
|
45
|
-
def advisory(command: str) -> str | None:
|
|
139
|
+
def advisory(command: str, root) -> str | None:
|
|
140
|
+
if protected_push(command, root):
|
|
141
|
+
return (
|
|
142
|
+
"Ultra observed a protected branch push. This portable hook cannot receive "
|
|
143
|
+
"the host's trusted owner-approval receipt, so it does not replace the host's "
|
|
144
|
+
"native authority flow. Proceed only after explicit owner authorization and "
|
|
145
|
+
"verify the remote result."
|
|
146
|
+
)
|
|
46
147
|
if re.search(
|
|
47
148
|
r"\b(?:alembic\s+upgrade|prisma\s+migrate|knex\s+migrate|sequelize\s+db:migrate|rails\s+db:migrate|manage\.py\s+migrate)\b",
|
|
48
149
|
command,
|
|
@@ -65,19 +166,24 @@ def main() -> int:
|
|
|
65
166
|
command = tool_input.get("command")
|
|
66
167
|
if not isinstance(command, str) or not command.strip():
|
|
67
168
|
return 0
|
|
68
|
-
|
|
169
|
+
effect = effect_of(command)
|
|
170
|
+
if is_inert_search(effect):
|
|
171
|
+
return 0
|
|
172
|
+
threat = classify(effect, root)
|
|
69
173
|
if threat is None:
|
|
70
|
-
note = advisory(
|
|
174
|
+
note = advisory(effect, root)
|
|
71
175
|
if note:
|
|
72
176
|
emit_context("PreToolUse", note)
|
|
73
177
|
return 0
|
|
74
|
-
digest = hashlib.sha256(
|
|
75
|
-
if os.environ.get(
|
|
178
|
+
digest = hashlib.sha256(effect.encode()).hexdigest()
|
|
179
|
+
if os.environ.get(APPROVAL_VAR) == digest:
|
|
76
180
|
return 0
|
|
77
181
|
reason = (
|
|
78
|
-
f"Ultra blocked {threat}. Protected effect: the exact shell command
|
|
79
|
-
f"
|
|
80
|
-
f"
|
|
182
|
+
f"Ultra blocked {threat}. Protected effect: the exact shell command, "
|
|
183
|
+
f"digest {digest}. Authorization comes from the owner's environment, never from "
|
|
184
|
+
f"the command text. Either run it yourself, or export "
|
|
185
|
+
f"{APPROVAL_VAR}={digest} in the environment that launches the agent and ask "
|
|
186
|
+
f"again. Prefixing the assignment onto this command does not authorize it."
|
|
81
187
|
)
|
|
82
188
|
print(json.dumps({
|
|
83
189
|
"decision": "block",
|
package/package.json
CHANGED
|
@@ -16,6 +16,10 @@ disagreement instead of resolving it.
|
|
|
16
16
|
2. Read `CONTEXT.md` for vocabulary and `.ultra/decisions/` for entries in scope.
|
|
17
17
|
3. Read `.ultra/north-star.md` — a Change that does not serve it is worth
|
|
18
18
|
questioning out loud before it is written down.
|
|
19
|
+
4. Grep `.ultra/changes/archive/` for Changes that already touched this area. Read
|
|
20
|
+
`delivery.md` when present; otherwise read `archive-summary.md`, `verification.md` and
|
|
21
|
+
remaining owner-readable Markdown. A missing `delivery.md` does not mean no history;
|
|
22
|
+
a module that keeps reappearing is an architecture signal.
|
|
19
23
|
|
|
20
24
|
## Whether this skill applies at all
|
|
21
25
|
|
|
@@ -59,8 +63,14 @@ Sort what you find into three buckets, each with your recommended disposition:
|
|
|
59
63
|
| Code implements it, no specification says so | Built and unpromised |
|
|
60
64
|
| Both speak and they conflict | Contradictory |
|
|
61
65
|
|
|
62
|
-
Take the buckets to the owner
|
|
63
|
-
disposition can quietly
|
|
66
|
+
Take the buckets to the owner — confirmed rather than assumed, because a
|
|
67
|
+
disposition can quietly withdraw a commitment. Sort by risk first and match the
|
|
68
|
+
asking to it: anything that touches a `HC-<n>` hard constraint or removes
|
|
69
|
+
something already promised goes one at a time with your recommendation; the
|
|
70
|
+
remaining low-risk rows go as a single list with a recommended disposition each,
|
|
71
|
+
for one confirmation. Twenty separate questions about rows that change nothing
|
|
72
|
+
spends the owner's attention where it was not needed, and trains them to approve
|
|
73
|
+
without reading.
|
|
64
74
|
|
|
65
75
|
## Write the intent
|
|
66
76
|
|
|
@@ -86,16 +96,24 @@ reconciliation justified, possibly a `.ultra/decisions/<id>.md`, and any
|
|
|
86
96
|
vocabulary update. Recommend `ultra-research` for a real evidence gap or
|
|
87
97
|
`ultra-plan` once the contract is evidenced enough; do not invoke either.
|
|
88
98
|
|
|
99
|
+
## Abandoning a Change
|
|
100
|
+
|
|
101
|
+
A Change that turns out to be the wrong thing to build exits by
|
|
102
|
+
`git mv .ultra/changes/active/<id> .ultra/changes/abandoned/<id>`, plus one line in
|
|
103
|
+
its `intent.md` saying why. Completed tasks keep their evidence; the work is
|
|
104
|
+
unlinked from the frontier, not deleted. This is the owner's call and a cheap one —
|
|
105
|
+
a Change kept alive to avoid admitting it was wrong poisons every later
|
|
106
|
+
reconciliation, which then measures the code against promises nobody intends to keep.
|
|
107
|
+
|
|
89
108
|
## When the owner decides
|
|
90
109
|
|
|
91
|
-
Every non-empty bucket, the Change boundary, and anything
|
|
92
|
-
that shrinks a prior commitment. A change that makes no
|
|
93
|
-
false needs no permission at all.
|
|
110
|
+
Every non-empty bucket, the Change boundary, abandonment, and anything
|
|
111
|
+
reconciliation turns up that shrinks a prior commitment. A change that makes no
|
|
112
|
+
specification sentence false needs no permission at all.
|
|
94
113
|
|
|
95
114
|
## References
|
|
96
115
|
|
|
97
116
|
- `../ultra-grilling/SKILL.md` — the loop for settling the boundary.
|
|
98
117
|
- `references/change-contract.md` — exact `intent.md` structure and profile fields.
|
|
99
|
-
- `../ultra-think/references/autonomy-boundary.md` — read before
|
|
100
|
-
bucket in a way that removes something already promised.
|
|
118
|
+
- `../ultra-think/references/autonomy-boundary.md` — read before removing a promise.
|
|
101
119
|
- `../ultra-tdd/SKILL.md` — read for an evidenced one-slice correction.
|
|
@@ -31,6 +31,10 @@ stable enough to survive a fresh session.
|
|
|
31
31
|
|
|
32
32
|
## Planning Posture
|
|
33
33
|
<EXPAND | SELECTIVE | HOLD | REDUCE, rationale, and owner confirmation>
|
|
34
|
+
<!-- Scope for this Change only. Not the commitment classification: REDUCE here
|
|
35
|
+
means "plan less work now", while a REDUCTION in a Change Log means "a
|
|
36
|
+
promise the specification already made no longer holds". -->
|
|
37
|
+
|
|
34
38
|
|
|
35
39
|
## Recovery
|
|
36
40
|
<reversal or recovery path and its verification>
|
|
@@ -45,8 +49,10 @@ heading, and do not add another file that restates the same contract.
|
|
|
45
49
|
## Contract fields
|
|
46
50
|
|
|
47
51
|
- `outcome`: one externally observable result.
|
|
48
|
-
- `acceptance`: stable ids
|
|
49
|
-
|
|
52
|
+
- `acceptance`: stable ids, one criterion each, and a `Verification` that is an
|
|
53
|
+
**executable command** — something with an exit code, not a description of an
|
|
54
|
+
intention. `curl -sf localhost:3000/health` qualifies; "check that the endpoint
|
|
55
|
+
responds" does not.
|
|
50
56
|
- `non_goals`: explicit boundaries that prevent accidental scope growth.
|
|
51
57
|
- `public_seams`: entry points or outputs through which acceptance is observed.
|
|
52
58
|
- `recovery`: a bounded reversal or recovery strategy and its verification.
|
|
@@ -55,6 +61,26 @@ heading, and do not add another file that restates the same contract.
|
|
|
55
61
|
Resolve every blocking decision before planning. Keep non-blocking uncertainty visible
|
|
56
62
|
in the task and verification contracts.
|
|
57
63
|
|
|
64
|
+
## Why verification has to be executable
|
|
65
|
+
|
|
66
|
+
A criterion whose verification cannot be run is not acceptance, it is a wish. Three
|
|
67
|
+
consumers downstream depend on it being runnable:
|
|
68
|
+
|
|
69
|
+
- task development can treat passing acceptance as an exit condition only when
|
|
70
|
+
something can actually decide "passing";
|
|
71
|
+
- the review tests lens maps each acceptance claim to executable evidence, and can
|
|
72
|
+
only report an honest gap when there is something to map onto;
|
|
73
|
+
- delivery cannot otherwise separate "shipped" from "believed shipped".
|
|
74
|
+
|
|
75
|
+
Writing the command is also the cheapest way to find out that a criterion is vague.
|
|
76
|
+
"The feature is wired up" resists a command until it becomes "this export has a
|
|
77
|
+
non-test importer", which is a `grep`.
|
|
78
|
+
|
|
79
|
+
Where a criterion is genuinely a judgement call — visual polish, wording, feel — it
|
|
80
|
+
does not belong in Acceptance at all. Record it as a taste decision for the owner and
|
|
81
|
+
keep Acceptance to what a machine can settle. Mixing the two is what makes an
|
|
82
|
+
acceptance set undecidable.
|
|
83
|
+
|
|
58
84
|
## Profile
|
|
59
85
|
|
|
60
86
|
- `quick`: one low-risk task, no material risk flags, and no research dependency.
|
|
@@ -21,6 +21,8 @@ semantic synthesis and remains the only writer of `.ultra/tasks.json`.
|
|
|
21
21
|
spec digests remain unchanged.
|
|
22
22
|
- The worker terminates as `finished`, `blocked` or `failed` in a schema-valid
|
|
23
23
|
`result.json`; declared paths equal the actual Git diff and stay in writable roots.
|
|
24
|
+
- No `writable_roots` entry is `.ultra/` or sits under it, and the actual diff touches
|
|
25
|
+
nothing there.
|
|
24
26
|
- Timeout and cancellation reach a terminal failed result and release `run.lock`.
|
|
25
27
|
- The primary host verifies the result against the delegated workflow's acceptance.
|
|
26
28
|
|
|
@@ -34,6 +36,11 @@ Write under `.ultra/.runtime/delegations/<id>/`:
|
|
|
34
36
|
|
|
35
37
|
`writable_roots` is an array of existing worktree-relative directories. An empty array
|
|
36
38
|
selects native read-only mode; one or more roots selects bounded write mode.
|
|
39
|
+
**Neither `.ultra/` nor any path under it may appear in it.** The worktree carries a
|
|
40
|
+
checkout of `.ultra` because Git tracks it, but the project's memory has exactly one
|
|
41
|
+
writer. Two workers appending to `tasks.json`, `progress/` or `evidence/` in separate
|
|
42
|
+
worktrees collide in the very files every later session reads to resume. Worker findings
|
|
43
|
+
and state changes travel back in `result.json` and are applied by the primary host.
|
|
37
44
|
`external_effects` must be empty in this portable launcher: commit, push, publish,
|
|
38
45
|
deployment and other effects stay with the primary host. There is no `readable_roots`
|
|
39
46
|
claim because the five host sandboxes do not share one mechanically enforceable read
|
|
@@ -12,8 +12,16 @@
|
|
|
12
12
|
|
|
13
13
|
Fields are exact. Roots are normalized worktree-relative directories that already
|
|
14
14
|
exist. An empty array selects native read-only mode; `.` deliberately grants the whole
|
|
15
|
-
isolated checkout
|
|
16
|
-
and non-empty external effects are
|
|
15
|
+
isolated checkout except `.ultra/`. Absolute paths, symlink escapes, unknown fields,
|
|
16
|
+
`readable_roots`, `.ultra` or any path beneath it, and non-empty external effects are
|
|
17
|
+
rejected.
|
|
18
|
+
|
|
19
|
+
`.ultra/` is never writable by a worker under any root, `.` included. The project's
|
|
20
|
+
memory has exactly one writer — the primary host — because two worktrees appending to
|
|
21
|
+
`tasks.json`, `progress/` or `evidence/` collide in precisely the files a later session
|
|
22
|
+
reads to resume. Enforced twice: the launcher rejects a `.ultra` root before the
|
|
23
|
+
delegation starts, and the worker fails an actual diff that touches it with
|
|
24
|
+
`unauthorized_write`.
|
|
17
25
|
|
|
18
26
|
## Model final response
|
|
19
27
|
|
|
@@ -18,7 +18,9 @@ separate effects; local readiness grants none of them automatically.
|
|
|
18
18
|
|
|
19
19
|
## Definition of done
|
|
20
20
|
|
|
21
|
-
- Actual outcome, specifications, docs, tests and aggregate review have been reconciled
|
|
21
|
+
- Actual outcome, specifications, docs, tests and aggregate review have been reconciled,
|
|
22
|
+
with every documentation file checked against the actual diff rather than from memory.
|
|
23
|
+
- Every changed export has a non-test consumer or a recorded owner disposition.
|
|
22
24
|
- Every omitted stage is explicitly recorded with its evidence-based rationale.
|
|
23
25
|
- Build and release checks have exact commands and real results.
|
|
24
26
|
- The Change is archived with `git mv`, and rollback remains a normal Git operation.
|
|
@@ -34,13 +36,48 @@ against the resulting HEAD.
|
|
|
34
36
|
|
|
35
37
|
1. Compare accepted intent and task traces with delivered behavior.
|
|
36
38
|
2. Apply justified specification corrections; route any REDUCTION to the owner.
|
|
37
|
-
3.
|
|
38
|
-
|
|
39
|
+
3. Reconcile every document against the actual diff, not only the ones you remember
|
|
40
|
+
touching. List the repository's documentation files, read the Change's full diff, and
|
|
41
|
+
repair each place a document now describes behavior that no longer exists. CHANGELOG
|
|
42
|
+
and README are the usual ones, but a stale example in a guide, a renamed flag in a
|
|
43
|
+
runbook and an obsolete field in an API note drift the same way and are found the
|
|
44
|
+
same way. Record bounded debt only in the active Change `delivery.md` under
|
|
45
|
+
`## Technical Debt`.
|
|
39
46
|
4. Run the repository's build and packaging checks.
|
|
40
47
|
5. Determine the version impact from the public contract and project convention.
|
|
41
48
|
6. Follow `references/baseline-reconciliation.md` and write the one canonical active
|
|
42
49
|
Change `delivery.md` with exact checks, residual risks, omissions and rollback.
|
|
43
50
|
|
|
51
|
+
Step 3 is the **exit** reconciliation and does not duplicate `ultra-change`'s entry
|
|
52
|
+
reconciliation. Entry asks whether the specifications already disagreed with the code
|
|
53
|
+
before this Change was written; exit asks which documents this Change just made wrong.
|
|
54
|
+
One keeps the intent from inheriting drift, the other keeps the Change from leaving new
|
|
55
|
+
drift behind.
|
|
56
|
+
|
|
57
|
+
## The one delivery gate
|
|
58
|
+
|
|
59
|
+
This gate applies only after the owner explicitly invokes `ultra-deliver`; it does not
|
|
60
|
+
attach itself to ordinary repository packaging outside this workflow.
|
|
61
|
+
|
|
62
|
+
Everything else in this workflow reports and hands over. This is the exception, and it
|
|
63
|
+
is deliberately narrow:
|
|
64
|
+
|
|
65
|
+
**Do not package while an export this Change added or changed has no non-test consumer
|
|
66
|
+
and no recorded owner disposition.**
|
|
67
|
+
|
|
68
|
+
| | |
|
|
69
|
+
|---|---|
|
|
70
|
+
| Invariant | Every changed export is either reachable from a non-test caller or explicitly declared internal |
|
|
71
|
+
| Fact source | The Wiring Verification results in `.ultra/test-report.json`, bound to the current HEAD — the audit already found these; this is not a fresh opinion |
|
|
72
|
+
| Blocked effect | Packaging and the release effects after it. Local commit and archival are untouched |
|
|
73
|
+
| Repair | Wire the export to its caller, or record the owner's disposition in `delivery.md` naming it internal-only and why. Either one clears the gate |
|
|
74
|
+
|
|
75
|
+
"Written but never connected" is the single defect that passes every other check: tests
|
|
76
|
+
green, review clean, evidence complete, feature absent. An advisory here would be
|
|
77
|
+
ignored exactly when it matters, because everything else already reads as done. The gate
|
|
78
|
+
sits at the last step rather than at edit time on purpose — a gate early in the loop
|
|
79
|
+
gets escaped by damaging the work.
|
|
80
|
+
|
|
44
81
|
## Archive locally
|
|
45
82
|
|
|
46
83
|
Move `.ultra/changes/active/<id>` to `.ultra/changes/archive/<id>` with `git mv` only
|
|
@@ -42,16 +42,37 @@ Follow `../ultra-tdd/SKILL.md`, writing tests only on the seams the plan already
|
|
|
42
42
|
confirmed, one slice at a time. Do no refactoring here — `ultra-review` owns it,
|
|
43
43
|
because what is worth restructuring only becomes visible after several slices.
|
|
44
44
|
|
|
45
|
+
## Converge on the task-scoped acceptance set
|
|
46
|
+
|
|
47
|
+
Development ends when the task's acceptance commands pass, not when the code looks
|
|
48
|
+
finished. Resolve the context's **Change Acceptance IDs** against the active `intent.md`
|
|
49
|
+
and use each named row's executable `Verification`. Commands under the context's
|
|
50
|
+
Acceptance Criteria may add task-local checks; they do not replace the Change mapping.
|
|
51
|
+
|
|
52
|
+
Run one baseline before repairing anything. Track the best-ever passing set of mapped
|
|
53
|
+
IDs and task-local commands, the total repair rounds, and consecutive rounds that add
|
|
54
|
+
nothing to that set. The loop has three explicit exits:
|
|
55
|
+
|
|
56
|
+
| Exit | Condition | Action |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| Converged | Every mapped Change verification and task-local command exits zero | Close out below |
|
|
59
|
+
| Stalled | Two consecutive repair rounds add no new item to the best-ever passing set, or three repair rounds finish without convergence | Stop; report the remaining criteria and what each repair tried |
|
|
60
|
+
| Unreachable | A command did not start because its executable, fixture, service or declared environment prerequisite is unavailable | Stop that criterion; report the missing prerequisite and its repair path |
|
|
61
|
+
|
|
62
|
+
A nonzero exit normally means a failing criterion, not an unreachable one; inspect its
|
|
63
|
+
output. A regression never shrinks the best-ever set, and the total round limit stops
|
|
64
|
+
oscillation where different criteria alternate between pass and fail.
|
|
65
|
+
|
|
45
66
|
## Answer the six evidence dimensions
|
|
46
67
|
|
|
47
68
|
Each has a rule you can check against the work rather than assert:
|
|
48
69
|
|
|
49
70
|
| Dimension | Answered when |
|
|
50
71
|
|---|---|
|
|
51
|
-
| `tests_written` | This diff changes a test file |
|
|
72
|
+
| `tests_written` | This diff adds or changes at least one assertion — touching a test file is not enough |
|
|
52
73
|
| `tests_passed` | The last test run exited zero and covered the files this diff touched |
|
|
53
74
|
| `persistence_real` | On any path that stores data, the test uses real storage or a container |
|
|
54
|
-
| `feature_flags_audit` | No flag this
|
|
75
|
+
| `feature_flags_audit` | No flag on this change's execution path defaults to off, including flags this task did not add but now depends on |
|
|
55
76
|
| `vertical_slice` | One test's execution path runs from the entry point through to persistence |
|
|
56
77
|
| `spec_trace` | The anchor the task's `trace_to` names exists in the specification |
|
|
57
78
|
|
|
@@ -92,9 +113,7 @@ as it stands and says so in the Resume Note instead of tidying it away.
|
|
|
92
113
|
|
|
93
114
|
## References
|
|
94
115
|
|
|
95
|
-
- `../ultra-tdd/SKILL.md` — read before the first test, for the seam and
|
|
96
|
-
|
|
97
|
-
- `../ultra-think/references/autonomy-boundary.md` — read the moment the
|
|
98
|
-
specification and the implementation disagree.
|
|
116
|
+
- `../ultra-tdd/SKILL.md` — read before the first test, for the seam and mock boundary.
|
|
117
|
+
- `../ultra-think/references/autonomy-boundary.md` — read when spec and code disagree.
|
|
99
118
|
- `../ultra-review/SKILL.md` — read when implementation evidence is ready for review.
|
|
100
119
|
- `references/debugging.md` — read for a reproduced failure before selecting a repair.
|
|
@@ -22,18 +22,37 @@ have answered by reading the repository spends the one input only they can give.
|
|
|
22
22
|
|
|
23
23
|
## Definition of done
|
|
24
24
|
|
|
25
|
-
- Every
|
|
26
|
-
reason recorded.
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
- Every field the caller named as required is either answered in the owner's own
|
|
26
|
+
words or explicitly deferred with the reason recorded. "Every branch of the
|
|
27
|
+
tree" is not something you can check against a file; the caller's field list is.
|
|
28
|
+
- The reframe below was put to the owner and either confirmed or corrected. It is
|
|
29
|
+
never skipped because the original wording sounded clear.
|
|
30
|
+
- Each answer carries the owner's confirmation, rather than something that
|
|
31
|
+
sounded like agreement.
|
|
29
32
|
- The calling skill holds a decision list it can write to a file: one line per
|
|
30
33
|
decision, each with the options rejected and why.
|
|
31
34
|
|
|
32
|
-
## Extract
|
|
35
|
+
## Extract, reframe, then ask
|
|
33
36
|
|
|
34
|
-
Restate what the owner already told you and ask them to confirm the
|
|
35
|
-
Ask only about what is genuinely missing. Re-asking something they
|
|
36
|
-
teaches them that answering does not stick.
|
|
37
|
+
**Extract.** Restate what the owner already told you and ask them to confirm the
|
|
38
|
+
restatement. Ask only about what is genuinely missing. Re-asking something they
|
|
39
|
+
answered teaches them that answering does not stick.
|
|
40
|
+
|
|
41
|
+
**Reframe.** The owner describes a *form* when they want a *role*. Say what you
|
|
42
|
+
believe they actually want, name the gap against their wording, and end on a
|
|
43
|
+
question:
|
|
44
|
+
|
|
45
|
+
> You said a daily briefing app. What you described is a personal chief of staff
|
|
46
|
+
> — the briefing is one of its outputs, not the thing itself. Have I got that
|
|
47
|
+
> right?
|
|
48
|
+
|
|
49
|
+
This is what separates the loop from a questionnaire. A form accepted at face
|
|
50
|
+
value yields a specification that is internally consistent and builds the wrong
|
|
51
|
+
product. Offer the reframe, never assert it, and treat a correction as the better
|
|
52
|
+
outcome — "no, it really is just the briefing" is a constraint you did not have a
|
|
53
|
+
minute ago. Read `references/reframing.md` for when it applies and how it fails.
|
|
54
|
+
|
|
55
|
+
**Then ask** only what the confirmed reframe leaves open.
|
|
37
56
|
|
|
38
57
|
## One question per turn
|
|
39
58
|
|
|
@@ -44,14 +63,27 @@ the load-bearing one skipped.
|
|
|
44
63
|
Every question carries your recommended answer and what would change it. A
|
|
45
64
|
question without a recommendation hands your own work back to the owner.
|
|
46
65
|
|
|
47
|
-
Order questions so that answering one unlocks the next
|
|
48
|
-
|
|
66
|
+
Order questions so that answering one unlocks the next. Ask the framing questions
|
|
67
|
+
before the detail questions — a detail settled inside the wrong frame has to be
|
|
68
|
+
asked again.
|
|
69
|
+
|
|
70
|
+
**Framing questions** come first — at most five, from the table in
|
|
71
|
+
`references/reframing.md`. They refuse the owner's framing on purpose, which is
|
|
72
|
+
how they surface what the request left out. Stop early once the frame stops
|
|
73
|
+
moving.
|
|
74
|
+
|
|
75
|
+
**Detail questions** fill in the confirmed frame:
|
|
49
76
|
|
|
50
77
|
- What happens when this goes wrong, and how would we find out?
|
|
51
78
|
- Which of these options is cheaper to reverse?
|
|
52
79
|
- What are we deliberately not doing?
|
|
53
80
|
- What does done look like, concretely enough to check?
|
|
54
81
|
|
|
82
|
+
An answer counts once it is specific enough to **rule something out**. "It should
|
|
83
|
+
be fast" rules nothing out; "the list renders before they finish typing" does.
|
|
84
|
+
When an answer rules nothing out, ask what would have to be true for the owner to
|
|
85
|
+
*reject* a candidate solution.
|
|
86
|
+
|
|
55
87
|
Skip what you can derive, what does not change the work, and what they already
|
|
56
88
|
settled.
|
|
57
89
|
|
|
@@ -61,19 +93,26 @@ This whole skill is owner-facing, so the boundary is narrow: hold the loop open
|
|
|
61
93
|
until each decision is confirmed explicitly, and start no implementation on an
|
|
62
94
|
inferred consensus.
|
|
63
95
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
96
|
+
## How the loop ends
|
|
97
|
+
|
|
98
|
+
Every ending hands back the same artifact: the decisions written one per line,
|
|
99
|
+
each with the options rejected and the reason they lost. The caller chooses where
|
|
100
|
+
it lands — `north-star.md`, `discovery.md`, a Change intent, or a decision file.
|
|
68
101
|
|
|
69
|
-
|
|
102
|
+
- **Resolved** — every required field answered or explicitly deferred.
|
|
103
|
+
- **Stalled** — two consecutive turns add no newly confirmed decision. Hand back
|
|
104
|
+
the open fields and what each one blocks.
|
|
105
|
+
- **Unavailable** — the host cannot ask, or the owner stopped answering. Hand back
|
|
106
|
+
the last confirmed state, every unanswered field named.
|
|
70
107
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
108
|
+
A loop with no exit traps the owner as much as you: re-asking what they cannot
|
|
109
|
+
currently answer costs more than deferring it. Deferral is a recorded outcome,
|
|
110
|
+
not a failure. Where the host has no structured question surface, ask one plain
|
|
111
|
+
question per turn instead.
|
|
75
112
|
|
|
76
113
|
## References
|
|
77
114
|
|
|
115
|
+
- `references/reframing.md` — read before the first question: when to reframe,
|
|
116
|
+
how it fails, the five framing questions, and what counts as an answer.
|
|
78
117
|
- `../ultra-think/references/autonomy-boundary.md` — read when an answer removes
|
|
79
118
|
something the specification already promised, or otherwise crosses C5.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Reframing: recovering the role from the form
|
|
2
|
+
|
|
3
|
+
An owner fluent in their own domain still describes a **form** when what they
|
|
4
|
+
want is a **role**. They are not being vague; they are naming the nearest thing
|
|
5
|
+
they can picture. Taken at face value, that name produces a specification that is
|
|
6
|
+
internally consistent and builds the wrong product.
|
|
7
|
+
|
|
8
|
+
## When to reframe
|
|
9
|
+
|
|
10
|
+
Most first asks qualify. Any one of these is enough:
|
|
11
|
+
|
|
12
|
+
- the request names an artifact — an app, a dashboard, a bot, a script — rather
|
|
13
|
+
than an outcome;
|
|
14
|
+
- the request names a solution whose problem has not been stated;
|
|
15
|
+
- the request would be satisfied by something far smaller, or is impossible as
|
|
16
|
+
worded;
|
|
17
|
+
- two readings of the request would lead to materially different builds;
|
|
18
|
+
- the request describes what a competitor has, rather than what the owner needs.
|
|
19
|
+
|
|
20
|
+
## How to put it
|
|
21
|
+
|
|
22
|
+
State what you believe they want, name the gap against the words they used, and
|
|
23
|
+
end on a question:
|
|
24
|
+
|
|
25
|
+
> You said a daily briefing app. What you described is a personal chief of staff
|
|
26
|
+
> — the briefing is one of its outputs, not the thing itself. Have I got that
|
|
27
|
+
> right?
|
|
28
|
+
|
|
29
|
+
Rules that keep this honest:
|
|
30
|
+
|
|
31
|
+
- **One reframe at a time.** Two competing reinterpretations in one turn is a
|
|
32
|
+
quiz, and the owner will pick the one that sounds more flattering.
|
|
33
|
+
- **Offer it, never assert it.** A reframe is a hypothesis about their intent,
|
|
34
|
+
and they are the only authority on it.
|
|
35
|
+
- **A correction is the better outcome.** "No, it really is just the briefing" is
|
|
36
|
+
a constraint you did not have a minute ago. Record it as a decision.
|
|
37
|
+
- **Never reframe toward what is easier to build.** If your reinterpretation
|
|
38
|
+
happens to shrink the work, say that out loud and let the owner weigh it.
|
|
39
|
+
- **Stop after two rejected reframes.** A third is no longer listening. Take the
|
|
40
|
+
owner's framing as given and move to the framing questions below.
|
|
41
|
+
|
|
42
|
+
## Framing questions
|
|
43
|
+
|
|
44
|
+
These refuse the owner's framing on purpose, which is how they surface what the
|
|
45
|
+
request left out. Ask at most five, and stop early once the frame stops moving.
|
|
46
|
+
|
|
47
|
+
| Question | What it recovers |
|
|
48
|
+
|---|---|
|
|
49
|
+
| What do you do today, without this? | The real job, with the proposed form stripped off |
|
|
50
|
+
| What would make you say this was a waste of effort? | Success via its negative — people picture failure far more concretely than they picture success |
|
|
51
|
+
| What must never happen, even if it would work better? | The hard constraints they were never going to volunteer |
|
|
52
|
+
| If it could only do one thing and you would still use it, which? | Core against periphery, before scope has a chance to spread |
|
|
53
|
+
| Whose situation gets worse when this exists? | Stakeholders, and the constraints attached to them |
|
|
54
|
+
|
|
55
|
+
Two of these are worth their place for a specific reason. Asking for success
|
|
56
|
+
directly gets an aspiration; asking what would make it a waste gets a threshold.
|
|
57
|
+
Asking who is made worse off surfaces the constraints an owner never thinks to
|
|
58
|
+
state, because to them they are simply how the world is.
|
|
59
|
+
|
|
60
|
+
## What counts as an answer
|
|
61
|
+
|
|
62
|
+
An answer counts once it is specific enough to **rule something out**.
|
|
63
|
+
|
|
64
|
+
| Not yet an answer | An answer |
|
|
65
|
+
|---|---|
|
|
66
|
+
| "It should be fast" | "The list renders before they finish typing" |
|
|
67
|
+
| "It should be secure" | "A support agent must never see a full card number" |
|
|
68
|
+
| "Keep costs reasonable" | "Under fifty dollars a month in API spend" |
|
|
69
|
+
|
|
70
|
+
When an answer rules nothing out, do not re-ask the same question louder. Ask
|
|
71
|
+
what would have to be true for the owner to **reject** a candidate solution — the
|
|
72
|
+
rejection criterion is the constraint, stated from the other side.
|
|
@@ -26,6 +26,11 @@ or refute. A technology choice is a claim, so it is not initialization's busines
|
|
|
26
26
|
## Definition of done
|
|
27
27
|
|
|
28
28
|
- `.ultra/north-star.md` carries the owner's one-line goal in their own words.
|
|
29
|
+
- Every `## Hard Constraints` entry has a stable `HC-<n>` id and can veto a
|
|
30
|
+
concrete technical decision. "Should be usable" vetoes nothing and is not yet a
|
|
31
|
+
constraint; "first paint under two seconds" is. Same bar for the success
|
|
32
|
+
metric: a threshold, not an aspiration. See
|
|
33
|
+
`../ultra-grilling/references/reframing.md` for what counts as an answer.
|
|
29
34
|
- Every file listed under **What gets written** exists; you read each one back
|
|
30
35
|
after writing and stopped at the first one missing.
|
|
31
36
|
- `.git` exists. Any initial commit is a separately authorized delivery effect.
|
|
@@ -56,7 +61,7 @@ genuinely missing. Five things come out of it:
|
|
|
56
61
|
|---|---|
|
|
57
62
|
| What you want to build, in one sentence, their words | `north-star.md`, `## One-line` |
|
|
58
63
|
| What counts as success | `specs/product.md`, behavioral requirements and acceptance |
|
|
59
|
-
| What must never happen | `north-star.md`, `## Hard Constraints` |
|
|
64
|
+
| What must never happen | `north-star.md`, `## Hard Constraints`, one `HC-<n>` per line |
|
|
60
65
|
| Who uses it, and how they cope today | `discovery.md`, marked as the owner's statement |
|
|
61
66
|
| **What you already know you are unsure about** | `discovery.md` — research's priority queue |
|
|
62
67
|
|
|
@@ -76,7 +81,7 @@ placeholders from verified facts and owner decisions.
|
|
|
76
81
|
.ultra/specs/{product,architecture,discovery}.md ## Observed, ## Decisions, ## Unknowns
|
|
77
82
|
.ultra/tasks.json {"tasks": []}
|
|
78
83
|
.ultra/test-report.json not-yet-run report with git_commit
|
|
79
|
-
.ultra/contexts
|
|
84
|
+
.ultra/{contexts,decisions,evidence,research}/ and changes/{active,archive,abandoned}/
|
|
80
85
|
CONTEXT.md repository root, once a term is settled
|
|
81
86
|
```
|
|
82
87
|
|
|
@@ -99,8 +104,11 @@ authority that already exists and looks healthy is the owner's call, never a
|
|
|
99
104
|
convenience on the way to a clean start — preserve it and report what you found.
|
|
100
105
|
|
|
101
106
|
Where the host cannot ask at all, leave the one-line goal empty and say plainly
|
|
102
|
-
that it is empty
|
|
103
|
-
|
|
107
|
+
that it is empty. Do not infer it from the directory name. An empty one-line goal
|
|
108
|
+
is a **blocking** state, not a note: goal injection, boundary read-back and a
|
|
109
|
+
Change's touched-constraints field all read from it, so planning and development
|
|
110
|
+
must not start until it is filled. Say that too, and recommend rerunning this
|
|
111
|
+
skill on a host that can ask.
|
|
104
112
|
|
|
105
113
|
## References
|
|
106
114
|
|
|
@@ -23,6 +23,10 @@ sessions and hosts; no runtime state decides whether the plan is meaningful.
|
|
|
23
23
|
- The owner confirmed the scope posture and the seam list.
|
|
24
24
|
- Every feature task is a tracer bullet touching at least two layers, unless the
|
|
25
25
|
Change itself demonstrably touches only one layer.
|
|
26
|
+
- Every context names the north-star hard constraints its work could violate, and
|
|
27
|
+
each `HC-<n>` it names resolves to a real entry in `.ultra/north-star.md`.
|
|
28
|
+
- Every Change acceptance id maps to at least one task context, and every context id
|
|
29
|
+
resolves back to the active Change.
|
|
26
30
|
- Coverage, dependency, trace, scope and context-budget checks have concrete results.
|
|
27
31
|
|
|
28
32
|
## Fix the planning posture
|
|
@@ -64,18 +68,27 @@ Each task records `id`, `title`, `type`, `priority`, `complexity`, `status`,
|
|
|
64
68
|
splitting and context signal: 1–2 is local, 3–5 is bounded, 6–7 crosses a boundary,
|
|
65
69
|
and complexity > 7 must split.
|
|
66
70
|
|
|
67
|
-
Each context records Acceptance
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
Each context records Change Acceptance IDs, task-local Acceptance, confirmed seams,
|
|
72
|
+
layers touched, target files, Implementation, verification commands, the hard
|
|
73
|
+
constraints the work could violate, Definition of Drift, Change Log, Completion and
|
|
74
|
+
Resume Note. Read every file back; task count and context count must match.
|
|
75
|
+
|
|
76
|
+
Name a hard constraint whenever the task could plausibly breach it, not only when you
|
|
77
|
+
expect it to. The entry costs one line and is what makes a later breach a checkable
|
|
78
|
+
question instead of a judgement call; `none` is a legitimate answer for a task that
|
|
79
|
+
touches nothing constrained.
|
|
70
80
|
|
|
71
81
|
## Verify the plan
|
|
72
82
|
|
|
73
|
-
1. Map every
|
|
83
|
+
1. Map every Change acceptance ID to at least one task context and reject dangling
|
|
84
|
+
context IDs. Map every in-scope user story or specification anchor to at least one task.
|
|
74
85
|
2. Walk dependencies and repair every cycle with the exact cycle chain visible.
|
|
75
86
|
3. Resolve every `trace_to` path and heading against a real file.
|
|
76
|
-
4.
|
|
87
|
+
4. Resolve every `HC-<n>` against `.ultra/north-star.md`. A dangling constraint id is
|
|
88
|
+
the same defect as a dangling `trace_to`: it reads as checked and never was.
|
|
89
|
+
5. Surface complexity, more than eight target files, or more than twenty tasks as
|
|
77
90
|
scope warnings; they are observations, not semantic verdicts.
|
|
78
|
-
|
|
91
|
+
6. Estimate context at roughly `complexity × 5%`; surface anything above 40%.
|
|
79
92
|
|
|
80
93
|
Report the graph, frontier, seams, warnings and first task. Recommend the next explicit
|
|
81
94
|
capability from the files; do not invoke it.
|
|
@@ -39,6 +39,12 @@ The three checkpoints are `04-product-strategy`, `21-features-scope`, and
|
|
|
39
39
|
recommendation, wait for the owner's decision, then continue. Other areas write their
|
|
40
40
|
report and mapped section immediately without another ceremony.
|
|
41
41
|
|
|
42
|
+
Areas sitting between two checkpoints are independent and may run in parallel through
|
|
43
|
+
the host's native bounded subagents, each loading exactly one reference. That
|
|
44
|
+
strengthens progressive disclosure rather than breaking it — the parent holds no step
|
|
45
|
+
prompt at all. The checkpoints stay barriers: nothing after one starts until the owner
|
|
46
|
+
has answered it, because its conclusion changes what the later areas are even asking.
|
|
47
|
+
|
|
42
48
|
## Investigate and write
|
|
43
49
|
|
|
44
50
|
For each selected area:
|
|
@@ -28,8 +28,10 @@ happens here, after several slices make a useful structure visible, not inside T
|
|
|
28
28
|
## Run the lenses
|
|
29
29
|
|
|
30
30
|
Use the host's native bounded subagents, in the background where available; otherwise
|
|
31
|
-
run them sequentially.
|
|
32
|
-
|
|
31
|
+
run them sequentially. **All six lenses are selected by default.** Skipping one requires
|
|
32
|
+
a stated reason recorded in `SUMMARY.json` — "its evidence cannot change the verdict"
|
|
33
|
+
is a judgement made before seeing the evidence, and left as a default it becomes a way
|
|
34
|
+
to run less work rather than a considered choice. Give each the packet path and digest,
|
|
33
35
|
`references/unified-schema.md`, and exactly one lens:
|
|
34
36
|
|
|
35
37
|
- `references/code.md`
|
|
@@ -60,6 +62,28 @@ three or more files do so, write `UNRESOLVED.md` with `ARCHITECTURAL_CONCERN` an
|
|
|
60
62
|
|
|
61
63
|
Report both axes, exact scope, checks, residual findings and any refactor performed.
|
|
62
64
|
|
|
65
|
+
## Recheck across model families
|
|
66
|
+
|
|
67
|
+
Six lenses are six angles from one model family, so they share blind spots: what all
|
|
68
|
+
six miss, a seventh angle from the same family misses too. Independence comes from a
|
|
69
|
+
different model, not from another lens.
|
|
70
|
+
|
|
71
|
+
For a `major` Change, or one touching authorization, payments, personal data or
|
|
72
|
+
migrations, recommend a cross-family recheck and wait for the owner's decision. Do not
|
|
73
|
+
invoke `ultra-delegate` unless the owner has explicitly asked for another model or host
|
|
74
|
+
for this review. Once that authority exists, follow `../ultra-delegate/SKILL.md`. For a
|
|
75
|
+
`quick` profile, skip the recommendation and say so in the report.
|
|
76
|
+
|
|
77
|
+
- Send the aggregated `SUMMARY.json` and the diff, **not** the raw lens artifacts. The
|
|
78
|
+
worker should form its own reading rather than grade this one.
|
|
79
|
+
- Ask two things: which findings the evidence does not actually support, and what this
|
|
80
|
+
diff gets wrong that no finding mentions. The second question is why the recheck is
|
|
81
|
+
worth its cost.
|
|
82
|
+
- A worker finding no local lens raised is a candidate, not a verdict. Verify it
|
|
83
|
+
against the source exactly as a lens finding is verified, and record its origin.
|
|
84
|
+
- Disagreement is information, not a tie to break. `ultra-delegate` already forbids
|
|
85
|
+
turning a vote or a score into truth; record both readings with their evidence.
|
|
86
|
+
|
|
63
87
|
## When the owner decides
|
|
64
88
|
|
|
65
89
|
The owner chooses risk acceptance, a scope reduction, or which stuck path to take.
|
|
@@ -70,4 +94,5 @@ Workers never edit source, task state or another lens artifact.
|
|
|
70
94
|
- `references/unified-schema.md` — JSON contract shared by all lenses.
|
|
71
95
|
- `references/worker-packet.md` — exact immutable input packet and digest procedure.
|
|
72
96
|
- `references/review-modes.md` — choose task, Change, full, or delta scope.
|
|
97
|
+
- `../ultra-delegate/SKILL.md` — read after the owner authorizes a cross-family recheck.
|
|
73
98
|
- `../ultra-think/references/autonomy-boundary.md` — read before a fix reduces intent.
|
|
@@ -45,6 +45,11 @@ the owner decides what to fix or accept.
|
|
|
45
45
|
6. **Security**: run the repository's dependency and security checks, then inspect the
|
|
46
46
|
trust boundaries changed by this Change.
|
|
47
47
|
|
|
48
|
+
The six are independent read-only audits and may run in parallel through the host's
|
|
49
|
+
native bounded subagents. Each returns its findings; the parent writes the one report.
|
|
50
|
+
A worker never writes `.ultra/test-report.json` itself — six writers on one canonical
|
|
51
|
+
file is how a report loses findings.
|
|
52
|
+
|
|
48
53
|
Read `references/export-syntax.md` before collecting exports. The table finds
|
|
49
54
|
candidates; repository conventions and real consumers decide what is public.
|
|
50
55
|
|