Declares the INPUT contracts of the host-driven lifecycle classes exported
by @objectstack/core — PluginHealthMonitor (reads PluginHealthCheck,
emits PluginHealthStatus / PluginHealthReport) and HotReloadManager
(reads HotReloadConfig, snapshots via PluginStateSnapshot). The kernel
does not construct either class: a HOST composes them and passes these
shapes directly (content/docs/protocol/kernel/lifecycle.mdx, the #11811
examples, is the supported usage).
This module deliberately declares NO authorable configuration surface — see
the #11825 retirement record below.
[REMOVED] HotReloadConfig.watchPatterns was removed in @objectstack/spec 17.3.0 (ADR-0049 enforce-or-remove) — nothing ever read it. Its only two uses were log lines in HotReloadManager, and one of them announced 'File watching started' at INFO level while no watcher was ever constructed: startWatching held a placeholder, and watchHandles was read, deleted, iterated and cleared but never set. So an author could declare a glob and no file change could ever trigger a reload. Delete the key. File watching is the HOST's job in this host-driven library: run your own watcher, declare your globs wherever that watcher reads them, and call HotReloadManager.scheduleReload(pluginName, reloadFn) when one matches — the debounced integration point this class does implement, and which is unchanged.
debounceDelayMs
integer
optional (default: 1000)
Wait time after change detection before reload, in milliseconds
debounceDelay
never
optional
[REMOVED] HotReloadConfig.debounceDelay was renamed to debounceDelayMs in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (milliseconds) lived in a source JSDoc only and the published describe named none, so the reference-page reader got a bare 1000. Rename the key to debounceDelayMs; the value (milliseconds) and the 1000 default are unchanged.
preserveState
boolean
optional (default: true)
Keep plugin state across reloads
stateStrategy
Enum<'memory' | 'none'>
optional (default: "memory")
How to preserve state during reload
shutdownTimeout
integer
optional (default: 30000)
Maximum time to wait for graceful shutdown, in milliseconds
How often to perform health checks, in milliseconds
timeoutMs
integer
optional (default: 5000)
Maximum time to wait for health check response, in milliseconds
failureThreshold
integer
optional (default: 3)
Consecutive failures needed to mark unhealthy
successThreshold
integer
optional (default: 1)
Consecutive successes needed to mark healthy
checkMethod
string
optional
Method name to call for health check
autoRestart
never
optional
[REMOVED] PluginHealthCheck.autoRestart was removed in @objectstack/spec 17.3.0 (ADR-0049 enforce-or-remove) — it never restarted a plugin.A PluginHealthMonitor never restarted anything. attemptRestart called plugin.destroy() and stopped there — the in-source comment said "Call destroy and init to restart", but init appeared in health-monitor.ts ONLY inside that comment. What a plugin actually got was: destroy, a log line reading 'Plugin restarted', status recovering, and periodic health checks continuing against the destroyed instance — which the default check ({ name: 'plugin-loaded', status: 'passed' }, used whenever no checkMethod resolves) passes forever, so the terminal report on a destroyed, never-re-initialised plugin was healthy. Delete the key. Restarting a plugin is the HOST's job in this host-driven library, and the monitor could not do it even in principle: Plugin.init(ctx) needs a PluginContext, which only the kernel constructs and which it exposes to nobody (ObjectKernel.context is private; KernelBase.createContext is protected). Poll getHealthStatus(pluginName) / getHealthReport(pluginName) and act on unhealthy / failed at the level that owns the plugin's lifetime — recreate the kernel, or let your supervisor restart the process. The monitor reports; it does not act.
maxRestartAttempts
never
optional
[REMOVED] PluginHealthCheck.maxRestartAttempts was removed in @objectstack/spec 17.3.0 (ADR-0049 enforce-or-remove) — it capped a restart that never happened.A PluginHealthMonitor never restarted anything. attemptRestart called plugin.destroy() and stopped there — the in-source comment said "Call destroy and init to restart", but init appeared in health-monitor.ts ONLY inside that comment. What a plugin actually got was: destroy, a log line reading 'Plugin restarted', status recovering, and periodic health checks continuing against the destroyed instance — which the default check ({ name: 'plugin-loaded', status: 'passed' }, used whenever no checkMethod resolves) passes forever, so the terminal report on a destroyed, never-re-initialised plugin was healthy. The cap counted destroy calls, so raising it only scheduled further "restarts" of a plugin that was never brought back up. Delete the key. Restarting a plugin is the HOST's job in this host-driven library, and the monitor could not do it even in principle: Plugin.init(ctx) needs a PluginContext, which only the kernel constructs and which it exposes to nobody (ObjectKernel.context is private; KernelBase.createContext is protected). Poll getHealthStatus(pluginName) / getHealthReport(pluginName) and act on unhealthy / failed at the level that owns the plugin's lifetime — recreate the kernel, or let your supervisor restart the process. The monitor reports; it does not act.
restartBackoff
never
optional
[REMOVED] PluginHealthCheck.restartBackoff was removed in @objectstack/spec 17.3.0 (ADR-0049 enforce-or-remove) — it delayed a restart that never happened.A PluginHealthMonitor never restarted anything. attemptRestart called plugin.destroy() and stopped there — the in-source comment said "Call destroy and init to restart", but init appeared in health-monitor.ts ONLY inside that comment. What a plugin actually got was: destroy, a log line reading 'Plugin restarted', status recovering, and periodic health checks continuing against the destroyed instance — which the default check ({ name: 'plugin-loaded', status: 'passed' }, used whenever no checkMethod resolves) passes forever, so the terminal report on a destroyed, never-re-initialised plugin was healthy. The chosen strategy only moved when the destroy landed. Delete the key. Restarting a plugin is the HOST's job in this host-driven library, and the monitor could not do it even in principle: Plugin.init(ctx) needs a PluginContext, which only the kernel constructs and which it exposes to nobody (ObjectKernel.context is private; KernelBase.createContext is protected). Poll getHealthStatus(pluginName) / getHealthReport(pluginName) and act on unhealthy / failed at the level that owns the plugin's lifetime — recreate the kernel, or let your supervisor restart the process. The monitor reports; it does not act.
interval
never
optional
[REMOVED] PluginHealthCheck.interval was renamed to intervalMs in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (milliseconds) lived in a source JSDoc only, and the published describe named no unit: its one unit-shaped token was the parenthetical "(default: 30s)", which names SECONDS for a value carried in milliseconds. Rename the key to intervalMs; the value (milliseconds) and the 30000 default are unchanged.
timeout
never
optional
[REMOVED] PluginHealthCheck.timeout was renamed to timeoutMs in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (milliseconds) lived in a source JSDoc only and the published describe named none, so the reference-page reader got a bare 5000. Rename the key to timeoutMs; the value (milliseconds) and the 5000 default are unchanged.
[REMOVED] PluginHealthReport.metrics.uptime was renamed to uptimeMs in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose, and this platform already spells a SECONDS-valued uptime with the same bare name on GET /health. Rename the key to uptimeMs; the value (milliseconds, Date.now() - startTime) is unchanged.
responseTime
never
optional
[REMOVED] PluginHealthReport.metrics.responseTime was renamed to responseTimeMs in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to responseTimeMs; the value (milliseconds) is unchanged.