Skip to content

os dev and os serve swallow every plugin boot-phase log line — WARN-level boot diagnostics are invisible on both CLI entrypoints #4012

Description

@os-zhuang

Found while verifying ADR-0110 D5's boot inventory (#4011). The inventory turned out to have its own placement bug (fixed there), but proving that exposed a bigger, older one: no plugin's boot-phase logger output reaches the console on either CLI entrypoint, at any log level.

Evidence

All on main (d6bfb3d), examples/app-todo, injected with a deliberately undeclared handler so a boot WARN is guaranteed to be emitted (verified below):

Run Lines Plugin boot WARNs bootstrap / kernel:ready traces
os dev (default level) 31 0 0
os dev --log-level debug 2,360 0 0
os serve objectstack.config.ts 19 0 0
Programmatic kernel.bootstrap() with a plain logger ✅ present ✅ present

The debug run is the damning one: it happily streams thousands of data-phase kernel lines ("event":"beforeFind" × 2,524, "event":"afterUpdate" × 2,472 …) yet contains zero boot-phase lines — not Triggering kernel:ready hook (kernel.ts:363, a plain logger.debug), not ✅ Bootstrap complete, not one plugin logger.warn. So the logger sink is live and verbose — but only from some point after boot. Everything a plugin says during init/start/kernel:ready goes nowhere.

The two lines that DO appear in the default output (⚠ Console dist not found…, ⚠ Flows: 4 flow(s) declared but…) are the CLI's own hand-rendered summary, not kernel logger output — which is presumably why the gap has been invisible: the summary looks like boot diagnostics exist.

Why this is a real defect and not cosmetics

What "fixed" looks like

Boot-phase logger.warn/logger.error from plugins reach the console on os dev and os serve at the default level, same as data-phase lines already do. Two plausible shapes:

  1. attach the console sink to the kernel logger before kernel.bootstrap() instead of after; or
  2. buffer boot-phase records and flush them right after the CLI banner/summary.

(1) is presumably how it was always meant to work. A regression test can reuse #4011's positive-control recipe: boot an example with an injected undeclared handler through the CLI path and assert [action-governance] appears on stdout — that single assertion covers the whole class, because it fails whenever boot-phase WARNs are swallowed.

Relationship to v17

Not release-blocking on its own — nothing that previously surfaced regresses. But it hollows out two documented v17 stories (the D5 checklist; ADR-0032's warn-by-default) until fixed, so it is worth triaging right behind the release.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions