@ultimat3/cli 29.3.2 → 30.0.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 (448) hide show
  1. package/CLAUDE.md +64 -40
  2. package/README.md +61 -11
  3. package/package.json +42 -28
  4. package/src/affected-tests.ts +97 -0
  5. package/src/affected-unowned.ts +43 -0
  6. package/src/affected.ts +25 -6
  7. package/src/app-boundaries.ts +29 -1
  8. package/src/app-evals.ts +12 -4
  9. package/src/app-load-unresolved.ts +62 -0
  10. package/src/app-load.ts +30 -37
  11. package/src/app-mcp.ts +14 -2
  12. package/src/app-module-graph.ts +232 -0
  13. package/src/app-reload-graph.ts +2 -2
  14. package/src/app-root.ts +37 -1
  15. package/src/bin.ts +1 -0
  16. package/src/boundary-findings.ts +6 -0
  17. package/src/budgets-freshness.ts +32 -0
  18. package/src/budgets.ts +20 -1
  19. package/src/build-capture-env.ts +9 -0
  20. package/src/cdp-shot-a11y.ts +2 -39
  21. package/src/ci-tested.ts +243 -0
  22. package/src/client-emit-customer-runtime.ts +139 -0
  23. package/src/client-emit-customer.ts +108 -0
  24. package/src/client-emit-drift.ts +72 -0
  25. package/src/client-emit-header.ts +67 -0
  26. package/src/client-emit-schemas.ts +175 -0
  27. package/src/client-emit-types.ts +121 -0
  28. package/src/client-emit-vendor.ts +146 -0
  29. package/src/client-errors-routes.ts +229 -0
  30. package/src/client-errors-script.ts +74 -0
  31. package/src/client-vitals-route.ts +197 -0
  32. package/src/client-vitals-script.ts +56 -0
  33. package/src/cmd-affected.ts +23 -0
  34. package/src/cmd-build-spec.ts +7 -1
  35. package/src/cmd-build.ts +35 -9
  36. package/src/cmd-ci-spec.ts +42 -6
  37. package/src/cmd-ci.ts +99 -2
  38. package/src/cmd-client-customer.ts +134 -0
  39. package/src/cmd-client-source.ts +81 -0
  40. package/src/cmd-client-spec.ts +48 -0
  41. package/src/cmd-client-write.ts +41 -0
  42. package/src/cmd-client.ts +111 -0
  43. package/src/cmd-db-recount.ts +120 -0
  44. package/src/cmd-db-spec.ts +36 -6
  45. package/src/cmd-db.ts +13 -3
  46. package/src/cmd-deploy-compose.ts +61 -3
  47. package/src/cmd-deploy-drain.ts +10 -2
  48. package/src/cmd-deploy-helm.ts +11 -0
  49. package/src/cmd-deploy-preflight.ts +118 -0
  50. package/src/cmd-deploy-spec.ts +58 -6
  51. package/src/cmd-deploy-verify.ts +380 -0
  52. package/src/cmd-deploy.ts +42 -9
  53. package/src/cmd-docs.ts +34 -4
  54. package/src/cmd-doctor.ts +66 -9
  55. package/src/cmd-drill-spec.ts +25 -0
  56. package/src/cmd-drill.ts +176 -0
  57. package/src/cmd-env-init.ts +102 -0
  58. package/src/cmd-env-spec.ts +10 -3
  59. package/src/cmd-env.ts +15 -10
  60. package/src/cmd-errors-recent.ts +60 -0
  61. package/src/cmd-errors-spec.ts +9 -1
  62. package/src/cmd-errors.ts +4 -0
  63. package/src/cmd-exercise-spec.ts +19 -0
  64. package/src/cmd-exercise.ts +129 -0
  65. package/src/cmd-generate-spec.ts +9 -1
  66. package/src/cmd-generate.ts +32 -27
  67. package/src/cmd-graph-load.ts +97 -0
  68. package/src/cmd-graph-spec.ts +16 -0
  69. package/src/cmd-graph.ts +73 -0
  70. package/src/cmd-i18n.ts +4 -1
  71. package/src/cmd-impact-spec.ts +13 -0
  72. package/src/cmd-impact.ts +64 -0
  73. package/src/cmd-jobs-resolve.ts +76 -0
  74. package/src/cmd-jobs-spec.ts +21 -2
  75. package/src/cmd-jobs.ts +10 -6
  76. package/src/cmd-mail-spec.ts +28 -0
  77. package/src/cmd-mail.ts +70 -0
  78. package/src/cmd-mcp-lock.ts +69 -0
  79. package/src/cmd-mcp-spec.ts +23 -4
  80. package/src/cmd-mcp.ts +17 -3
  81. package/src/cmd-new-spec.ts +8 -1
  82. package/src/cmd-new.ts +61 -9
  83. package/src/cmd-planned.ts +0 -6
  84. package/src/cmd-repro-spec.ts +31 -0
  85. package/src/cmd-repro.ts +174 -0
  86. package/src/cmd-stop-spec.ts +21 -0
  87. package/src/cmd-stop.ts +166 -0
  88. package/src/cmd-test-spec.ts +17 -4
  89. package/src/cmd-test.ts +70 -14
  90. package/src/cmd-upgrade-spec.ts +26 -0
  91. package/src/cmd-upgrade.ts +274 -0
  92. package/src/cmd-verify-spec.ts +3 -3
  93. package/src/db-backfill.ts +6 -0
  94. package/src/db-diagnostics.ts +106 -0
  95. package/src/db-generate.ts +28 -8
  96. package/src/db-reset-template.ts +1 -1
  97. package/src/db-rolling.ts +45 -0
  98. package/src/db-seed-generate.ts +188 -0
  99. package/src/deploy-verify-findings.ts +98 -0
  100. package/src/deploy-verify-flags.ts +109 -0
  101. package/src/deploy-verify-grade.ts +185 -0
  102. package/src/deploy-verify-queues.ts +53 -0
  103. package/src/dev-boot.ts +35 -15
  104. package/src/dev-child-watch.ts +16 -4
  105. package/src/dev-dashboard-guard.ts +8 -1
  106. package/src/dev-dashboard.ts +7 -0
  107. package/src/dev-lock-identity.ts +61 -0
  108. package/src/dev-lock-port-holder.ts +80 -0
  109. package/src/dev-lock-steal.ts +124 -0
  110. package/src/dev-lock.ts +92 -120
  111. package/src/dev-mail-templates.ts +51 -0
  112. package/src/dev-rebuild.ts +26 -2
  113. package/src/dev-route-table.ts +17 -0
  114. package/src/dev-supervisor.ts +5 -2
  115. package/src/dev-watch-tree.ts +11 -10
  116. package/src/dev-watch.ts +1 -1
  117. package/src/dispatch.ts +29 -6
  118. package/src/docs-section.ts +69 -0
  119. package/src/docs-sources.ts +100 -0
  120. package/src/doctor-auth.ts +11 -2
  121. package/src/doctor-chart-alerts.ts +55 -0
  122. package/src/doctor-pooler.ts +107 -0
  123. package/src/doctor-rolling.ts +35 -0
  124. package/src/doctor-row-security.ts +40 -0
  125. package/src/document-options.ts +13 -0
  126. package/src/drill-sync-lane.ts +25 -0
  127. package/src/drill-targets.ts +39 -0
  128. package/src/duplicate-packages.ts +1 -1
  129. package/src/env-production.ts +93 -0
  130. package/src/error-codes-shot.ts +59 -0
  131. package/src/error-codes-tooling.ts +29 -0
  132. package/src/error-codes.ts +100 -54
  133. package/src/error-contract.ts +2 -2
  134. package/src/errors.ts +22 -3
  135. package/src/exercise-database.ts +99 -0
  136. package/src/exercise-findings.ts +159 -0
  137. package/src/exercise-overrides.ts +42 -0
  138. package/src/exercise-registration.ts +58 -0
  139. package/src/exercise-static.ts +88 -0
  140. package/src/exercise-subject.ts +69 -0
  141. package/src/failure-capture-boot.ts +30 -0
  142. package/src/framework-env.ts +7 -1
  143. package/src/framework-schema.ts +72 -5
  144. package/src/generate-catalog-locales.ts +19 -0
  145. package/src/generate-chart-alerts.ts +156 -0
  146. package/src/generate-feature-required.ts +65 -0
  147. package/src/generate-feature.ts +83 -6
  148. package/src/generate-files.ts +24 -0
  149. package/src/generate-format-written.ts +32 -0
  150. package/src/generate-kinds.ts +6 -0
  151. package/src/generate-sign-in-config.ts +100 -0
  152. package/src/generate-sign-in-manifest.ts +28 -0
  153. package/src/generate-sign-in-mode.ts +101 -0
  154. package/src/generate-sign-in.ts +250 -0
  155. package/src/generate-write.ts +44 -7
  156. package/src/hand-rolled-socket.ts +72 -0
  157. package/src/i18n-app-key-shapes.ts +29 -0
  158. package/src/i18n-audit.ts +10 -3
  159. package/src/i18n-registration.ts +18 -3
  160. package/src/index.ts +2 -0
  161. package/src/island-bundle.ts +4 -3
  162. package/src/island-disposer.ts +116 -0
  163. package/src/island-realtime-state.ts +34 -6
  164. package/src/island-realtime.ts +6 -2
  165. package/src/island-routes.ts +3 -2
  166. package/src/isr-query-advice.ts +6 -11
  167. package/src/isr-query-guard.ts +4 -3
  168. package/src/job-budget.ts +95 -0
  169. package/src/jobs-json.ts +11 -0
  170. package/src/lint-findings.ts +104 -0
  171. package/src/local-cli.ts +34 -4
  172. package/src/loopback-host.ts +2 -2
  173. package/src/mail-preview-findings.ts +24 -0
  174. package/src/mcp-errors.ts +82 -2
  175. package/src/mcp-host.ts +11 -1
  176. package/src/mcp-lock-findings.ts +57 -0
  177. package/src/measure-paths.ts +12 -4
  178. package/src/measure-scope.ts +27 -13
  179. package/src/messages-client.ts +23 -0
  180. package/src/messages-db.ts +56 -0
  181. package/src/messages-gate.ts +107 -0
  182. package/src/messages-repro.ts +11 -0
  183. package/src/messages-shot.ts +51 -0
  184. package/src/messages-upgrade.ts +45 -0
  185. package/src/messages.ts +53 -178
  186. package/src/metrics-endpoint.ts +23 -5
  187. package/src/new-shapes-generate.ts +71 -0
  188. package/src/new-shapes.ts +63 -0
  189. package/src/openapi-compile-ir.ts +68 -0
  190. package/src/openapi-compile-schema.ts +284 -0
  191. package/src/openapi-compile.ts +273 -0
  192. package/src/openapi-refuse.ts +45 -0
  193. package/src/otlp-export.ts +2 -1
  194. package/src/output-findings.ts +123 -0
  195. package/src/output.ts +32 -8
  196. package/src/package-boundaries.ts +110 -0
  197. package/src/page-pins.ts +23 -0
  198. package/src/plain-routes.ts +13 -0
  199. package/src/prerender-entries.ts +59 -0
  200. package/src/prerender-heaviest.ts +27 -0
  201. package/src/prerender-preload.ts +6 -0
  202. package/src/prerender-report.ts +12 -0
  203. package/src/prerender-seo-reads.ts +38 -0
  204. package/src/prerender-served.ts +22 -7
  205. package/src/prerender-vitals.ts +42 -0
  206. package/src/prerender.ts +61 -32
  207. package/src/pwa-artifacts.ts +4 -3
  208. package/src/pwa-manifest-locales.ts +1 -1
  209. package/src/registry.ts +18 -0
  210. package/src/repro-bundle.ts +65 -0
  211. package/src/repro-errors.ts +47 -0
  212. package/src/repro-job.ts +72 -0
  213. package/src/repro-literal.ts +41 -0
  214. package/src/repro-request.ts +48 -0
  215. package/src/repro-write.ts +100 -0
  216. package/src/retain-sweep.ts +27 -0
  217. package/src/retained-assets-boot.ts +113 -0
  218. package/src/retained-assets-layout.ts +110 -0
  219. package/src/retained-assets-read.ts +142 -0
  220. package/src/retained-assets-sweep.ts +70 -0
  221. package/src/retained-assets.ts +171 -0
  222. package/src/revalidated-response.ts +8 -5
  223. package/src/role-replicator.ts +7 -1
  224. package/src/role-start-devices.ts +119 -0
  225. package/src/role-start-types.ts +6 -0
  226. package/src/role-start.ts +22 -5
  227. package/src/role-sync.ts +7 -1
  228. package/src/route-islands.ts +42 -0
  229. package/src/route-table.ts +2 -1
  230. package/src/row-security-boot.ts +58 -0
  231. package/src/row-security-wanted.ts +32 -0
  232. package/src/runtime-admin.ts +0 -1
  233. package/src/runtime-assets-site-cache.ts +55 -0
  234. package/src/runtime-assets-site.ts +136 -0
  235. package/src/runtime-assets.ts +99 -55
  236. package/src/runtime-bindings.ts +19 -3
  237. package/src/runtime-cache.ts +23 -14
  238. package/src/runtime-isr-outcome.ts +114 -60
  239. package/src/runtime-purge.ts +14 -2
  240. package/src/runtime-queue.ts +31 -4
  241. package/src/runtime-render-document.ts +204 -0
  242. package/src/runtime-render.ts +48 -198
  243. package/src/runtime-replica-position.ts +62 -0
  244. package/src/runtime-replica.ts +18 -3
  245. package/src/runtime-s3-path-style.ts +17 -0
  246. package/src/runtime-services.ts +19 -6
  247. package/src/runtime-statement-bound.ts +22 -0
  248. package/src/runtime-storage-upload.ts +9 -0
  249. package/src/runtime-storage.ts +42 -138
  250. package/src/schema-diff-views.ts +54 -0
  251. package/src/schema-diff.ts +21 -3
  252. package/src/schema-drift.ts +28 -9
  253. package/src/schema-dump-drift.ts +91 -7
  254. package/src/script-csp.ts +1 -1
  255. package/src/seo-cards.ts +26 -0
  256. package/src/seo-routes.ts +22 -8
  257. package/src/serve-boot.ts +54 -21
  258. package/src/serve-drain.ts +1 -0
  259. package/src/serve-env.ts +26 -8
  260. package/src/serve-retire.ts +12 -6
  261. package/src/serve-web.ts +42 -4
  262. package/src/serve.ts +9 -7
  263. package/src/site-asset-routes.ts +17 -27
  264. package/src/site-config.ts +4 -0
  265. package/src/site-llms-pages.ts +106 -0
  266. package/src/site-llms.ts +64 -0
  267. package/src/site-seo-write.ts +4 -2
  268. package/src/site-seo.ts +55 -6
  269. package/src/source-mtime.ts +50 -0
  270. package/src/static-capture-errors.ts +41 -0
  271. package/src/static-capture.ts +56 -0
  272. package/src/static-cards-serve.ts +39 -0
  273. package/src/static-cards.ts +93 -0
  274. package/src/static-document.ts +14 -13
  275. package/src/static-images.ts +115 -0
  276. package/src/stream-hole-scope.ts +55 -0
  277. package/src/style-bundle.ts +1 -1
  278. package/src/style-routes.ts +3 -2
  279. package/src/sw-precache-plan.ts +2 -2
  280. package/src/sw-routes.ts +2 -2
  281. package/src/templates/action-tests.ts +306 -0
  282. package/src/templates/action.ts +81 -269
  283. package/src/templates/backfill.ts +1 -1
  284. package/src/templates/entity.ts +21 -5
  285. package/src/templates/github/ci.yml.ts +8 -9
  286. package/src/templates/guard-bare-error.ts +2 -2
  287. package/src/templates/guard-error-declared.ts +263 -0
  288. package/src/templates/guard-native-confirm.ts +132 -0
  289. package/src/templates/guard-raw-fetch.ts +151 -0
  290. package/src/templates/guard-raw-interval.ts +121 -0
  291. package/src/templates/guard-repo-raw-sql.ts +71 -2
  292. package/src/templates/job.ts +1 -1
  293. package/src/templates/naming.ts +5 -0
  294. package/src/templates/pinned/docker-compose.yml +6 -0
  295. package/src/templates/pinned-images.ts +8 -0
  296. package/src/templates/policy.ts +85 -2
  297. package/src/templates/query.ts +70 -13
  298. package/src/templates/resource-create.ts +3 -1
  299. package/src/templates/resource-form-island.ts +15 -4
  300. package/src/templates/resource-page-db.ts +83 -0
  301. package/src/templates/resource-page.ts +161 -52
  302. package/src/templates/route.ts +4 -6
  303. package/src/templates/scaffold-app.ts +3 -0
  304. package/src/templates/scaffold-auth.ts +2 -1
  305. package/src/templates/scaffold-bin.ts +5 -52
  306. package/src/templates/scaffold-claude-agents.ts +19 -19
  307. package/src/templates/scaffold-claude-commands.ts +28 -31
  308. package/src/templates/scaffold-claude.ts +26 -23
  309. package/src/templates/scaffold-container-compose.ts +6 -1
  310. package/src/templates/scaffold-container.ts +24 -4
  311. package/src/templates/scaffold-dashboard-bare.ts +3 -3
  312. package/src/templates/scaffold-dashboard-example-tests.ts +49 -9
  313. package/src/templates/scaffold-dashboard-example-view.ts +156 -0
  314. package/src/templates/scaffold-dashboard-example.ts +43 -131
  315. package/src/templates/scaffold-dashboard-shared.ts +3 -7
  316. package/src/templates/scaffold-db-client.ts +20 -6
  317. package/src/templates/scaffold-db-package.ts +5 -14
  318. package/src/templates/scaffold-docs.ts +73 -57
  319. package/src/templates/scaffold-domain-package.ts +18 -14
  320. package/src/templates/scaffold-entries.ts +7 -2
  321. package/src/templates/scaffold-exercise.ts +37 -0
  322. package/src/templates/scaffold-guards.ts +13 -1
  323. package/src/templates/scaffold-helm-alerts.ts +234 -0
  324. package/src/templates/scaffold-helm-templates.ts +7 -5
  325. package/src/templates/scaffold-helm.ts +46 -12
  326. package/src/templates/scaffold-i18n.ts +6 -2
  327. package/src/templates/scaffold-mcp-endpoint.ts +182 -0
  328. package/src/templates/scaffold-mcp-json.ts +31 -0
  329. package/src/templates/scaffold-mcp-package.ts +59 -56
  330. package/src/templates/scaffold-repo.ts +7 -2
  331. package/src/templates/scaffold-shell.ts +45 -79
  332. package/src/templates/scaffold-test-services.ts +13 -5
  333. package/src/templates/shapes/api-keys.ts +170 -0
  334. package/src/templates/shapes/api.ts +101 -0
  335. package/src/templates/shapes/blog-site.ts +340 -0
  336. package/src/templates/shapes/blog-slice.ts +265 -0
  337. package/src/templates/shapes/blog.ts +114 -0
  338. package/src/templates/shapes/dashboard-detail.ts +242 -0
  339. package/src/templates/shapes/dashboard.ts +53 -0
  340. package/src/templates/shapes/index.ts +17 -0
  341. package/src/templates/shapes/overlay.ts +99 -0
  342. package/src/templates/shapes/shared-edits.ts +46 -0
  343. package/src/templates/sign-in-action-tests.ts +237 -0
  344. package/src/templates/sign-in-authenticator.ts +112 -0
  345. package/src/templates/sign-in-oidc.ts +189 -0
  346. package/src/templates/sign-in-pages.ts +148 -0
  347. package/src/templates/sign-in-password.ts +216 -0
  348. package/src/templates/sign-in-shared.ts +268 -0
  349. package/src/templates/slice-foundation.ts +70 -15
  350. package/src/test-batches.ts +1 -1
  351. package/src/test-database.ts +1 -1
  352. package/src/test-shards.ts +7 -1
  353. package/src/test-workers.ts +18 -12
  354. package/src/tool-gate-names.ts +34 -0
  355. package/src/upgrade-agents-link.ts +49 -0
  356. package/src/upgrade-bun-floor.ts +225 -0
  357. package/src/upgrade-gate.ts +228 -0
  358. package/src/upgrade-pins.ts +63 -0
  359. package/src/upgrade-plan.ts +214 -0
  360. package/src/upgrade-registry.ts +53 -0
  361. package/src/upgrade-report.ts +139 -0
  362. package/src/upgrade-root.ts +74 -0
  363. package/src/verify-budgets-build.ts +118 -0
  364. package/src/verify-checks.ts +67 -24
  365. package/src/verify-coverage-run.ts +1 -1
  366. package/src/verify-e2e-lane.ts +41 -0
  367. package/src/verify-exercise.ts +64 -0
  368. package/src/verify-floor.ts +41 -0
  369. package/src/verify-merge.ts +19 -4
  370. package/src/verify-role-load.ts +2 -0
  371. package/src/verify-run.ts +28 -8
  372. package/src/verify-shard.ts +12 -2
  373. package/src/verify-skip-ceiling.ts +87 -0
  374. package/src/verify-step.ts +5 -0
  375. package/src/verify-tests.ts +25 -5
  376. package/src/view-drift.ts +55 -0
  377. package/src/worker-bundle.ts +3 -2
  378. package/src/workspace-graph.ts +38 -19
  379. package/src/write-generated.ts +43 -0
  380. package/src/zone-boot.ts +20 -0
  381. package/wiki/Actions.md +342 -0
  382. package/wiki/Admin-Dashboard.md +432 -0
  383. package/wiki/Agents.md +958 -0
  384. package/wiki/Auth.md +195 -0
  385. package/wiki/Bare-VM.md +111 -0
  386. package/wiki/Batching-And-Preloading.md +136 -0
  387. package/wiki/Building-Your-Own-Base.md +203 -0
  388. package/wiki/CI-Parallel-Gate.md +220 -0
  389. package/wiki/CLI-Reference.md +1894 -0
  390. package/wiki/Caching-And-Invalidation.md +255 -0
  391. package/wiki/Client-Data.md +194 -0
  392. package/wiki/Client-Navigation.md +513 -0
  393. package/wiki/Compared.md +93 -0
  394. package/wiki/Configuration.md +868 -0
  395. package/wiki/Contributing.md +12 -0
  396. package/wiki/Deploy-Recipes.md +122 -0
  397. package/wiki/Deployment.md +508 -0
  398. package/wiki/Entities-And-Migrations.md +1116 -0
  399. package/wiki/FAQ.md +175 -0
  400. package/wiki/Feature-Flags.md +65 -0
  401. package/wiki/Getting-Started.md +221 -0
  402. package/wiki/Home.md +160 -0
  403. package/wiki/I18n.md +239 -0
  404. package/wiki/Installation.md +206 -0
  405. package/wiki/Interface-Rules.md +339 -0
  406. package/wiki/Jobs-And-Workflows.md +783 -0
  407. package/wiki/Known-Gaps.md +185 -0
  408. package/wiki/MCP-And-AI.md +753 -0
  409. package/wiki/Mail.md +138 -0
  410. package/wiki/Migrating-An-Existing-App.md +594 -0
  411. package/wiki/Migrating-From-Django.md +54 -0
  412. package/wiki/Migrating-From-Laravel.md +53 -0
  413. package/wiki/Migrating-From-Node-Drizzle.md +53 -0
  414. package/wiki/Migrating-From-Rails.md +53 -0
  415. package/wiki/Migrations-And-Backfills.md +552 -0
  416. package/wiki/Money.md +338 -0
  417. package/wiki/N-Plus-One-Detection.md +197 -0
  418. package/wiki/Notify.md +208 -0
  419. package/wiki/Observability.md +245 -0
  420. package/wiki/Outbound-HTTP.md +109 -0
  421. package/wiki/PWA-And-Offline.md +343 -0
  422. package/wiki/Policies-And-Authz.md +251 -0
  423. package/wiki/Project-Layout.md +150 -0
  424. package/wiki/Queries-And-Live-Queries.md +429 -0
  425. package/wiki/Realtime.md +734 -0
  426. package/wiki/Resource-Management.md +121 -0
  427. package/wiki/Routes-And-Render-Modes.md +521 -0
  428. package/wiki/SEO.md +288 -0
  429. package/wiki/Scheduled-Tasks.md +175 -0
  430. package/wiki/Scraping.md +493 -0
  431. package/wiki/Shapes.md +63 -0
  432. package/wiki/Stability.md +97 -0
  433. package/wiki/Static-Assets.md +166 -0
  434. package/wiki/Storage-And-Uploads.md +404 -0
  435. package/wiki/Testing.md +1313 -0
  436. package/wiki/The-Eight-Primitives.md +247 -0
  437. package/wiki/Theming.md +362 -0
  438. package/wiki/Timezones-And-Dates.md +194 -0
  439. package/wiki/Troubleshooting.md +163 -0
  440. package/wiki/Tutorial-01-First-App.md +289 -0
  441. package/wiki/Tutorial-02-First-Feature.md +339 -0
  442. package/wiki/Tutorial-03-Auth-And-Admin.md +379 -0
  443. package/wiki/Tutorial-04-Jobs-And-Realtime.md +263 -0
  444. package/wiki/Tutorial-05-Deploy-Free.md +231 -0
  445. package/wiki/Tutorial-06-Growing-Up.md +158 -0
  446. package/wiki/UI-Components.md +156 -0
  447. package/wiki/Upgrading.md +3667 -0
  448. package/src/stored-object-headers.ts +0 -43
