Repository navigation
Description
Filed by the PM seat as option C of PR-less card #9707's disposition. The #9707 dev measured this while establishing that "just import ./runtime instead" is not an available fix, and recommended it as a cheap rider. Ruled: ship it.
The trap
packages/lint publishes a ./runtime subpath whose doc comment advertises it as the light, kernel-safe entry. Measured, it is not:
| modules reached | bytes on disk | |
|---|---|---|
. (index.ts) |
72 | 532,262 |
./runtime |
71 — 70 of them shared with . |
498,225 (93.6% of .) |
And the part that makes it a trap rather than a rounding error: ./runtime does not export validateCapabilityReferences at all — the one rule a browser consumer wants.
So a reader who believes the comment and switches to ./runtime gets 93.6% of the weight and none of the rule, and finds out only after a console build (~20 minutes).
What to change
The doc comment on the ./runtime entry — in packages/lint's exports map and/or src/runtime.ts's header, wherever the "light entry" claim is actually made. Locate it by content, not by the description here.
State what is true, derived rather than asserted:
- what
./runtimeis for (whatever the real distinction from.turns out to be — the 2-module difference is the whole delta, so name it); - that it is not materially lighter than
.; - that it does not carry
validateCapabilityReferences.
packages/lint/src reproduces them cheaply and needs no console build.
⛔ Out of scope
- ⛔ Do not add a new subpath export. That is option B of [finding] The whole 520 KB
@objectstack/lintentry rides the console's eagerly-loaded vendor chunk, to serve one advisory rule — and itsmodule/fs/pathimports are browser-stubbed #9707's disposition and it was ruled against — objectui#5266's one-line chunker fix captures the entire eager win (-89.0 KiB gzipped per console page load) with zero framework surface. Do not re-open it. - ⛔ Do not shrink, split or restructure
.or./runtime. Ruling 1 of [finding] The whole 520 KB@objectstack/lintentry rides the console's eagerly-loaded vendor chunk, to serve one advisory rule — and itsmodule/fs/pathimports are browser-stubbed #9707 stands: the.entry serves node consumers and is not to be optimised for the browser's benefit. - ⛔ Do not remove the
module/fs/pathimports. Measured: lint reachessucrase/typescriptthroughcreateRequireat call time, and that code is not on the console's path, so the heavy transpilers are already not bundled. The externalization warnings are a symptom, not the cost.
Worth checking while you are there
Are there other subpath doc comments in this package (or in sibling packages with multi-entry exports maps) making a weight or safety claim nobody has measured? A "light entry" claim is exactly the kind that is written once at authoring time and never re-checked. Report what you find; fold in only what is unambiguously false by measurement, card anything needing judgement.
Changeset
packages/lint is published, so follow the precedent for comment-only changes to published packages — check whether the touched file ships in files, and whether the comment reaches the published .d.ts. If nothing published changes, skip-changeset (added with POST, not a set-replacing PUT, so the labeler bot's labels survive).
Refs: #9707 · objectstack-ai/objectui#5266 · #9659 (pm:on-hold, the per-package injection verdicts) · #9771
Generated by Claude Code
Activity
os-support-ai commentedon Aug 18, 2026
Triage: grading = de-label —
findingoff; confirmedpm:queue·domain:devx· Task. Lane-PM ruling ("ship it", option C of the #9707 disposition) accepted; comment-only fix with the published-package changeset caveat as written in the card.Generated by Claude Code
os-steve commentedon Aug 18, 2026
Claiming this card.
session_01XqDQYVU5smx29ts9pAErjaclaude/issue-9772-runtime-subpath-docPlan: re-measure the import graph over
packages/lint/src(H1), name the 2-module delta that is./runtime's actual reason to exist (H2), sweep every copy of the "light entry" claim (H3), then sweep sibling multi-entry packages for the same unmeasured weight/safety shape (H4). Prose only — no executable change, no new subpath.Generated by Claude Code
os-steve commentedon Aug 19, 2026
{ "issue": 9772, "status": "done", "branch": "claude/issue-9772-runtime-subpath-doc", "pr": "https://github.com/objectstack-ai/objectstack/pull/9802", "premise_still_valid": true, "summary": "H1 re-measured, no figure quoted from the card. Module counts reproduce EXACTLY (. = 72, ./runtime = 71 with 70 shared); the byte figures moved with main and the ratio did not: the card's basis is the built ESM bundle, 532,262/498,225 (93.6%) then vs 552,936/518,583 (93.79%) now (CJS 570,928/520,268, 91.13%). Two sharper facts the card lacked: the honest headline is a PAIR - ./runtime carries 93.8% of the bytes and 1.9% of the export surface (5 names of 263, a strict subset of .'s) - and validateCapabilityReferences is COMPILED INTO dist/runtime.js (function body at bundle line 6435, it is a member of the one shared registry) and merely not exported, so a consumer pays its bytes and cannot call it. H2: the 72/71 delta is three files, two of them the barrels themselves, so the real delta is exactly ONE module, lint-startup-registry-verdict.ts - and it is not the entry's reason to exist, since ./runtime still reaches validate-react-pages.ts, validate-react-page-props.ts and validate-hook-body-writes.ts. Derived purpose: ./runtime is an EXPORT-SURFACE boundary, machine-checked (authoring-rule-wiring.test.ts's third invariant fails if metadata-protocol's gate imports the root barrel), not a weight boundary; the lazy loading of typescript/sucrase/ajv is the PACKAGE's property, pinned by lazy-deps.test.ts over all of src/, so . has it too. The entry is justified - the pin is real - but justified on grounds the comments never stated. Prose only; nothing that executes changed.", "tests": "At final commit 44b030592 (re-run after the last commit, on the pushed tree): `pnpm --filter @objectstack/lint test` -> 'Test Files 74 passed (74) / Tests 2088 passed (2088)'; `pnpm --filter @objectstack/lint typecheck` (tsc --noEmit) -> clean, exit 0. Gate union derived from the ACTUAL changed paths via `node scripts/pm/dispatch-gates.mjs` (the dispatch word named no gates), all exit 0 at 44b030592: check:nul-bytes, check:cross-package-test-inputs, check:engine-double-contract, check:where-matcher, check:query-options-erasure, check:type-check-coverage, scripts/docs-audit/check-affected-docs.mjs ('affected-docs self-test: 242 cases pass'). Heavy steps ran under flock -E 99 on /tmp/os-heavy-verify.lock; one 10-min call was lost to lock queueing behind worktrees objectstack-9691 and objectstack-9779 (both live, identified with fuser -v), so the test leg was re-acquired and re-run rather than reported from the earlier pass. NOT run locally: check:type-check-debt --re-measure, which needs the whole workspace closure built; this diff adds no test file and no code (comments plus one assertion MESSAGE string in an existing test) so it cannot move a tsc error count - CI runs it. No ablation applicable: nothing executable changed, so there is no guard to mutate. Published-artifact delta measured directly instead: md5 of packages/lint/dist/* before and after a rebuild shows EXACTLY two changed files, dist/index.cjs.map and dist/runtime.cjs.map, via embedded sourcesContent - no .js, .cjs, .d.ts or .d.cts differs, and the edited comment text greps to zero hits in all of them. That is what supports skip-changeset (applied by additive POST to the labels endpoint, then read back: size/s, tests, skip-changeset all present, so the bot's labels survived).", "open_questions": [], "out_of_scope_findings": [ "filed as #9803: `@objectstack/objectql/core`'s \"268KB metadata protocol\" figure is unverified at HEAD - the structural claim (no value import of @objectstack/metadata-protocol; measured, . has one and ./core does not) holds and is ratcheted by ADR-0076 D2, but metadata-protocol/src is 3.6 MB today and comparing published bundles needs a build I had no reason to pay for on a prose card. Carded not folded, per the card's 'card anything needing judgement'; unassigned, `finding` + `domain:devx`, no pm:queue.", "reported not filed - `content/docs/releases/v17.mdx` line 2352 carries the same claim, and packages/lint, packages/cli and packages/metadata-protocol CHANGELOG.md carry it in generated changeset history. Both are historical records of what shipped and content/docs/releases/** is off-limits in a code PR (ruling 5), so neither was touched. Raising as PM-visible rather than as a card because correcting a shipped release note is a release-process decision, not a dev one.", "no card - H4 clean negative on the rest: swept all 8 multi-entry `exports` packages (spec 18, platform-objects 11, metadata 4, types/objectql/metadata-core/lint/core 2 each) and MEASURED every weight/safety claim found. @objectstack/types `.` vs `./node` (13 modules and 0 node builtins vs 2 and all 4, pinned by node-isolation.test.ts), @objectstack/core `./logger` (1 module, 0 static node builtins) and @objectstack/metadata `./errors` (2 modules, 5.6% of `.`, reaches neither manager nor loaders) are all TRUE as written. packages/lint's was the only unambiguously false one." ] }Detail, evidence tables and the full H3/H4 sweeps are in PR #9802's body.
Generated by Claude Code