ultra-builder-pro-cli 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/.ultra-template/contexts/TEMPLATE.md +87 -0
  2. package/.ultra-template/decisions/.gitkeep +1 -0
  3. package/.ultra-template/evidence/.gitkeep +1 -0
  4. package/.ultra-template/north-star.md +46 -0
  5. package/.ultra-template/research/.gitkeep +1 -0
  6. package/.ultra-template/specs/discovery.md +2 -2
  7. package/.ultra-template/tasks.json +3 -0
  8. package/.ultra-template/test-report.json +27 -0
  9. package/CHANGELOG.md +49 -0
  10. package/README.md +217 -579
  11. package/adapters/_shared/delegate-profiles/kimi-read-only.md +15 -0
  12. package/adapters/_shared/delegate-profiles/kimi-write.md +17 -0
  13. package/adapters/_shared/file-ops.cjs +76 -2
  14. package/adapters/_shared/host-profile.cjs +97 -0
  15. package/adapters/_shared/plugin-core.cjs +204 -0
  16. package/adapters/_shared/runtime-assets.cjs +31 -96
  17. package/adapters/claude.js +92 -291
  18. package/adapters/codex.js +309 -842
  19. package/adapters/grok.js +143 -1469
  20. package/adapters/kimi.js +124 -1053
  21. package/adapters/opencode.js +230 -742
  22. package/bin/delegate-worker.cjs +323 -0
  23. package/bin/delegate.cjs +456 -0
  24. package/bin/install.js +38 -11
  25. package/docs/ARCHITECTURE.md +122 -216
  26. package/docs/ARTIFACT-AUTHORITY.md +90 -268
  27. package/docs/DECISIONS.md +75 -87
  28. package/docs/PHILOSOPHY.md +177 -0
  29. package/docs/PLUGIN-ISOLATION-CONTRACT.md +62 -39
  30. package/docs/RUNTIME-COMPAT-MATRIX.md +99 -156
  31. package/docs/SKILL-AUTHORING.md +94 -73
  32. package/docs/WORKFLOW-LIFECYCLE.md +93 -189
  33. package/hooks/README.md +17 -37
  34. package/hooks/_common.py +113 -0
  35. package/hooks/adapters/codex.py +9 -16
  36. package/hooks/adapters/grok.py +5 -5
  37. package/hooks/adapters/kimi.py +8 -14
  38. package/hooks/block_dangerous_commands.py +95 -0
  39. package/hooks/compact_context.py +65 -0
  40. package/hooks/mid_workflow_recall.py +25 -0
  41. package/hooks/post_edit_guard.py +105 -0
  42. package/hooks/session_context.py +30 -0
  43. package/package.json +17 -52
  44. package/skills/ultra-change/SKILL.md +97 -50
  45. package/skills/ultra-change/references/change-contract.md +40 -1
  46. package/skills/ultra-delegate/SKILL.md +82 -0
  47. package/skills/ultra-delegate/references/delegation-contract.md +51 -0
  48. package/skills/ultra-delegate/scripts/delegate_wait.py +86 -0
  49. package/skills/ultra-deliver/SKILL.md +61 -42
  50. package/skills/ultra-deliver/references/baseline-reconciliation.md +39 -20
  51. package/skills/ultra-dev/SKILL.md +96 -62
  52. package/skills/ultra-dev/references/debugging.md +22 -0
  53. package/skills/ultra-domain-modeling/SKILL.md +79 -0
  54. package/skills/ultra-grilling/SKILL.md +79 -0
  55. package/skills/ultra-init/SKILL.md +94 -37
  56. package/skills/ultra-init/references/brownfield-adoption.md +33 -83
  57. package/skills/ultra-init/scripts/init_project.cjs +84 -0
  58. package/skills/ultra-plan/SKILL.md +88 -68
  59. package/skills/ultra-research/SKILL.md +62 -48
  60. package/skills/ultra-research/references/00-problem-validation.md +5 -5
  61. package/skills/ultra-research/references/01-opportunity-discovery.md +3 -3
  62. package/skills/ultra-research/references/02-market-assessment.md +5 -4
  63. package/skills/ultra-research/references/03-competitive-landscape.md +3 -3
  64. package/skills/ultra-research/references/04-product-strategy.md +3 -3
  65. package/skills/ultra-research/references/05-assumptions-validation.md +5 -5
  66. package/skills/ultra-research/references/10-user-personas.md +3 -2
  67. package/skills/ultra-research/references/11-user-scenarios.md +3 -3
  68. package/skills/ultra-research/references/20-user-stories.md +4 -3
  69. package/skills/ultra-research/references/21-features-scope.md +3 -2
  70. package/skills/ultra-research/references/22-success-metrics.md +3 -3
  71. package/skills/ultra-research/references/30-architecture-context.md +3 -3
  72. package/skills/ultra-research/references/31-solution-strategy.md +3 -3
  73. package/skills/ultra-research/references/32-building-blocks.md +3 -3
  74. package/skills/ultra-research/references/40-deployment.md +3 -3
  75. package/skills/ultra-research/references/41-quality-risks.md +3 -3
  76. package/skills/ultra-research/references/99-synthesis.md +7 -7
  77. package/skills/ultra-review/SKILL.md +59 -32
  78. package/skills/ultra-review/references/code.md +17 -0
  79. package/skills/ultra-review/references/comments.md +12 -0
  80. package/skills/ultra-review/references/design.md +12 -0
  81. package/skills/ultra-review/references/errors.md +13 -0
  82. package/skills/ultra-review/references/spec.md +13 -0
  83. package/skills/ultra-review/references/tests.md +12 -0
  84. package/skills/ultra-review/references/worker-packet.md +40 -0
  85. package/skills/ultra-review/scripts/review_wait.py +26 -15
  86. package/skills/ultra-status/SKILL.md +61 -36
  87. package/skills/ultra-tdd/SKILL.md +81 -0
  88. package/skills/ultra-tdd/references/templates/README.md +20 -0
  89. package/skills/ultra-tdd/references/templates/feature-flag-default-audit.sh +79 -0
  90. package/skills/ultra-tdd/references/templates/persistence-real.ts +78 -0
  91. package/skills/ultra-tdd/references/templates/testcontainer-postgres.py +78 -0
  92. package/skills/ultra-tdd/references/templates/testcontainer-postgres.ts +73 -0
  93. package/skills/ultra-tdd/references/templates/vertical-slice.ts +66 -0
  94. package/skills/ultra-tdd/references/test-execution.md +18 -0
  95. package/skills/ultra-test/SKILL.md +70 -30
  96. package/skills/ultra-test/references/export-syntax.md +18 -0
  97. package/skills/ultra-test/scripts/worktree_digest.cjs +54 -0
  98. package/skills/ultra-think/SKILL.md +49 -27
  99. package/skills/ultra-think/references/autonomy-boundary.md +48 -0
  100. package/skills/ultra-think/references/interaction-boundary.md +18 -33
  101. package/.ultra-template/docs/research/README.md +0 -55
  102. package/.ultra-template/reports/templates/delivery-report.json +0 -17
  103. package/.ultra-template/reports/templates/test-report.json +0 -18
  104. package/.ultra-template/tasks/tasks.json +0 -15
  105. package/.ultra-template/templates/task-context.md +0 -19
  106. package/adapters/_shared/codex-assets.cjs +0 -725
  107. package/adapters/_shared/codex-ultra-tools-entry.cjs +0 -11
  108. package/adapters/_shared/interaction-contract.cjs +0 -129
  109. package/adapters/_shared/path-rewrite.cjs +0 -79
  110. package/adapters/_shared/runtime-native.cjs +0 -132
  111. package/adapters/_shared/settings-merge.cjs +0 -76
  112. package/agents/code-reviewer.md +0 -42
  113. package/agents/debugger.md +0 -40
  114. package/agents/review-code.md +0 -49
  115. package/agents/review-comments.md +0 -38
  116. package/agents/review-coordinator.md +0 -56
  117. package/agents/review-design.md +0 -40
  118. package/agents/review-errors.md +0 -43
  119. package/agents/review-spec.md +0 -39
  120. package/agents/review-tests.md +0 -40
  121. package/agents/tdd-runner.md +0 -38
  122. package/bin/orchestrator.js +0 -383
  123. package/commands/ultra-change.md +0 -10
  124. package/commands/ultra-deliver.md +0 -10
  125. package/commands/ultra-dev.md +0 -10
  126. package/commands/ultra-doctor.md +0 -10
  127. package/commands/ultra-init.md +0 -10
  128. package/commands/ultra-plan.md +0 -10
  129. package/commands/ultra-research.md +0 -10
  130. package/commands/ultra-review.md +0 -10
  131. package/commands/ultra-status.md +0 -10
  132. package/commands/ultra-test.md +0 -10
  133. package/commands/ultra-think.md +0 -10
  134. package/docs/AGENT-CONTEXT.md +0 -191
  135. package/docs/COMMIT-HASH-BACKFILL.md +0 -51
  136. package/docs/LEGACY-CLI-CROSSWALK.md +0 -175
  137. package/docs/ROADMAP.md +0 -101
  138. package/docs/STATE-DB-ACCESS-POLICY.md +0 -161
  139. package/hooks/active_task_context.py +0 -152
  140. package/hooks/context_envelope.py +0 -100
  141. package/hooks/health_check.py +0 -196
  142. package/hooks/pre_stop_check.py +0 -66
  143. package/hooks/runtime_paths.py +0 -396
  144. package/hooks/subagent_tracker.py +0 -88
  145. package/hooks/workflow_checkpoint.py +0 -76
  146. package/hooks/workflow_context.py +0 -48
  147. package/hooks/workflow_resume.py +0 -84
  148. package/mcp-server/hook-context.cjs +0 -38
  149. package/mcp-server/hook-event.cjs +0 -34
  150. package/mcp-server/lib/archive-journal.cjs +0 -1119
  151. package/mcp-server/lib/archive-mutation-worker.py +0 -365
  152. package/mcp-server/lib/artifact-registry.cjs +0 -1232
  153. package/mcp-server/lib/baseline-workflow.cjs +0 -1193
  154. package/mcp-server/lib/canonical-json.cjs +0 -19
  155. package/mcp-server/lib/change-authority.cjs +0 -26
  156. package/mcp-server/lib/change-packet.cjs +0 -790
  157. package/mcp-server/lib/change-workflow.cjs +0 -65
  158. package/mcp-server/lib/context-envelope.cjs +0 -581
  159. package/mcp-server/lib/context-paths.cjs +0 -142
  160. package/mcp-server/lib/decision-records.cjs +0 -423
  161. package/mcp-server/lib/delivery-transaction.cjs +0 -471
  162. package/mcp-server/lib/doctor-backup-worker.cjs +0 -328
  163. package/mcp-server/lib/doctor.cjs +0 -627
  164. package/mcp-server/lib/git-bootstrap.cjs +0 -651
  165. package/mcp-server/lib/init-project.cjs +0 -1021
  166. package/mcp-server/lib/kernel-change-workflow.cjs +0 -2029
  167. package/mcp-server/lib/legacy-change-workflow.cjs +0 -3032
  168. package/mcp-server/lib/managed-file-write.cjs +0 -172
  169. package/mcp-server/lib/plan-checkpoint.cjs +0 -177
  170. package/mcp-server/lib/plan-publication-worker.cjs +0 -830
  171. package/mcp-server/lib/plan-store.cjs +0 -794
  172. package/mcp-server/lib/prd-parser.cjs +0 -83
  173. package/mcp-server/lib/pricing.cjs +0 -44
  174. package/mcp-server/lib/project-context.cjs +0 -178
  175. package/mcp-server/lib/projector.cjs +0 -386
  176. package/mcp-server/lib/provider-refs.cjs +0 -42
  177. package/mcp-server/lib/runtime-paths.cjs +0 -1687
  178. package/mcp-server/lib/runtime-state.cjs +0 -222
  179. package/mcp-server/lib/safe-project-file.cjs +0 -385
  180. package/mcp-server/lib/stage-checkpoints.cjs +0 -463
  181. package/mcp-server/lib/state-authority.cjs +0 -95
  182. package/mcp-server/lib/state-db.cjs +0 -1580
  183. package/mcp-server/lib/state-ops.cjs +0 -1428
  184. package/mcp-server/lib/task-contract.cjs +0 -404
  185. package/mcp-server/lib/task-expander.cjs +0 -105
  186. package/mcp-server/lib/task-ledger.cjs +0 -1964
  187. package/mcp-server/lib/telemetry.cjs +0 -85
  188. package/mcp-server/lib/topo.cjs +0 -131
  189. package/mcp-server/lib/ultra-facade.cjs +0 -2684
  190. package/mcp-server/lib/worker-packet.cjs +0 -358
  191. package/mcp-server/server.cjs +0 -437
  192. package/orchestrator/auto-merge.cjs +0 -128
  193. package/orchestrator/daemon.cjs +0 -264
  194. package/orchestrator/dispatch-rules.cjs +0 -78
  195. package/orchestrator/parallel-orchestrator.cjs +0 -903
  196. package/orchestrator/planner/plan-builder.cjs +0 -125
  197. package/orchestrator/recovery.cjs +0 -188
  198. package/orchestrator/session-close-journal-worker.cjs +0 -5
  199. package/orchestrator/session-close-journal.cjs +0 -1014
  200. package/orchestrator/session-runner.cjs +0 -1153
  201. package/orchestrator/worktree-manager.cjs +0 -282
  202. package/settings.json +0 -7
  203. package/skills/cc-collab/SKILL.md +0 -42
  204. package/skills/code-review-expert/SKILL.md +0 -43
  205. package/skills/code-review-expert/references/correctness-reliability.md +0 -30
  206. package/skills/code-review-expert/references/design-boundaries.md +0 -26
  207. package/skills/code-review-expert/references/removal-plan.md +0 -24
  208. package/skills/codex-collab/SKILL.md +0 -49
  209. package/skills/codex-collab/evals/evals.json +0 -35
  210. package/skills/integration-rules/SKILL.md +0 -32
  211. package/skills/security-rules/SKILL.md +0 -38
  212. package/skills/testing-rules/SKILL.md +0 -32
  213. package/skills/ultra-doctor/SKILL.md +0 -41
  214. package/skills/ultra-plan/references/semantic-preflight.md +0 -20
  215. package/skills/ultra-verify/SKILL.md +0 -46
  216. package/skills/ultra-verify/evals/evals.json +0 -46
  217. package/skills/ultra-verify/references/cross-verify-modes.md +0 -28
  218. package/skills/ultra-verify/references/evidence-status.md +0 -21
  219. package/skills/ultra-verify/scripts/verify_wait.py +0 -94
  220. package/spec/cli-protocol.md +0 -102
  221. package/spec/mcp-tools.yaml +0 -312
  222. package/spec/schemas/baseline-reconciliation.v1.schema.json +0 -73
  223. package/spec/schemas/change-delta.v1.schema.json +0 -153
  224. package/spec/schemas/command-manifest.schema.json +0 -29
  225. package/spec/schemas/context-file.v4.5.schema.json +0 -54
  226. package/spec/schemas/delivery-report.v1.schema.json +0 -66
  227. package/spec/schemas/documentation-reconciliation.v1.schema.json +0 -106
  228. package/spec/schemas/mcp-tools.schema.json +0 -136
  229. package/spec/schemas/skill-manifest.schema.json +0 -24
  230. package/spec/schemas/state-db.sql +0 -641
  231. package/spec/schemas/task-ledger.v2.schema.json +0 -296
  232. package/spec/schemas/tasks.v4.5.schema.json +0 -96
  233. package/spec/schemas/test-report.v1.schema.json +0 -225
  234. package/ultra-tools/cli.cjs +0 -129
  235. package/ultra-tools/commands/db.cjs +0 -226
  236. package/ultra-tools/commands/legacy-memory.cjs +0 -159
  237. package/ultra-tools/commands/migrate.cjs +0 -1386
  238. package/ultra-tools/commands/session.cjs +0 -213
  239. package/ultra-tools/commands/status.cjs +0 -559
  240. package/ultra-tools/commands/system.cjs +0 -498
  241. package/ultra-tools/commands/task.cjs +0 -105
