@ultimat3/cli 9.0.0 → 10.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 (53) hide show
  1. package/package.json +26 -26
  2. package/src/affected.ts +0 -3
  3. package/src/app-boundaries.ts +4 -5
  4. package/src/app-env.ts +7 -2
  5. package/src/browser-launcher.ts +0 -2
  6. package/src/budgets.ts +4 -3
  7. package/src/cmd-build.ts +2 -2
  8. package/src/cmd-db-branch.ts +2 -2
  9. package/src/cmd-deploy.ts +14 -3
  10. package/src/cmd-docs.ts +2 -1
  11. package/src/cmd-doctor.ts +3 -5
  12. package/src/cmd-env.ts +2 -2
  13. package/src/cmd-fix.ts +2 -4
  14. package/src/cmd-new.ts +2 -2
  15. package/src/cmd-shot.ts +22 -2
  16. package/src/db-finding.ts +2 -2
  17. package/src/db-seed.ts +0 -3
  18. package/src/dev-cache.ts +12 -5
  19. package/src/dev-lock.ts +8 -7
  20. package/src/dev-runtime.ts +11 -3
  21. package/src/dev-storage.ts +8 -2
  22. package/src/dev-sync.ts +37 -2
  23. package/src/document-styles.ts +2 -1
  24. package/src/drift.ts +3 -2
  25. package/src/error-codes.ts +9 -2
  26. package/src/error-contract.ts +5 -5
  27. package/src/errors.ts +1 -29
  28. package/src/flag-reads.ts +2 -2
  29. package/src/generate-write.ts +3 -2
  30. package/src/guards.ts +4 -4
  31. package/src/index.ts +2 -6
  32. package/src/island-bundle.ts +32 -4
  33. package/src/island-routes.ts +7 -1
  34. package/src/mcp-errors.ts +2 -2
  35. package/src/metrics-endpoint.ts +0 -2
  36. package/src/output.ts +2 -2
  37. package/src/prerender.ts +32 -19
  38. package/src/static-report.ts +41 -3
  39. package/src/templates/scaffold-container.ts +12 -0
  40. package/src/templates/scaffold-docs.ts +1 -1
  41. package/src/templates/scaffold-domain-package.ts +3 -1
  42. package/src/templates/scaffold-repo.ts +16 -8
  43. package/src/templates/slice-foundation.ts +3 -5
  44. package/src/test-shards.ts +2 -2
  45. package/src/tsconfig-references.ts +2 -2
  46. package/src/verify-checks.ts +3 -2
  47. package/src/verify-floor.ts +8 -6
  48. package/src/verify-run.ts +2 -2
  49. package/src/verify-step.ts +2 -1
  50. package/src/verify-test-run.ts +2 -2
  51. package/src/workspace-checks.ts +10 -12
  52. package/src/workspace-graph.ts +3 -2
  53. package/src/write-line.ts +7 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/cli",
3
- "version": "9.0.0",
3
+ "version": "10.0.0",
4
4
  "description": "The `x` binary: new, dev, build, verify, generate, db, mcp, doctor, deploy",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,31 +37,31 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@babel/core": "^7.28.4",
40
- "@ultimat3/action": "9.0.0",
41
- "@ultimat3/admin": "9.0.0",
42
- "@ultimat3/ai": "9.0.0",
43
- "@ultimat3/auth": "9.0.0",
44
- "@ultimat3/cache": "9.0.0",
45
- "@ultimat3/core": "9.0.0",
46
- "@ultimat3/db": "9.0.0",
47
- "@ultimat3/entity": "9.0.0",
48
- "@ultimat3/http": "9.0.0",
49
- "@ultimat3/i18n": "9.0.0",
50
- "@ultimat3/jobs": "9.0.0",
51
- "@ultimat3/mail": "9.0.0",
52
- "@ultimat3/manifest": "9.0.0",
53
- "@ultimat3/mcp": "9.0.0",
54
- "@ultimat3/policy": "9.0.0",
55
- "@ultimat3/pwa": "9.0.0",
56
- "@ultimat3/query": "9.0.0",
57
- "@ultimat3/realtime": "9.0.0",
58
- "@ultimat3/render": "9.0.0",
59
- "@ultimat3/schema": "9.0.0",
60
- "@ultimat3/scraping": "9.0.0",
61
- "@ultimat3/seo": "9.0.0",
62
- "@ultimat3/storage": "9.0.0",
63
- "@ultimat3/testing": "9.0.0",
64
- "@ultimat3/time": "9.0.0",
40
+ "@ultimat3/action": "10.0.0",
41
+ "@ultimat3/admin": "10.0.0",
42
+ "@ultimat3/ai": "10.0.0",
43
+ "@ultimat3/auth": "10.0.0",
44
+ "@ultimat3/cache": "10.0.0",
45
+ "@ultimat3/core": "10.0.0",
46
+ "@ultimat3/db": "10.0.0",
47
+ "@ultimat3/entity": "10.0.0",
48
+ "@ultimat3/http": "10.0.0",
49
+ "@ultimat3/i18n": "10.0.0",
50
+ "@ultimat3/jobs": "10.0.0",
51
+ "@ultimat3/mail": "10.0.0",
52
+ "@ultimat3/manifest": "10.0.0",
53
+ "@ultimat3/mcp": "10.0.0",
54
+ "@ultimat3/policy": "10.0.0",
55
+ "@ultimat3/pwa": "10.0.0",
56
+ "@ultimat3/query": "10.0.0",
57
+ "@ultimat3/realtime": "10.0.0",
58
+ "@ultimat3/render": "10.0.0",
59
+ "@ultimat3/schema": "10.0.0",
60
+ "@ultimat3/scraping": "10.0.0",
61
+ "@ultimat3/seo": "10.0.0",
62
+ "@ultimat3/storage": "10.0.0",
63
+ "@ultimat3/testing": "10.0.0",
64
+ "@ultimat3/time": "10.0.0",
65
65
  "babel-preset-solid": "^1.9.15"
66
66
  }
67
67
  }
package/src/affected.ts CHANGED
@@ -13,7 +13,6 @@
13
13
  // directory is checkout-relative while a caller's scan yields paths relative to its own root.
14
14
  import { join, relative } from 'node:path';
15
15
  import { singleLine, UltimateError } from '@ultimat3/core';
16
- import { docsFor } from './error-codes';
17
16
  import { BadFlagError } from './errors';
18
17
  import type { ExecResult, Runner } from './exec';
19
18
  import { execOutput } from './exec';
@@ -193,7 +192,6 @@ export async function gitRoot(runner: Runner, cwd: string, command: string): Pro
193
192
  code: 'X_CLI_UNEXPECTED',
194
193
  cause: `x ${command} reads its diff from git and "git rev-parse --show-toplevel" exited ${result.code} in ${cwd}: ${singleLine(execOutput(result))}`,
195
194
  fix: `run x ${command} from inside a git checkout — confirm with: git rev-parse --show-toplevel`,
196
- docs: docsFor('X_CLI_UNEXPECTED'),
197
195
  });
198
196
  }
199
197
 
@@ -245,7 +243,6 @@ export async function changedFiles(
245
243
  code: 'X_CLI_UNEXPECTED',
246
244
  cause: `"${failed.command.join(' ')}" exited ${failed.code} in ${options.cwd}: ${singleLine(execOutput(failed))}`,
247
245
  fix: `run it yourself to see why: ${failed.command.join(' ')}`,
248
- docs: docsFor('X_CLI_UNEXPECTED'),
249
246
  });
250
247
  }
251
248
  return [...new Set(runs.flatMap((run) => paths(run.stdout)))].sort();
@@ -14,6 +14,7 @@
14
14
  import { join as joinPath } from 'node:path';
15
15
  // The POSIX variants resolve specifiers against import-graph keys, which are POSIX on every host.
16
16
  import { dirname, join, normalize, relative } from 'node:path/posix';
17
+ import { ERROR_DOCS_URL } from '@ultimat3/core';
17
18
  import type { BoundaryRule, ImportGraph } from '@ultimat3/render';
18
19
  import { checkSurfaceBoundary, importGraph, SURFACES } from '@ultimat3/render';
19
20
  import type { Finding } from './output';
@@ -48,8 +49,6 @@ const CODE_OF: Readonly<Record<BoundaryRule, BoundaryCode>> = {
48
49
  */
49
50
  export const boundaryCodeOf = (rule: BoundaryRule): BoundaryCode => CODE_OF[rule];
50
51
 
51
- const docs = (code: BoundaryCode): string => `https://ultimate.dev/errors/${code}`;
52
-
53
52
  const isRoute = (path: string): boolean => /\/(page|layout|route)\.[cm]?tsx?$/.test(path);
54
53
  const isService = (path: string): boolean => /\/service\.[cm]?ts$/.test(path);
55
54
  const isDbSpecifier = (specifier: string): boolean =>
@@ -128,7 +127,7 @@ const surfaceFindings = (graph: ImportGraph): readonly Finding[] =>
128
127
  code,
129
128
  cause: violation.cause,
130
129
  fix: violation.fix,
131
- docs: docs(code),
130
+ docs: ERROR_DOCS_URL,
132
131
  at: violation.importer,
133
132
  };
134
133
  });
@@ -198,7 +197,7 @@ function layerFindings(scanned: readonly ScannedFile[]): readonly Finding[] {
198
197
  code: 'X_BOUNDARY_ROUTE_TO_DB',
199
198
  cause: `route imports the database ("${specifier}") — routes call actions and queries`,
200
199
  fix: generate('query', file.path, 'then call it from'),
201
- docs: docs('X_BOUNDARY_ROUTE_TO_DB'),
200
+ docs: ERROR_DOCS_URL,
202
201
  at: file.path,
203
202
  });
204
203
  }
@@ -207,7 +206,7 @@ function layerFindings(scanned: readonly ScannedFile[]): readonly Finding[] {
207
206
  code: 'X_BOUNDARY_SERVICE_TO_HTTP',
208
207
  cause: `service imports HTTP ("${specifier}") — a service that knows about requests cannot be reused by a job`,
209
208
  fix: generate('action', file.path, 'read the request there and pass plain values to'),
210
- docs: docs('X_BOUNDARY_SERVICE_TO_HTTP'),
209
+ docs: ERROR_DOCS_URL,
211
210
  at: file.path,
212
211
  });
213
212
  }
package/src/app-env.ts CHANGED
@@ -7,7 +7,12 @@
7
7
  import { existsSync } from 'node:fs';
8
8
  import { join } from 'node:path';
9
9
  import type { EnvSchema, EnvVarDecl } from '@ultimat3/core';
10
- import { checkEnvExample, ENV_EXAMPLE_PATH, renderEnvExample } from '@ultimat3/core';
10
+ import {
11
+ checkEnvExample,
12
+ ENV_EXAMPLE_PATH,
13
+ ERROR_DOCS_URL,
14
+ renderEnvExample,
15
+ } from '@ultimat3/core';
11
16
  import { APP_CONFIG_FILE } from './app-root';
12
17
  import type { Finding } from './output';
13
18
  import { findingFrom } from './output';
@@ -63,7 +68,7 @@ const driftFinding = (cause: string): Finding => ({
63
68
  // The generator, not the assertion: `assertEnvExample`'s own fix is a `Bun.write(…)` call for
64
69
  // an app that has a schema object in scope, and a gate reader has a shell.
65
70
  fix: 'x env example',
66
- docs: 'https://ultimate.dev/errors/X_ENV_EXAMPLE_DRIFT',
71
+ docs: ERROR_DOCS_URL,
67
72
  at: ENV_EXAMPLE_PATH,
68
73
  });
69
74
 
@@ -7,7 +7,6 @@ import { existsSync } from 'node:fs';
7
7
  import { UltimateError } from '@ultimat3/core';
8
8
  import type { CdpLauncherLike, ScrapeDriver } from '@ultimat3/scraping';
9
9
  import { localBrowser } from '@ultimat3/scraping';
10
- import { docsFor } from './error-codes';
11
10
 
12
11
  /**
13
12
  * The one library this works against. Playwright is not an alternative and is not a flag:
@@ -33,7 +32,6 @@ export class ShotBrowserMissingError extends UltimateError {
33
32
  // one literal, and a fix line the gate cannot read is a fix line nothing holds to the
34
33
  // contract. `browser-launcher.test.ts` pins it against the constant instead.
35
34
  fix: 'bun add -d puppeteer-core',
36
- docs: docsFor('X_SHOT_BROWSER_MISSING'),
37
35
  meta: { root: input.root, package: BROWSER_PACKAGE },
38
36
  });
39
37
  }
package/src/budgets.ts CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  import { existsSync } from 'node:fs';
10
10
  import { join } from 'node:path';
11
+ import { ERROR_DOCS_URL } from '@ultimat3/core';
11
12
  import type { Manifest, RouteFact } from '@ultimat3/manifest';
12
13
  import { formatBytes, parseByteBudget } from '@ultimat3/render';
13
14
  import type { Finding } from './output';
@@ -75,7 +76,7 @@ function unmeasuredFinding(url: string, declared: string, built: boolean): Findi
75
76
  fix: built
76
77
  ? `x build --target static --json # its "unmeasured" list says why ${url} could not be weighed`
77
78
  : 'x build --target static --json && x verify --json',
78
- docs: 'https://ultimate.dev/errors/X_BUDGET_UNMEASURED',
79
+ docs: ERROR_DOCS_URL,
79
80
  at: url,
80
81
  };
81
82
  }
@@ -106,7 +107,7 @@ export function checkBudgets(
106
107
  code: 'X_BUDGET_EXCEEDED',
107
108
  cause: `${route.url} ships ${formatBytes(measured.jsBytes)} of JS over a ${formatBytes(js)} budget via ${chainOf(measured)}`,
108
109
  fix: `x routes --json to see the chain, then move the heavy import behind hydrate: 'interaction'`,
109
- docs: 'https://ultimate.dev/errors/X_BUDGET_EXCEEDED',
110
+ docs: ERROR_DOCS_URL,
110
111
  at: route.url,
111
112
  });
112
113
  }
@@ -115,7 +116,7 @@ export function checkBudgets(
115
116
  code: 'X_BUDGET_EXCEEDED',
116
117
  cause: `${route.url} LCP ${measured.lcpMs}ms over the ${lcp}ms budget`,
117
118
  fix: `raise the budget in defineRoute, or switch render to 'isr' to serve it prebuilt`,
118
- docs: 'https://ultimate.dev/errors/X_BUDGET_EXCEEDED',
119
+ docs: ERROR_DOCS_URL,
119
120
  at: route.url,
120
121
  });
121
122
  }
package/src/cmd-build.ts CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { existsSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
- import { frameworkVersion, VERSION_DEFINE } from '@ultimat3/core';
6
+ import { ERROR_DOCS_URL, frameworkVersion, VERSION_DEFINE } from '@ultimat3/core';
7
7
  import { requireAppRoot } from './app-root';
8
8
  import { runVerify } from './cmd-verify';
9
9
  import type { CliCommand, CommandContext } from './command';
@@ -143,7 +143,7 @@ export function buildResult(input: {
143
143
  code: 'X_BUILD_FAILED',
144
144
  cause: `${input.command.join(' ')} exited ${result.code}`,
145
145
  fix: target === 'docker' ? 'x doctor --json && docker info' : 'x verify --json',
146
- docs: 'https://ultimate.dev/errors/X_BUILD_FAILED',
146
+ docs: ERROR_DOCS_URL,
147
147
  },
148
148
  ],
149
149
  data: {
@@ -3,7 +3,7 @@
3
3
  // `x db branch ls` used to clone a database called `ls`, because the argument was the name.
4
4
  // The facts (what a branch is, per mode) are `db-branch.ts`; the client lifetime is here.
5
5
 
6
- import { nearestName } from '@ultimat3/core';
6
+ import { ERROR_DOCS_URL, nearestName } from '@ultimat3/core';
7
7
  import { createPostgresClient, type DbClient } from '@ultimat3/db';
8
8
  import type { CommandContext } from './command';
9
9
  import type { BranchRow } from './db-branch';
@@ -215,6 +215,6 @@ function notABranch(services: DevServices, name: string): CommandResult {
215
215
  code: 'X_DB_BRANCH_FAILED',
216
216
  cause: `"${name}" is not a branch of this database, so nothing was dropped (it would be ${target})`,
217
217
  fix: LIST_FIX,
218
- docs: 'https://ultimate.dev/errors/X_DB_BRANCH_FAILED',
218
+ docs: ERROR_DOCS_URL,
219
219
  });
220
220
  }
package/src/cmd-deploy.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  // anything that runs containers can execute.
4
4
 
5
5
  import { join } from 'node:path';
6
+ import { ERROR_DOCS_URL } from '@ultimat3/core';
6
7
  import { requireAppRoot } from './app-root';
7
8
  import type { CliCommand, CommandContext } from './command';
8
9
  import { BadFlagError, UnknownCommandError } from './errors';
@@ -31,6 +32,13 @@ import { quoteArg } from './shell-quote';
31
32
  * honours. Both compose definitions carry it — `docker/docker-compose.prod.yml`'s `backfill` and
32
33
  * the one `templates/scaffold-container.ts` scaffolds, which also gates on `migrate` completing.
33
34
  * This paragraph said they "still owe" both for as long as they have had them.
35
+ *
36
+ * COMPOSE-ONLY, and `backfill` is why that has to be written down. `docker/helm`'s `roles:` map is
37
+ * `web|sync|worker|scheduler|replicator` plus a `migrate` Job — there is no `backfill` object in
38
+ * the chart at all — and the helm plan is one `helm upgrade --install`, so this list describes
39
+ * neither the objects a chart deploy creates nor the steps it runs. Every reader of it is therefore
40
+ * inside the compose branch; the SUMMARY reads `plan.steps` instead, or `x deploy --method helm`
41
+ * reports a post-deploy sweep to an operator that nothing will ever run.
34
42
  */
