Skip to content

fix(scripts): type js-comment-mask.mjs's parameters so consumer call sites are checked - #9423

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-9324-js-comment-mask-params
Sep 13, 2026
Merged

baozhoutao merged 2 commits into
mainfrom
claude/issue-9324-js-comment-mask-params

Conversation

@claude

@claude claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Part of objectui#9324.

tsconfig.scripts.json compiles scripts/** with allowJs: true and checkJs: false deliberately (objectui#3494), so a .ts consumer's types for scripts/js-comment-mask.mjs come from inference over the .mjs source, steered by JSDoc and by nothing else. Four exports take parameters; only scanSource documented them.

What was wrong, re-measured on the ref

⚠️ Every line number and count below was re-measured with git show against fb4ec65daf — the card's own line citations were corrected once already, and the correction was re-checked too. The ref is named beside each reading.

export line at fb4ec65daf docblock @param
scanSource :222 yes @param {string} source — the control, untouched
blank :440 yes, ONE-LINE prose ❌ — both parameters any
stripComments :469 yes, prose-only
maskComments :485 yes, prose-only

⚠️ Two corrections to the card, both in the same cell. The card and its own errata both record blank as having no docblock at all. It has one — a single-line prose docblock on the line above the declaration. The blob is byte-identical at the filing base and at this ref, so that cell was never right. The substance is unaffected: what blank lacked is the @param, not the docblock.

The measurement that makes it more than a style nit

pnpm type-check:scripts is the command that covers scripts/ — per-package type-check does not reach it. The masker is in that program (tsc --listFiles names scripts/js-comment-mask.mjs among 935 files), so a green there is a measurement and not a vacuous pass.

A probe file inside the program, holding a number passed to each string parameter:

                      BEFORE                     AFTER
wrong-typed calls     exit 0,  0 x TS2345        exit 2,  3 x TS2345
correctly-typed       exit 0,  0 x TS2345        exit 0,  0 x TS2345

⇒ Before this PR the type error was not merely unreported, it was unreachable. That is why objectui#9322 had to carry a hand-written const mask: (source: string) => string = maskComments; to keep its one call site checked.

Consumer population, re-derived

Counted over scripts/**/*.ts — the files tsconfig.scripts.json actually type-checks — reading each file's code only, with comments removed by the repo's own stripComments, so a mention in prose is not scored as a call.

population count at fb4ec65daf
exports of the module, total 5
exports taking parameters 4 (selfTest takes none)
exports carrying @param 1 (scanSource)
call sites inferring any 13, across 7 distinct files

Broken out: maskComments 10 unannotated calls across 5 files; blank 3 across 3 files; stripComments 0 (no importer — latent only). One further maskComments call, in check-spec-range-floors.test.ts, goes through the hand-written alias above and was already checked, so it is excluded from the unchecked count.

⇒ The card said 12 across 6. It does not match, and the difference is ordinary drift, not error — the card named its base, and importers have landed since.

Behaviour is unchanged, and that is pinned

Several gates read this module as the single authority on "is this span a comment, or code?", and objectui#9183 routed 29 test files onto it for that reason. All four exports were run over a nine-file corpus of real repo sources — 299,880 characters, 141,075 of them flagged as comment, both non-zero as a guard — before and after the change. Every output digest is identical:

scanSource     68c81f10823f1061a95ae6093e0c13b2
blank          62a77e79dd51ca5ca1396ece606d3cf3
stripComments  15b3e78ce882f59e7fbcc79cc1a29aed
maskComments   62a77e79dd51ca5ca1396ece606d3cf3

Nothing about what counts as a comment is widened or narrowed. blank and maskComments agree because maskComments(s) is blank(s, scanSource(s).comment); the guard above is what keeps that from being two empty strings agreeing.

The new test, and why it is not a spelling check

Asserting that the tag is present asserts the spelling, and a docblock saying @param is worth nothing unless TypeScript acts on it. js-comment-mask-param-types-9324.test.ts compiles real calls against the real module with the real project options and asserts the diagnostic: a wrong-typed argument must produce TS2345, a correctly-typed one must produce nothing. The correctly-typed half is load-bearing too — without it, "the wrong call errors" is also satisfied by a signature so narrow that every real call errors.

Ablation. Removing the three @param blocks from the committed tree and re-running:

4 failed | 6 passed (10)
  x rejects a wrong-typed argument to maskComments
  x rejects a wrong-typed argument to stripComments
  x rejects a wrong-typed argument to blank (first parameter)
  x rejects a wrong-typed argument to blank (second parameter)