@@ -0,0 +1,194 @@
1
+ # Timezones and dates
2
+
3
+ Store UTC. Format at the edge with `Intl.DateTimeFormat` and an **explicit IANA `timeZone`**.
4
+
5
+ A `Intl.DateTimeFormat` or `toLocaleString` call with no `timeZone` option is a lint failure and fails `x verify` (check 2). It silently uses the process `TZ`, which in a container is `UTC` and in a laptop is not — the same code renders two different days depending on where it runs.
6
+
7
+ ## Storage
8
+
9
+ | Rule | Detail |
10
+ |---|---|
11
+ | Column type | `timestamptz`, always. `timestamp` (without zone) is a build error in a generated migration |
12
+ | Stored value | the UTC instant. Postgres normalizes on write; the session `TimeZone` is `UTC` on every role |
13
+ | Never stored | a formatted string, a local wall-clock time, or an offset in a separate column |
14
+ | Date-only values | `date` column for a true civil date (birthday, invoice date). A `date` has no instant and is never converted |
15
+ | Wall-clock intent | when a user means "9am in their city", store `timestamptz` **plus** the IANA zone in its own `text` column. An offset (`+02:00`) is not a zone — it does not survive DST |
16
+ | Zone strings | IANA identifiers only: `Europe/Berlin`, `America/Sao_Paulo`. Never `CET`, never `GMT+2`, never `PST` |
17
+
18
+ ## The actor's zone
19
+
20
+ ```ts
21
+ import { currentTimeZone } from '@ultimat3/time';
22
+ ```
23
+
24
+ `resolveTimeZone` reads, first valid IANA name wins, canonicalized; an invalid one is skipped, never thrown. As of 2026-11:
25
+
26
+ | Source | Precedence |
27
+ |---|---|
28
+ | the member's saved zone (`actor.tz`) | 1 — what a person chose |
29
+ | `x_timezone` cookie, written by a zone picker | 2 — chosen |
30
+ | `?tz=Europe/Berlin` | 3 — share links, email previews |
31
+ | `x-timezone` header, sent by a client from `Intl` | 4 — what the browser is installed as |
32
+ | `x_timezone_detected` cookie, written by the zone script under `time.detect` | 5 — a guess, never written over a pick |
33
+ | `configureTime({ defaultZone })` | 6 — `UTC` unless the app says otherwise |
34
+ | Process `TZ` | never |
35
+
36
+ ### Detecting a new visitor's zone
37
+
38
+ A document navigation sends no `x-timezone`, so a new visitor's server-rendered `app/` pages render in the default zone. `time: { detect: true }` in `app.config.ts` (off by default: it writes a cookie) puts a 153 B inline script on every `app/` document — never on `site/` — that writes `x_timezone_detected` from `Intl.DateTimeFormat().resolvedOptions().timeZone`. The first paint stays the default; every page after it is in the visitor's zone. The script is admitted by its own CSP hash, and it never touches the chosen `x_timezone` cookie.
39
+
40
+ ```ts
41
+ import { defineConfig } from '@ultimat3/core';
42
+
43
+ export const config = defineConfig({ name: 'my-app', time: { detect: true } });
44
+ ```
45
+
46
+ The zone rides the ALS request context alongside the locale, so `format*` helpers take neither argument. Jobs and scheduled tasks carry the enqueueing actor's zone in the payload — a worker has no request and must not invent one.
47
+
48
+ ## Formatting
49
+
50
+ | Helper | Output | Notes |
51
+ |---|---|---|
52
+ | `formatDate(instant)` | `2026-07-26` in the actor's zone + locale | `Intl.DateTimeFormat`, `dateStyle: 'medium'` by default |
53
+ | `formatTime(instant)` | `14:30` | 12/24h from the locale, never hardcoded |
54
+ | `formatDateTime(instant)` | date + time | one formatter, cached per (locale, zone, style) |
55
+ | `formatRelative(instant)` | `3 days ago` | `Intl.RelativeTimeFormat`; computed against the frozen clock in tests. From a day apart the number is **calendar days in the zone** — 47 hours ahead across two midnights is `in 2 days`, never `tomorrow` — so it takes `zone` like every other formatter |
56
+ | `formatRange(a, b)` | `Jul 24 – 26, 2026` | `formatRange` on the native formatter, so the collapse rules are CLDR's |
57
+ | `formatZone(zone)` | `Central European Summer Time` | `timeZoneName: 'long'` |
58
+ | `zonedParts(instant, zone)` | `{ year, month, day, hour, … }` | for arithmetic that must respect civil calendars |
59
+
60
+ All of them read locale and zone from the context and pass `timeZone` explicitly to `Intl`. There is no variant that omits it.
61
+
62
+ ### Pickers
63
+
64
+ `As of 2026-11`. A calendar date the user picks is a `PlainDate` — `DatePicker`, `DateRangePicker`
65
+ and `Calendar` take and post `YYYY-MM-DD` and know no zone. Month and weekday names are
66
+ `Intl.DateTimeFormat` with `timeZone: 'UTC'` on the plain date's UTC midnight, which names the date
67
+ and never shifts it; the week starts on the locale's day (`Intl.Locale#getWeekInfo`). A *window* is
68
+ instants: `timeRangeUrl(url, { presets, default, timeZone, now })` reads a custom `from`/`to` as
69
+ wall-clock time in `timeZone` (a spring-forward gap resolves forward) and `TimeRangePicker` requires
70
+ the same `timeZone` as a prop — omitting it is a type error. "Today" is the caller's: pass `month`
71
+ (or `now`) computed with `plainDateIn(now(), actor.tz)`; with none, `Calendar` opens on today in
72
+ `useUi().timeZone`, the request's zone, never the device's.
73
+
74
+ ## Common mistakes
75
+
76
+ | Mistake | What breaks | Fix |
77
+ |---|---|---|
78
+ | `new Date().toLocaleDateString()` | uses process `TZ`; wrong day for half your users | `formatDate(instant)` |
79
+ | `Intl.DateTimeFormat(locale)` with no `timeZone` | same, and lint-failing | pass `timeZone` or use a helper |
80
+ | `timestamp` column | the offset is lost on write; two writers disagree | `timestamptz` |
81
+ | Storing `+02:00` as "the zone" | breaks at the next DST transition | store the IANA zone |
82
+ | `Date.now()` in a test assertion | flake | `clock.advance('3d')` and assert on the frozen instant |
83
+ | `setHours(0, 0, 0, 0)` for "start of day" | midnight in the server's zone, not the user's | `startOfDay(instant, zone)` via `zonedParts` |
84
+ | Adding `24 * 60 * 60 * 1000` for "tomorrow" | wrong on the 23h and 25h DST days | add one **calendar** day in the zone |
85
+ | `date` column read as an instant | shifts by a day west of UTC | `date` columns are civil dates; never convert |
86
+ | Formatting in a service or repo | untestable, unlocalizable | format in the route/component only |
87
+ | `date.setMonth(date.getMonth() + 1)` | Jan 31 + 1 rolls into March | `addMonthsInZone(at, 1, zone)` or `addPlainMonths(date, 1)` — [Month arithmetic](#month-arithmetic) |
88
+
89
+ ## Month arithmetic
90
+
91
+ A month has no fixed length, so both helpers clamp the day to the target month's last day.
92
+
93
+ | Function | Answers |
94
+ |---|---|
95
+ | `addPlainMonths(date, months)` | a `PlainDate`: `2026-01-31` + 1 → `2026-02-28`; `2024-01-31` + 1 → `2024-02-29`; negative counts go back. A non-integer count or a year outside `0000`–`9999` is `X_SCHEDULE_INVALID` |
96
+ | `addMonthsInZone(at, months, timeZone)` | an `Instant` at the same **local** wall-clock time `months` calendar months away; `timeZone` is required. A wall time that does not exist moves forward by the gap; one that exists twice takes the earlier instant |
97
+ | `plainDateRange(start, end, { exclusive?, stepDays? })` | a frozen array of `PlainDate`s, `[start, end]` by default; a span over `MAX_PLAIN_DATE_RANGE_DAYS` (3660) is `X_SCHEDULE_INVALID` |
98
+
99
+ **Compute a recurring date from its anchor, never by chaining.** A clamp does not compose:
100
+ `2026-01-31` + 1 + 1 is `2026-03-28`, `2026-01-31` + 2 is `2026-03-31`.
101
+
102
+ ```ts
103
+ import { addMonthsInZone, fromIso } from '@ultimat3/time';
104
+
105
+ const anchor = fromIso('2026-01-31T00:00:00-05:00');
106
+ const renewal = (n: number) => addMonthsInZone(anchor, n, 'America/Bogota');
107
+ // renewal(1): Feb 28 00:00, renewal(2): Mar 31 00:00 — never stuck on the 28th
108
+ ```
109
+
110
+ Full rules: [`packages/time/README.md`](https://github.com/developerz-ai/ultimate/blob/main/packages/time/README.md#months-clamp).
111
+
112
+ ## Duration strings
113
+
114
+ One notation for every "how long" field.
115
+
116
+ | String | Means | Used by |
117
+ |---|---|---|
118
+ | `'30s'` | 30 seconds | cache TTL, retry backoff floor |
119
+ | `'15m'` | 15 minutes | `step.sleep`, live-query reconnect window |
120
+ | `'6h'` | 6 hours | ISR revalidate TTL |
121
+ | `'3d'` | 3 days | `step.sleep`, semantic cache `ttl` |
122
+ | `'7d'` | 7 days | LLM semantic cache default |
123
+
124
+ Parsed once into milliseconds. A bare number is a type error — the unit must be in the string. See [Caching and invalidation](Caching-And-Invalidation) and [Jobs and workflows](Jobs-And-Workflows).
125
+
126
+ ## Scheduled tasks
127
+
128
+ `tz` is required on every `task` and must be an explicit IANA zone. There is no default.
129
+
130
+ ```ts
131
+ // task (cron)
132
+ export const nightlyDigest = task({
133
+ cron: '0 3 * * *',
134
+ tz: 'UTC',
135
+ enqueue: () => [[sendDigest, {}]],
136
+ });
137
+ ```
138
+
139
+ | Concern | Rule |
140
+ |---|---|
141
+ | Missing `tz` | type error, then `X_CONFIG_INVALID` at boot if bypassed |
142
+ | `'UTC'` | correct for machine work: digests, compaction, exports |
143
+ | A civil zone | correct for user-facing schedules: "9am local" is `tz: 'Europe/Berlin'`, not `'0 7 * * *'` in UTC |
144
+ | Leader election | one `scheduler` role, holding an expiring lease row in `x_scheduler_leader` — never an advisory lock. A task fires once per cluster, not once per pod |
145
+ | Catch-up | a missed window is logged and skipped, never replayed silently |
146
+
147
+ See [Scheduled tasks](Scheduled-Tasks).
148
+
149
+ ### DST-crossing recurrence
150
+
151
+ | Case | Behavior |
152
+ |---|---|
153
+ | Spring forward, `0 2 * * *` in a zone that skips 02:00 | fires at the zone's next valid instant that day (03:00) — shifted, never skipped |
154
+ | Fall back, `0 2 * * *` in a zone that repeats 02:00 | a fixed time fires **once**, on the first pass |
155
+ | Fall back, `*/5 * * * *` or `0 * * * *` — the minute or hour field is `*` or `*/n` | an interval runs through **both** passes of the repeated hour: it is real elapsed time, and no hour of the night is dark |
156
+ | `step.sleep('1d')` across a transition | sleeps 24h of elapsed time, not one calendar day. For calendar semantics, compute the next instant in the zone and `step.sleepUntil` |
157
+ | Monthly on the 31st | months without a 31st are skipped, not clamped to the 30th. Use `'0 3 28 * *'` if you need every month |
158
+
159
+ Cron is a civil-calendar schedule; sleeps are elapsed time. Mixing them is where "the job ran twice in November" comes from.
160
+
161
+ ## Tests
162
+
163
+ | Control | Behavior |
164
+ |---|---|
165
+ | Frozen clock | time starts at a fixed instant, does not advance on its own |
166
+ | `clock.advance('3d')` | moves it, and also drives `step.sleep` and cron dispatch |
167
+ | Fixed zone | `UTC` unless a test declares otherwise |
168
+ | Fixed locale | `en-US` unless a test declares otherwise |
169
+ | tz-dependent bugs | fail deterministically — declare a zone in the test and the bug reproduces every run |
170
+ | Wall clock | never asserted on. `Date.now()` in an expectation is a rejected PR |
171
+
172
+ Declare a zone when the behavior is the point:
173
+
174
+ ```ts
175
+ test('digest window respects the org zone', async ({ seed, clock }) => {
176
+ const { org } = await seed('org-in-berlin');
177
+ clock.advance('1d');
178
+ const window = digestWindow(org, 'Europe/Berlin');
179
+ expect(window.label).toBe('Jul 27, 2026');
180
+ });
181
+ ```
182
+
183
+ See [Testing](Testing).
184
+
185
+ ## Rules
186
+
187
+ - `timestamptz` for instants, `date` for civil dates. Nothing else.
188
+ - Never format without an explicit IANA `timeZone`.
189
+ - Never read the process `TZ`. Roles run with `TZ=UTC` and it is not an input.
190
+ - Zone comes from the actor; a worker gets it from the job payload.
191
+ - Format at the edge only — routes and components, never services or repos.
192
+ - Durations are strings with units.
193
+ - `tz` on a `task` is explicit and required.
194
+ - Advance the frozen clock; never sleep in a test.
@@ -0,0 +1,163 @@
1
+ # Troubleshooting
2
+
3
+ Symptom → cause → fix. Every `X_*` error already carries its own cause and exact fix command; this page is for symptoms that do not start with a code.
4
+
5
+ ## Triage
6
+
7
+ Run these first, in this order. All support `--json`.
8
+
9
+ | Command | Answers |
10
+ |---|---|
11
+ | `x doctor --json` | Bun version, env schema, DB/transport/storage reachability, port conflicts |
12
+ | `x verify --json` | the gate — 21 steps, in this order: typecheck, lint, boundaries, filesize, package-shape, errors, unit, contract, live, job, exercise, e2e, eval, drift, contract-diff, budgets, seo, i18n, policy, manifest, roadmap |
13
+ | `x errors explain <CODE> --json` | cause, fix command, docs URL for any `X_*` code |
14
+ | `x docs "<symptom or question>" --json` | the framework's own docs and this wiki, offline from the install — the first lookup for a symptom with no code |
15
+ | `x doctor --json` | environment, versions, drift, ports, PWA prerequisites — each with a fix |
16
+ | `x dev` then `/_x` | the live panels: routes, timeline, jobs, db, mail, cache, policy, manifest |
17
+ | `x status --json` · `x logs tail --json` | **planned**, not shipped — both throw `X_NOT_IMPLEMENTED` naming the two rows above ([CLI reference](CLI-Reference)) |
18
+
19
+ The `--json` form is the same content as the terminal form. Paste the JSON into a bug report; do not paraphrase the terminal.
20
+
21
+ ## Boot and env
22
+
23
+ | Symptom | Likely cause | Fix |
24
+ |---|---|---|
25
+ | Process exits in ~40ms, `X_ENV_MISSING` | a key in the `defineEnv` schema is missing, or present but fails its schema (short secret, non-URL, bad enum) | the cause names every offending key and its constraint at once; `x doctor --json` lists them too |
26
+ | `X_CONFIG_INVALID` at load | `app.config.ts` field invalid — `defaultLocale` not in `locales`, `db.pool < 1`, non-IANA `timeZone`, `realtime.transport` set without `realtime.urlEnv` | `x config show --json`, then edit the field named in `cause` |
27
+ | `X_ROLE_INVALID` | `ROLE` is not one of `web sync worker scheduler migrate replicator all` | fix the env var on that service |
28
+ | `X_BUN_VERSION` | below the Bun floor, `>= 1.4.4` (`engines.bun`) | `bun upgrade` |
29
+ | Container starts then loops | `/readyz` failing, not `/healthz` — a registered check answers `failing`, and which one is in the body | `curl /readyz` **from the container itself** (`docker exec`, `kubectl exec`, a port-forward — the detail goes to `healthDetailPeers`, default `['loopback']`) and read `checks`, a map of name → `ok`/`failing`: `database` is registered always, `transport` whenever it can report a connection, so a disconnected NATS node fails on that one. Read `registered` with it: `0` means nothing was checked, so the 200 meant only that the socket was bound |
30
+ | Config edits have no effect | you edited a per-environment file that does not exist — config is **one file** | put the difference in an env var ([Configuration](Configuration)) |
31
+
32
+ ## Database
33
+
34
+ | Symptom | Likely cause | Fix |
35
+ |---|---|---|
36
+ | `X_DB_DRIFT` | schema differs from migrations (a column added by hand, or a generated migration never applied) | `x db gen "<message>"` then `x db migrate`. A column no entity declares is an empty diff: declare it, or restore the migration and `x db reset` |
37
+ | `X_DB_DRIFT`, cause *the dump holds a column no migration's snapshot records* | an applied migration was edited, and `x db gen` wrote the edit into `packages/db/schema/` | `git checkout -- packages/db/migrations packages/db/schema`. Meant it: declare the column on its entity, then `x db gen "<change>"` |
38
+ | `X_MIGRATION_CONFLICT`, *was applied with checksum* | an applied migration's file was edited | `git log -- packages/db/migrations/<id>.sql`, then `git checkout <rev> -- …` the revision whose checksum the ledger names, then `x db gen "<change>"`. `x db gen` first exits 0 and poisons the dump |
39
+ | `X_APP_IMPORT_UNRESOLVED` | an app module imports a package nobody installed, or a path with no file behind it. One finding per specifier | `bun add <pkg>`, or edit the import in the file the finding names. `x doctor` reports it too |
40
+ | `X_DB_DRIFT` on a brand-new app, cause *packages/db has a schema but no migration recorded it* | expected: `x new` writes no migration, and `x db gen` is the only writer of `packages/db/migrations`. Only an app that declares an entity reports it — zero declared against zero recorded is agreement | `x db gen "initial"` then `x db migrate` — `bun run setup` does both |
41
+ | `X_DB_DRIFT` after deleting the last entity, migrations still committed | correct, and not the case above: the migrations record tables the source no longer declares | `x db gen "drop <table>"` → it refuses with `X_MIGRATION_IRREVERSIBLE` → re-run as `x db gen "drop <table>" --allow-destructive`, or put the entity back |
42
+ | `X_MIGRATION_SNAPSHOT_MISSING`, and `x db gen` refuses before writing anything | the newest migration on disk carries no `.snapshot.json` — hand-written, or the sidecar was deleted | `git checkout -- packages/db/migrations/<id>.snapshot.json`; if it was never written, `rm packages/db/migrations/<id>.* && x db gen "<name>"` — the delete **first**, or the generate refuses again |
43
+ | `ROLE=migrate` sits there doing nothing | another version's `ROLE=migrate` holds the session-pinned migration lock. This one **waits up to 60s**, polling once per 500ms, then exits non-zero with `X_MIGRATE_CONCURRENT` (`As of 2026-08`; on 1.2.0 it waits forever) | let the first exit 0 — the second then applies. If nothing else is deploying, the holder is a wedged backend: `psql "$DATABASE_URL" -c "select pid, application_name, state from pg_stat_activity join pg_locks using (pid) where locktype = 'advisory'"`, then `pg_terminate_backend(pid)` it |
44
+ | `ROLE=migrate` exits non-zero, deploy blocked | migration failure — correct, the roll is supposed to stop | read the SQL error, fix the migration, re-run. Do not start `web` on the old schema |
45
+ | `X_TIMEOUT` on one query | past `db.statementTimeout` (default `'10s'`) | add the index the plan wants, or narrow the query. Raising the timeout hides it |
46
+ | Connection exhaustion under load | `db.pool` × replicas × roles exceeds Postgres `max_connections` | lower `db.pool`, or a pooler in front |
47
+ | Every test suddenly slow | the template DB is being rebuilt per worker | `x test --json` reports template build time; check migrations that are not idempotent |
48
+
49
+ ## Import boundaries
50
+
51
+ | Symptom | Likely cause | Fix |
52
+ |---|---|---|
53
+ | `X_BOUNDARY_VIOLATION` on a file that imports nothing suspicious | a **transitive** chain — the error prints it, e.g. `site/pricing → shared/ui/button → app/billing/service` | break the chain at the lowest hop; move the shared piece into `shared/` |
54
+ | `X_BOUNDARY_SITE_TO_APP` | a `site/` route reached into `app/` | duplicate the small thing, or move it to `shared/`. `site/` must stay 0kb JS |
55
+ | `X_BOUNDARY_SHARED_LEAF` | `shared/` imported `site/` or `app/` | `shared/` is a leaf, always |
56
+ | `X_BOUNDARY_ROUTE_TO_DB` | a `page`/`layout`/`route` file imports the database: `packages/db`, `@<scope>/db`, `drizzle-orm`, **or a slice's `repo.ts`** (`../posts/repo` counts; `report` and `repository` do not). A page reading the repo skips the query that carries the read's policy, bound and cache tag. `As of 2026-10` (`isDbSpecifier`, `packages/cli/src/app-boundaries.ts`) | run the printed `x g query <name> --feature <slice>`, then call that query from the route — route → `query`/`action` → `repo.ts` |
57
+ | `X_BOUNDARY_SERVICE_TO_HTTP` | a service imported request/headers | a service that knows about requests cannot be reused by a job |
58
+ | `X_BOUNDARY_PACKAGE_TO_APP` | a file under `packages/` imports `apps/` at runtime, relative or by workspace name. `import type` is fine, and so is `packages/db/src/` reading an entity module | move the shared code into the package, or import in the opposite direction |
59
+ | `X_FEATURE_REQUIRED` | `x g query` or `x g backfill` named no slice with an `entity.ts`: neither creates a table | run the printed line: `--feature <closest slice>`, or `x g resource <name>` for a new table |
60
+ | Tier violation in a framework package | imported sideways or upward | `bun run boundaries`; consult the tier table in [Project layout](Project-Layout#framework-package-tiers) |
61
+
62
+ Boundaries run on pre-push and inside `x verify`. They are build errors, never lint warnings.
63
+
64
+ ## Budgets, SEO, i18n
65
+
66
+ | Symptom | Likely cause | Fix |
67
+ |---|---|---|
68
+ | `X_BUDGET_EXCEEDED` on `js` | one import pulled a library into a surface | the error names the **import chain**; `x routes --json` for per-route budgets |
69
+ | A `site/` route reports non-zero JS | a component with client state leaked into the static surface | move it to `app/`, or set `hydrate: 'never'` |
70
+ | LCP or CLS regression | an unsized image or a late-loading font | `x routes --json` for the route's budget; images go through the pipeline, never a raw `<img>` |
71
+ | `X_SEO_META_MISSING` | an indexable route's `meta` has no `title`, or no `description`. One code for both — `cause` names the field and the file | add it to the route's `meta`. Deleting a description is a build error, by design. Over-length is a different code, `X_SEO_META_TOO_LONG` (title > 60, description > 160). |
72
+ | `X_ROUTE_META_MISSING` | a route has no `meta` at all | every route sets `render`, `offline`, `hydrate`, `meta` |
73
+ | `X_CATALOG_MISSING_KEYS` | a key exists in one locale's catalog and not another | the cause lists key + locale; add the translation. There is no silent English fallback |
74
+ | `⟦some.key⟧` rendered in the UI | the key is missing everywhere | add it to the default catalog; `x verify` fails until you do |
75
+ | Lighthouse gate fails | below `seo.lighthouse.seo` (100) or `accessibility` (95) | fix the audit, don't lower the threshold |
76
+
77
+ ## Jobs
78
+
79
+ | Symptom | Likely cause | Fix |
80
+ |---|---|---|
81
+ | `X_IDEMPOTENCY_REQUIRED` (compile error) | `idempotencyKey` omitted — it is required by the type | add an `idempotencyKey` derived from `input` only, e.g. `onboard:${orgId}` |
82
+ | `X_STEP_DUPLICATE` | two `step.run` calls with the same name in one `run` | rename one. Step names must be unique and stable |
83
+ | A step re-ran after a deploy | the step was **renamed** — renaming invalidates its stored result | treat a rename as a new step; keep old names |
84
+ | `X_IDEMPOTENCY_CONFLICT` | same key, different input, inside the dedupe window | the key is not deterministic from `input`. Remove the timestamp or random part |
85
+ | Job stuck "in-flight" after a worker was killed | the lease has not expired yet | wait `jobs.visibilityTimeout` (default `'30s'`); the row is re-claimed and resumes at the **next** step, never mid-step. `x jobs show <id> --json` |
86
+ | Job in dead-letter | `retry.attempts` exhausted | `x jobs show <id> --json` for the step trace, then `x jobs retry <id>` — it replays from the failed step |
87
+ | Nothing is processing | no `worker` for that queue name | check `WORKER_QUEUES` against `jobs.queues` |
88
+ | A job ran but the row it needs doesn't exist | enqueued outside the transaction | enqueue via `<job>.enqueue` inside the action's `handle`; `X_OUTBOX_NO_TX` catches the rest |
89
+ | Cron never fires | no `scheduler`, or another node holds the lease | `scheduler` is fixed at 1 active and leadership is a row: `select * from x_scheduler_leader` names the holder and its `expires_at`. A standby has no `/readyz` to check — it serves the metrics port only — so read the row, or `x jobs list --json` |
90
+
91
+ ## Realtime
92
+
93
+ | Symptom | Likely cause | Fix |
94
+ |---|---|---|
95
+ | `X_TRANSPORT_UNAVAILABLE` | fanout bus unreachable — `NATS_URL` names a server nothing answers on | `x doctor`; set `NATS_URL`, or unset it for in-process fanout |
96
+ | `X_TRANSPORT_PROTOCOL` | nats-server older than 2.11, started without `-js`, or something other than NATS on the port | presence needs batch direct get and per-message TTL — run `nats:2.11-alpine` or newer with `-js` |
97
+ | Live query rejected at build | unbounded — missing `orderBy` or `limit` | add both. An unbounded result has no bounded change buffer and no bounded reconnect snapshot |
98
+ | Live query rejected for non-determinism | `now()` / `random()` in the `sql` | move it to `input`; the same `(input, row)` must always yield the same membership answer |
99
+ | `X_SUBSCRIPTION_LIMIT` | a socket, actor, tenant or node hit a cap — the error names which scope refused, and channel topics have their own | **live queries:** raise `maxPerSocket` / `maxPerTenant` / `maxEntries` on the `LiveQueryRegistry` (per socket, default 128), or unsubscribe unused ones. **Per actor** (default 1,000 per node, anonymous sockets per address): `realtime.maxSubscriptionsPerActor` in `app.config.ts`. **Channel topics:** raise `maxTopicsPerSocket` (default 64) / `maxTopicsPerNode` (default 10,000) on the `ChannelHub`. Only the per-actor cap is an `app.config.ts` field → [Configuration](Configuration) |
100
+ | `X_CURSOR_STALE` | resume cursor outside the change buffer window — or a reconnect that landed on a `sync` node which never served that `qid`, since the ring is per node | raise `capacity` on `new RingChangeBuffer({ capacity })` (default 1024), or pass `'snapshot'` to `resumeFrom()` so the fallback re-snapshots. Not an `app.config.ts` field → [Configuration](Configuration) |
101
+ | `X_TOPIC_FORBIDDEN` | tier-1 topic guard denied the actor | fix the topic scope; the cause names actor + topic, never the topic's data |
102
+ | Reconnect storm after a deploy | drain was truncated by SIGKILL, so no `reconnect` frame was sent | the kill timer must outlast the whole drain. Compose: `stop_grace_period` ≥ the app's `drain.readinessGraceMs` + `drain.deadlineMs` + teardown, raised by hand. Helm: `terminationGracePeriodSeconds` is derived per role from the chart's values — `preStopSleepSeconds` (web/sync, Kubernetes 1.30+) + readiness grace (web/sync) + drain budget + `teardownMarginSeconds` — with the grace and budget passed by `x deploy --method helm`; never set it by hand ([Deployment](Deployment)) |
103
+ | Reconnects still spiky with a clean drain | not a config field — `realtime.drain.*` does not exist. A draining node sends a `reconnect` frame carrying a per-client `afterMs`; if clients still stampede, they are reconnecting on their own `backoffDelay()` because no frame reached them | confirm the drain path actually ran — a `SIGKILL` sends no frame, which is the case the 50k benchmark measures → [Configuration](Configuration) |
104
+ | A channel message never arrived, and nothing errored | backpressure. `channel_frames_dropped_total` moved and `channel.frames_dropped` names the topic — a channel has no cursor and no re-snapshot, so a dropped frame is not replayed | put anything that must arrive on a live query, which repairs. Alert on any non-zero rate → [Observability](Observability) |
105
+ | `useChannel()` reads `joining` on a page that was `live`, or `x dev` logs `ultimate bus is away` | the `sync` node's bus (NATS) is away: it answers the page's beat with `X_TRANSPORT_UNAVAILABLE`, which is its condition, never a decision about the subscriber `As of 2026-10` | nothing in the app: the beat re-asks every 10 s and the membership is `live` again within one beat of the bus returning, with no reload. Find the outage on the node — `sync.bus_unavailable`, `nats transport error` — and fix NATS. `failed` is the state that means a decision (policy, undeclared channel, cap) → [Realtime](Realtime#a-bus-outage-seen-from-an-open-page) |
106
+ | A client is connected but receives nothing, and never reconnects | half-open socket: the TCP connection died without a `close`, so no handler fired | the page socket's heartbeat ends it: 10 s, two silent windows, then close `4000`. In 21.0.0 there is no option to turn it off → [Realtime](Realtime) |
107
+ | Topics silent after the first reconnect, live queries fine | a client that does not re-announce its topics. **`hello` carries nothing to resume with** `As of 2026-08` — no cursors, no membership; a `subscribe` frame carries both, one per topic and one per live query with that subscription's cursor | the page socket re-sends all of them on open. A hand-written client must send one `subscribe` per topic **and** one per live query carrying its resume cursor, or the topics are silent, presence sweeps the membership, and every live query re-snapshots → [Realtime](Realtime) |
108
+ | Every client re-snapshots for the length of a deploy | the `qid` hash changed with the framework version, so a resuming cursor names a ring entry the new node does not have | expected and correct: the miss falls back to one bounded snapshot per subscription. It ends when the rollout does |
109
+ | A row appeared that the user shouldn't see | not possible via the framework path — policy is re-checked per delivered row. Suspect an unscoped predicate | `X_TENANCY_UNSCOPED`; tenant scope comes from `ctx`, never from `input` |
110
+ | `sync` never becomes ready | replication feed lag over threshold, or NATS not subscribed | check the `replicator` first — it owns the slot |
111
+
112
+ ## PWA, build skew, deploys
113
+
114
+ | Symptom | Likely cause | Fix |
115
+ |---|---|---|
116
+ | White screen after a deploy, 404 on a lazy chunk | version skew — a tab holding build `A`'s document asked for a hashed file only build `A` served. With `assets.retain` unset (the default) a web pod serves only what it built | set `assets: { retain: { disk: '<a disk every web pod shares>', builds: <deploys a tab may sit open across> } }` in `app.config.ts`; with it set, raise `builds` → [PWA and offline](PWA-And-Offline) |
117
+ | `X_BUILD_SKEW` on an action | the input schema changed incompatibly since the client's build | the `fix:` line names the action; version the action instead of changing it in place |
118
+ | Users stuck on an old version | your app never renders the `AppUpdateAvailable` affordance | subscribe to the signal and show "Update available — reload". The framework never force-navigates |
119
+ | Need everyone off a build now | security patch | **You cannot — the framework force-reloads nothing, `As of 2026-08`.** The forced-reload half of `version-skew` was deleted in 9.0.0: nothing performed the reload it described, and no runtime could have called it (`http` is tier 2 and `sync` is tier 3, both below `pwa` at tier 4). What ships is *notification*: read `useConnection().updateAvailable` from `@ultimat3/realtime` and render your own affordance. A deploy has no channel to a running client either way |
120
+ | `X_SW_HAND_EDITED` | **reserved, never raised** — `x build` writes `sw.js`, `As of 2026-08`, but it carries no checksum, so an edit survives a build ([Error codes → Not thrown yet](Error-Codes#not-thrown-yet)) | change the **route**, which is the input the generator is designed around; the emitted file is overwritten on the next build either way |
121
+ | `X_SW_UNCACHEABLE` | **reserved, never raised** — `offline: 'precache'` on an `ssr` route is accepted | caching a per-request render is a correctness bug. Use `runtime` or `network-only`, and review the pairing yourself |
122
+ | Precache budget warning | `x build --target static --json` reports it under `serviceWorkerWarnings`, `As of 2026-08` — a manifest past 5 MB stalls the install on a bad connection. `PrecacheManifest.warnings` was computed and read by nothing until then ([#390](https://github.com/developerz-ai/ultimate/issues/390)) | drop routes from `offline: 'precache'`, or cut the island chunks the manifest carries — `x build --target static --json` lists both |
123
+ | Offline shows the browser dinosaur | `pwa.enabled` is false, or the page was never controlled — a worker that has activated is not yet the page's controller, and a first load is not controlled until it claims | check `navigator.serviceWorker.controller !== null` in the console; then → [PWA and offline](PWA-And-Offline) |
124
+ | Preview build poisoned a cache | impossible via the framework — build ID scopes the SW cache namespace and scope | confirm the branch build ID in `x manifest --json` |
125
+
126
+ ## Tests
127
+
128
+ | Symptom | Likely cause | Fix |
129
+ |---|---|---|
130
+ | `X_TEST_NETWORK_SEALED` | a test reached the network unmocked | the error names the URL. Mock it — sealed network is the design, not a bug |
131
+ | A test passes alone, fails in the suite | shared state that should not exist — each worker gets its own cloned DB | check for a module-level singleton or a fixture written outside `seed()` |
132
+ | Time-dependent failure | asserted on wall clock | use the frozen clock and `clock.advance('3d')` — it also drives `step.sleep` and cron |
133
+ | A test flakes | **fix it or delete it the same day** | there is no `retry: 3`. A test that passes twice and fails the third trains people to ignore red |
134
+ | Snapshot/UUID churn between runs | not using `seed(name)` | seeds are deterministic: same input → identical rows, identical UUIDs |
135
+ | Job test doesn't drain | queue not advanced | `await runJobs.drain()`; workers run deterministically in tests |
136
+ | Want the failing worker's database after the run | there is **no** `--keep-db` — `x test` declares `--workers`, `--isolate`, `--filter`, `--allow-empty`, `--sample`, `--seed` and the `--affected` trio, and nothing else, and the harness calls `drop()` at teardown ([`packages/testing/src/harness.ts:108`](https://github.com/developerz-ai/ultimate/blob/main/packages/testing/src/harness.ts)) | what survives is the migrated template, `ultimate_test_template` — the clones are `ultimate_test_template_w<N>`. Inspect the template: `psql "$TEST_DATABASE_URL" -c "\l"`, then connect to it. To hold a clone open, assert inside the test rather than after it |
137
+
138
+ ## MCP and AI
139
+
140
+ | Symptom | Likely cause | Fix |
141
+ |---|---|---|
142
+ | `X_MCP_TOOL_UNKNOWN`, or a tool absent from `tools/list` | the tool is hidden from this caller, or the name is stale — role-hidden and absent answer identically, on purpose | visibility is fail-closed: check the caller against the tool's `visibleTo` (a role allowlist or a predicate over the caller). Otherwise `tools/list` for the catalog this caller may use, and `x manifest` if the committed manifest is stale |
143
+ | `X_MCP_TOOL_UNDECLARED`, and MCP refuses to boot | an action or query written out in `defineAppMcp`'s `actions:`/`queries:` never declared `mcp: { expose: true }` — a boot-time configuration error, not a hidden tool | add `mcp: { expose: true, description: '<what it does>' }` beside the primitive's policy, or drop it from the list and let `include: 'exposed'` project what opted in |
144
+ | `X_MCP_SCOPE_UNKNOWN`, and MCP refuses to boot | `defineAppMcp`'s `scopes:` map names a tool by a name the server does not project — a typo, or the primitive was renamed or dropped from `actions:`/`queries:`/`tools:` | spell the name as one of the tools the server actually projects, or drop it from that `scopes` entry |
145
+ | `X_MCP_SCOPE_DENIED` | the connection's token does not carry the tool's scope — scope is a property of the token, not of the actor's permissions | reconnect with a token whose scopes include the one `cause` names — the app's `resolveToken(token)` returns them — or drop that scope from `defineAppMcp({ scopes })`. Scopes are fixed for the life of a connection, so a grant takes effect on the next one. `x token grant` is **planned** and exits `X_NOT_IMPLEMENTED` |
146
+ | `X_FORBIDDEN` from a `tools/call` | the tool was invoked and its policy refused this input — the same denial the HTTP route returns for the same call | grant the human the permission — an agent can never exceed the human it acts for |
147
+ | Dev MCP server not reachable | `x dev` not running, or you pointed at prod | default socket is `mcp.devSocket` (`ws://localhost:9229`). The dev server is **never** bound in `ROLE=web` |
148
+ | `X_MCP_QUERY_REJECTED` | `db.query` was not given exactly one read-only statement | send a single **read-only** `SELECT`/`WITH`/`EXPLAIN`/`SHOW`/`TABLE`/`VALUES` — a data-modifying CTE is not a read. MCP has no arbitrary-write path: change data by calling an action exposed with `mcp: { expose: true }`, change schema with `db.migrate` on a branch database |
149
+ | `X_MCP_NOT_BRANCH_DB` | `db.migrate` was aimed at a database that is not a branch | `x db branch create <name> # then retry db.migrate` |
150
+ | `X_LLM_OUTPUT_INVALID` | structured output failed its schema twice | tighten the prompt or loosen the schema; the retry already happened once |
151
+ | Prompt change had no effect | semantic cache hit | bump the prompt version — editing a prompt requires it. (`x ai cache --json` is **planned**; `x test eval --json` is the shipped command) |
152
+ | `x verify` fails on a prompt | no evals file | an unevaluated prompt is untested code. Add `<prompt>.evals.ts` |
153
+
154
+ ## Still stuck
155
+
156
+ ```
157
+ x verify --json > verify.json
158
+ x doctor --json > doctor.json
159
+ ```
160
+
161
+ Open an issue with both files attached, plus your Bun version, your `@ultimat3/*` pin, and the `x errors explain <CODE> --json` output for any code you hit. Security issues go through [`SECURITY.md`](https://github.com/developerz-ai/ultimate/blob/main/SECURITY.md), never a public issue.
162
+
163
+ Code index: [Error codes](Error-Codes). Config fields: [Configuration](Configuration). Upgrade failures: [Upgrading](Upgrading).