Skip to content

test(types): give the inert comment projection a subject that reddens (objectui#9768) - #9814

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-9768-inert-comment-projection
Sep 18, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-9768-inert-comment-projection

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Fixes #9768

The comment projection at the three packages/types readers was correct and inert. This gives it a subject it actually defends.

Population first — the card's number was not re-derived, it was re-measured

⛔ The card asserted inertness over "16 interface bodies" and I could not reproduce that figure, so I established the population mechanically rather than inheriting it. Method: instrument stripComments in scripts/js-comment-mask.mjs to record every input plus its calling test file, run the three readers, restore the module from HEAD and verify the restore by blob hash, then replay each captured body through the readers' own member regex twice — once through the projection, once with no projection at all.

Reading (this run, on 6a0d1a435):

stripComments calls across the three readers 67
of those, bodies located in a tracked non-test file 63
synthetic string literals handed to members() 4
DISTINCT (file, interface) bodies 20 — 10 declarations, 10 docs fences
bodies where the projection deletes at least one byte of prose 17 / 20
bodies where projection and NO projection give a different member map 0 / 20

The 10 declarations are the nine overlay interfaces the 7081 reader enumerates plus EmptySchema in feedback.ts; the 10 fences are their docs pages plus feedback/empty.mdx. The projection is doing real work — it removes 11,754 bytes of prose from the AlertDialogSchema body alone — it simply never changes the answer.

Triage's escalation condition: NOT met

⭐ No real subject reads differently with and without the projection (0 of 20), so there is no live defect, the three readers get nothing wrong today, and the grade does not move to p2. The fixture stays the right deliverable.

⚠️ One finding from the same run, which strengthens the card rather than weakening it: all 4 synthetic literals are inert too, including the one counter-probe that reads as though it exercised the projection — the JSDoc stripping does not eat real rows probe in overlay-node-slot-doc-types-7082.test.ts. Its member-shaped line sits behind a docblock gutter (three spaces and a star) while members() anchors on exactly two spaces followed by an identifier, so it passes identically with the projection removed. Before this change nothing in the tree, subject or literal, could force the guard.

What this lands

Each of the three readers declares CommentProjectionForcingSubject and pins the member list it reads off it. The body carries a member-shaped row inside an ordinary block comment — no * gutter, so the row sits on the two-space anchor — and the pin reads the file off disk and extracts that body exactly as it extracts a declaration.

  • ⛔ It is a SUBJECT, not a synthetic string handed to the reader: the shape is on disk, in a file the compiler reads (tsconfig.test.json covers these files, and two type-level legs per reader assert the declared rows), and the extraction path is the readers' own interfaceBody + members.
  • It is declared per file, deliberately: each reader carries its OWN copy of members(), so a pin living in one file cannot red for a projection dropped in another.
  • ⛔ Behaviour unchanged: no reader's projection, regex or subject list moved. scripts/js-comment-mask.mjs is untouched.

Red before green — the ablation, both legs

The mutation is the same in both legs: const bare = stripComments(body); becomes const bare = body; in all three readers, proven on disk (3 markers injected, 0 surviving calls) before anything is read. Restoration is git checkout HEAD -- ... under a trap, verified by comparing each file's blob hash with its HEAD blob and by git diff HEAD coming back empty.

  • Leg A — the PRE-FIX state (6a0d1a435, the three readers as they were), projection removed: Test Files 3 passed (3), Tests 155 passed (155), exit 0. ⇒ the guard was inert.
  • Leg B — with the forcing subject, projection removed: Test Files 3 failed (3), Tests 3 failed | 158 passed (161), exit 1. One failure per reader, all on the same assertion:
× `members()` reads the two DECLARED rows and not the row in the comment
AssertionError: expected [ 'phantom', 'real', 'label' ] to deeply equal [ 'real', 'label' ]

⛔ Not a count that happened to move: the assertion that moved names the member LIST, and the subject is added rather than an existing one altered, so a grep count over the tree would read the same in both legs.

Verification

Heavy legs through the shared lock at ../objectstack/scripts/pm/os-verify-lock.sh, verdict lines quoted:

  • pnpm --filter @object-ui/types type-check — os-verify-lock: VERDICT command-exit 0 · held the lock 33s · waited 0s (three programs: tsc --noEmit, tsconfig.examples.json, tsconfig.test.json)
  • pnpm --filter @object-ui/types test — os-verify-lock: VERDICT command-exit 0 · held the lock 26s · waited 0s; Test Files 204 passed (204), Tests 4777 passed (4777)
  • The three readers alone: Tests 161 passed (161) (155 before this change)

Gates, run by POPULATION rather than by name — each of these reads this diff while naming none of its paths:

  • check:comment-mask-corpus exit 0 — 5078 files, 1 disagree (0 comment bytes read as code, 1517 code bytes read as comment), i.e. the objectui#7882 residue unchanged and inside its declared ceiling
  • scripts/check-hand-rolled-comment-mask.mjs exit 0 — 6 private comment projection(s) in 5 file(s); DEBT names 5; this diff adds no carrier and the DEBT ratchet does not move (the one regex added is a LOOKUP for the row, not a removal position)
  • check:pending-changeset-literals exit 0, markdown-test-inputs --audit exit 0 (102 candidate test files, all adjudicated)
  • check:control-bytes exit 0 (7890 tracked text files), check:test-path-roots exit 0 — the new read is rooted at the test file itself, never at the cwd
  • check:new-line-citations exit 0 (0 new citation(s)), check:changeset-claims exit 0, check-changeset-presence exit 0 — the empty-frontmatter changeset is the declared exemption
  • node scripts/check-lint-coverage.mjs exit 0 (46/46 packages linted, 0 with outstanding errors); pnpm --filter @object-ui/types lint 0 errors (the two warnings printed against overlay-trigger-union-7081.test.ts are pre-existing data?: any rows, untouched by this diff)

⛔ check:node-esm-load is not coupled to this diff: nothing under any package's published files[] moves — tsconfig.json excludes **/__tests__/** from the build — so no dist artefact changes. It is named here as a deliberate omission rather than left unsaid.

Acceptance notes

  • noted, not filed: the four synthetic literals in these readers' counter-probes all pass with the projection removed, so the probes named for JSDoc stripping measure the member regex rather than the projection. Carrier for a later repair: whoever next edits those probes; ⛔ not filed, because they are honest as tests of the regex and this pull request now supplies what they were mistaken for.
  • The 16 interface bodies figure on the card is not reproducible against the readers' actual subject lists. It is consistent with a count over one reader's docs pages plus the declarations (10 + 6), but that is a reconstruction, not a reading — I am reporting 20, measured, with the method above.

🤖 Generated with Claude Code

https://claude.ai/code/session_015h79niBMyoB1xcaQje3uiz


Generated by Claude Code

… (objectui#9768)

The comment projection at `overlay-node-slot-doc-types-7082`,
`alert-dialog-read-dialect-7104` and `overlay-trigger-union-7081` was correct
and inert: over the whole population those three readers project, the member map
built with `scripts/js-comment-mask.mjs` and the map built with no projection at
all are identical, so nothing would have noticed the guard being deleted,
weakened, or reverted to a hand-rolled regex.

Each reader now declares `CommentProjectionForcingSubject`, whose body carries a
member-shaped row inside an ORDINARY block comment -- no `*` gutter, so the row
sits on the two-space anchor `members()` matches -- and pins the member list it
reads off that subject. The subject is read off disk and extracted the same way
a declaration is, so it is a subject rather than a synthetic string handed to
the reader. It is declared per file because each reader carries its own copy of
`members()`.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3049.6 KB 3104.5 KB
Main entry chunk (gzip) 145.7 KB 350 KB
Entry file index-x7xwLwj_.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 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) 545.99KB 130.71KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 215.98KB 59.97KB
fields (index.js) 249.23KB 62.88KB
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) 5.52KB 2.10KB
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.92KB 14.22KB
plugin-charts (index.js) 71.71KB 20.07KB
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.28KB 65.87KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.71KB 34.16KB
plugin-gantt (index.js) 167.62KB 41.26KB
plugin-grid (index.js) 212.61KB 57.90KB
plugin-kanban (index.js) 48.10KB 14.94KB
plugin-list (index.js) 112.74KB 27.70KB
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) 10.58KB 3.72KB
plugin-view (index.js) 85.05KB 21.01KB
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) 104.82KB 34.67KB
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) 4.11KB 2.06KB
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

@os-try-charles
os-try-charles marked this pull request as ready for review September 18, 2026 07:03
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit 30a170e Sep 18, 2026
38 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-9768-inert-comment-projection branch September 18, 2026 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants