Uh oh!
There was an error while loading. Please reload this page.
fix(runtime): install ctx.log.debug in the sandbox — the fourth level the CLI and docs already promise - #7908
Conversation
`ctx.log.debug` was declared on three surfaces and implemented on none: the CLI capability extractor matched it and granted `log`, the docs table taught it, and the QuickJS install loop covered only `info`/`warn`/`error`. A body that followed the documentation therefore threw `TypeError: not a function` inside the VM — and under `onError: 'abort'` that aborted the write. Enforced rather than retired (ADR-0049). The `crypto.hash` precedent this shape echoes (#4391) was removed because implementing it widened the sandbox's security surface; emitting a debug-level diagnostic carries no such argument, and `Logger.debug(message, meta)` already existed on the contract. - `quickjs-runner.ts`: the install loop now covers four levels. - `script-runner.ts`: `ScriptContext['log']` declares `debug`. - `body-runner.ts`: the host-side log surface forwards `debug` to the factory's logger, and warns for it in the no-logger branch. Without this the new VM method would be a SILENT DROP rather than a throw, since `installCtx` forwards through the optional call `ctx.log?.[level]?.(…)`. Two existing test doubles built a three-member `ctx.log`; they now build four. Reverse-verified in both directions: with the install reverted the new pin fails with the card's own `TypeError: not a function`, and with only the host-side forward removed it fails on the delivery assertions while nothing throws — so the pin cannot be satisfied by a no-op `debug`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CUymLqPDq3d7PgiwpZsbA2
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 20 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also reference the affected code. These are read-only:
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#7661
ctx.log.debugwas declared on three surfaces and implemented on none. An author who followed the documentation wrote a body whose declared capability was satisfied and whose call then threwTypeError: not a functioninside the VM — underonError: 'abort', an aborted write rather than a missing log line.Direction is the enforce arm of ADR-0049, per the ruling on the card: all four surfaces now agree on four methods.
The premise, measured before any code was written
The ruling hangs on two halves, both verified on
origin/main@d91fad5:Logger.debug(message, meta)exists on the contractpackages/spec/src/contracts/logger.ts:15— declared, two-arg, alongsideinfo/warn/error/fatallogcapability is served from carries a callabledebugopts.logger(body-runner.tsbuildBodyLogSurface, #7448), which all fourapp-plugin.tsconstruction sites populate with the kernel'sctx.logger=createLogger()→ObjectLogger, whosedebug(packages/core/src/logger.ts:401) writes at leveldebugthrough the real sink. Not absent, not a throwing stub, not a no-op.body-runner.ts:164already callsopts.logger?.debug?.(…)on that same object — the[BodyRunner] hook firedline QA run #7439 observed at--log-level debug.And the gap itself is still live on current
main— this is not an already-fixed card:packages/cli/src/utils/extract-hook-body.ts:56—/ctx\.log\.(?:info|warn|error|debug)\b/→log,debugstill in the alternationcontent/docs/automation/hook-bodies.mdx:317— still teachesctx.log.info / warn / error / debugquickjs-runner.ts:639— still['info', 'warn', 'error']What changed
quickjs-runner.ts— thectx.loginstall loop covers four levels.script-runner.ts—ScriptContext['log']declaresdebug.body-runner.ts— the host-side surface forwardsdebugto the factory's logger, and warns for it in the no-logger branch. This file is load-bearing for the fix, not incidental:installCtxforwards through the optional callctx.log?.[level]?.(…), so a VM-sidedebugwith no host-side member is not a throw but a silent drop — the [finding] Hook body ctx.log output is unobservable — body-runner wires log: engineCtx?.logger with no fallback, so the declared ['log'] capability can silently produce nothing #7448 defect verbatim. (Noted for the file-surface declaration: the card namedquickjs-runner.ts+script-runner.ts;body-runner.tsis the third file in the sameruntime/src/sandbox/**directory the claim reserved, and the consequence cannot be delivered without it. Nothing outside that directory is touched.)Two pre-existing test doubles built a three-member
ctx.log; they now build four.packages/cli/src/utils/extract-hook-body.tsand the docs table are deliberately untouched — under the enforce arm both were already correct.Reverse-verification — measured in both directions
The pin must fail for a missing
debugand for a no-opdebug. Both arms were run.1. Install reverted (i.e. the pin against unmodified
main) — red, with the card's own error:2. VM install kept, host-side forward removed (the no-op arm) — still red, and nothing throws:
That is the point the card insisted on: a
debuginstalled as a no-op passes a throw-only test, so every assertion is on what the host logger received, not on the absence of an exception.3. After the fix — green:
Verification record
npx vitest run src/sandbox/body-log-capability.test.tsnpx vitest run src/sandbox/npx vitest run(whole@objectstack/runtime)pnpm --filter @objectstack/runtime... buildpnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*'pnpm check:changeset-gate-self-testsnode scripts/check-empty-changeset.mjsnode scripts/check-changeset-no-major.mjsmajorbumpnode scripts/check-nul-bytes.mjspnpm check:type-check-debtGate families derived with
node scripts/pm/dispatch-gates.mjs <changed paths>(→check:changeset-gate-self-tests), plus the convention-scoped gates and the affected package's suites.On the type-check ratchet. The first run reported
@objectstack/runtimeTEST_DEBT227 → 229 (+2). The two new errors were real and mine: makingdebugrequired onScriptContext['log']broke the two three-member test doubles (capability-denial-is-a-fault.test.ts:95,quickjs-runner.test.ts:114, bothTS2741: Property 'debug' is missing). They were fixed, not ledgered — the entry is back to exactly its frozen 227 and the ceiling was not raised.Generated by Claude Code