@teamscala/service-boot 0.23.459 → 0.23.460

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "name": "@teamscala/service-boot",
8
8
  "type": "module",
9
- "version": "0.23.459",
9
+ "version": "0.23.460",
10
10
  "sideEffects": false,
11
11
  "imports": {
12
12
  "#service-boot/*": "./src/*",
@@ -281,13 +281,16 @@ export async function buildMinimalApp(
281
281
  }
282
282
 
283
283
  const { components, loaded, skipped } = discovered;
284
- if (loaded.length === 0) {
285
- throw new BootFatalError(
286
- "ui-service.page-manifest",
287
- serviceSlug,
288
- "Zero Puck components loaded from src/page-manifest.ts. Fix service_install.block_packages or block_schema, regenerate the page manifest, then boot again.",
289
- );
290
- }
284
+ // REPORT THE DISCOVERY BEFORE JUDGING IT. This used to throw BootFatalError
285
+ // on `loaded.length === 0` ABOVE these two log lines, so the one boot that
286
+ // most needed the diagnosis was the only boot that printed none of it: the
287
+ // operator saw "Zero Puck components loaded" and nothing about WHICH rows
288
+ // were considered or WHY each was rejected. Measured 2026-09-03: 91 active
289
+ // block_schema rows, zero loaded, zero skip lines — and the absence of skip
290
+ // lines was itself unreadable, because "no candidate survived the install
291
+ // pre-filter" and "every candidate failed to import" are indistinguishable
292
+ // when neither prints. Hours went into re-deriving from outside the process
293
+ // what these lines already knew.
291
294
  if (loaded.length > 0) {
292
295
  log.info(
293
296
  `[two-phase-boot:${serviceSlug}] Discovered ${loaded.length} block(s): ${loaded.join(", ")}`,
@@ -299,6 +302,23 @@ export async function buildMinimalApp(
299
302
  `(missing componentPath/componentExport or import failed): ${skipped.join(", ")}`,
300
303
  );
301
304
  }
305
+ // SOFT-CRASH, NEVER HARD-CRASH (operator ruling 2026-09-03: "it's meant to
306
+ // soft crash with errors, so why the fuck is it hard crashing"). A service
307
+ // that refuses to start serves NOTHING — no page, no health endpoint, no
308
+ // error page — so a block-discovery problem presents to a client as a 502
309
+ // from a dead port, which is strictly less information than a served page
310
+ // with its blocks missing. The degraded state is loud (ERROR, both counts,
311
+ // every skip reason) and inspectable over HTTP, which is what makes it
312
+ // fixable; refusing the boot only hid the cause. `no-uncontrolled-repetition-
313
+ // or-cascade` is unaffected — nothing restarts, the process stays up.
314
+ if (loaded.length === 0) {
315
+ log.error(
316
+ `[two-phase-boot:${serviceSlug}] DEGRADED: zero Puck components loaded ` +
317
+ `from ${skipped.length} considered block_schema row(s). Pages will render ` +
318
+ `without blocks until this is fixed. Check service_install.block_packages, ` +
319
+ `the block_schema rows, and the skip reasons logged above.`,
320
+ );
321
+ }
302
322
 
303
323
  // Run boot hooks BEFORE serving - some hooks may register routes and must
304
324
  // run before Hono's matcher is compiled by the first request