ultra-builder-pro-cli 0.26.2 → 3.0.2

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.
Files changed (67) hide show
  1. package/.ultra-template/contexts/TEMPLATE.md +64 -29
  2. package/.ultra-template/north-star.md +35 -18
  3. package/.ultra-template/tasks.json +1 -0
  4. package/.ultra-template/test-report.json +17 -1
  5. package/CHANGELOG.md +163 -1
  6. package/README.md +108 -38
  7. package/adapters/_shared/host-profile.cjs +68 -12
  8. package/adapters/_shared/plugin-core.cjs +4 -5
  9. package/adapters/_shared/runtime-assets.cjs +11 -2
  10. package/adapters/zcode.js +375 -0
  11. package/bin/delegate-worker.cjs +20 -0
  12. package/bin/delegate.cjs +94 -25
  13. package/bin/install.js +11 -6
  14. package/docs/ARCHITECTURE.md +84 -23
  15. package/docs/ARTIFACT-AUTHORITY.md +167 -22
  16. package/docs/DECISIONS.md +131 -17
  17. package/docs/PHILOSOPHY.md +58 -7
  18. package/docs/PLUGIN-ISOLATION-CONTRACT.md +6 -0
  19. package/docs/RUNTIME-COMPAT-MATRIX.md +106 -13
  20. package/docs/SKILL-AUTHORING.md +4 -3
  21. package/docs/WORKFLOW-LIFECYCLE.md +126 -28
  22. package/docs/evals/adversarial-review-2026-08-14.md +84 -0
  23. package/docs/evals/zcode-automation-2026-08-14.md +103 -0
  24. package/hooks/README.md +27 -4
  25. package/hooks/_common.py +1678 -61
  26. package/hooks/adapters/zcode.py +227 -0
  27. package/hooks/compact_context.py +176 -17
  28. package/hooks/mid_workflow_recall.py +27 -5
  29. package/hooks/post_edit_guard.py +133 -23
  30. package/hooks/session_context.py +707 -22
  31. package/package.json +6 -3
  32. package/skills/ultra-change/SKILL.md +40 -9
  33. package/skills/ultra-change/references/change-contract.md +93 -27
  34. package/skills/ultra-change/references/execution-grant.md +109 -0
  35. package/skills/ultra-change/references/primary-transfer.md +273 -0
  36. package/skills/ultra-change/scripts/validate_primary_transfer.cjs +1928 -0
  37. package/skills/ultra-delegate/SKILL.md +24 -2
  38. package/skills/ultra-delegate/references/delegation-contract.md +21 -1
  39. package/skills/ultra-deliver/SKILL.md +85 -11
  40. package/skills/ultra-dev/SKILL.md +171 -41
  41. package/skills/ultra-grilling/SKILL.md +10 -7
  42. package/skills/ultra-grilling/references/reframing.md +7 -3
  43. package/skills/ultra-init/SKILL.md +44 -7
  44. package/skills/ultra-init/scripts/init_project.cjs +968 -21
  45. package/skills/ultra-plan/SKILL.md +70 -44
  46. package/skills/ultra-plan/references/task-evidence-v2.md +300 -0
  47. package/skills/ultra-plan/scripts/validate_task_evidence.cjs +859 -0
  48. package/skills/ultra-research/SKILL.md +38 -10
  49. package/skills/ultra-research/references/04-product-strategy.md +11 -2
  50. package/skills/ultra-research/references/21-features-scope.md +8 -0
  51. package/skills/ultra-research/references/22-success-metrics.md +4 -3
  52. package/skills/ultra-research/references/99-synthesis.md +19 -2
  53. package/skills/ultra-research/references/north-star-v2.md +168 -0
  54. package/skills/ultra-research/references/wayfinding.md +8 -0
  55. package/skills/ultra-research/scripts/validate_north_star.cjs +1174 -0
  56. package/skills/ultra-review/SKILL.md +201 -27
  57. package/skills/ultra-review/references/adversarial-evaluation.md +31 -0
  58. package/skills/ultra-review/references/spec.md +5 -0
  59. package/skills/ultra-review/references/unified-schema.md +146 -11
  60. package/skills/ultra-review/references/worker-packet.md +151 -8
  61. package/skills/ultra-review/scripts/review_wait.py +2653 -63
  62. package/skills/ultra-status/SKILL.md +95 -11
  63. package/skills/ultra-tdd/SKILL.md +11 -4
  64. package/skills/ultra-tdd/references/test-execution.md +6 -1
  65. package/skills/ultra-test/SKILL.md +145 -17
  66. package/skills/ultra-test/scripts/validate_review_transport.cjs +549 -0
  67. package/skills/ultra-test/scripts/worktree_digest.cjs +518 -30
@@ -9,36 +9,41 @@ Planning owns decomposition and technical design; files carry it across sessions
9
9
 
10
10
  ## Before you start
11
11
 
12
- 1. Resolve exactly one `.ultra/changes/active/<change_id>/intent.md`. If none or more
13
- than one exists, stop with that file conflict. The intent must be `accepted`, every
14
- blocking decision resolved, and its `## Research Disposition` exit evidence
15
- satisfied before decomposition.
16
- 2. Read `.ultra/tasks.json`; select matching tasks and read each unfinished context and
12
+ 1. If model-selected, verify the live execution grant in `../ultra-change/references/execution-grant.md` — a current session-local activation or a stably verified durable work-package grant; without either, stop.
13
+ 2. Read `../ultra-change/references/change-contract.md` and apply its **Active Change
14
+ authority resolution** before reading any active `intent.md` or resolving a current
15
+ `change_id`. This workflow requires its one valid active authority; any zero result
16
+ or typed diagnostic stops before decomposition until the stated repair or retry
17
+ succeeds. The intent must be `accepted`, every blocking decision resolved, its
18
+ `## Research Disposition` exit evidence satisfied, and its `## North Star Trace`
19
+ current before decomposition.
20
+ 3. Read `.ultra/tasks.json`; select matching tasks and read each unfinished context and
17
21
  Resume Note. Preserve all historical tasks in the append-only ledger.
18
- 3. Read `CONTEXT.md` for vocabulary and the relevant `.ultra/decisions/` entries.
19
- 4. Read the active Change intent, its `trace_to` specification anchors, and the
22
+ 4. Read `CONTEXT.md` for vocabulary and the relevant `.ultra/decisions/` entries.
23
+ 5. Read the active Change intent, its `trace_to` specification anchors, and the
20
24
  source, tests, consumers and recovery paths those anchors describe.
21
25
 
22
26
  ## Definition of done
23
27
 
24
- - `.ultra/tasks.json` and one `.ultra/contexts/task-<id>.md` per current-Change task
25
- agree on identifiers, stable `change_id`, status, dependencies and trace anchors.
28
+ - `.ultra/tasks.json` uses `$schema: "ultra-task-ledger-v2"` and is the sole
29
+ task-status authority. Every current-Change row resolves one context whose stable
30
+ identifiers, dependencies and trace anchors agree with the ledger.
26
31
  - The owner confirmed any material posture. Seams resolve to code; technical selection
27
32
  stays model-owned unless it changes public contract, accepted risk, or material trade-off.
28
- - Every feature task is a tracer bullet touching at least two layers, unless the
29
- Change itself demonstrably touches only one layer.
30
- - Every context names the north-star hard constraints its work could violate, and
31
- each `HC-<n>` it names resolves to a real entry in `.ultra/north-star.md`.
33
+ - Every feature task is a tracer bullet crossing the real boundaries needed to make its
34
+ observable behavior work; a genuinely local Change does not invent extra layers.
35
+ - Every task context records resolving `FP-<n>` premises, `NS-<n>` outcomes, and
36
+ `HC-<n>` constraints as IDs only. It explains the task-local causal contribution and
37
+ potential constraint breach without mirroring North Star prose.
32
38
  - Every Change acceptance id maps to at least one task context, and every context id
33
39
  resolves back to the active Change.
34
- - Coverage, dependency, trace, scope and context-budget checks have concrete results.
40
+ - Coverage, dependency, trace, scope and context-pressure checks have concrete results.
35
41
 
36
42
  ## Fix the planning posture
37
43
 
38
- Choose `EXPAND`, `SELECTIVE`, `HOLD` or `REDUCE`; default to `SELECTIVE`. Once
39
- chosen, keep that posture visible in the active Change intent rather than silently drifting.
40
- Write it to the active Change `intent.md` under `## Planning Posture`; there is no
41
- separate `plan.md` authority.
44
+ Choose `EXPAND`, `SELECTIVE`, `HOLD` or `REDUCE`; default to `SELECTIVE`. Write it under
45
+ `## Planning Posture` in active `intent.md`; there is no separate `plan.md` authority.
46
+ Keep the posture visible rather than silently drifting.
42
47
  Use `../ultra-grilling/SKILL.md` through the host-native question surface when the
43
48
  choice remains material, one question with a recommendation at a time.
44
49
 
@@ -54,11 +59,14 @@ expand with old and new forms, migrate bounded batches, then contract the old fo
54
59
 
55
60
  Build the graph with these structural defences:
56
61
 
57
- - **Walking Skeleton**: Task 1 traverses every layer this Change touches through one
58
- real request and real data. A genuinely one-layer Change does not invent one.
59
- - **Contract task**: create it before both implementations when targets cross two top-
60
- level source directories or two processes/services.
61
- - **Integration Checkpoint**: insert one after every three or four feature tasks.
62
+ - **Walking Skeleton**: the earliest executable tracer bullet traverses the real
63
+ boundaries this Change touches with real data. A genuinely one-layer Change does not
64
+ invent extra layers.
65
+ - **Contract task**: create one before dependent implementations when a shared contract
66
+ must remain valid while independently changed boundaries coexist.
67
+ - **Integration Checkpoint**: insert one where independently developed slices first
68
+ compose, or where the observed coupling or recovery risk makes an intermediate
69
+ whole-path check useful.
62
70
  - A feature task that touches only one of several affected layers is merged or split
63
71
  into a tracer bullet; moving a whole layer into one task is horizontal slicing.
64
72
 
@@ -68,21 +76,27 @@ public contract or another material product, risk, or recovery trade-off.
68
76
 
69
77
  ## Write the files
70
78
 
71
- Each task records `id`, `title`, `type`, `priority`, `complexity`, `status`,
72
- `dependencies`, `context_file`, `trace_to` and `change_id`. Task ids are globally
73
- unique, and every dependency must name a task with the same `change_id`; an archived
74
- Change must never become an implicit prerequisite of current work. Complexity is only a
75
- splitting and context signal: 1–2 is local, 3–5 is bounded, 6–7 crosses a boundary,
76
- and complexity > 7 must split.
79
+ The ledger root records `$schema: "ultra-task-ledger-v2"` and `tasks`. Each new task
80
+ records `id`, `title`, `type`, `priority`, `status`, `dependencies`, `context_file`,
81
+ `trace_to` and `change_id`. Task ids are globally unique, and every dependency must name
82
+ a task with the same `change_id`; an archived Change must never become an implicit
83
+ prerequisite of current work. A legacy `complexity` field remains readable only as a
84
+ migration diagnostic. It is not copied into new rows and never decides splitting,
85
+ priority, scope, context, or completion.
77
86
 
78
87
  Append new tasks or repair matching current-Change tasks in place; never replace the
79
- ledger with only the latest graph. A `quick` Change produces exactly one minimal task
80
- and context rather than bypassing the task/evidence lifecycle.
81
-
82
- Each context records Change Acceptance IDs, task-local Acceptance, confirmed seams,
83
- layers touched, target files, Implementation, verification commands, the hard
84
- constraints the work could violate, Definition of Drift, Change Log, Completion and
85
- Resume Note. Read every file back; task count and context count must match.
88
+ ledger with only the latest graph. Every active Change receives the smallest graph that
89
+ covers its real seams, evidence, review, and recovery needs. A profile does not decide
90
+ the number of tasks or contexts.
91
+
92
+ Each context records Change Acceptance IDs, a task-local Acceptance table with `ID`,
93
+ `Criterion`, `Verification type`, and `Required evidence`, confirmed seams, layers
94
+ touched, target files, Implementation, verification commands, the hard constraints the
95
+ work could violate, a Trace containing `FP-<n>`, `NS-<n>`, and `HC-<n>` IDs, Definition
96
+ of Drift, Change Log, Completion, Task Review, and Resume Note. A v2 context does not
97
+ repeat task status. If a legacy context contains a Status or Complexity header, preserve
98
+ it as a migration diagnostic and use the ledger value. Read every file back and verify
99
+ that every row resolves its named context and every current context resolves one row.
86
100
 
87
101
  Name a hard constraint whenever the task could plausibly breach it, not only when you
88
102
  expect it to. The entry costs one line and is what makes a later breach a checkable
@@ -95,11 +109,21 @@ touches nothing constrained.
95
109
  context IDs. Map every in-scope user story or specification anchor to at least one task.
96
110
  2. Walk dependencies and repair every cycle with the exact cycle chain visible.
97
111
  3. Resolve every `trace_to` path and heading against a real file.
98
- 4. Resolve every `HC-<n>` against `.ultra/north-star.md`. A dangling constraint id is
99
- the same defect as a dangling `trace_to`: it reads as checked and never was.
100
- 5. Surface complexity, more than eight target files, or more than twenty tasks as
101
- scope warnings; they are observations, not semantic verdicts.
102
- 6. Estimate context at roughly `complexity × 5%`; surface anything above 40%.
112
+ 4. Resolve the Change and task `North Star Trace` `FP-<n>`/`NS-<n>`/`HC-<n>` ids
113
+ against `.ultra/north-star.md`. A revision mismatch is a stale observation that
114
+ returns to Change reconciliation, not a semantic verdict about alignment.
115
+ 5. Surface concrete scope pressure: unresolved dependencies, duplicated ownership,
116
+ boundaries that cannot be tested independently, evidence that cannot fit the named
117
+ seam, or a context that no longer supports a reliable resume. File, task, line, and
118
+ context counts do not decide plan quality.
119
+ 6. Validate exact ledger fields, ids, dependency edges, paths and typed acceptance
120
+ shapes. A validator reports structural diagnostics only; it never decides whether
121
+ the decomposition, criterion, evidence, or plan is semantically sufficient.
122
+ Follow `../ultra-review/SKILL.md` in plan mode. Require a validated current
123
+ `SUMMARY.json`; resolve every blocking finding and refresh affected evidence before
124
+ handoff. If further repair is not justified or an authorized resource ceiling is
125
+ reached, preserve the findings and return the evidence to the responsible model or
126
+ owner. Attempt and finding counts never manufacture convergence or failure.
103
127
 
104
128
  Report the graph, frontier, seams, warnings and first task. Recommend the next explicit
105
129
  capability from the files; do not invoke it.
@@ -107,10 +131,12 @@ capability from the files; do not invoke it.
107
131
  ## When the owner decides
108
132
 
109
133
  The owner chooses material posture, reductions, omissions, and any seam changing public
110
- contract or material trade-off. The model owns technical decomposition and seams.
111
- Repair mechanical cycles and broken paths before handoff.
112
-
134
+ contract or material trade-off. The model owns decomposition and repairs broken paths.
113
135
  ## References
114
136
 
137
+ - `../ultra-change/references/change-contract.md` — canonical Active Change authority resolution.
115
138
  - `../ultra-grilling/SKILL.md` — read before a material posture or seam question.
116
139
  - `../ultra-think/SKILL.md` — read when one evidenced decision blocks decomposition.