35
43
  export const DEPLOY_ROLES = ['migrate', 'web', 'sync', 'worker', 'scheduler', 'backfill'] as const;
36
44
 
@@ -202,11 +210,14 @@ export const deployCommand: CliCommand = {
202
210
  env: { ...plan.env },
203
211
  steps: plan.steps.map((step) => ({ role: step.role, command: step.command.join(' ') })),
204
212
  };
213
+ // The roles THIS plan has, never the compose list: on `--method helm` there is one step,
214
+ // `all`, and naming `backfill` there promises an operator a sweep the chart cannot run.
215
+ const roles = plan.steps.map((step) => step.role).join(',');
205
216
  if (flagBool(ctx.args, 'dry-run')) {
206
217
  return {
207
218
  ok: true,
208
219
  command: 'deploy',
209
- summary: msg('cli.deploy.plan', { images: 1, roles: DEPLOY_ROLES.join(',') }),
220
+ summary: msg('cli.deploy.plan', { images: 1, roles }),
210
221
  data: planJson,
211
222
  lines: plan.steps.map(
212
223
  (step) => ` ${step.role.padEnd(10)} ${stepLine(plan.env, step.command)}`,
@@ -225,7 +236,7 @@ export const deployCommand: CliCommand = {
225
236
  code: 'X_DEPLOY_FAILED',
226
237
  cause: `role "${step.role}" step exited ${result.code}`,
227
238
  fix: `${stepLine(plan.env, step.command)} # run it directly to see the full output`,
228
- docs: 'https://ultimate.dev/errors/X_DEPLOY_FAILED',
239
+ docs: ERROR_DOCS_URL,
229
240
  },
230
241
  ],
231
242
  data: planJson,
@@ -235,7 +246,7 @@ export const deployCommand: CliCommand = {
235
246
  return {
236
247
  ok: true,
237
248
  command: 'deploy',
238
- summary: msg('cli.deploy.plan', { images: 1, roles: DEPLOY_ROLES.join(',') }),
249
+ summary: msg('cli.deploy.plan', { images: 1, roles }),
239
250
  data: planJson,
240
251
  };
241
252
  },
package/src/cmd-docs.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  // should not have to guess which of 29 packages holds the answer, and it must never be handed a
5
5
  // URL: `node_modules` already contains every doc, because the published artifact IS the source.
6
6
 
7
+ import { ERROR_DOCS_URL } from '@ultimat3/core';
7
8
  import type { DocEntry, DocHit } from '@ultimat3/manifest';
8
9
  import { nearestTopics, scanInstalledDocs, searchDocs } from '@ultimat3/manifest';
9
10
  import type { CliCommand, CommandContext } from './command';
@@ -22,7 +23,7 @@ const unresolvedFinding = (): Finding => ({
22
23
  code: 'X_CLI_UNEXPECTED',
23
24
  cause: '@ultimat3/core does not resolve from the installed CLI, so no docs could be read',
24
25
  fix: 'bun install && x doctor --json',
25
- docs: 'https://ultimate.dev/errors/X_CLI_UNEXPECTED',
26
+ docs: ERROR_DOCS_URL,
26
27
  at: import.meta.dir,
27
28
  });
28
29
 
package/src/cmd-doctor.ts CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { existsSync } from 'node:fs';
6
6
  import { join } from 'node:path';
7
- import { tryResolveEnvironment, usesDevCursorSecret } from '@ultimat3/core';
7
+ import { ERROR_DOCS_URL, tryResolveEnvironment, usesDevCursorSecret } from '@ultimat3/core';
8
8
  import { STORAGE_SIGNING_SECRET_KEY, usesDevStorageSecret } from '@ultimat3/storage';
9
9
  import { findAppRoot, REQUIRED_BUN, versionAtLeast } from './app-root';
10
10
  import type { CliCommand, CommandContext } from './command';
@@ -49,12 +49,10 @@ export interface DoctorProbe {
49
49
  snapshots(): Promise<readonly Finding[]>;
50
50
  }
51
51
 
52
- const docs = (code: string): string => `https://ultimate.dev/errors/${code}`;
53
-
54
52
  const finding = (code: string, cause: string, fix: string, at?: string): Finding =>
55
53
  at === undefined
56
- ? { code, cause, fix, docs: docs(code) }
57
- : { code, cause, fix, docs: docs(code), at };
54
+ ? { code, cause, fix, docs: ERROR_DOCS_URL }
55
+ : { code, cause, fix, docs: ERROR_DOCS_URL, at };
58
56
 
59
57
  export const OFFLINE_FALLBACK = 'apps/web/app/offline.tsx';
60
58
 
package/src/cmd-env.ts CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  // Bun ships no path-join primitive, and `.env.example` is written app-root-relative.
6
6
  import { join } from 'node:path';
7
- import { checkEnv, ENV_EXAMPLE_PATH, maskedEnvValues } from '@ultimat3/core';
7
+ import { checkEnv, ENV_EXAMPLE_PATH, ERROR_DOCS_URL, maskedEnvValues } from '@ultimat3/core';
8
8
  import { ENV_SCHEMA_EXPORT, envExampleFor, loadEnvSchema } from './app-env';
9
9
  import { APP_CONFIG_FILE, requireAppRoot } from './app-root';
10
10
  import type { CliCommand, CommandContext } from './command';
@@ -54,7 +54,7 @@ async function checkProcessEnv(ctx: CommandContext): Promise<CommandResult> {
54
54
  code: 'X_ENV_MISSING',
55
55
  cause: `${issue.key} is ${issue.reason} (expected ${issue.expected})`,
56
56
  fix: issue.fix,
57
- docs: 'https://ultimate.dev/errors/X_ENV_MISSING',
57
+ docs: ERROR_DOCS_URL,
58
58
  at: ENV_EXAMPLE_PATH,
59
59
  }));