⭐ The scanSource case is absent from that exhaustive four-item failure list — it kept firing while the other three went quiet. That is the discriminator the test was shaped for: three going quiet points at those three tags, whereas all four going quiet would point at allowJs or at the harness. The mutation was proved to reach disk by blob hash before the run (@param lines 5 → 1), and the restore was proved by the file's blob hash returning to its HEAD value.

Checks run

check result
pnpm type-check:scripts exit 0
vitest run over the masker + all 10 consumer/pin test files exit 0 — 11 files, 292 tests
check:control-bytes, check:comment-mask-corpus, check:new-line-citations, check:esm-specifiers, check:test-path-roots, check:changeset-claims exit 0
check:governed-queue-guard --test on both changed paths NOT GOVERNED
check-changeset-presence exit 0; a changeset is added anyway, with empty frontmatter, to declare no release
check:node-esm-load exit 1 — ⚠️ pre-existing and environmental, not this PR. It refuses on turbo cross-worktree cache provenance (objectui#7276) and names sibling worktrees as the producers. Reproduced identically on a pristine checkout of this PR's base with none of these changes present. This diff touches no file under packages/ or apps/.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr


Generated by Claude Code

…sites are checked

`tsconfig.scripts.json` compiles `scripts/**` with `allowJs: true` and
`checkJs: false` on purpose (objectui#3494), so a `.ts` consumer's types for
these helpers come from inference over the `.mjs` source, steered by JSDoc and
by nothing else.

Four exports take parameters; only `scanSource` documented them. `blank` had a
one-line prose docblock, `stripComments` and `maskComments` had prose-only
multi-line ones -- so their parameters inferred `any` and every consumer call
site was accepted unchecked. Measured on this tree before the change:
`maskComments(12345)` -- a number passed to a string parameter -- type-checked
clean at exit 0. The error was not merely unreported, it was unreachable, which
is why objectui#9322 had to carry a hand-written
`const mask: (source: string) => string = maskComments;` to keep its one call
site checked.

`scanSource` is the control that proved the gap was the missing tag rather than
`allowJs` failing to type anything: it is imported alongside `maskComments` in
the same files, under the same config, and it was checked. It is left exactly as
it was.

No masking behaviour changes. All four exports were run over a nine-file corpus
of real repo sources (299,880 characters, 141,075 of them flagged as comment)
before and after, and every output digest is identical -- which matters because
several gates read this module as the single authority on "is this span a
comment, or code?".

The new test is what keeps the tags from being decorative. It compiles real
calls against the real module with the real project options and asserts the
DIAGNOSTIC rather than the tag's spelling: a wrong-typed argument must produce
TS2345 and a correctly-typed one must produce nothing. Deleting a `@param` again
makes the wrong-typed half stop erroring, which is the direction a grep for the
tag cannot see.

Part of objectui#9324

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
@github-actions github-actions Bot added the tests label Sep 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Console Performance Budget — gauge not trustworthy

The eager closure was measured, but one of the ceilings it is measured against no longer means what it names, so this run carries no pass/fail verdict for the performance budget.

This is not a budget violation. Nothing grew: the half marked below is a verdict about the gauge, and a ceiling that has stopped measuring anything can neither clear a bundle nor condemn one.

Step Outcome
Build packages success
Check console performance budget failure

Which half objected:

Eager-closure half Verdict
Aggregate closure ceiling ✅ pass
Per-chunk ceilings ✅ pass
Ceiling sensitivity (headroom) ⚠️ broken gauge
Ceiling freshness (checkout vs. base branch) ✅ pass

⚠️ A broken gauge half is a verdict about the ceiling, not about the bundle: that line has drifted out of range of the regression it exists to catch, or the report behind it cannot be trusted. It does not say anything grew. The Check console performance budget step log carries the ceiling and the number it was compared against.

Reason: The entry chunk measured 144.5 KB, but the eager-closure half of this gate returned no trustworthy VERDICT: the report could not be read, a ceiling has drifted out of range of the regression it must catch, or (objectui#6245) a ceiling was replaced on the base branch after this checkout was made. The step log says which. This is not a passing budget — and it is not a size regression either.

See the workflow run for details.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 502.03KB 115.16KB
core (index.js) 8.52KB 3.41KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 213.54KB 59.33KB
fields (index.js) 247.89KB 62.50KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.83KB 10.95KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.25KB 13.99KB
plugin-charts (index.js) 71.34KB 19.90KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.44KB 34.65KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 253.46KB 65.85KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.71KB 34.16KB
plugin-gantt (index.js) 166.95KB 41.04KB
plugin-grid (index.js) 211.68KB 57.52KB
plugin-kanban (index.js) 46.00KB 14.30KB
plugin-list (index.js) 112.53KB 27.63KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.36KB 20.78KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 96.00KB 31.71KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.04KB 5.36KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…am-type test

`Lint` was red on the repo-wide root run, and the single error in it was this
file's line 2: an unused `import fs`. `object-ui/no-unused-imports` is
error-level and `@typescript-eslint/no-unused-vars` is warning-level, so the
same finding was reported twice and only the first one failed the gate.

Both declarations are leftovers from an earlier draft that read the masker from
disk, before the harness switched to resolving it through the case file's own
relative import. Neither is scaffolding: counted over this file with comments
stripped, `fs` and `maskerPath` each occurred exactly once -- their own
declaration, with zero uses -- while `path`, `ts`, `repoRoot` and `configPath`
all hit as controls on the same input. So they are removed rather than renamed;
prefixing an underscore would have silenced the report without retiring the dead
code, and `maskerPath`'s report was only a warning and was failing nothing.

`scripts/js-comment-mask.mjs` is untouched, verified by blob hash. Nothing else
in the run is touched: the 32 warnings that remain are pre-existing, on
unrelated files.

`pnpm lint:root` exit 1 -> 0 (35 problems / 1 error -> 32 problems / 0 errors).
`pnpm type-check:scripts` exit 0. The param-type test and its neighbours still
pass: 4 files, 75 tests.

Part of objectui#9324

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Console Performance Budget — gauge not trustworthy

The eager closure was measured, but one of the ceilings it is measured against no longer means what it names, so this run carries no pass/fail verdict for the performance budget.

This is not a budget violation. Nothing grew: the half marked below is a verdict about the gauge, and a ceiling that has stopped measuring anything can neither clear a bundle nor condemn one.

Step Outcome
Build packages success
Check console performance budget failure

Which half objected:

Eager-closure half Verdict
Aggregate closure ceiling ✅ pass
Per-chunk ceilings ✅ pass
Ceiling sensitivity (headroom) ⚠️ broken gauge
Ceiling freshness (checkout vs. base branch) ✅ pass

⚠️ A broken gauge half is a verdict about the ceiling, not about the bundle: that line has drifted out of range of the regression it exists to catch, or the report behind it cannot be trusted. It does not say anything grew. The Check console performance budget step log carries the ceiling and the number it was compared against.

Reason: The entry chunk measured 144.5 KB, but the eager-closure half of this gate returned no trustworthy VERDICT: the report could not be read, a ceiling has drifted out of range of the regression it must catch, or (objectui#6245) a ceiling was replaced on the base branch after this checkout was made. The step log says which. This is not a passing budget — and it is not a size regression either.

See the workflow run for details.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 502.03KB 115.16KB
core (index.js) 8.52KB 3.41KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 213.54KB 59.33KB
fields (index.js) 247.89KB 62.50KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.83KB 10.95KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.25KB 13.99KB
plugin-charts (index.js) 71.34KB 19.90KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.44KB 34.65KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 253.46KB 65.85KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.71KB 34.16KB
plugin-gantt (index.js) 166.95KB 41.04KB
plugin-grid (index.js) 211.68KB 57.52KB
plugin-kanban (index.js) 46.00KB 14.30KB
plugin-list (index.js) 112.53KB 27.63KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.36KB 20.78KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 96.00KB 31.71KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.04KB 5.36KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

PM pre-merge probe — domain:devx @ objectui seat (#5748)

⚠️ Posted BEFORE the merge. Every value re-taken by this seat on the ACTUAL current base, ⛔ not copied from the dev's report.

⛔ ERRATA 62b — base moved, and this time the mover was MY OWN MERGE

sha
base this PR records cb725e78fb
ACTUAL origin/main at probe time 0a6372e3a9docs(prompts): renumber ui-library prompt sections (#9421)

⭐ That is this seat's own previous landing — the fourth time today the thing that moved the base under a PR was my own merge. Measured: git diff cb725e78fb 0a6372e3a9 -- scripts/js-comment-mask.mjs is EMPTY, so the subject file is unmoved by every advance and the pre-values below stand. ⚠️ The final merge parent is whatever the queue puts in front; I re-confirm against the real <merge>^ in the LANDED note.

Leg 1 — @param per exported function, BOTH SIDES, populations named

Population: every export function in scripts/js-comment-mask.mjs, paired with the @param count of the docblock immediately above it.

export params pre post
scanSource (source) 1 1 ← control, already correct, must not move
blank (source, flags) 0 2
stripComments (source) 0 1
maskComments (source) 0 1
selfTest () 0 0 ← takes no parameters; correctly gained nothing

selfTest staying at 0 is the leg that shows this was not a blanket sweep: a change that "adds @param everywhere" would have touched it.

Leg 2 — the control is BYTE-IDENTICAL

scanSource body, L222..437 on both sides: sha256[:16] = 8e715c3a20dc63fc, identical. Its docblock likewise (32b5471d114abcbc). Guard is non-empty and is ⛔ not e3b0c44298fc1c14 (sha256 of the empty string).

⚠️ I got this wrong on my first reading and record it because the error is instructive: I initially reported scanSource as CHANGED. My segment ran from its docblock to the next export function, so it swallowed blank's docblock — which the dev legitimately grew from 1 line to 7. A segment boundary drawn at "the next declaration" measures the next thing's docblock too. Bounding the read at scanSource's own closing brace gives the identity above.

Leg 3 — ⭐ the ACCEPTANCE, verified with the compiler rather than by reading tags

The card's acceptance is 「call sites become CHECKED」, ⛔ not 「the tag text exists」. I built a minimal program with this PR's own option set (allowJs: true, checkJs: false, strict) against the pre and post copies of the module, calling all three functions with wrong-typed arguments:

PRE : TS2345 = 0   (total diagnostics 0)   <- wrong-typed calls pass SILENTLY
POST: TS2345 = 3   (total diagnostics 3)   <- all three now caught
        Argument of type 'number' is not assignable to parameter of type 'string'.  x3

⇒ the tags are load-bearing, not decorative. TypeScript 6.0.2, ts.createProgram + getPreEmitDiagnostics.

⚠️ My first run of this read 2, not 3, and the fault was mine: I had written // @ts-ignore-nothing as a label above the first call. TypeScript parses that as @ts-ignore and suppressed the very diagnostic I was measuring — verified directly against a guaranteed type error (0 diagnostics). Removing it gives 3, matching the dev exactly. ⭐ A comment I wrote as documentation silently became a suppression directive.

Leg 4 — why the .mjs call sites are NOT the population

tsconfig.scripts.json is include: ["scripts/**/*.ts"] with allowJs: true, checkJs: false. ⇒ the .mjs callers are consumed for inferred types but never type-checked; the call sites that become checked are the .ts suites — 13 across 7 files (1+4+2+1+2+1+2). ⚠️ I first read 6 across 6 by counting .mjs invocations: a different population, ⛔ not a discrepancy in the dev's figure. The card's own 12/6 is genuine drift from landed importers, and the dev stated that rather than quietly adopting it.

Leg 5 — the cross-package TS2578 hazard, which is objectui#3535's failure mode

31 files under packages/** import this module, 31 of 31 behind // @ts-expect-error — plain-JS shared helper, intentionally untyped. Had these tags made those imports type cleanly, all 31 directives would go unused → TS2578, reddening files this PR never touched. It cannot happen, and the robust reason is ⛔ not allowJs:

  • every packages/*/tsconfig.json excludes **/__tests__/** and **/*.test.ts; all 31 importers match those globs ⇒ 0 are in any package program. A directive in a file the compiler never opens cannot go unused. ⭐ This survives a future allowJs: true on the root config.
  • (The allowJs argument is true but weaker, and ⚠️ the file usually cited for it — tsconfig.base.jsongoverns nothing here: no packages/* config extends it. allowJs is absent from the resolved options entirely, i.e. at TypeScript's default. That is objectui#9330's thesis in the wild.)

⚠️ Population note: 32 files match the string js-comment-mask; 31 carry a real import. The 32nd mentions it in a docblock. I first read that file as 「an importer with no directive」 — ⛔ wrong, prose scored as code.

CI on b82347722d

36 runs: 32 success, 3 skipped, 1 failure. All 9 required contexts green: Lint · Type Check · Build & E2E · Test (shard 1/4 … 4/4) · Build Docs · Changeset Declaration.

The one failure is Bundle Analysis — ⛔ not a required context (established on objectui#9155, which merged with it red), red across this lane, ⛔ not caused by this diff and ⛔ not chased.

⚠️ Lint was RED on the first head (4a3873fe13) and it was this PR's own: an unused import fs in its new test file — the single error among 34 pre-existing warnings. Fixed in commit 2 (-2/+0, one file), no amend, no force-push, 0 eslint-disable in the diff (control expect( → 5).

⇒ Flipping ready and enqueueing.


Generated by Claude Code

@baozhoutao
baozhoutao marked this pull request as ready for review September 13, 2026 19:09
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 13, 2026
Merged via the queue into main with commit fcdc4d0 Sep 13, 2026
37 of 38 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-9324-js-comment-mask-params branch September 13, 2026 19:27
@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

✅ LANDED — fcdc4d0150

Merged through the queue at 2026-09-13T19:27:17Z. Timeline: added_to_merge_queue 19:10:10Z → merged 19:27:17Z.

⛔ ERRATA 62b — re-confirmed against the ACTUAL <merge>^

merge commit : fcdc4d0150  fix(scripts): type js-comment-mask.mjs's parameters … (#9423)
<merge>^     : 0a6372e3a9  docs(prompts): renumber ui-library prompt sections … (#9421)

<merge>^ is this seat's own previous landing — the fifth time today the thing that moved the base under a PR was my own merge. The PR recorded cb725e78fb; the real parent is two advances later. Re-taken there, the pre-values are unchanged (the subject file is untouched by every advance), so the pre-merge probe #issuecomment-5655447081 stands as published.

pre (0a6372e3a9) post (fcdc4d0150, on main)
scanSource @param 1 1 ← control, unmoved
blank 0 2
stripComments 0 1
maskComments 0 1
selfTest (takes none) 0 0
scanSource body sha256[:16] 8e715c3a20dc63fc 8e715c3a20dc63fcidentical across the merge

What actually landed, and why the tags are not decorative

The acceptance was 「call sites become CHECKED」, ⛔ not 「the tag text exists」. Verified with the compiler under this PR's own option set (allowJs: true, checkJs: false, strict): wrong-typed calls to all three functions go TS2345 = 0 → 3. Before this PR, stripComments(someNumber) compiled silently.

The population that becomes checked is the .ts suites — tsconfig.scripts.json is include: ["scripts/**/*.ts"] with checkJs: false, so the .mjs callers are never type-checked. 13 call sites across 7 files.

⚠️ Three corrections this seat made AGAINST ITSELF while reviewing, recorded because the PR's value depends on them

  1. I read scanSource as CHANGED. Wrong — my segment ran from its docblock to the next export function and swallowed blank's docblock, which the dev legitimately grew from 1 line to 7. ⭐ A segment boundary drawn at 「the next declaration」 measures the next thing too.
  2. I read 6 call sites across 6 files against the dev's 13/7. Wrong — I counted .mjs invocations, a population checkJs: false excludes from checking entirely. The dev's figure was right; the card's 12/6 is genuine drift.
  3. My first acceptance run read TS2345 = 2, not 3. Wrong — I had written // @ts-ignore-nothing as a LABEL above the first case, and TypeScript parses that as @ts-ignore and silently suppressed the diagnostic I was measuring (verified directly: 0 diagnostics on a guaranteed type error). ⭐ A comment written as documentation became a real directive.

Three defective legs from the reviewer, against one off-by-one from the dev (32 vs 31 masker consumers — a docblock mention scored as an import, which they owned unprompted). ⛔ None of mine changed the outcome; all three are recorded so the numbers above can be trusted for the right reasons.

⭐ The hazard the dev went looking for unprompted — objectui#3535's failure mode

31 files under packages/** import this module, 31 of 31 behind // @ts-expect-error — plain-JS shared helper, intentionally untyped. Had these tags made those imports type cleanly, every directive would go unused → TS2578, reddening 31 files this PR never touched. That is precisely the collision objectui#3535 documents (and which I closed as measured-not-reachable earlier today).

It cannot bite, and ⭐ the robust reason is not the one first cited: all 31 importers sit under __tests__/ or *.test.ts, which every packages/*/tsconfig.json excludestsc never opens them (31 of 31 excluded, 0 in-program). A directive in a file the compiler never reads cannot go unused, whatever allowJs does. ⚠️ The allowJs argument is true but weaker, and the file usually cited for it — tsconfig.base.jsongoverns nothing here: no packages/* config extends it, so allowJs sits at TypeScript's default. That is objectui#9330's thesis in the wild, found from the other side.

Not this PR's

Bundle Analysis red — ⛔ not a required context (objectui#9155 merged with it red), red across this lane. check:node-esm-load red — the dev established it is inherited using a pristine control worktree detached at their exact base with none of their edits, which failed identically (37 refused vs 2). ⭐ That is how you prove a red is not yours.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants