Found while implementing #11787 (PR for the JSON block in the same section). Out of that card's scope — #11787 measured the JSON report sketch and explicitly recorded that PluginHealthCheckParsed "was not audited against its schema". It has now been audited incidentally, and it diverges. Filed rather than fixed, because the right shape is a design question rather than a mechanical correction (see below).
What was measured
content/docs/protocol/kernel/lifecycle.mdx, ### Custom Health Checks, the TypeScript example immediately above the JSON block:
exportdefault{name: '@vendor/salesforce',healthChecks: {salesforce_connection: async({ context })=>{
...
return{status: 'healthy',latency_ms: response.duration,records_synced_last_hour: ... };},},};The real configuration type is PluginHealthCheckSchema (packages/spec/src/kernel/plugin-lifecycle-advanced.zod.ts:36-84):
interval: z.number().int().min(1000).default(30000),timeout: z.number().int().min(100).default(5000),failureThreshold: z.number().int().min(1).default(3),successThreshold: z.number().int().min(1).default(1),checkMethod: z.string().optional().describe('Method name to call for health check'),autoRestart: z.boolean().default(false),maxRestartAttempts: z.number().int().min(0).default(3),restartBackoff: z.enum(['fixed','linear','exponential']).default('exponential'),and its only consumer, packages/core/src/health-monitor.ts:109-122:
if(config.checkMethod&&typeof(pluginasany)[config.checkMethod]==='function'){constcheckResult=awaitthis.raceCheckTimeout((pluginasany)[config.checkMethod](),config.timeout, ...);if(checkResult===false||(checkResult&&checkResult.status==='unhealthy')){status='unhealthy'; ... checks.push({name: config.checkMethod,status: 'failed', message });}else{checks.push({name: config.checkMethod,status: 'passed'});}}| aspect | doc example | real config + consumer |
|---|
| declaration | healthChecks, a map of named async functions on the plugin default export | a single checkMethodstring naming a method on the plugin object |
| call signature | async ({ context }) => ... | plugin[checkMethod]() — called with no arguments; nothing supplies a context |
| named checks | one entry per key (salesforce_connection) | exactly one check per plugin, named after checkMethod (or 'plugin-loaded' when none is configured) |
| return value | { status: 'healthy', latency_ms, records_synced_last_hour } | only false and { status: 'unhealthy' } are read; 'healthy', latency_ms and every other key are ignored |
healthChecks as an author-writable field: 0 occurrences. The 5 hits in packages/ are PluginHealthMonitor's own private Map<string, PluginHealthCheckParsed> (health-monitor.ts:19,35,51,301) plus one example reading that private map (packages/core/examples/phase2-integration.ts:151) — none of them a declared plugin field. Positive control in the same sweep: checkMethod = 8 hits, spanning the schema field, the consumer, and two test files (plugin-lifecycle-advanced.test.ts:52, health-monitor.test.ts:108), so the zero is a reading rather than a dead probe.
Why this is filed and not fixed
The <Callout> above the section already says these checks are "not yet exposed as a dedicated HTTP endpoint or as a declarative plugin field" — so the example is flagged as aspirational, and a reader who reads the callout is not being told a lie about healthChecks existing.
That is also exactly why the correction is not mechanical. Two readings, and they teach opposite things:
- A — rewrite the example against
checkMethod. The page then shows a shape a plugin author can actually write today: a healthCheck() method on the plugin plus the PluginHealthCheckSchema config that names it. Costs the per-check naming the current example illustrates (the real model supports exactly one check per plugin). - B — keep
healthChecks as the declared intent and mark it explicitly unimplemented. Defensible if the map-of-named-checks shape is the direction the model is meant to grow toward — the callout's "not yet" reads that way. Then the fix is a sharper "not implemented" marker on the block, not a rewrite.
Answering that needs someone who knows whether healthChecks is planned or abandoned, which is above the pay grade of a docs-accuracy pass.
Not asserting more than was checked
Only the TypeScript example, PluginHealthCheckSchema and health-monitor.ts were compared. The JSON report block in the same section is #11787's subject and is being fixed there. No other page was examined, and raceCheckTimeout's behaviour was read only as far as "the check is invoked with no arguments".
Generated by Claude Code
Found while implementing #11787 (PR for the JSON block in the same section). Out of that card's scope — #11787 measured the JSON report sketch and explicitly recorded that
PluginHealthCheckParsed"was not audited against its schema". It has now been audited incidentally, and it diverges. Filed rather than fixed, because the right shape is a design question rather than a mechanical correction (see below).What was measured
content/docs/protocol/kernel/lifecycle.mdx,### Custom Health Checks, the TypeScript example immediately above the JSON block:The real configuration type is
PluginHealthCheckSchema(packages/spec/src/kernel/plugin-lifecycle-advanced.zod.ts:36-84):and its only consumer,
packages/core/src/health-monitor.ts:109-122:healthChecks, a map of named async functions on the plugin default exportcheckMethodstring naming a method on the plugin objectasync ({ context }) => ...plugin[checkMethod]()— called with no arguments; nothing supplies acontextsalesforce_connection)checkMethod(or'plugin-loaded'when none is configured){ status: 'healthy', latency_ms, records_synced_last_hour }falseand{ status: 'unhealthy' }are read;'healthy',latency_msand every other key are ignoredhealthChecksas an author-writable field: 0 occurrences. The 5 hits inpackages/arePluginHealthMonitor's own privateMap<string, PluginHealthCheckParsed>(health-monitor.ts:19,35,51,301) plus one example reading that private map (packages/core/examples/phase2-integration.ts:151) — none of them a declared plugin field. Positive control in the same sweep:checkMethod= 8 hits, spanning the schema field, the consumer, and two test files (plugin-lifecycle-advanced.test.ts:52,health-monitor.test.ts:108), so the zero is a reading rather than a dead probe.Why this is filed and not fixed
The
<Callout>above the section already says these checks are "not yet exposed as a dedicated HTTP endpoint or as a declarative plugin field" — so the example is flagged as aspirational, and a reader who reads the callout is not being told a lie abouthealthChecksexisting.That is also exactly why the correction is not mechanical. Two readings, and they teach opposite things:
checkMethod. The page then shows a shape a plugin author can actually write today: ahealthCheck()method on the plugin plus thePluginHealthCheckSchemaconfig that names it. Costs the per-check naming the current example illustrates (the real model supports exactly one check per plugin).healthChecksas the declared intent and mark it explicitly unimplemented. Defensible if the map-of-named-checks shape is the direction the model is meant to grow toward — the callout's "not yet" reads that way. Then the fix is a sharper "not implemented" marker on the block, not a rewrite.Answering that needs someone who knows whether
healthChecksis planned or abandoned, which is above the pay grade of a docs-accuracy pass.Not asserting more than was checked
Only the TypeScript example,
PluginHealthCheckSchemaandhealth-monitor.tswere compared. The JSON report block in the same section is #11787's subject and is being fixed there. No other page was examined, andraceCheckTimeout's behaviour was read only as far as "the check is invoked with no arguments".Generated by Claude Code