140
+ - `../ultra-review/SKILL.md` — read after plan files pass mechanical verification.
141
+ - `../ultra-change/references/execution-grant.md` — read only for grant-activated continuation.
142
+ - `references/task-evidence-v2.md` — canonical typed task evidence and task-review contract.
@@ -0,0 +1,300 @@
1
+ # Task ledger, context, and evidence v2
2
+
3
+ Use this contract when Plan creates a task or when Dev refreshes completion evidence.
4
+ The ledger owns mechanical task status. A task context contains meaning and resume
5
+ information but does not repeat `status`, `priority`, or `complexity` in a metadata
6
+ header. A legacy header is readable only as an observation; the ledger wins and the
7
+ reader reports a migration diagnostic.
8
+
9
+ ## Ledger and context
10
+
11
+ The ledger root is exactly `$schema` plus `tasks`, with `$schema` set to
12
+ `ultra-task-ledger-v2`. A current task row has these fields:
13
+
14
+ ```text
15
+ id, title, type, priority, status, dependencies, context_file, trace_to, change_id
16
+ ```
17
+
18
+ Legacy rows may retain `complexity`; do not use it to decide task, file, question,
19
+ finding, repair-round, or quality limits. The Acceptance section in every current
20
+ context starts with the Change Acceptance IDs and this exact table:
21
+
22
+ ```markdown
23
+ | ID | Criterion | Verification type | Required evidence |
24
+ |---|---|---|---|
25
+ ```
26
+
27
+ Criterion IDs are unique inside one task. Verification type is exactly `command`,
28
+ `inspection`, `owner-judgment`, or `external-observation`. The required-evidence cell
29
+ names evidence that can actually establish the criterion; it is not a second status.
30
+
31
+ ## Evidence root
32
+
33
+ `.ultra/evidence/<task-id>/evidence.json` is the one final completion record. It uses
34
+ `ultra-task-evidence-v2` and the exact ordered root fields below:
35
+
36
+ The product-worktree digest has one fixed boundary: it excludes `.ultra/evidence/**`,
37
+ whose command and external-observation entries bind raw bytes as
38
+ `raw_evidence_sha256` before stable exact record bytes are bound as `evidence_digest` by
39
+ aggregate Test. This makes evidence publication and refresh non-self-referential without
40
+ hiding provenance. No workflow supplies an additional exclusion.
41
+
42
+ ```text
43
+ $schema, task_id, change_id, context, subject, acceptance, dimensions,
44
+ task_review, artifacts, limitations, timestamp
45
+ ```
46
+
47
+ `context` is exactly `{path, acceptance_sha256}`. Hash the UTF-8 bytes beginning with
48
+ the `## Acceptance Criteria` heading and ending immediately before the next level-two
49
+ heading. Do not bind the whole mutable task context. `subject` is exactly
50
+ `{git_head, worktree_digest, observed_at}`. The `subject` is an independently captured
51
+ completion-snapshot freshness observation: capture it after the final strict task Review
52
+ validates and immediately before evidence publication. `task_review` separately binds
53
+ the retained strict summary. Worker Packet v1 carries no worktree digest and its
54
+ `SUMMARY.json` records `worktree_digest: null`, so neither review artifact proves or
55
+ cryptographically binds `subject.worktree_digest`. The subject is not rebound to a later
56
+ aggregate Change worktree.
57
+
58
+ Each acceptance item is exactly:
59
+
60
+ ```json
61
+ {
62
+ "criterion_id": "A-01",
63
+ "verification_type": "inspection",
64
+ "evidence": {
65
+ "source": "path/to/source",
66
+ "observation": "The observable fact.",
67
+ "revision": "the observed revision"
68
+ },
69
+ "disposition": {
70
+ "authority": "model",
71
+ "result": "satisfied",
72
+ "rationale": "Why the evidence supports this disposition."
73
+ }
74
+ }
75
+ ```
76
+
77
+ `result` is `satisfied`, `gap`, or `not_applicable`. The validator checks the record's
78
+ shape and authority token. It never infers the result from an exit code, digest,
79
+ counter, validator success, or model assertion.
80
+
81
+ ## Typed evidence
82
+
83
+ Use exactly one evidence object for each criterion:
84
+
85
+ - `command`: `{command, cwd, exit_code, raw_evidence_ref, raw_evidence_sha256,
86
+ freshness_identity}`, where freshness identity is
87
+ `{git_head, worktree_digest, observed_at}`.
88
+ - `inspection`: `{source, observation, revision}`.
89
+ - `owner-judgment`: `{owner_record_ref, owner_statement_or_disposition}`. Its
90
+ disposition authority must be `owner`; the model and validator cannot satisfy it.
91
+ - `external-observation`: `{provider, run_id, observed_at, raw_evidence_ref,
92
+ raw_evidence_sha256, observation}`.
93
+
94
+ `raw_evidence_sha256` is the lowercase SHA-256 of the exact bytes named by
95
+ `raw_evidence_ref`. The structural validator requires a normalized, mechanically safe
96
+ repository-relative ref and an exact 64-hex digest; structural mode does not dereference
97
+ the ref. Dev, Test, Status, and Deliver resolve it below the real repository root, require
98
+ every parent and the final file to remain repository-contained and non-symlink, open the
99
+ final ordinary regular file nonblocking and no-follow, cap the snapshot at 8 MiB, and
100
+ compare path and descriptor identity before and after reading. They hash only that one
101
+ bounded stable byte snapshot. A missing, special, symlinked, escaped, oversized, or
102
+ replaced ref is a typed evidence gap with retry or owning-task repair, never accepted
103
+ provenance.
104
+
105
+ `dimensions` contains exactly `tests_written`, `tests_passed`, `persistence_real`,
106
+ `feature_flags_audit`, `vertical_slice`, and `spec_trace`. Each dimension is an explicit
107
+ `{status, evidence_refs, rationale}` observation; its status uses the same three result
108
+ tokens and is not a semantic score.
109
+
110
+ ## Task review
111
+
112
+ First-review admission does not consume this final record. It consumes the ledger's
113
+ `in_progress` row, the task context and acceptance bytes, the immutable review packet,
114
+ and actual pre-review evidence already observed at the four typed authorities. Raw
115
+ outputs and citations may exist before review, but they do not form another evidence
116
+ schema, completion record, or task-status authority. Do not write `evidence.json` before the task's validated final `SUMMARY.json` exists.
117
+
118
+ `task_review` is exactly:
119
+
120
+ ```json
121
+ {
122
+ "execution_packet": {
123
+ "state": "available",
124
+ "digest": "<sha256>",
125
+ "limitation": null
126
+ },
127
+ "session_id": "<review-session>",
128
+ "summary_ref": ".ultra/reviews/<review-session>/SUMMARY.json",
129
+ "summary_digest": "<sha256>",
130
+ "blocking_findings": [
131
+ {
132
+ "id": "<finding-id>",
133
+ "resolution": "<what changed>",
134
+ "disposition": "<resolved, accepted risk, or still a gap>",
135
+ "evidence_refresh_refs": ["<fresh evidence>"]
136
+ }
137
+ ],
138
+ "retention": "<when the derived review may be removed>"
139
+ }
140
+ ```
141
+
142
+ For work that predates Execution Packet v1, use `state: pre-v1-unavailable`, a null
143
+ digest, and a non-empty limitation. Never manufacture a bootstrap digest. Keep the task
144
+ `in_progress` through implementation and blocking review repair. If a repair changes
145
+ implementation or evidence in review scope, create and validate a new immutable review
146
+ session before closeout; do not claim that Worker Packet v1 binds the resulting worktree.
147
+
148
+ ### Task-review provenance branches
149
+
150
+ `task_review` carries exactly one of two discriminated provenance branches. Records
151
+ with no `review_mode` field remain the strict-v4 branch, so every existing v2 record
152
+ and aggregate projection stays valid without migration.
153
+
154
+ The **strict-v4 branch** (`review_mode: "strict-v4"` or absent) is exactly the shape
155
+ above: a real retained `.ultra/reviews/<session>/SUMMARY.json` identity consumed by
156
+ the review waiter and the transport validator.
157
+
158
+ The **external-manual branch** (`review_mode: "external-manual"`) binds one real
159
+ repository-relative JSON receipt published by the owner-designated external reviewer
160
+ under `.ultra/evidence/<task-id>/`, never under `.ultra/reviews/`:
161
+
162
+ ```json
163
+ {
164
+ "review_mode": "external-manual",
165
+ "execution_packet": { "state": "pre-v1-unavailable", "digest": null, "limitation": "..." },
166
+ "receipt_ref": ".ultra/evidence/<task-id>/external-review.json",
167
+ "receipt_sha256": "<sha256-of-exact-receipt-bytes>",
168
+ "blocking_findings": [],
169
+ "retention": "Retain the exact external receipt bytes; it is a reconstructable observation, never semantic authority."
170
+ }
171
+ ```
172
+
173
+ The receipt itself uses `$schema: ultra-external-review-receipt-v1` with exactly
174
+ `reviewer` (identity), `reviewer_role: "read-only"`, `task_id`, `change_id`,
175
+ `reviewer_authority` (`ref` + `sha256` of the owner record authorizing the external
176
+ review mode/reviewer), `reviewed_contract` (`ref` + `sha256` of the reviewed
177
+ contract bytes), `subject` (`git_head` 40-hex + `worktree_digest` 64-hex of the
178
+ reviewed product worktree), `verdict` (`approve | request_changes`), `findings` (an
179
+ exact array of `{id, severity, title}` with severity P0–P3 and unique ids), and an
180
+ RFC 3339 `timestamp`. It is a reconstructable observation of who reviewed what bytes
181
+ with what result — it is not semantic authority, not owner acceptance, and never a
182
+ fabricated strict SUMMARY/ADMISSION/session. Only current P0/P1 (or owner-promoted)
183
+ receipt findings may appear in `blocking_findings`, and the blocking disposition id
184
+ set must equal exactly the receipt's P0/P1 id set: `approve` is rejected with any
185
+ unresolved P0/P1, `request_changes` with none, and P2/P3 stay recorded and
186
+ non-blocking.
187
+
188
+ Receipt verification is mandatory: the normal canonical sensor invocation below
189
+ verifies an external-manual record's receipt automatically, and
190
+ `--verify-external-receipt` remains a compatible alias:
191
+
192
+ ```bash
193
+ node skills/ultra-plan/scripts/validate_task_evidence.cjs \
194
+ .ultra/evidence/<task-id>/evidence.json
195
+ ```
196
+
197
+ The sensor reuses one canonical stable bounded no-follow repository-chain snapshot
198
+ for the receipt, the reviewed contract, and the reviewer-authority record: the real
199
+ repository root and every managed parent must stay ordinary non-symlink directories
200
+ (identities rechecked after reading), and the final entry must be an ordinary
201
+ regular file. It checks only authority/provenance facts: safe normalized receipt
202
+ location inside the task's evidence directory and outside `.ultra/reviews/`, exact
203
+ stable bytes against `receipt_sha256`, the exact receipt schema, task/change
204
+ identity equality with the evidence, reviewed HEAD and product-worktree digest
205
+ equality with the completion subject, exact stable bytes and digests for the
206
+ reviewed contract and the reviewer-authority record, well-formed severities, the
207
+ exact blocker/verdict set, and that every blocking disposition binds a P0/P1
208
+ finding that actually exists in the receipt. A missing, malformed, symlinked,
209
+ special, escaped, oversized, replaced, digest-mismatched, identity- or
210
+ subject-mismatched, unbound-contract, unbound-authority, or substituted receipt
211
+ returns typed reachable repair and is never treated as accepted. It never infers
212
+ semantic acceptance: an `approve` verdict is a recorded observation, and owner
213
+ acceptance remains a separate owner-judgment.
214
+
215
+ The same invocation with `--projection` emits, after successful verification, the
216
+ exact branch-specific aggregate Test projection item for the record. A strict-v4
217
+ record keeps the byte-compatible
218
+ `{task_id, schema, evidence_ref, evidence_digest, task_review_session,
219
+ task_review_summary_digest}` shape; an external-manual record carries
220
+ `{task_id, schema, evidence_ref, evidence_digest, task_review_mode:
221
+ "external-manual", task_review_receipt_ref, task_review_receipt_digest}` instead.
222
+ Test, Status, and Deliver consume that mechanical result verbatim; a strict session
223
+ identity can never substitute for the receipt fields and neither branch's
224
+ projection is rewritten into the other's. The projection is withheld whenever any
225
+ diagnostic is present.
226
+
227
+ Aggregate Test, Status, and Deliver preserve and recheck the declared branch: strict
228
+ items replay the retained strict summary through the existing waiter and transport
229
+ consumers; external-manual items take the bounded stable receipt bytes, recompute
230
+ `receipt_sha256`, and rerun the sensor's verify mode instead. An aggregate
231
+ projection item for an external-manual task substitutes
232
+ `task_review_mode: "external-manual"` plus `task_review_receipt_ref` and
233
+ `task_review_receipt_digest` for the strict `task_review_session` and
234
+ `task_review_summary_digest` fields; strict items keep their existing exact shape.
235
+ No consumer may rewrite one branch into the other or accept a strict SUMMARY where
236
+ the branch declares an external receipt.
237
+ When the newest current-subject summary returns `REQUEST_CHANGES`, consume its exact
238
+ validated `findings` array rather than a count or list copied from any historical summary.
239
+ Preserve every finding id, resolve or authoritatively disposition every current P0/P1,
240
+ and refresh each affected evidence reference before creating one fresh subject and
241
+ review. The blocking disposition set binds only current P0/P1 findings (or a P2 the
242
+ owner promoted after the current review reclassified it as P1 on evidence); P2 and P3
243
+ findings stay recorded in the retained summary as non-blocking backlog and never block
244
+ closeout, and no consumer may implicitly promote them to blockers inside the same task.
245
+ A later summary may contain a different set; that current exact set controls
246
+ recovery.
247
+ After the final validated `SUMMARY.json`, independently capture the completion subject and immediately write one canonical `ultra-task-evidence-v2` record with its separate exact task-review binding.
248
+ Write `completed` to the ledger only after every blocking finding has a disposition,
249
+ relevant evidence is refreshed, the canonical record and context review facts are
250
+ durable, and both are read back.
251
+
252
+ If later work invalidates a completed task, reopening is an explicit recovery action.
253
+ A reopen changes the ledger-authoritative row from `completed` to `in_progress`; there
254
+ is no silent demotion. Before the transition, record the affected criterion IDs and reason in both the context Change Log and Resume Note. Preserve the prior frozen review
255
+ as historical evidence, read the ledger write back, refresh only the affected evidence,
256
+ obtain a new final review, then capture and publish a new completion subject.
257
+
258
+ ## Aggregate Test projection
259
+
260
+ The v2 Test template carries ordered `task_evidence` immediately after `task_ids`.
261
+ Every item is exactly:
262
+
263
+ ```json
264
+ {
265
+ "task_id": "<task-id>",
266
+ "schema": "ultra-task-evidence-v2",
267
+ "evidence_ref": ".ultra/evidence/<task-id>/evidence.json",
268
+ "evidence_digest": "<sha256>",
269
+ "task_review_session": "<review-session>",
270
+ "task_review_summary_digest": "<sha256>"
271
+ }
272
+ ```
273
+
274
+ The evidence digest already binds `context.acceptance_sha256`; do not copy that field
275
+ into the Test projection. Historical `ultra-task-evidence-v1` remains readable and is
276
+ classified `legacy-v1`, but it cannot support a new v2 completion claim without an
277
+ honest migration.
278
+
279
+ The projection preserves each task's independently captured completion-snapshot
280
+ freshness observation and its separate task-review provenance. Aggregate Test binds its
281
+ report subject independently to the current whole Change; it never requires an earlier
282
+ task `subject.worktree_digest` to equal that aggregate digest and never treats the
283
+ retained task-review summary as proof of the completion subject. Instead it independently
284
+ rechecks the current Acceptance bytes, typed criterion IDs and verification types,
285
+ retained strict task-review summary, durable owner records, and every cited affected
286
+ artifact. An invalidated item uses the explicit reopen path above.
287
+
288
+ Run the structural sensor with:
289
+
290
+ ```bash
291
+ node skills/ultra-plan/scripts/validate_task_evidence.cjs \
292
+ .ultra/evidence/<task-id>/evidence.json
293
+ ```
294
+
295
+ The sensor resolves one input path and captures at most 8 MiB from a regular,
296
+ non-symlink file opened nonblocking and no-follow where the platform supports it. It
297
+ compares path and descriptor identity before and after the read, decodes the captured
298
+ bytes as strict UTF-8, and parses JSON from that same snapshot. Typed `input_*`
299
+ diagnostics return control for retry when the path is missing, replaced, oversized,
300
+ non-regular, a symlink, invalid UTF-8, or invalid JSON.