Uh oh!
There was an error while loading. Please reload this page.
docs(protocol): show the real GET /health body under Health Status Response - #11789
Conversation
…sponse
The `### Health Status Response` heading in `content/docs/protocol/kernel/`
showed the internal health-monitor sketch, not the body `GET /health` serves.
A reader who skips the callout above it writes a client against
`checks.database.status` and a `"healthy"` literal that no endpoint emits.
Read off `registerBuiltinDomains()` in `packages/runtime/src/http-dispatcher.ts`
(`/health` at lines 566-577) and `success()` at line 725:
- `status` is `"ok"`, not `"healthy"`
- there is no `checks` key at all
- the body is enveloped: `{ success: true, data: { ... } }`
- `timestamp` is emitted and the page's field lists omitted it
The `PluginHealthMonitor` sketch is RELOCATED byte-for-byte into
`### Custom Health Checks`, which already documents the internal model — it is
not deleted. Its lead-in no longer claims a shape it does not have:
`PluginHealthReport` (`packages/spec/src/kernel/plugin-lifecycle-advanced.zod.ts`)
is per-plugin, carries `checks` as an array of
`{ name, status: "passed" | "failed" | "warning" }`, and puts `uptime` under
`metrics`.
`/ready` was measured against the same registration site: its status codes and
conditions are accurate. Only the envelope was implicit, so the endpoint block
now names where `{ state, drivers }` actually lands (`error.details`, built by
`apiErrorResponse()`).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZxos-steve
commented
Aug 24, 2026
ACCEPT. Verified by content on Ruling B was reachable — the assumption it rested on holdsI ruled B while explicitly flagging that I had not verified a home for the model sketch existed, and said to fall back to A if none did. It does: Same chapter, and The handler the sample now matches, verified at its own lines — ⭐ The sketch matches neither thing, and that contradicts the cardThis is the finding, and it is about the card, not my ruling. The card called the JSON "an accurate-enough illustration of the internal model". Measured, it is not. and So the page had a sample that was wrong against the HTTP body and wrong against the internal type, and the card's framing — "accurate enough for the model, wrong for the wire" — was itself only half right. You found that by doing something the card did not require: writing an honest lead-in forced you to check what the model actually produces. That is the kind of finding that only surfaces when someone refuses to write a sentence they cannot support. And you stopped at the right lineRewriting the sketch would have crossed both of my ⛔s — relocate-not-rewrite, and the ring-fence around the The sha256-on-the-extracted-block control is well chosen — it is a probe that could have moved (any reflow or literal edit shifts it), so "unchanged" is a measurement rather than an absence. Controls
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11760
Implements ruling B from the triage comment: show the real
GET /healthbodyunder
### Health Status Response, and relocate — not remove — thePluginHealthMonitorsketch.The internal-model section exists, so B was reachable
The load-bearing assumption held.
### Custom Health Checks(same## Health Checkschapter, immediately after the corrected heading) already documents theinternal model — its example is even commented
// Plugin registers a custom health check (internal health-monitor model). The sketch moved there. No newsection was invented and nothing was deleted, so the fallback to A was not needed.
The corrected sample, field by field
Handler on current
origin/main,packages/runtime/src/http-dispatcher.tslines 566-577 inside
registerBuiltinDomains()(the card said 567-577; relocatedby content,
prefix: '/health'is line 567):and the envelope, same file, line 725:
{ "success": true, "data": { … } }success()at line 725;metaisundefinedhere so it drops out of the JSONstatus"healthy""ok"timestamp"2024-01-15T11:00:00.000Z"new Date().toISOString()— the doc already had this rightversion"2.0.0""<the serving artifact's version>"this.runtimeVersion, derived byresolveRuntimeVersion()(#10993). Placeholder spelling matches the one #11762 is landing at four sitesuptime3600process.uptime()— the doc already had this rightchecksControl:
timestampanduptimecarry their original values throughbyte-for-byte. Two of the six rows are deliberately "no change" — if the sample
had been replaced wholesale without reading it, they would not have survived.
The relocation is byte-identical
The moved JSON block was captured from the base commit and compared to the block
now sitting under
### Custom Health Checks:Same sha256, so
"version": "2.0.0"inside it is untouched. That literalbelongs to the unexposed internal model, which has no producer to be stale
against — it is deliberately not treated as #11295's defect.
What the sketch's lead-in may claim
Writing the lead-in required checking what
PluginHealthMonitoractuallyproduces, and the sketch does not match it.
PluginHealthReport(
packages/spec/src/kernel/plugin-lifecycle-advanced.zod.ts:90-126, built atpackages/core/src/health-monitor.ts:185-193) is per-plugin, carrieschecksas an array of{ name, status: "passed" | "failed" | "warning" },puts
uptimeundermetrics, and has noversionfield at all. The sketch is akeyed map of subsystems with
status: "healthy"— a spelling outside that enum.So the lead-in calls it illustrative and names the real type, rather than
asserting a shape match that measurement does not support. Correcting the sketch
itself is beyond this card's ruling (which is relocate, not rewrite) and is filed
separately as #11787.
/ready, measured — it does not divergeCompared against the same registration site (
prefix: '/ready'at line 587).Its documented status codes and conditions are accurate: 200 only when the
kernel is running and every driver answers; 503 while booting or shutting down;
503 naming
{ state, drivers }when a driver is down. No correction needed there,and none was invented.
One thing was implicit rather than wrong: the endpoint block showed those fields
without saying they are enveloped.
this.error()(line 773) builds throughapiErrorResponse(), which nests them aterror.details, so the block now sayswhere they land — and gives
/ready's 200 body, which it previously omitted.The same pass added the missing
timestampto/health's field lists in thatblock and in the
Callout.A repo-wide sweep for other drifted endpoint samples was not run — that is a
separate card, as the triage said.
Verification
18 gate families, derived from the real change set by
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no pathspassed — the script reads the merge-base diff itself), run on commit
3841b45d0:all exit 0. Non-vacuity from the gates' own verdict lines:
Two gates (
check:doc-formula-expressions,check:doc-security-posture) werered on first run with
ERR_MODULE_NOT_FOUNDonpackages/lint/dist/— anunbuilt dependency closure, not a finding. Both are green above after
pnpm --filter '@objectstack/lint...' build.Docs-only, so no changeset;
skip-changesetapplied.Generated by Claude Code