Found by QA run #10663 driving cli.hook-body-extraction-gates at framework 79ebb37. The security net is intact throughout — no forbidden body ever shipped as body.source, and every forbidden/free-identifier hook was still refused under --strict-body. Three defects in the reporting/reachability, not the enforcement:
1. // @capabilities override is unreachable through os build (product/docs gap)
A handler authored in objectstack.config.ts with a first line // @capabilities api.read api.write produces artifact capabilities []. The config loader (config.ts:loadConfig → bundle-require → esbuild transformSync{loader:'ts'}) strips // line comments before String(fn) runs, so the override at extract-hook-body.ts:118-131 — documented as working at hook-bodies.mdx:320-327 — never receives the comment. The pin lower-callables.test.ts masks it by feeding raw JS function literals that keep their comment, never exercising the esbuild load path. Fix: move the directive off a // comment (e.g. a real property), or state in docs that it is authorable only in pre-bundled JS; add an os build-level test.
2. require() FORBIDDEN pattern is effectively dead (assertion/coverage gap)
require('node:os') in a TS config is rewritten by esbuild's ESM shim to __require("node:os"), so FORBIDDEN_PATTERNS[/\brequire\s*\(/] (extract-hook-body.ts:35) never matches. The refusal still fires (exit 1) — via the #1876 free-identifier gate naming __require — so enforcement holds, but the require()-specific worded reason the acceptance promises is never emitted for the real authoring path.
3. Default os build silently warn-and-bundles forbidden patterns (header contradiction)
A default (non---strict-body) os build of a hook containing a forbidden pattern exits 0 with no output: lower-callables.ts:63-78 catches the extraction error and falls back to the .mjs bundle; the warning is recorded into bodyExtractionWarnings but compile.ts prints it nowhere and :437--json warnings carries rule advisories only. This contradicts the extractor header extract-hook-body.ts:14-18 ("makes the build fail … no silent fallback"). Docs hook-bodies.mdx:256 agree with the code, so the header is the outlier. Fix: surface the warning on the default path (at minimum in --json), or correct the header to describe warn-and-bundle.
Clauses that pass
Capability inference (.find→api.read, .update→api.write, const api=ctx.api alias caught), crypto.hash infers nothing (#4391 regression), free-identifier bundle fallback (#1876), all-body-only skip + .mjs cleanup.
QA-source: #10663 · cli.hook-body-extraction-gates · clauses 3, 0, 6
Found by QA run #10663 driving
cli.hook-body-extraction-gatesat framework79ebb37. The security net is intact throughout — no forbidden body ever shipped asbody.source, and every forbidden/free-identifier hook was still refused under--strict-body. Three defects in the reporting/reachability, not the enforcement:1.
// @capabilitiesoverride is unreachable throughos build(product/docs gap)A handler authored in
objectstack.config.tswith a first line// @capabilities api.read api.writeproduces artifact capabilities[]. The config loader (config.ts:loadConfig→bundle-require→ esbuildtransformSync{loader:'ts'}) strips//line comments beforeString(fn)runs, so the override atextract-hook-body.ts:118-131— documented as working athook-bodies.mdx:320-327— never receives the comment. The pinlower-callables.test.tsmasks it by feeding raw JS function literals that keep their comment, never exercising the esbuild load path. Fix: move the directive off a//comment (e.g. a real property), or state in docs that it is authorable only in pre-bundled JS; add anos build-level test.2.
require()FORBIDDEN pattern is effectively dead (assertion/coverage gap)require('node:os')in a TS config is rewritten by esbuild's ESM shim to__require("node:os"), soFORBIDDEN_PATTERNS[/\brequire\s*\(/](extract-hook-body.ts:35) never matches. The refusal still fires (exit 1) — via the #1876 free-identifier gate naming__require— so enforcement holds, but therequire()-specific worded reason the acceptance promises is never emitted for the real authoring path.3. Default
os buildsilently warn-and-bundles forbidden patterns (header contradiction)A default (non-
--strict-body)os buildof a hook containing a forbidden pattern exits 0 with no output:lower-callables.ts:63-78catches the extraction error and falls back to the.mjsbundle; the warning is recorded intobodyExtractionWarningsbutcompile.tsprints it nowhere and:437--json warningscarries rule advisories only. This contradicts the extractor headerextract-hook-body.ts:14-18("makes the build fail … no silent fallback"). Docshook-bodies.mdx:256agree with the code, so the header is the outlier. Fix: surface the warning on the default path (at minimum in--json), or correct the header to describe warn-and-bundle.Clauses that pass
Capability inference (
.find→api.read,.update→api.write,const api=ctx.apialias caught),crypto.hashinfers nothing (#4391 regression), free-identifier bundle fallback (#1876), all-body-only skip +.mjscleanup.QA-source: #10663 · cli.hook-body-extraction-gates · clauses 3, 0, 6