Skip to content

feat(spec)!: RuntimeConfig resourceLimits.timeout carries its unit in the key name (#17781) - #17983

Merged
zhuangjianguo merged 4 commits into
mainfrom
claude/issue-17781-plugin-security-timeout-unit
Sep 13, 2026
Merged

feat(spec)!: RuntimeConfig resourceLimits.timeout carries its unit in the key name (#17781)#17983
zhuangjianguo merged 4 commits into
mainfrom
claude/issue-17781-plugin-security-timeout-unit

Conversation

@claude

@claude claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #17781

Clause-②: yes

Executes director-seat ruling A on #15939 (2026-09-11, maintainer 「同意」, decision batch #115) — the per-file remediation of the #14478 duration-unit rule. This card owns exactly one row, in packages/spec/src/kernel/plugin-security-advanced.zod.ts. The gate PR (#17635) is sequenced to land LAST and is untouched here.

⚠️ The declaration reads yes, not the no ruling A wrote, and the changeset is minor, not patch: both were corrected by the epic PM before dispatch and recorded publicly on #17784 (5652094166) and #15939 (5652120294) — a rename puts a spelling on a published payload no author could write before, which references/contract-review.md's mechanical floor reads as a mandatory affirmative, and the #15678 / #15679 shape ruling A names shipped as feat(spec)! at minor in every one of its four landed siblings. needs:contract-review is hung on the card and on this PR; check-changeset-no-major reads that label as a clause-② affirmative carrier that overrides the body line, so the body line above reads the affirmative too.

What changed

RuntimeConfig.resourceLimits.timeout is the key the whole of #15939 was filed about, and the one #15678 deliberately left alone. It named its unit in a source JSDoc — "Execution timeout in milliseconds" — and nowhere else. The .describe() that content/docs/references/kernel/plugin-security-advanced.mdx renders read "Maximum execution time" and named no unit at all, so the reader of the published reference page could not tell 60000 milliseconds from 60000 seconds. check:duration-unit-keys reads .describe() and .meta({ description }), not JSDoc, so it listed the key in its census without judging it — neither an offender nor an exemption. That gap is #15939, and this is its remediation.

before after
authored key resourceLimits.timeout: 60000 resourceLimits.timeoutMs: 60000
published describe Maximum execution time Maximum execution time in milliseconds
value + bound milliseconds, int().min(0) unchanged

The spelling is Ms, derived from how the suffixed family already spells itself on this tree rather than from the dispatch order: 29 key-position timeoutMs declarations across packages/spec/src/**/*.zod.ts, 40 distinct *Ms keys, and zero timeoutMillis / timeout_ms / timeoutMS variants anywhere in packages/spec/src. SandboxConfig.process.timeoutMs, renamed by #15678 on this same file, already carries the token.

The kit, following the #15678 / #15679 shape the ruling names:

  • a retiredKey() tombstone on the old spelling — tsc types it never and a value reaching the parse raises the rename prescription instead of being silently stripped (the nested resourceLimits object is not .strict())
  • ADR-0087 D3 semantic entry kernel-runtime-config-timeout-unit-in-key and the RETIRED_KEYS_BY_MAJOR[18] row kernel/RuntimeConfig:resourceLimits.timeout, both as migrations/entries/ files with registry.ts regenerated by gen:migration-registry (never hand-merged)
  • no D2 conversion: a RuntimeConfig is the engine block of the SandboxConfig a host or a plugin security manifest constructs, stack.zod.ts declares no sandbox, security-policy or runtime-config collection, and it is not a stored sys_metadata row — so the chain has no seam that runs on it. That is the reading [#14478 stack 3/6] kernel/: the 14 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers (runtime-emitted measurements included) #15678 recorded for the four keys it renamed.
  • content/docs/references/kernel/plugin-security-advanced.mdx regenerated by gen:docs — three rows move and the tombstone prescription renders in place of the old describe
  • a minor changeset carrying the FROM to TO mapping and the adr-0087: registered disposition

One implementation detail worth a reviewer's eye: the tombstone string const is declared above RuntimeConfigSchema, not with the other four RETIRED consts below it. gen:schema and check:authorable-surface both run with OS_EAGER_SCHEMAS=1, which makes lazySchema evaluate its factory at module load — a const declared after the schema would be read from its temporal dead zone. The four existing consts are each already declared before the block that reads them; this one had to move to keep that true.

The pin test this card was warned about — replaced, not silenced

plugin-security-advanced.test.ts carried a NEGATIVE control asserting this exact key stays bare, with a comment stating why it exists: "Without this test, a later sweep reads the four renames above as 'every timeout on this file'." This card is that later sweep, so the guard succeeded by failing.

before after
what it pinned RuntimeConfigSchema.parse({ resourceLimits: { timeout: 60000 } }) succeeds and returns 60000 the bare spelling is REFUSED with the rename prescription; timeoutMs parses at the same magnitude beside its siblings; the describe publishes the unit; the two same-named timeout retirements on this file name their own shapes apart
its comment "leaves it bare — its describe names no unit … the JSDoc-channel gap is #15939" records what the slot used to pin, why the control was written, and that #15939 IS the sweep it was written for
where it lives inside describe('Plugin security durations carry their unit (#15678)') its own top-level describe, so #15678's block header — "FOUR durations … all four old spellings are retiredKey() tombstones" — stays exactly true about #15678

⛔ It was not deleted, not weakened, not .skipped, and not "fixed green" by loosening an assertion. The refusal assertions pin the ADR-0112-shaped facts a tombstone owes — the issue is not unrecognized_keys, and the message carries the FROM to TO mapping — never a bare toThrow().

#15678's semantic entry was NOT amended. Its "One key deliberately left alone: RuntimeConfig.resourceLimits.timeout … it is outside this rename" is a scoped, past-tense statement about what #15678 did, it stays true, and it is published through the upgrade guide. Instead, this card's own semantic entry opens by stating that it completes what #15678 deliberately left alone, citing #15678 and #15939, so the two read as a sequence rather than a contradiction.

Verification

Heavy runs through scripts/pm/os-verify-lock.sh (slot issue-17781), verdicts read from its own VERDICT command-exit line; every gate's exit code captured before any pipe (cmd > log 2>&1; ex=$?).

  • pnpm --filter '@objectstack/spec^...' buildempty closure (No projects matched): packages/spec has no workspace dependencies, so step ① is a documented no-op
  • pnpm --filter @objectstack/spec buildVERDICT command-exit 0, re-run after the last source edit and after the main merge
  • pnpm --filter @objectstack/spec test and pnpm --filter @objectstack/spec typecheck — see the round report for the counts
  • pnpm --filter @objectstack/spec check:generatedall 15 generated artifacts up to date after gen:migration-registry + gen:docs, re-run clean after the main merge. check:authorable-surface is green without regeneration and that is correct: the ratchet records top-level keys per def, and kernel/RuntimeConfig: carries exactly engine, engineConfig and resourceLimits — this key is nested one level below, so no row moves.
  • check:duration-unit-keys (the gate as it stands on main, not feat(spec): refuse a duration key whose JSDoc names a unit its describe does not #17635's) — exit 0
  • main merged with bash scripts/pm/os-regen-merge.sh, never by hand; the registry was regenerated, and the sibling entries were asserted present by exact-name grep afterwards with a dark control at 0

Reverse verification of the new pin

The refusal assertions were proven able to fail, from the committed state: the tombstone line was deleted, the deletion proven on disk (anchor grep -o | wc -l 1 → 0, blob hash 160ab18650abe71c), and the suite re-run — 2 tests red, exactly the refusal pair, with the acceptance and describe tests still green because the ablation removed only the tombstone. Restored with git checkout HEAD -- PATH under an EXIT INT TERM trap and proven byte-identical (git hash-object back to 160ab186, git diff HEAD empty, git status --porcelain empty); the suite re-run green. No ablation artefact is left in the tree. There is no dist leg: the test imports the schema by relative path from src, so the built package is not on the resolution path for this ablation.

The cross-repo reading, with a lit control

git grep of the pinned objectui checkout at .objectui-sha = 53ded82bf7a494f54e344e19099dbf00854b8694 (re-read from this tree; the commit is reachable in the local clone, 6409 tracked files):

term occurrences
resourceLimits.timeout 0
resourceLimits 2
RuntimeConfig 236 (lit control)
timeout 832 (lit control)
sandbox 106 (lit control)
a fabricated token 0 (dark control)

Both resourceLimits hits are prose in packages/app-shell recording that objectui's own AppShellRuntimeConfig "share not one key" with the spec's RuntimeConfig, and both name only the top-level keys — they stay accurate after a rename one level below. ⇒ nothing in the pinned sibling authors this key, no objectui-side fix and no pin bump are owed (AGENTS.md Post-Task Checklist step 4).

Acceptance notes

⛔ Draft on purpose: the in-seat clause-② contract review at CONTRACT_REVIEW_TIER that this PR declares is owed before it may turn ready or enqueue. That is the PM's step, not this round's.

Round report, with every reading above and its exit code: the os-dev-report comment on #17781.

Authored in Claude Code session session_015c5G6TmpMKgnusmTpD7Ntt (mode:cloud), dispatched by the epic PM for #15939.


Generated by Claude Code

… the key name

Rename `RuntimeConfig.resourceLimits.timeout` to `timeoutMs` on
`kernel/plugin-security-advanced.zod.ts`, the fifth duration on this file and
the one #15678 deliberately left alone because its unit lived in a source
JSDoc that `check:duration-unit-keys` does not read.

- `retiredKey()` tombstone on the old spelling (the nested `resourceLimits`
  object is not strict, so a bare deletion would silently strip the key)
- ADR-0087 D3 semantic entry `kernel-runtime-config-timeout-unit-in-key` and
  the `RETIRED_KEYS_BY_MAJOR[18]` row, registry regenerated by
  `gen:migration-registry`
- the pin test that asserted the key stays bare is replaced, not removed
- reference page regenerated by `gen:docs`
- `minor` changeset with the FROM to TO mapping and the ADR-0087 disposition

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Sep 13, 2026
@github-actions

github-actions Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

4 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/migrations/entries/retired-keys/18.kernel__RuntimeConfig__resourceLimits.timeout.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/src/migrations/entries/retired-keys/18.kernel__RuntimeConfig__resourceLimits.timeout.ts) — pages documenting those are invisible to this run
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 00c332b4d341f49c9810136f65a92d317f7586b0packageMentionDocs.

Which tree this was computed on

This run read content/docs from 711f9dff6f42da6de8f034dd02a6cdd1f16ae19a — the merge of head 65dae07b9053953d606db247d1b6f70dffd2309c into base 00c332b4d341f49c9810136f65a92d317f7586b0, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 711f9dff6f42da6de8f034dd02a6cdd1f16ae19a && git checkout 711f9dff6f42da6de8f034dd02a6cdd1f16ae19a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 00c332b4d341f49c9810136f65a92d317f7586b0 65dae07b9053953d606db247d1b6f70dffd2309c && git checkout -B drift-repro 00c332b4d341f49c9810136f65a92d317f7586b0 && git merge --no-ff 65dae07b9053953d606db247d1b6f70dffd2309c

node scripts/docs-audit/affected-docs.mjs --json 00c332b4d341f49c9810136f65a92d317f7586b0

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

…ecognises

`check:objectui-pin-citations` accepts exactly two spellings and a third is a
hard red. The semantic entry's citation broke across a string concatenation, so
the sha landed on a source line the mention could not reach — unrecognised, and
therefore outside every check. The reading was taken against the sha read out of
this tree's `.objectui-sha`, i.e. the pin we build against, so the asserting `=`
form is the true one.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt

Copy link
Copy Markdown
Collaborator

Contract review

Head sha reviewed: 65dae07b9053953d606db247d1b6f70dffd2309c — re-read from GitHub after every measurement below (last read after the full test run): unchanged. Merge base with origin/main (4dab2bc5c): e5272b774. PR still draft; needs:contract-review on PR and card #17781; 7 files, none on a governed surface; content/docs/releases/ untouched; base main at 45b90b6a9 per GitHub. The os-dev-report landed on the card at 10:10Z (5652629214) with open_questions: [].

Every tree reading was taken in a fresh detached worktree at that sha (pnpm install --frozen-lockfile --offline, exit 0), @objectstack/spec built through bash scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 227 s). Judged from the diff and by parsing, never from the PR body.

① derived judgments — accept set and public surface

  1. resourceLimits.timeout: <any defined value> moves accept → refuse. Parsed at head: 60000, 0 and null are each REFUSED with one issue at path resourceLimits.timeout, code invalid_type, message = the rename prescription; undefined still parses. The refusal reaches every path to the def: RuntimeConfigSchema itself, the runtime: RuntimeConfigSchema.optional() arm at packages/spec/src/kernel/plugin-security-advanced.zod.ts:373 (issue at runtime.resourceLimits.timeout), and PluginSecurityManifestSchema.sandbox at :710 (issue at sandbox.runtime.resourceLimits.timeout). There is no union arm to miss — RuntimeConfigSchema has exactly three references in packages/spec/src outside tests: its declaration :193, the .optional() at :373, and the type exports :784-786. The tsc half is also measured: a probe assigning timeout: 60000 to RuntimeConfig fails TS2322: Type 'number' is not assignable to type 'undefined' at exactly that key, while timeoutMs: 60000 and timeout: undefined compile. PR characterisation ("raises the rename prescription instead of being silently stripped") — right.
  2. resourceLimits.timeoutMs: n moves from accepted-and-stripped to accepted-and-honoured. Under the merge-base schema the new acceptance pin fails with expected undefined to be 60000 (plugin-security-advanced.test.ts:435) — the non-strict object dropped the key silently; at head it carries 60000 with the int().min(0) bound (-1too_small, 1.5expected int). So on the pure payload accept/reject axis this PR is a strict narrowing; what widens is the public surface: a new authorable spelling with effect, a new property on the exported RuntimeConfig/RuntimeConfigParsed types (:784-786) and transitively on SandboxConfig*/PluginSecurityManifest*, and a new reference-page row. The PR's "a spelling on a published payload no author could write before" is right on the surface limb, imprecise on the accept-set limb (that payload parsed before, silently). Both limbs read clause-② yes (③ F1).
  3. Published describe Maximum execution timeMaximum execution time in milliseconds (:318, read back from the schema), tombstone describe [REMOVED] … — rendered at content/docs/references/kernel/plugin-security-advanced.mdx:362,370-371,398. gen:docs re-run at head: 222 files, git status --porcelain empty ⇒ generator output byte-exact. Right.
  4. Non-strict control: a typo key timeoutms: 1 is still accepted-and-stripped at head (pre-existing, untouched) — exactly why a bare deletion would have been the ADR-0049 silent strip; the tombstone closes that door for the old spelling only. Right (PR: "the nested resourceLimits object is not .strict()").
  5. Exports and ratchets: nothing moves, and that is correct for the nesting depth. check:generated at head on the fresh dist: all 15 artifacts up to date (exit 0). authorable-surface/kernel.json:661-663 and authorable-surface.base.json:4907-4909 record kernel/RuntimeConfig: as exactly engine, engineConfig, resourceLimits; packages/spec/scripts/build-schemas.ts:850-856 reads schema.properties one level deep, so no level-2 key can ever move that ratchet (lit control on the same file: kernel/SandboxConfig:process is recorded at kernel.json:684, process.timeoutMs is not). json-schema.manifest/kernel.json:133 records the def name only; api-surface records export existence only. Should a ratchet have moved? No — none can see this key by construction; consequence recorded under ③ F5. Right.
  6. ADR-0087 ledger: +1 semantic entry in step18 (registry.ts:8686-8744, id kernel-runtime-config-timeout-unit-in-key) and +1 row under RETIRED_KEYS_BY_MAJOR[18] (registry.ts:12790), beside the four [#14478 stack 3/6] kernel/: the 14 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers (runtime-emitted measurements included) #15678 rows on the same file (:12159,:12168,:12762,:12801). gen:migration-registry re-run → git status --porcelain empty (208 semantic / 169 retired-key / 178 retired-def); check:migration-registry exit 0. Generated, not hand-merged. spec-changes.json / upgrade guide do not move because protocol 18 is the open major — same as every sibling in step18.
  7. "No D2 conversion" — right in-repo, by measurement: stack.zod.ts declares no sandbox/security-policy/runtime-config collection (its security hits at :39-43 are permission/capability/sharing); MetadataTypeSchema (kernel/metadata-plugin.zod.ts, 27 types) has none that carries a SandboxConfig; applyConversionsToStoredItem (packages/spec/src/conversions/stored.ts:64-70) is keyed by metadata type; conversions/registry.ts has 0 kernel/ surfaces (its 4 sandbox hits at :3499,:4143,:4172,:4553 are prose about script sandboxes; lit control flow 172); the one runtime reader, packages/core/src/security/sandbox-runtime.ts:344-346, reads resourceLimits.maxCpu only and imports SandboxConfig as a type. Outside this repo (cloud, customer projects): NOT MEASURED — bounded: a stored old-spelling shape fails loudly with the prescription at parse and at tsc, never strips silently. Observation: no in-repo runtime reads timeout or timeoutMs at all, so the entry's acceptance-criteria sentence "aborts execution after sixty seconds exactly as timeout: 60000 did" is vacuously true here — pre-existing (the key was unenforced before), inside check:liveness's remit (green), not introduced by this PR.
  8. Consumers: resourceLimits.timeout outside packages/spec / generated docs / changelogs at head = 0 against lit control resourceLimits = 4 (sandbox-runtime.ts:344-346 ×3, a worker-option comment at scripts/check-dts-emitted.mjs:52); examples/ + skills/ = 0. Pinned objectui commit 53ded82bf7… (git cat-file -t = commit, 6409 tracked files, grepped as the commit object): resourceLimits\.timeout 0 · resourceLimits 2 (packages/app-shell/src/runtime-config.ts:261, __tests__/spec-symbol-parity.test.ts:162, both prose naming top-level keys only) · lit timeoutMs 92 / RuntimeConfig 236 / \btimeout\b 688 / sandbox 106 · dark qqzzxxnotakey 0. No consumer fixture can flip. Consumer-package suites NOT MEASURED locally; bounded by the zero census and by CI on this head (Test Core 1–6, Type Check · workspace, Build Core all success). ⚠️ Console Pin Gate is skipped on this head, so the objectui answer rests on the grep, not on that gate.
  9. Prose the entry bakes into the published upgrade guide (18.kernel-runtime-config-timeout-unit-in-key.ts:28-31): "29 key-position timeoutMs" is the merge-base count (head reads 30 — it now includes its own); "no timeoutMillis/timeout_ms/timeoutMS variant" is true on the base tree and true at head outside the entry's own self-mention (6 hits, all in the entry ×3 and its registry mirror ×3); "spells timeout 0 times" is true case-sensitively (NodeJS.Timeout at sandbox-runtime.ts:57 is a type name). Not contract facts; verdict-neutral; recorded so the next reader is not misled.
  10. Nothing else on the def moves — the source diff is confined to :179-192 (the const, declared above its consumer for the OS_EAGER_SCHEMAS=1 TDZ reason; check:authorable-surface, which is the eager run, is green) and :305-320. check:duration-unit-keys (main's gate) exit 0, 211 keys, zero offenders.

⭐ The pin-test replacement (the item this review was pointed at): run against the pre-change schema, not by deleting the tombstone. git restore --source=<merge-base> of the zod file (blob 160ab1868daf629b3427, anchor RUNTIME_RESOURCE_LIMITS_TIMEOUT_RETIRED 2 → 0 on disk), then the test file: 4 failed / 20 passed — exactly the four new pins: :418 expected true to be false (bare spelling was accepted), :435 expected undefined to be 60000 (timeoutMs was stripped), :445 (no timeoutMs describe), :458 (no refusal to read a message from). The 20 passing are the lit control that the harness ran. Restored with git checkout HEAD -- (blob back to 160ab1868d, anchor 2, porcelain empty, git diff HEAD empty); at head 24/24. ⇒ every new assertion fails against the pre-change schema and passes after — the slot pins something real. The round's own ablation (tombstone line only, 2 red) was a weaker cut; both agree. The rewritten comment (:397-411) is true: it says the slot held a negative control, why, that #15939 is the sweep it was written for, and that it now pins the opposite fact — which is what :413-466 pins. Moving the block out of describe('… (#15678)') keeps that header's "FOUR durations" exactly true.

② semver grading — minor, feat(spec)!

  • What the diff does: removes a published authorable spelling and adds one. Strict semver: major.
  • What the repo's written convention says: scripts/check-changeset-no-major.mjs:36-88 — during the launch window breaking changes ship as minor; major is refused while the guard is armed (it is: no .changeset/pre.json, no allow-major label on this PR); "the bump level tells a consumer nothing about whether the release breaks them", and the mandatory carriers are the BREAKING banner and the ADR-0087 disposition. Both present: .changeset/17781-runtime-config-resource-limits-timeout-ms.md:9 **BREAKING**, :7 <!-- adr-0087: registered kernel-runtime-config-timeout-unit-in-key -->, :20-25 FROM→TO diff + one-line fix. check-adr-0087-registration --base origin/main exit 0 ("registered … new here"); check-changeset-no-major --base origin/main exit 0; CI Check Changeset success on this head (the level axis with the PR payload: Clause-②: yes ⇒ ≥ minor on the moved package — satisfied by :2).
  • Is major the honest level? Under strict semver yes, and the repo says so itself ("that is the whole cost of the window"); under the convention in force it is refused, and the honesty is carried by the banner + disposition, both of which are here. minor is therefore the correct grade on this tree; major would be a gate red, patch would carry no breaking signal and fail the level axis.
  • Were the siblings right? Yes — for that written reason, not because they are siblings: CHANGELOG.md feat(spec)! entries under ## 17.4.0 corroborate, they are not the argument. Ruling A's patch was contradicted by its own "[#14478 stack 3/6] kernel/: the 14 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers (runtime-emitted measurements included) #15678/[#14478 stack 4/6] system/: the 15 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers; metrics.zod.ts size needs an honest name, not the mechanical one #15679 shape" and by the gate; correction 5652120294 is right.
  • Observation, pre-existing and tree-wide, not this PR's: the tombstone says "in @objectstack/spec 17" (package major; the four sibling tombstones on this file at :325,:331,:344 say the same) while the ledger row sits under protocol 18 (140 rows under 18: vs 29 under 17:; build-schemas.ts:848 CURRENT_MAJOR = 17). Consequence: the aging clock (:1101, 2 majors) starts at 18, so this tombstone cannot age out before package major 20. Consistent with every sibling; not a defect of this diff.

③ boundary flags

Implemented-by: claude/issue-17781-plugin-security-timeout-unit
Reviewed-by: session_015c5G6TmpMKgnusmTpD7Ntt

(Disclosed, not hidden: dispatcher, PM and this reviewer share one session — 席内至档 as recorded on #15939 5652016540; the pair reader will flag the same-session correction. The review worktree and owned ref were removed; the shared checkout is at 84e6b05 with an empty git status.)

PASS — the replacement pin is proven to fail against the pre-change schema and its comment is true, the tombstone refuses on the def and on every path that reaches it, the registry and reference page are byte-exact generator output, "no D2" holds in-repo by measurement, and both PM corrections are correct on the repo's own written text.


Provenance and tier verification — the seat's own record

Adopted verbatim by the epic PM seat for #15939, session_015c5G6TmpMKgnusmTpD7Ntt, 2026-09-13T10:22Z. The fuse permits adoption or voiding, ⛔ never rewriting or abridging.

  • Served tier, from the harness-stamped transcript, ⛔ not a self-report: 100 messages stamped "model":"claude-fable-5-1", zero other values — exact match to CONTRACT_REVIEW_TIER. Discriminating control: the authoring round's transcript over the same grep reads 239 × "model":"claude-opus-5".
  • Context-isolated seat, fed only the card, the standing rulings and the PR — ⛔ never the dispatch order or this seat's conclusions. It inherits this session id (席内至档) and discloses that itself.

Where this review beat the round it reviewed: the round proved its new pin by ablating the tombstone line only (2 assertions red). The reviewer instead restored the whole zod file to its merge-base state and got 4 failed / 20 passed — every one of the four new pins red against the pre-change schema, with the 20 passing as the lit control that the harness actually ran. Its own words: "the round's own ablation … was a weaker cut; both agree." That is the difference between "the tombstone is load-bearing" and "the slot pins something real", and only the second is what a replacement pin owes.

⚠️ Declared gaps I am accepting with the verdict, ⛔ not glossing: consumer-package suites were not run locally (bounded by a zero census plus CI green on this head), Console Pin Gate is skipped on this head so the objectui answer rests on the grep rather than that gate, and the cloud/customer population for the "no D2 conversion" reading is NOT MEASURED (bounded: a stored old spelling fails loudly at parse and at tsc, never strips silently).

F4's escalation is carried, not closed: retired-keys/18.kernel__SandboxConfig__process.timeout.ts:6-9 is now doubly stale about this key. It is #17635's owned correction, and #17635's own rewritten sentence must be re-read against the tree after all six renames land. Logged on the epic's landing checklist — ⛔ a green check:duration-unit-keys will not detect it.

epic PM for #15939 · session_015c5G6TmpMKgnusmTpD7Ntt · 2026-09-13T10:22Z


Generated by Claude Code

@zhuangjianguo
zhuangjianguo marked this pull request as ready for review September 13, 2026 10:22
@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Sep 13, 2026
Merged via the queue into main with commit cbcae14 Sep 13, 2026
40 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-17781-plugin-security-timeout-unit branch September 13, 2026 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec: 1 duration key(s) in kernel/plugin-security-advanced.zod.ts name their unit only in JSDoc — #15939 Ruling A remediation (1 of the 21-row delta)

2 participants