60
60
  return {
package/src/cmd-fix.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // (`docs/architecture/02-boundaries.md`) — a caller runs the printed edit, or the generated
4
4
  // `git mv`, itself.
5
5
 
6
- import { nearestName } from '@ultimat3/core';
6
+ import { ERROR_DOCS_URL, nearestName } from '@ultimat3/core';
7
7
  import { appImportGraph, readAppSources } from './app-boundaries';
8
8
  import { requireAppRoot } from './app-root';
9
9
  import type { BoundaryCut } from './boundary-cuts';
@@ -18,8 +18,6 @@ export { planBoundaryCuts };
18
18
 
19
19
  export const FIX_SUBCOMMANDS = ['boundary'] as const;
20
20
 
21
- const docsUrl = (code: string): string => `https://ultimate.dev/errors/${code}`;
22
-
23
21
  /**
24
22
  * Accept either an app-root-relative path or a suffix that matches exactly one scanned file —
25
23
  * an agent copying the path out of a `fix:` line has the short form
@@ -81,7 +79,7 @@ const findingForCut = (cut: BoundaryCut): Finding => ({
81
79
  code: cut.code,
82
80
  cause: cut.cause,
83
81
  fix: cut.edit,
84
- docs: docsUrl(cut.code),
82
+ docs: ERROR_DOCS_URL,
85
83
  at: cut.at,
86
84
  });
87
85
 
package/src/cmd-new.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  import { existsSync } from 'node:fs';
6
6
  import { chmod } from 'node:fs/promises';
7
7
  import { isAbsolute, join, resolve } from 'node:path';
8
- import { renderThrowable } from '@ultimat3/core';
8
+ import { ERROR_DOCS_URL, renderThrowable } from '@ultimat3/core';
9
9
  import { dedupe } from './cmd-generate';
10
10
  import type { CliCommand, CommandContext } from './command';
11
11
  import { MissingPositionalError } from './errors';
@@ -195,7 +195,7 @@ export const newCommand: CliCommand = {
195
195
  code: 'X_GENERATE_CONFLICT',
196
196
  cause: `${target} already exists`,
197
197
  fix: `x new ${app.kebab} --force, or choose another name`,
198
- docs: 'https://ultimate.dev/errors/X_GENERATE_CONFLICT',
198
+ docs: ERROR_DOCS_URL,
199
199
  at: target,
200
200
  },
201
201
  ],
package/src/cmd-shot.ts CHANGED
@@ -164,6 +164,17 @@ const intFlag = (
164
164
  fallback,
165
165
  );
166
166
 
167
+ /**
168
+ * How `devServerFor` starts a scratch server. A parameter with a default rather than a direct
169
+ * call, for the reason every `Runner` in this package is one: the failure path below — a boot that
170
+ * throws, and the lock it has to hand back — is otherwise only reachable by breaking a real app.
171
+ */
172
+ export type BootDevServer = (input: {
173
+ readonly root: string;
174
+ readonly port: number;
175
+ readonly env: Readonly<Record<string, string | undefined>>;
176
+ }) => Promise<{ readonly url: string; stop(): Promise<void> }>;
177
+
167
178
  export interface ShotServer {
168
179
  readonly url: string;
169
180
  /** Which server the picture is of. Reported, because the two have different failure modes. */
@@ -272,6 +283,7 @@ export async function devServerFor(
272
283
  root: string,
273
284
  env: Readonly<Record<string, string | undefined>>,
274
285
  port: number,
286
+ boot: BootDevServer = (input) => startDev(input),
275
287
  ): Promise<ShotServer> {
276
288
  const services = resolveServices(root, env);
277
289
  const file = Bun.file(lockPath(services.stateDir));
@@ -281,13 +293,21 @@ export async function devServerFor(
281
293
  return { url: lock.url, origin: 'reused', stop: () => Promise.resolve() };
282
294
  }
283
295
  }
284
- await preflight({
296
+ const { release } = await preflight({
285
297
  stateDir: services.stateDir,
286
298
  port,
287
299
  hostname: DEV_BINDING.hostname,
288
300
  embeddedDb: services.db.mode === 'embedded',
289
301
  });
290
- const dev = await startDev({ root, port, env });
302
+ // The directory is CLAIMED from here down — `preflight` returns holding it, never having merely
303
+ // looked — so a boot that throws has to give it back. `cmd-dev.ts` states the same rule at the
304
+ // same seam. Without it one failed `x shot` refused every later `x dev` and `x shot` on this
305
+ // checkout, naming a pid that had already exited. The original error is re-thrown untouched: a
306
+ // teardown must never replace the failure it is cleaning up after.
307
+ const dev = await boot({ root, port, env }).catch((error: unknown) => {
308
+ release();
309
+ throw error;
310
+ });
291
311
  await writeLock(services.stateDir, {
292
312
  pid: process.pid,
293
313
  port,
package/src/db-finding.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // step that failed. Its own module because `cmd-db.ts` and `cmd-db-branch.ts` both need it and
4
4
  // neither may import the other.
5
5
 
6
- import { renderThrowable } from '@ultimat3/core';
6
+ import { ERROR_DOCS_URL, renderThrowable } from '@ultimat3/core';
7
7
  import type { Finding } from './output';
8
8
  import { findingFrom, isUltimateErrorShape } from './output';
9
9
 
@@ -24,5 +24,5 @@ export const stepFinding = (error: unknown, code: string): Finding =>
24
24
  // a TypeError raised while reporting it.
25
25
  cause: renderThrowable(error),
26
26
  fix: 'x doctor --json',
27
- docs: `https://ultimate.dev/errors/${code}`,
27
+ docs: ERROR_DOCS_URL,
28
28
  };
package/src/db-seed.ts CHANGED
@@ -12,7 +12,6 @@ import type { Environment } from '@ultimat3/core';
12
12
  import { UltimateError } from '@ultimat3/core';
13
13
  import type { Driver, Seed, SeedTier } from '@ultimat3/entity';
14
14
  import { isSeed, SEED_TIERS, seedTiersFor } from '@ultimat3/entity';
15
- import { docsFor } from './error-codes';
16
15
  import { BadFlagError } from './errors';
17
16
  import type { Finding, JsonValue } from './output';
18
17
  import { findingFrom } from './output';
@@ -49,7 +48,6 @@ export class SeedUnknownError extends UltimateError {
49
48
  // A dry run, never a bare `x db seed`: the command that answers "which seeds are there" must
50
49
  // not be the command that writes them.
51
50
  fix: 'x db seed --dry-run --json',
52
- docs: docsFor('X_DECLARATION_UNKNOWN'),
53
51
  });
54
52
  }
55
53
  }
@@ -75,7 +73,6 @@ export class SeedEnvironmentError extends UltimateError {
75
73
  code: 'X_SEED_ENVIRONMENT',
76
74
  cause: `seed "${input.seed}" is tier ${input.tier} and ULTIMATE_ENV resolved ${input.environment}, where x db seed runs ${input.tiers.join(', ')} — ULTIMATE_SEED_TIER=${input.tier} says this deploy takes it anyway`,
77
75
  fix: `x db seed ${input.seed} --tier ${input.tier} --json`,
78
- docs: docsFor('X_SEED_ENVIRONMENT'),
79
76
  });
80
77
  }
81
78
  }
package/src/dev-cache.ts CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  resetTiers,
21
21
  } from '@ultimat3/cache';
22
22
  import type { CacheTierName } from '@ultimat3/core';
23
- import { CACHE_TIERS, defineConfig, logger } from '@ultimat3/core';
23
+ import { CACHE_TIERS, defineConfig, logger, renderThrowable } from '@ultimat3/core';
24
24
  import type { Transport, TransportSubscription } from '@ultimat3/realtime/server';
25
25
  import { APP_CONFIG_EXPORT } from './app-auth';
26
26
  import { APP_CONFIG_FILE } from './app-root';
@@ -187,7 +187,7 @@ export function startCacheTiers(options: CacheTiersOptions): () => Promise<void>
187
187
  void applyBroadcast(payload);
188
188
  })
189
189
  .catch((error: unknown) => {
190
- logger.warn('cache.broadcast.subscribe-failed', { error: messageOf(error) });
190
+ logger.warn('cache.broadcast.subscribe-failed', { error: broadcastErrorText(error) });
191
191
  return undefined;
192
192
  });
193
193
 
@@ -199,8 +199,15 @@ export function startCacheTiers(options: CacheTiersOptions): () => Promise<void>
199
199
  };
200
200
  }
201
201
 
202
- const messageOf = (error: unknown): string =>
203
- error instanceof Error ? error.message : 'unknown error';
202
+ /**
203
+ * `renderThrowable`, never `instanceof Error` + `.message`. Both run on a value this process did
204
+ * not build — a `Proxy` traps `getPrototypeOf` and a `message` getter can raise — and a throw here
205
+ * is inside the handler whose whole job is to keep the subscriber loop alive: losing it ends
206
+ * cross-instance cache invalidation for the process, quietly, which is the failure the loop's own
207
+ * `try` exists to prevent. The old form also answered `'unknown error'` for every non-`Error`
208
+ * throw, so a driver rejecting with a string reported nothing at all.
209
+ */
210
+ export const broadcastErrorText = (error: unknown): string => renderThrowable(error);
204
211
 