@@ -2,8 +2,8 @@
2
2
  """Wait for and validate Ultra review v2 artifacts.
3
3
 
4
4
  Usage:
5
- python3 review_wait.py <session_path> agents <artifact-stem> [<artifact-stem> ...]
6
- python3 review_wait.py <session_path> summary
5
+ python3 review_wait.py <session_path> agents --packet-digest <sha256> <artifact-stem> [<artifact-stem> ...]
6
+ python3 review_wait.py <session_path> summary --packet-digest <sha256>
7
7
 
8
8
  The agents mode validates the exact named JSON files. The summary mode validates the
9
9
  two-axis verdict contract. Timeout and poll intervals can be shortened in tests with
@@ -96,13 +96,15 @@ def validate_finding(finding, artifact_axis: str, seen_ids):
96
96
  return None
97
97
 
98
98
 
99
- def validate_specialist(data):
99
+ def validate_specialist(data, expected_packet_digest: str):
100
100
  if data.get("$schema") != FINDINGS_SCHEMA:
101
101
  return f"$schema must be {FINDINGS_SCHEMA}"
102
102
  if not nonempty_string(data.get("agent")):
103
103
  return "agent must be a non-empty string"
104
104
  if not digest_string(data.get("packet_digest")):
105
105
  return "packet_digest must be a lowercase SHA-256 digest"
106
+ if data["packet_digest"] != expected_packet_digest:
107
+ return f"packet_digest does not match expected immutable packet {expected_packet_digest}"
106
108
  axis = data.get("axis")
107
109
  if axis not in AXES:
108
110
  return "axis must be spec_fidelity or engineering_standards"
@@ -137,7 +139,7 @@ def validate_specialist(data):
137
139
  return None
138
140
 
139
141
 
140
- def evaluate_artifacts(session_path: Path, expected):
142
+ def evaluate_artifacts(session_path: Path, expected, expected_packet_digest: str):
141
143
  done = []
142
144
  missing = []
143
145
  invalid = []
@@ -149,7 +151,7 @@ def evaluate_artifacts(session_path: Path, expected):
149
151
  continue
150
152
  data, error = read_json(path)
151
153
  if error is None:
152
- error = validate_specialist(data)
154
+ error = validate_specialist(data, expected_packet_digest)
153
155
  if error:
154
156
  invalid.append(stem)
155
157
  errors[stem] = error
@@ -158,10 +160,12 @@ def evaluate_artifacts(session_path: Path, expected):
158
160
  return done, missing, invalid, errors
159
161
 
160
162
 
161
- def wait_for_agents(session_path: Path, expected, timeout: float) -> bool:
163
+ def wait_for_agents(session_path: Path, expected, expected_packet_digest: str, timeout: float) -> bool:
162
164
  deadline = time.monotonic() + timeout
163
165
  while True:
164
- done, missing, invalid, errors = evaluate_artifacts(session_path, expected)
166
+ done, missing, invalid, errors = evaluate_artifacts(
167
+ session_path, expected, expected_packet_digest
168
+ )
165
169
  if len(done) == len(expected):
166
170
  print(json.dumps({
167
171
  "status": "complete",
@@ -195,7 +199,7 @@ def expected_overall_verdict(data) -> str:
195
199
  return "APPROVE"
196
200
 
197
201
 
198
- def validate_summary(data):
202
+ def validate_summary(data, expected_packet_digest: str):
199
203
  if data.get("$schema") != SUMMARY_SCHEMA:
200
204
  return f"$schema must be {SUMMARY_SCHEMA}"
201
205
  if data.get("mode") not in REVIEW_MODES:
@@ -205,6 +209,8 @@ def validate_summary(data):
205
209
  return f"{field} must be a non-empty string"
206
210
  if not digest_string(data.get("packet_digest")):
207
211
  return "packet_digest must be a lowercase SHA-256 digest"
212
+ if data["packet_digest"] != expected_packet_digest:
213
+ return f"packet_digest does not match expected immutable packet {expected_packet_digest}"
208
214
  if data.get("worktree_digest") is not None and not nonempty_string(data.get("worktree_digest")):
209
215
  return "worktree_digest must be null or a non-empty string"
210
216
  task_ids = data.get("task_ids")
@@ -282,7 +288,7 @@ def validate_summary(data):
282
288
  return None
283
289
 
284
290
 
285
- def wait_for_summary(session_path: Path, timeout: float) -> bool:
291
+ def wait_for_summary(session_path: Path, expected_packet_digest: str, timeout: float) -> bool:
286
292
  summary_path = session_path / "SUMMARY.json"
287
293
  deadline = time.monotonic() + timeout
288
294
  last_error = "SUMMARY.json is missing"
@@ -290,7 +296,7 @@ def wait_for_summary(session_path: Path, timeout: float) -> bool:
290
296
  if summary_path.exists():
291
297
  data, error = read_json(summary_path)
292
298
  if error is None:
293
- error = validate_summary(data)
299
+ error = validate_summary(data, expected_packet_digest)
294
300
  if error is None:
295
301
  counts = {severity: 0 for severity in sorted(SEVERITIES)}
296
302
  for finding in data["findings"]:
@@ -319,19 +325,24 @@ def main():
319
325
  print(f"Error: session directory not found: {session_path}", file=sys.stderr)
320
326
  sys.exit(2)
321
327
 
328
+ if len(sys.argv) < 5 or sys.argv[3] != "--packet-digest" or not digest_string(sys.argv[4]):
329
+ print("Error: --packet-digest requires the expected lowercase SHA-256 digest", file=sys.stderr)
330
+ sys.exit(2)
331
+ expected_packet_digest = sys.argv[4]
332
+
322
333
  if mode == "agents":
323
- expected = sys.argv[3:]
334
+ expected = sys.argv[5:]
324
335
  if not expected or len(expected) != len(set(expected)) or not all(
325
336
  ARTIFACT_STEM.fullmatch(stem) for stem in expected
326
337
  ):
327
338
  print("Error: agents mode requires unique safe artifact stems", file=sys.stderr)
328
339
  sys.exit(2)
329
- ok = wait_for_agents(session_path, expected, DEFAULT_TIMEOUT)
340
+ ok = wait_for_agents(session_path, expected, expected_packet_digest, DEFAULT_TIMEOUT)
330
341
  elif mode == "summary":
331
- if len(sys.argv) != 3:
332
- print("Error: summary mode accepts no additional arguments", file=sys.stderr)
342
+ if len(sys.argv) != 5:
343
+ print("Error: summary mode accepts only --packet-digest", file=sys.stderr)
333
344
  sys.exit(2)
334
- ok = wait_for_summary(session_path, DEFAULT_TIMEOUT)
345
+ ok = wait_for_summary(session_path, expected_packet_digest, DEFAULT_TIMEOUT)
335
346
  else:
336
347
  print(f"Error: unknown mode '{mode}'. Use 'agents' or 'summary'.", file=sys.stderr)
337
348
  sys.exit(2)
@@ -1,40 +1,65 @@
1
1
  ---
2
2
  name: ultra-status
3
- description: Read authoritative Ultra health, workflows, decisions, changes, tasks, evidence freshness, and team checkpoint state. Use when the user asks what is complete, blocked, stale, or currently possible.
3
+ description: Infer the current Ultra workflow position, stale evidence, task risk, and installation health from repository files and host manifests. Use when the owner asks what is complete, blocked, stale, unhealthy, or useful to do next.
4
4
  ---
5
5
 
6
- # Report authoritative state
7
-
8
- This Skill is read-only.
9
-
10
- ## Read
11
-
12
- Call `ultra.context { stage: project, detail: full }`. Use `ultra.sync { action:
13
- inspect }` only when the user needs team-checkpoint detail. Do not import, publish,
14
- repair, compile context, or mutate state.
15
- Never fall back to the Git team checkpoint, generated task JSON, or report files as
16
- live authority when `ultra.context` reports missing or unhealthy local state.
17
-
18
- Report:
19
-
20
- ```text
21
- Ultra: <healthy|degraded> · <branch>@<head|unborn|non-git>
22
- Baseline: <mode>/<status> · gaps=<open>/<blocking>
23
- Stage checkpoints: drafts=<count> · accepted=<current|stale|none>
24
- Change: <id/status|none> · delta/docs=<state>
25
- Task: <id/status|none> · Sessions: <active>
26
- Evidence: plan=<state> · test=<state> · review=<axes> · delivery=<state>
27
- Team checkpoint: <current|drifted|revalidation_required|missing|invalid>
28
- Blockers: <hard mechanical blockers or none>
29
- Warnings: <advisory semantic diagnostics or none>
30
- Model recommendation: <capability and concise rationale>
31
- ```
32
-
33
- Treat warnings and failed draft checks as information, not mechanical orders. Only
34
- corruption, unsafe paths, real concurrency conflicts, permissions, or irreversible
35
- external effects are hard blockers.
36
-
37
- The host model recommends the next useful capability from accepted intent, current
38
- evidence, cost of interruption, and owner goal. SQLite does not choose the route.
39
- Separate verified facts, model inference, and unavailable evidence. Never invoke the
40
- recommendation automatically.
6
+ # Route from artifacts without changing them
7
+
8
+ This router is read-only. It reports verified files, model inference and unavailable
9
+ evidence separately, then recommends one explicit capability without invoking it.
10
+
11
+ ## Before you start
12
+
13
+ 1. Read `.ultra/tasks.json` if present; read the active task's `context_file` and
14
+ closing `## Resume Note`.
15
+ 2. Read `CONTEXT.md` and relevant `.ultra/decisions/` entries when they exist.
16
+ 3. Inspect Git `HEAD`, worktree status, active/archive Change directories and installed
17
+ host manifests without repairing them.
18
+
19
+ ## Definition of done
20
+
21
+ - The artifact route below is evaluated in order and the matching evidence is named.
22
+ - Stale test evidence, dirty worktree state and task graph risks are visible.
23
+ - Installation health reports exact missing or drifted files without mutation.
24
+ - The recommendation says why it follows; it does not launch the capability.
25
+
26
+ ## Infer the route
27
+
28
+ | Observable files | Recommendation |
29
+ |---|---|
30
+ | No `.ultra/` | `ultra-init` |
31
+ | Product specification missing or contains `[NEEDS CLARIFICATION]` | `ultra-research` |
32
+ | A new request exists and no active Change exists | `ultra-change` |
33
+ | An active Change exists and `.ultra/tasks.json` is missing or `tasks` is empty | `ultra-plan` |
34
+ | A frontier task is pending or in progress | `ultra-dev`, naming the task |
35
+ | All tasks completed and no current report | `ultra-test` |
36
+ | `test-report.passed` is false | `ultra-dev`, with blocking findings |
37
+ | Report passed and `git_commit` equals `HEAD` | `ultra-deliver` |
38
+ | No active Change and no new request | Report the idle state; do not manufacture work |
39
+
40
+ A report whose `git_commit` differs from `HEAD`, or whose recorded `worktree.diff_digest`
41
+ differs from the result of resolving the installed `ultra-test` Skill and running
42
+ `node <ultra-test-skill-dir>/scripts/worktree_digest.cjs --project <repository-root>`, is stale. A dirty
43
+ worktree is a warning, not evidence of failure.
44
+
45
+ ## Surface risk and installation health
46
+
47
+ List unmet task dependencies, any `in_progress` task older than 3 days, complexity
48
+ concentration and broken `trace_to` or `context_file` paths. These are sensors.
49
+
50
+ For installation health, compare the selected host's plugin path, skill inventory,
51
+ version, provenance and hook manifest against the installed files. Report broken links
52
+ and missing registrations. Recommend `ubp install` or `ubp update` as the reachable
53
+ repair; this read-only skill never performs it.
54
+
55
+ ## When the owner decides
56
+
57
+ The owner chooses the next workflow, risk disposition and any reinstall. Contradictory
58
+ file facts are reported as contradictions rather than silently selecting one.
59
+
60
+ ## References
61
+
62
+ - `../ultra-think/SKILL.md` — read only when contradictory evidence creates a real
63
+ decision rather than a mechanical repair.
64
+ - `../ultra-think/references/autonomy-boundary.md` — read before recommending a route
65
+ that would reduce an accepted commitment.
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: ultra-tdd
3
+ description: Drive one slice of behavior through red then green — a failing test on a confirmed seam, then the smallest code that passes it. Use when another skill is about to write or change behavior and needs the feedback loop that proves the code actually runs, including a small change that goes straight to implementation.
4
+ ---
5
+
6
+ # Write one failing test on a seam, then just enough code to pass it
7
+
8
+ Without feedback from code that actually ran, the work is blind flying. This is
9
+ the loop that supplies it, and it serves Goal 3, Production-Ready.
10
+
11
+ ## Before you start
12
+
13
+ 1. Read the current task context for the seams already confirmed during
14
+ planning. Tests live on those, and choosing a new one is a planning decision.
15
+ 2. Run the repository's existing test command once, unchanged, to see what
16
+ passing currently looks like. Read `references/test-execution.md` before recording
17
+ that run or any red/green evidence.
18
+ 3. Read `CONTEXT.md` for vocabulary — test names carry the domain words.
19
+
20
+ ## Definition of done
21
+
22
+ - One slice is complete: one seam, one test, one minimal implementation.
23
+ - The test was observed failing before the implementation existed, and observed
24
+ passing after. Both runs are real command output.
25
+ - The test reads as a specification of behavior through a public interface, and
26
+ survives replacing the implementation underneath it.
27
+
28
+ ## Seams, and what a good test on one looks like
29
+
30
+ A seam is a place where behavior can change without editing at that place — the
31
+ module interface. Tests live on seams and never reach for internals. Prefer a
32
+ seam that already exists, take the highest one that works, and one is the ideal
33
+ number. Verify behavior through that public interface: a name like "user can
34
+ checkout with a valid cart" shows at a glance what capability exists, and one
35
+ logical assertion per test keeps it readable.
36
+
37
+ ## Red, then green
38
+
39
+ Write the failing test first and run it, so that red is observed rather than
40
+ assumed. Then write the smallest code that turns it green. Predict no later
41
+ tests and add no speculative capability. Then take the next slice.
42
+
43
+ Refactoring is not part of this loop; `ultra-review` owns it, because the
44
+ restructuring worth doing only becomes visible after three or four slices.
45
+
46
+ ## Three patterns that produce tests worth deleting
47
+
48
+ | Pattern | How you recognize it |
49
+ |---|---|
50
+ | Implementation-coupled | Mocks an internal collaborator, tests a private method, asserts on call counts or ordering, or reaches past the interface into the database. The check: behavior is unchanged after restructuring, yet the test breaks. |
51
+ | Tautological | Recomputes the expected value the same way the implementation does, so it can never fail. Expected values come from an independent source — a known literal, a hand-worked example, the specification. |
52
+ | All tests first | Writing every test before any implementation tests imagined behavior. It captures shape rather than user-visible behavior, is insensitive to real change, and freezes the test structure before the implementation is understood. Take one test, one implementation, and repeat. |
53
+
54
+ ## Mock only at the system boundary
55
+
56
+ External APIs, time and randomness, sometimes the filesystem. Prefer a real test
57
+ library over mocking the database. Your own classes, modules and internal
58
+ collaborators stay real.
59
+
60
+ Design for that boundary: inject dependencies, and give each external operation
61
+ its own named function rather than one generic fetcher — mocking then needs no
62
+ conditional logic, and which endpoints a test touches stays visible. When a real
63
+ dependency is the right answer, copy
64
+ `references/templates/testcontainer-postgres.ts` or
65
+ `references/templates/testcontainer-postgres.py`, and
66
+ `references/templates/vertical-slice.ts` for a path that runs end to end.
67
+
68
+ ## When the owner decides
69
+
70
+ Weakening an assertion, skipping a relevant test, or adjusting an expected value
71
+ to obtain green output crosses the C5 boundary — stop and surface it. A test that
72
+ is genuinely wrong about the specification is a specification question, so it
73
+ goes to the owner as one.
74
+
75
+ ## References
76
+
77
+ - `../ultra-think/references/autonomy-boundary.md` — read before replacing a real
78
+ dependency with a fake, or when a test stands between the work and green.
79
+ - `references/templates/README.md` — read when choosing which enabling template
80
+ fits the dependency you need to make real.
81
+ - `references/test-execution.md` — exact command, failure and result evidence contract.
@@ -0,0 +1,20 @@
1
+ # Enabling templates
2
+
3
+ These runnable examples make the real integration path cheaper than a fake. Read this
4
+ index when `ultra-tdd` reaches a database, feature flag, or multi-layer seam, then copy
5
+ only the smallest relevant file into the project and adapt it to repository conventions.
6
+
7
+ | Template | When to copy |
8
+ |---|---|
9
+ | [testcontainer-postgres.ts](testcontainer-postgres.ts) | A TypeScript/Node test needs real Postgres instead of an internal Repository mock |
10
+ | [testcontainer-postgres.py](testcontainer-postgres.py) | A pytest test needs real Postgres instead of a `MagicMock` Repository |
11
+ | [vertical-slice.ts](vertical-slice.ts) | One test must prove HTTP → use case → database → response |
12
+ | [persistence-real.ts](persistence-real.ts) | A Repository needs real storage rather than an in-memory `Map` |
13
+ | [feature-flag-default-audit.sh](feature-flag-default-audit.sh) | A Change must surface default-off flags that could hide unfinished work |
14
+
15
+ The templates travel with the `ultra-tdd` skill; they are rule-side examples, not
16
+ project authority. Do not copy this directory wholesale into `.ultra/`.
17
+
18
+ Each template must remain runnable after its documented dependencies are installed,
19
+ name the exact verification command in its header, stay short enough to inspect before
20
+ use, and state which Ultra principle makes the example preferable.
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env bash
2
+ # feature-flag-default-audit.sh
3
+ #
4
+ # Surface every `default off` / `enabled: false` / commented-out feature so the
5
+ # user knows what is *quietly* disabled. Catches the "agent shipped task by
6
+ # turning the feature off" failure mode v7 fixes.
7
+ #
8
+ # Usage:
9
+ # bash feature-flag-default-audit.sh [path]
10
+ #
11
+ # Default path: src/ (override with first arg)
12
+ #
13
+ # PHILOSOPHY: enables C5 (Bounded Autonomy) — default-off without rationale is
14
+ # scope reduction in disguise; this surfaces it so the user can decide.
15
+
16
+ set -euo pipefail
17
+
18
+ ROOT="${1:-src}"
19
+ if [ ! -d "$ROOT" ]; then
20
+ echo "[audit] path not found: $ROOT" >&2
21
+ exit 1
22
+ fi
23
+
24
+ echo "## Feature-flag default audit"
25
+ echo "Path: $ROOT"
26
+ echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
27
+ echo ""
28
+
29
+ # Patterns we care about. Adjust per project conventions.
30
+ patterns=(
31
+ '\benabled:\s*false\b'
32
+ '\bdefault\s*[:=]\s*false\b'
33
+ '\bDISABLED\s*=\s*true\b'
34
+ '\bif\s*\(\s*false\s*\)'
35
+ 'FEATURE_[A-Z_]+\s*=\s*false'
36
+ )
37
+
38
+ found_any=0
39
+ for p in "${patterns[@]}"; do
40
+ hits=$(grep -REn "$p" "$ROOT" \
41
+ --include='*.ts' --include='*.tsx' \
42
+ --include='*.js' --include='*.jsx' \
43
+ --include='*.py' --include='*.go' \
44
+ --include='*.rs' --include='*.sol' \
45
+ --include='*.yaml' --include='*.yml' \
46
+ --include='*.json' --include='*.toml' 2>/dev/null || true)
47
+
48
+ if [ -n "$hits" ]; then
49
+ found_any=1
50
+ echo "### Pattern: $p"
51
+ echo '```'
52
+ echo "$hits"
53
+ echo '```'
54
+ echo ""
55
+ fi
56
+ done
57
+
58
+ # Also surface TODO-style "off until later" markers
59
+ todo_hits=$(grep -REn '(TODO|FIXME).*(enable|turn on|flip on)' "$ROOT" 2>/dev/null || true)
60
+ if [ -n "$todo_hits" ]; then
61
+ found_any=1
62
+ echo "### TODOs to re-enable later"
63
+ echo '```'
64
+ echo "$todo_hits"
65
+ echo '```'
66
+ echo ""
67
+ fi
68
+
69
+ if [ "$found_any" -eq 0 ]; then
70
+ echo "_No default-off features detected._"
71
+ exit 0
72
+ fi
73
+
74
+ echo "---"
75
+ echo ""
76
+ echo "**Action**: For each entry above, confirm with the user whether it is:"
77
+ echo "- (A) Pre-launch: feature is built but gated until release — fine"
78
+ echo "- (B) Genuine kill-switch: stays off in normal operation — fine, document why"
79
+ echo "- (C) Hiding incomplete work: agent shipped task by turning it off — **must fix**"
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Real-persistence Repository skeleton (TypeScript)
3
+ *
4
+ * Why this exists: in-memory `Map` Repositories are a v7 anti-pattern. They
5
+ * pass tests, don't survive restart, hide migration bugs, and silently break
6
+ * production. This template shows the minimum real Repository.
7
+ *
8
+ * Required deps:
9
+ * pnpm add pg
10
+ * # Optional ORM: drizzle / prisma / kysely
11
+ *
12
+ * PHILOSOPHY: enables C4 progress.json `persistence_real` dimension. Pair with
13
+ * testcontainer-postgres.ts for the test side.
14
+ */
15
+
16
+ import type { Pool, PoolClient } from 'pg';
17
+
18
+ // Domain entity — keep separate from row shape
19
+ export type User = {
20
+ id: number;
21
+ email: string;
22
+ createdAt: Date;
23
+ };
24
+
25
+ // Optional: row→entity mapper if column names differ from field names
26
+ function rowToUser(row: { id: number; email: string; created_at: Date }): User {
27
+ return { id: row.id, email: row.email, createdAt: row.created_at };
28
+ }
29
+
30
+ export class UserRepo {
31
+ constructor(private readonly pool: Pool) {}
32
+
33
+ async create(input: { email: string }): Promise<User> {
34
+ const { rows } = await this.pool.query<{
35
+ id: number;
36
+ email: string;
37
+ created_at: Date;
38
+ }>(
39
+ `INSERT INTO users (email) VALUES ($1)
40
+ RETURNING id, email, created_at`,
41
+ [input.email],
42
+ );
43
+ return rowToUser(rows[0]);
44
+ }
45
+
46
+ async findById(id: number): Promise<User | null> {
47
+ const { rows } = await this.pool.query<{
48
+ id: number;
49
+ email: string;
50
+ created_at: Date;
51
+ }>(
52
+ `SELECT id, email, created_at FROM users WHERE id = $1`,
53
+ [id],
54
+ );
55
+ return rows[0] ? rowToUser(rows[0]) : null;
56
+ }
57
+
58
+ // Multi-statement work — pass in a client to keep it on a single connection
59
+ async withTransaction<T>(work: (client: PoolClient) => Promise<T>): Promise<T> {
60
+ const client = await this.pool.connect();
61
+ try {
62
+ await client.query('BEGIN');
63
+ const result = await work(client);
64
+ await client.query('COMMIT');
65
+ return result;
66
+ } catch (e) {
67
+ await client.query('ROLLBACK');
68
+ throw e;
69
+ } finally {
70
+ client.release();
71
+ }
72
+ }
73
+ }
74
+
75
+ // What this template intentionally does NOT do (and why):
76
+ // - No `Map<number, User>` field. That is the in-memory anti-pattern v7 surfaces.
77
+ // - No silent error swallowing (catch + return-null). Errors propagate; callers handle.
78
+ // - No mock-friendly singleton. Inject the Pool so testcontainers work cleanly.
@@ -0,0 +1,78 @@
1
+ """
2
+ Testcontainer-Postgres starter (Python / pytest)
3
+
4
+ Why this exists: Real DB in tests catches migration drift, schema bugs, and
5
+ concurrency issues that mocked Repositories silently miss. Prefer this to
6
+ `MagicMock(spec=Repo)` for any Repository or Service that touches data.
7
+
8
+ Required deps:
9
+ pip install testcontainers[postgres] psycopg[binary] pytest
10
+
11
+ Verify:
12
+ pytest tests/repo/test_user_repo_testcontainer.py -v
13
+
14
+ PHILOSOPHY: enables C2 (Enabling > Defensive) — the cheaper path becomes the
15
+ right path, so agents stop reaching for mocks under pressure.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import psycopg
21
+ import pytest
22
+ from testcontainers.postgres import PostgresContainer
23
+
24
+
25
+ @pytest.fixture(scope="module")
26
+ def pg():
27
+ """Module-scoped real Postgres. Slow on first pull, fast after."""
28
+ with PostgresContainer("postgres:16-alpine") as c:
29
+ with psycopg.connect(c.get_connection_url()) as conn:
30
+ with conn.cursor() as cur:
31
+ cur.execute("""
32
+ CREATE TABLE users (
33
+ id SERIAL PRIMARY KEY,
34
+ email TEXT UNIQUE NOT NULL,
35
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
36
+ );
37
+ """)
38
+ conn.commit()
39
+ yield c
40
+
41
+
42
+ @pytest.fixture
43
+ def conn(pg):
44
+ """Per-test connection with truncate-reset so each test is independent."""
45
+ with psycopg.connect(pg.get_connection_url()) as c:
46
+ with c.cursor() as cur:
47
+ cur.execute("TRUNCATE users RESTART IDENTITY CASCADE")
48
+ c.commit()
49
+ yield c
50
+
51
+
52
+ def make_user_repo(conn):
53
+ """Replace with import from your real Repository."""
54
+ class UserRepo:
55
+ def create(self, email: str) -> dict:
56
+ with conn.cursor() as cur:
57
+ cur.execute(
58
+ "INSERT INTO users (email) VALUES (%s) RETURNING id, email, created_at",
59
+ (email,),
60
+ )
61
+ row = cur.fetchone()
62
+ conn.commit()
63
+ return {"id": row[0], "email": row[1], "created_at": row[2]}
64
+
65
+ def find_by_id(self, user_id: int) -> dict | None:
66
+ with conn.cursor() as cur:
67
+ cur.execute("SELECT id, email, created_at FROM users WHERE id = %s", (user_id,))
68
+ row = cur.fetchone()
69
+ return None if row is None else {"id": row[0], "email": row[1], "created_at": row[2]}
70
+
71
+ return UserRepo()
72
+
73
+
74
+ def test_insert_and_fetch_round_trips(conn):
75
+ repo = make_user_repo(conn)
76
+ created = repo.create("a@example.com")
77
+ found = repo.find_by_id(created["id"])
78
+ assert found == created
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Testcontainer-Postgres starter (TypeScript / vitest or jest)
3
+ *
4
+ * Why this exists: Real DB in tests catches migration drift, schema bugs, and
5
+ * concurrency issues that mocked Repositories silently miss. Prefer this to
6
+ * `jest.fn()` / `vi.fn()` for any Repository or Service that touches data.
7
+ *
8
+ * Required deps:
9
+ * pnpm add -D @testcontainers/postgresql pg
10
+ *
11
+ * Verify:
12
+ * pnpm vitest run src/repo/__tests__/userRepo.testcontainer.test.ts
13
+ *
14
+ * PHILOSOPHY: enables C2 (Enabling > Defensive) — the cheaper path becomes the
15
+ * right path, so agents stop reaching for mocks under pressure.
16
+ */
17
+
18
+ import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';
19
+ import { Pool } from 'pg';
20
+ import { afterAll, beforeAll, beforeEach, describe, expect, test } from 'vitest';
21
+
22
+ let container: StartedPostgreSqlContainer;
23
+ let pool: Pool;
24
+
25
+ beforeAll(async () => {
26
+ container = await new PostgreSqlContainer('postgres:16-alpine').start();
27
+ pool = new Pool({ connectionString: container.getConnectionUri() });
28
+ // Replace with your migration runner (drizzle/prisma/knex/raw SQL)
29
+ await pool.query(`
30
+ CREATE TABLE users (
31
+ id SERIAL PRIMARY KEY,
32
+ email TEXT UNIQUE NOT NULL,
33
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
34
+ );
35
+ `);
36
+ }, 60_000); // pulling postgres image can be slow on first run
37
+
38
+ afterAll(async () => {
39
+ await pool.end();
40
+ await container.stop();
41
+ });
42
+
43
+ beforeEach(async () => {
44
+ // Reset between tests so each is independent
45
+ await pool.query('TRUNCATE users RESTART IDENTITY CASCADE');
46
+ });
47
+
48
+ describe('UserRepo (real Postgres)', () => {
49
+ test('insert and fetch round-trips', async () => {
50
+ // Replace with your actual Repository
51
+ const repo = makeUserRepo(pool);
52
+ const created = await repo.create({ email: 'a@example.com' });
53
+ const found = await repo.findById(created.id);
54
+ expect(found).toEqual(created);
55
+ });
56
+ });
57
+
58
+ // Drop your real Repository factory here
59
+ function makeUserRepo(pool: Pool) {
60
+ return {
61
+ async create(input: { email: string }) {
62
+ const { rows } = await pool.query(
63
+ 'INSERT INTO users (email) VALUES ($1) RETURNING *',
64
+ [input.email],
65
+ );
66
+ return rows[0];
67
+ },
68
+ async findById(id: number) {
69
+ const { rows } = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
70
+ return rows[0] ?? null;
71
+ },
72
+ };
73
+ }