205
212
  /**
206
213
  * A peer's wire tags, applied here. Never throws: a malformed frame or an undeclared tag must not
@@ -214,6 +221,6 @@ async function applyBroadcast(payload: string): Promise<void> {
214
221
  const wire = parsed.filter((value): value is string => typeof value === 'string');
215
222
  if (wire.length > 0) await receiveInvalidationBroadcast(wire);
216
223
  } catch (error) {
217
- logger.warn('cache.broadcast.apply-failed', { error: messageOf(error) });
224
+ logger.warn('cache.broadcast.apply-failed', { error: broadcastErrorText(error) });
218
225
  }
219
226
  }
package/src/dev-lock.ts CHANGED
@@ -16,8 +16,7 @@
16
16
 
17
17
  import { closeSync, mkdirSync, openSync, unlinkSync, writeFileSync } from 'node:fs';
18
18
  import { join } from 'node:path';
19
- import { UltimateError } from '@ultimat3/core';
20
- import { docsFor } from './error-codes';
19
+ import { stringField, UltimateError } from '@ultimat3/core';
21
20
  import { exec, type Runner } from './exec';
22
21
  import { quoteArg } from './shell-quote';
23
22
 
@@ -68,7 +67,11 @@ export const isProcessAlive = (pid: number): boolean => {
68
67
  return true;
69
68
  } catch (error) {
70
69
  // EPERM means it exists and belongs to another user. Alive, and not ours to signal.
71
- return (error as { code?: string }).code === 'EPERM';
70
+ // `stringField`, never a cast plus a property read: the rule `metrics-endpoint.ts` states and
71
+ // `caught-value-reads.test.ts` enforces — a getter that throws would take this path down one
72
+ // line before the guard meant to make it safe, and this guard decides whether a second `x dev`
73
+ // is allowed to open a single-writer data directory.
74
+ return stringField(error, 'code') === 'EPERM';
72
75
  }
73
76
  };
74
77
 
@@ -96,7 +99,6 @@ export class DevAlreadyRunningError extends UltimateError {
96
99
  code: 'X_DEV_ALREADY_RUNNING',
97
100
  cause: `pid ${input.lock.pid} is already running x dev on ${input.lock.url} and holds ${input.stateDir}${single}`,
98
101
  fix: `use the one already running at ${input.lock.url}, or stop it: kill ${input.lock.pid}`,
99
- docs: docsFor('X_DEV_ALREADY_RUNNING'),
100
102
  meta: { pid: input.lock.pid, port: input.lock.port, stateDir: input.stateDir },
101
103
  });
102
104
  }
@@ -118,7 +120,6 @@ export class DevLockUnreadableError extends UltimateError {
118
120
  code: 'X_DEV_LOCK_UNREADABLE',
119
121
  cause: `${input.path} could not be parsed as a dev lock and could not be removed, so x dev cannot tell whether another process owns ${input.stateDir}`,
120
122
  fix: `rm ${quoteArg(input.path)} # then re-run x dev`,
121
- docs: docsFor('X_DEV_LOCK_UNREADABLE'),
122
123
  meta: { path: input.path, stateDir: input.stateDir },
123
124
  });
124
125
  }
@@ -198,7 +199,6 @@ export class DevPortInUseError extends UltimateError {
198
199
  holder.pid === undefined
199
200
  ? `x dev --port ${input.suggestion}`
200
201
  : `x dev --port ${input.suggestion} # or free it, if that pid is yours: kill ${holder.pid}`,
201
- docs: docsFor('X_PORT_IN_USE'),
202
202
  meta: { port: input.port, ...holder },
203
203
  });
204
204
  }
@@ -247,7 +247,8 @@ function claimExclusive(path: string, lock: DevLock): boolean {
247
247
  try {
248
248
  fd = openSync(path, 'wx');
249
249
  } catch (error) {
250
- if ((error as { code?: string }).code === 'EEXIST') return false;
250
+ // Same rule as `isProcessAlive` above: read the field, never cast and dereference.
251
+ if (stringField(error, 'code') === 'EEXIST') return false;
251
252
  throw error;
252
253
  }
253
254
  try {
@@ -186,8 +186,14 @@ export function startStorage(services: DevServices, env: Env, override?: Storage
186
186
  // missing" from a helper the operator never configured. Not an outright ban on the local disk in
187
187
  // production: a single-node Compose deploy on a mounted volume WITH a real secret is a rung on
188
188
  // the scale ladder, and refusing it would be a deploy-shape decision, not a security fix.
189
- if (!isLocal() && usesDevStorageSecret()) {
190
- throw new LocalDiskUnsafeError({ environment: resolveEnvironment(), root });
189
+ // `{ env }` on ALL THREE, never the ambient `process.env`: this function is HANDED the boot's
190
+ // environment and reads `S3_BUCKET` off it one branch above, so a guard asking a second source
191
+ // could answer `development` for a process booting as `production` — or, with
192
+ // `usesDevStorageSecret({ env })` left bare, refuse a boot whose own env carries a real
193
+ // `STORAGE_SIGNING_SECRET` because the PROCESS does not. Which environment, whether a secret
194
+ // exists, and the name the message prints are one question about one table.
195
+ if (!isLocal({ env }) && usesDevStorageSecret({ env })) {
196
+ throw new LocalDiskUnsafeError({ environment: resolveEnvironment({ env }), root });
191
197
  }
192
198
  try {
193
199
  mkdirSync(root, { recursive: true });
@@ -198,7 +204,9 @@ export function startStorage(services: DevServices, env: Env, override?: Storage
198
204
  `mount a writable volume at ${root}, or set S3_ENDPOINT and S3_BUCKET to use object storage instead`,
199
205
  );
200
206
  }
201
- return defineStorage({ disks: { local: localDriver({ root }) }, default: 'local' });
207
+ // The guard three lines up reads `env`; so must the disk it guards. Otherwise the boot's
208
+ // environment decides whether signing is allowed and the process's decides what key is used.
209
+ return defineStorage({ disks: { local: localDriver({ root, env }) }, default: 'local' });
202
210
  }
203
211
 
204
212
  /**
@@ -151,8 +151,14 @@ export function parseByteRange(
151
151
  if (from === '' && to === '') return undefined;
152
152
  if (from === '') {
153
153
  const wanted = Number(to);
154
- // A suffix longer than the object is the whole object, not a refusal.
155
- return wanted === 0 ? UNSATISFIABLE : { start: Math.max(size - wanted, 0), end: size - 1 };
154
+ // A suffix longer than the object is the whole object, not a refusal — but there is no whole
155
+ // object to fall back to at `size === 0`, and the arithmetic below answers `{ start: 0, end:
156
+ // -1 }`, which the route renders as `content-range: bytes 0--1/0` with status 206. RFC 9110
157
+ // requires 416. The non-suffix branch already gets this right through `start >= size`; this
158
+ // one had no equivalent test.
159
+ return size === 0 || wanted === 0
160
+ ? UNSATISFIABLE
161
+ : { start: Math.max(size - wanted, 0), end: size - 1 };
156
162
  }
157
163
  const start = Number(from);
158
164
  const end = to === '' ? size - 1 : Math.min(Number(to), size - 1);