Uh oh!
There was an error while loading. Please reload this page.
feat(non-grid): a platform row ceiling with a loud footnote, and the settled-schema convergence - #7391
Conversation
❌ Console Performance Budget
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. Which half objected:
📦 Bundle Size Report
Size Limits
|
…ow ceiling objectui#7210 half 2, maintainer ruling a' (2026-09-02, director seat). The four non-grid views each issued a `find` with no `$top` at all, so the request returned the entire filtered result set — invisible at 186 rows, the whole table into the browser at 100k, and unbounded by anything an author could write, since `pagination.pageSize` cannot cap a query that never carried a cap. They now ask for one probe row past a platform ceiling, draw at most the ceiling, and say so LOUDLY when the cut bites: a `role="note"` footnote naming both N and M, following objectui#7148's chart footnote for placement and tone. Silent truncation is the direction the ruling names as dangerous — a cut-off schedule still looks like a schedule. The ceiling is 2000, one constant for all four, chosen after measuring them: gantt, calendar and map hold their DOM flat as rows grow (virtualisation, four events per day cell, auto-clustering above 100 markers); ObjectTree flattens every expanded node at a measured 5.2 DOM elements per record and is therefore the binding view. 2000 rows puts it at ~10,400 elements. Not authorable, by the ruling: the two `$top` pins that used to assert the absence of a cap now assert that the cap is the PLATFORM's and that an authored `limit` still cannot reach it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…plicate query objectui#7225, maintainer ruling B (2026-09-02, director seat), which AMENDS the 2026-08-27 #6482 ruling that had barred a one-shot multi-package refactor — amended because the cost was measured at zero behaviour delta. `useSettledSchema` shipped with exactly one non-test adopter, so a published export was owed compatibility forever while the duplication it was named for stayed. ObjectKanban, plugin-view/ObjectView and ObjectCalendar now call it. The hook was extracted FROM these three shapes, so each becomes a one-line call; gate placement stays local, which is what #6482 ruled and what made ObjectCalendar's named obstacle a non-obstacle — it was about the gate half. ObjectCalendar uses the hook's own documented recipe for it: pass the data source as `undefined` for a render that must not read metadata. The kanban's rejected read moves from console.warn to console.error with a `[useSettledSchema]` prefix, and its test spy moves with it — asserting on the channel now, not merely silencing one. Ask 2: the gantt's DUPLICATE query is gated. `reload` listed `objectSchema` in its dependency list, so a load issued two unbounded queries, the first with no `$expand` at all. Per #6482's per-component measurement standard this is the profile where gating pays: with the metadata read the slower of the two — the common case on a cold MetadataCache — the user saw raw foreign-key ids, then the loading placeholder again, then the expanded rows. Gating required the schema resolution to settle on EVERY exit (objectui#7232): the hand-rolled effect returned without settling on `!effectiveDataSource`, on `!resource` and in its `catch`. Harmless while nothing waited; a chart that never loads once something does. The hook settles on all three, and both exits are pinned. The #7231 stale-reload pin keeps every assertion and changes only how it GENERATES two overlapping reloads: it used to use the gantt's duplicate mount query, which no longer exists, and now uses a silent toolbar refresh superseded by a filter-change reload — a pair that is real and untouched by gating. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
AGENTS.md #2 — docs reflect the code. Kept as its own commit so the two card halves stay independently checkable as code changes. - `packages/react/README.md`: a `NON_GRID_ROW_CEILING` section (objectui#7210) with the three-export usage shape, why the `$top` is the ceiling PLUS ONE, and the standing "not authorable, and a cap without the note is a defect" fence. `useSettledSchema`'s section stops describing ObjectKanban / ObjectView / ObjectCalendar as hand copies — they call it now (objectui#7225) — and names all five adopters. - `content/docs/guide/data-source.md`: the per-block binding table said `— no row cap` for `object-calendar` / `object-gantt` / `object-map`. That is no longer true and the sentence it implied was the dangerous one. The cells now read `— platform ceiling`, with a paragraph saying what the cell still means: an authored `limit` / `pagination.pageSize` STILL cannot reach these queries, because the ceiling is a renderer constant by ruling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…'s budget Measured, with a control, not assumed. `check:eager-closure` weighs the console's eagerly-loaded chunks per chunk as well as in aggregate, and the first build of this branch put `framework` 0.2 KB OVER its 511.7 KB ceiling. The control says the bytes are mine, so they get paid for rather than budgeted around — a build of plain `origin/main` (1688986) in a second worktree measures `framework` at 510.8 KB with 0.9 KB of headroom, against 511.9 KB on this branch. A per-chunk diff of the two eager-closure reports attributes exactly 1,075 gzipped bytes to this branch, split ~227 into `@object-ui/react` and the rest into the eagerly-loaded locale packs. ⛔ The ceiling is NOT raised. The gate offers that route for intended growth; this growth is real but the copy was simply longer than it needed to be. - Both footnote sentences tighten to the form the ruling itself uses — "showing first N of M records; narrow the filter" — in all ten packs. The copy is shorter AND closer to the ruled wording. - The same two sentences ship twice in `framework` (the `en` pack and the provider-less fallback map), so each edit counts double; the fallback map now says so, with the measured headroom, next to the strings. - `data-ceiling-drawn` / `data-ceiling-total` were test-only attributes on a note that already renders both numbers as text. Dropped; the three pins that read them assert the text instead, which is what a user sees anyway. `framework` is now 511.6 KB against the 511.7 KB ceiling and the gate exits 0.⚠️ 0.2 KB is not comfort. `main` moved this chunk 510.8 KB in the hour before this measurement, and CI weighs the MERGE ref — so another lane landing framework bytes first can turn this red with no further change here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…scope
CI red on `Test (shard 1/4)`: two files died at module-mock time with
'No "createSafeTranslation" export is defined on the "@object-ui/i18n" mock'
— zero tests failed, both files failed to import.
The cause is placement, not the mock. `nonGridRowCeiling` is re-exported from
`@object-ui/react`'s entry, so a module-scope `createSafeTranslation(...)`
factory ran on IMPORT for everything that touches the barrel — and threw
inside any test that partially mocks `@object-ui/i18n` with an object literal
instead of `importOriginal`. Enumerated rather than guessed: 92 files in this
repo mock that package, and the mock lacks `importOriginal` in 26 of them
(plus DeclaredActionsBar, whose i18n mock lacks it while the file uses the
helper elsewhere) — a blast radius no barrel-level module-scope call should
have.
Fixed at the cause, so no test file changes: the component now calls
`useObjectTranslation()` at render. That hook also interpolates on the
provider-less path (objectui#6219), so `{{shown}}` / `{{total}}` are filled
whether or not the host mounted an I18nProvider — which is what the retired
factory was there for. ⛔ No test skipped, quarantined, or converted.
The `defaultValue` is read from the `en` pack rather than retyped, and is
dereferenced inside the component for the same reason the hook call is: a
module-scope `en.common.…` read would reintroduce the identical trap. It also
stops shipping the same English twice in one eagerly-loaded chunk, and makes
an inline default that disagrees with `en` unrepresentable rather than merely
policed by check:i18n-call-site-keys.
Verified over the whole enumerated population plus both named CI casualties
and the react suite: 96 files / 1085 tests, all passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyCc5a4629 to
91876ebCompare❌ Console Performance Budget
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. Which half objected:
📦 Bundle Size Report
Size Limits
|
os-project-manager
commented
Sep 2, 2026
Standing down on |
| build | framework gzip | vs. ceiling |
|---|---|---|
main alone (control: worktree detached to origin/main) | 523,823 B | 177 B under |
| this PR as delivered | 524,476 B | over by 476 B |
| this PR with all ten-pack copy deleted | 524,053 B | still over by 53 B |
The two i18n keys cost 423 B; the mechanism's code alone — constant, helper, note component, zero strings — costs 230 B, which already exceeds the 177 B available. ⇒ No wording of the ruled footnote fits, including no footnote at all. ~600 B were already recovered and kept on their own merits; there is nothing left to shave that closes a 53 B gap.
Why I am not making it green
The two available moves are both refused deliberately:
- ⛔ Raising
PER_CHUNK_GZIP_CEILINGS['framework']is 门禁削弱 — weakening a gate threshold sits on the maintainer's floor, not an execution lane's. - ⛔ Weakening the footnote below what ruling a′ specifies (it must name both N and M) would buy bytes by removing exactly the signal the ruling exists to require. A ruled fix delivered smaller than its ruling is not a delivery.
advancedChunks would turn this check green without removing one byte the browser fetches. That is the first move with its cost hidden, and the gate's own text warns against widening "just to get a green check".
Where the decision lives
#7399 — filed as a maintainer decision covering this PR and #7194 together, since both need ruled user-facing copy in the same locale packs and meet the same 177 bytes. It carries the measurements above, the two-day trend (this chunk read 492.9 KB / 500.0 KB ceiling on 2026-08-31; it reads 512.2 / 511.7 today), and three options with costs.
#7210 and #7225 are now pm:blocked with Blocked-by: #7399 and Unlock-action: re-check PR #7391. ⛔ This PR stays draft and is not enqueued. It is not waiting on review — it is waiting on one governance decision.
Generated by Claude Code
❌ Console Performance Budget
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. Which half objected:
📦 Bundle Size Report
Size Limits
|
…hema
Two files conflicted textually; both were settled as a union of intents. A
third file conflicted SEMANTICALLY without conflicting textually, and needed
the same treatment — it is named below because a merge commit is the only
place that fact is recoverable.
packages/plugin-gantt/src/ObjectGantt.tsx
main inserted `usePermissions()` at exactly the point where this branch
inserts its `useSettledSchema` resolution, and rewrote the `$expand`
computation into an FLS-filtered one (objectui#7230, PR objectui#7428).
Both hook calls and both bodies kept: the query now carries main's
FLS-filtered `$expand` AND this branch's `$top` ceiling probe, and
`reload`'s dependency list is the union (`objectSchema, perms`), so the
expansion is still rebuilt the moment the policy answers. main's removal of
the unused `GanttInteractions` import (PR objectui#7332) is kept as-is.
packages/plugin-calendar/src/ObjectCalendar.tsx
main kept the hand-rolled schema-fetch effect that this branch replaces with
the shared `useSettledSchema`, and rewrote the events memo into the
`{ events, unscheduledRecords }` pair (objectui#7071, PR objectui#7453) over
the same lines. The retired effect is dropped — its `setSchemaResolution`
setter no longer exists — and all of main's rewrite is kept. Both render
additions survive: the row-ceiling note, and the unscheduled area below it.
packages/plugin-gantt/src/ObjectGantt.expandFls-7230.test.tsx
Semantic conflict, no textual one. Its `expandFor` helper waited for `find`
to have been called MORE THAN ONCE — that was how it told main's
schema-refined query apart from the unexpanded query the gantt used to issue
before the schema landed. objectui#7225 ask 2 on this branch deletes that
first query: the object schema now GATES the fetch instead of refining it
afterwards, and `ObjectGantt.fetchGate-7225.test.tsx` pins the count at
exactly one. The wait therefore became unsatisfiable, and all six FLS pins
timed out while the behaviour they grade was fully intact. The helper now
waits for at least one call — the shape the sibling
`__tests__/ObjectCalendar.expandFls-7230.test.tsx` already uses for a
component whose fetch was gated first. No assertion power is given up: every
recorded `find` is schema-dependent by construction under the gate, and a
gantt that stopped fetching altogether still times out rather than reading as
an empty expansion.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyCos-project-manager
commented
Sep 3, 2026
Merge of |
| file | main's intent | this branch's intent | how both survive |
|---|---|---|---|
packages/plugin-gantt/src/ObjectGantt.tsx | FLS-gate $expand (objectui#7230), drop the unused GanttInteractions import | useSettledSchema resolution, $top row ceiling, footnote | both hook calls kept; the query carries the FLS-filtered $expandand the $top probe; reload's dep list is the union objectSchema, perms |
packages/plugin-calendar/src/ObjectCalendar.tsx | the "unscheduled" containment area + the { events, unscheduledRecords } memo (objectui#7071) | useSettledSchema, $top ceiling, footnote | main's rewrite kept whole; the hand-rolled schema effect this branch retires stays deleted (its setSchemaResolution setter no longer exists); both render additions present — ceiling note, then the unscheduled area |
packages/plugin-gantt/src/ObjectGantt.expandFls-7230.test.tsx | pin the FLS filtering | one query per load, schema-gated | see below |
The semantic conflict. That pin's expandFor helper waited for find to have been called more than once — its way of telling main's schema-refined query apart from the unexpanded query the gantt issued before the schema landed. objectui#7225 ask 2 on this branch deletes that first query (the schema now gates the fetch), and ObjectGantt.fetchGate-7225.test.tsx pins the count at exactly one. The wait became unsatisfiable and all six FLS pins timed out while the behaviour they grade was fully intact. The helper now waits for at least one call — the shape the sibling ObjectCalendar.expandFls-7230.test.tsx already uses for a component whose fetch was gated first. Nothing is given up: every recorded find is schema-dependent by construction under the gate, and a gantt that stopped fetching still times out rather than reading as an empty expansion.
Ablation confirms the re-expressed pin still measures what it grades — removing the FLS filter (mutation proved on disk, restored under a trap with absolute paths, restore proved by blob hash back to the HEAD blob): 4 of its 6 pins go red, the two controls stay green, and fetchGate-7225 stays green.
⭐ The "BLOCKED — the framework per-chunk gzip ceiling" section of the description above is DISCHARGED
Read it as history, not as an outstanding fork. With 177afeba1 on main, check:eager-closurepasses at 9a556bdf7 with not one byte of this branch's copy changed:
Console eager closure is 3181.9 KB gzipped across 50 of 518 chunks (budget: 3191.4 KB, headroom: 9.5 KB).
Per-chunk eager budgets (4 chunks weighed):
vendor-objectstack 926.1 KB / 944.3 KB ceiling (headroom 18.2 KB)
i18n-locales 437.5 KB / 444.3 KB ceiling (headroom 6.9 KB)
ui-components 387.0 KB / 389.6 KB ceiling (headroom 2.7 KB)
framework 61.0 KB / 69.3 KB ceiling (headroom 8.3 KB)
Verification, all at 9a556bdf7
- Tests —
pnpm exec vitest runfrom the repo root overplugin-gantt,plugin-calendar,plugin-kanban,plugin-map,plugin-tree,plugin-view,react,i18n: 292 files / 2927 tests, all passing. Every one of this branch's own pins included and green. - type-check —
turbo run type-checkover the eight changed packages, dependency closure built first: 25/25 tasks successful. The edited test file is provably inside the program (tsconfig.test.jsonincludessrc/**/*.test.tsx). - lint —
turbo run lintover the same eight: 9/9 successful, 0 errors (warnings pre-existing). - Gates — each redirected to a file before its exit code was read, never through a pipe:
check:i18n-keys0,check:i18n-drift0,check:control-bytes0,check:eager-closure0,check-changeset-presence0,check-readme-exports0.
Left as draft; auto-merge not enabled.
Generated by Claude Code
✅ Console Performance Budget
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
Size Limits
|
os-project-manager
commented
Sep 3, 2026
Byte blocker discharged · ⛔ but this PR is Clause-② yes and has never been reviewed — gate hung, review commissioned
1. The |
os-project-manager
commented
Sep 3, 2026
⏸ Held on infrastructure, not on the work — the tier review has been killed by HTTP 529 three times
What is blockingThis PR is
All three died before reading anything. This is server-side capacity on the review tier, not a finding about this PR and not a defect in the merge. ⛔ What I am not doing, and why
What happens nextThe review is re-dispatched on a timer, not abandoned; this seat holds a check-in that will retry it. The PR stays draft with the gate on all three carriers until a verified PASS exists.
Generated by Claude Code |
hotlong
commented
Sep 3, 2026
Contract review: PASS — head |
Uh oh!
There was an error while loading. Please reload this page.
os-project-manager
commented
Sep 3, 2026
Post-hoc contract audit of the merged PR — DEFECTS FOUNDThis PR landed without its Clause-② contract review: another actor flipped it ready and merged it at 14:41 while this seat still held it, after three consecutive Tier verification (维护者 2026-08-27 裁), run before adopting anything: the auditor's transcript carries 75 assistant turns, 75 stamped Per the same ruling the parent seat may adopt verbatim or void entirely — ⛔ never abridge or polish. What follows from the rule is the auditor's own text, unedited. Audit of |
Fixes#7210
Fixes#7225
Two maintainer rulings from decision batch #6 (2026-09-02), both of which direct one dispatch on the same components. Each card's half is its own commit so each is independently checkable.
3e3d9f19c546bf93d15425bb6b4c5a46298cframeworkchunk's gzip budget91876eb55Half 1 — #7210 ruling a′: bounded, and never quietly
A non-grid visualisation may fetch the whole filtered result set — a gantt cannot compute a truthful
min(start)tomax(end)from one page, a map fits its camera to every marker, a tree assembled from a page loses every node whose parent fell outside it — but the fetch now carries a platform ceiling expressed as a named constant in the renderer, not an authorable view key. Past it the view draws the first N rows and shows a footnote naming both N and M.Before this, all four issued a
findwith no$topat all: invisible at the 186 rows the card was filed from, the whole table into the browser at 100k, and unbounded by anything an author could write, sincepagination.pageSizecannot cap a query that never carried a cap.The ceiling is 2000, and here is how it was chosen. The ruling asks for one constant across the four, so the binding view sets it. Measured in this repo's jsdom lane (real child views, inline
valueprovider, mount to settled paint) — DOM elements materialised and mount duration:Three of the four hold their DOM flat as rows grow, for structural reasons that will not change: the gantt virtualises its task list and timeline window, the calendar month grid draws at most four events per day cell, and the map auto-clusters above 100 markers.
ObjectTreeis the outlier and therefore the constraint — it flattens every expanded node into the document at a strictly linear 5.2 DOM elements per record, with no virtualisation on that path.Budget applied: keep the worst of the four inside ~10,000 DOM elements — an order of magnitude above Lighthouse's ~1,400-element "excessive DOM size" warning, and the last point where the tree's mount stays under ~3s in an environment that does no layout and no paint at all. 2,000 is where that lands, measured rather than interpolated: 10,406 elements. It is also ~10x the real application result set this card came from, which is the property that keeps the note meaningful when it does appear.
The mechanism.
NON_GRID_ROW_CEILING_TOPis the ceiling plus one probe row, and that is deliberate: with$topexactly at the ceiling, a result set of exactly 2,000 and one of 200,000 come back as the same 2,000 rows, separated only by atotalthe adapter is not obliged to send (QueryResult.totalis optional, and a bare-array response carries none). One extra row makes truncation a fact about the rows in hand, so detection never depends on the adapters least likely to be paging correctly.applyNonGridRowCeilingslices the probe row back off.Pins — the ruling's own, on each surface.
packages/plugin-treechecks it literally, against real renderedtbody trrows, because the tree is the only one whose DOM tracks the result set:$topis the ceiling-plus-one, footnote present naming both numbers;valueset is never capped by us and never footnoted.⛔ The first case would still pass if the footnote were deleted and only the cap kept, so it asserts the note's text and both numbers — silent truncation is the direction the ruling names as dangerous, and a cut-off schedule still looks like a schedule.
Three existing pins moved, deliberately, keeping their point
All three asserted the absence of a cap, and all three were written while half 2 was an open decision —
ObjectGantt.hostDataProp-7210.test.tsxsays so in as many words. The ruling settled it, so they now assert that the cap is the platform's:ObjectGantt.hostDataProp-7210$topundefined$topis the ceiling, and notpagination.pageSize(2)ObjectGantt.elementDataSource$topundefined$topis the ceiling, and not the authoredlimit: 3ObjectMap.elementDataSource$topundefinedWhat they exist to pin is unchanged and is the half that matters: an authored
limit/ a binding'slimit/ a view'spagination.pageSizestill cannot reach these queries. The ceiling is not authorable and must not become so.Half 2 — #7225 ruling B: the convergence, and the gantt's gate
useSettledSchemawas extracted and published with exactly one non-test adopter.ObjectKanban,plugin-view/ObjectViewandObjectCalendarnow call it; each becomes a one-line call, because the hook was extracted from these three shapes. Gate placement stays local, which is what #6482 ruled — and is whyObjectCalendar, the named obstacle, was never actually blocked: the obstacle was about the gate half. It fits via the recipe the hook's own doc comment prescribes for it by name, passing the data source asundefinedfor a render that must not read metadata.⭐ This amends the 2026-08-27 #6482 ruling, which had barred exactly this one-shot multi-package refactor, amended because the cost measured at zero behaviour delta. Not re-derived here.
The kanban's rejected definition read moves from
console.warntoconsole.errorwith a[useSettledSchema]prefix, and its test spy moves with it — now asserting on the channel rather than merely silencing one, since a silenced channel nobody checks is how a moved log goes unnoticed.Ask 2 — the gantt's duplicate query is gated.
reloadlistedobjectSchemain its dependency list, so every load issued two unbounded queries, the first with no$expandat all. Per #6482's per-component measurement standard, this is the profile where gating pays: when the metadata read is the slower of the two — the common case on a coldMetadataCache— the user saw the full three-step paint, raw foreign-key ids, back to the loading placeholder, then the expanded rows. It now issues one query, already expanded.⛔ Gating is not capping. The two halves touch the same lines of
ObjectGantt.reloadand are separate commits and separate pins for exactly that reason.#7232 is reported, not absorbed
Gating requires readiness, and the gantt's schema effect had three exits that returned without settling —
if (!effectiveDataSource) return;,if (!resource) return;, and itscatch. Harmless while nothing waited on them; a query held open forever once something does, i.e. a chart that never loads on a code path that reads as correct.I did not write a bespoke settle, and #7232 is NOT repaired as a card here. The gantt now uses the already-published
useSettledSchema, which settles on every exit by construction — which is what #7232's own body directs: "whoever picks up the gantt's gating … should read this first and add the settle-on-every-exit as part of that change." There is no closing keyword for it here, and both settle-with-nothing paths (nogetObjectSchema; a read that rejects) are pinned behaviourally.The #7231 pin: every assertion kept, its overlap generator replaced
ObjectGantt.staleReloadFinally-7231.test.tsxgenerated its two in-flight reloads out of the duplicate mount query —getObjectSchemaresolved, re-keyedreload, issued a secondfindwhile the first was pending — so all three cases opened withexpect(find.mock.calls.length).toBe(2). That duplicate is exactly what this PR removes, so a test waiting for two would wait forever.The overlap now comes from a pair that is real, is the reason the guard exists, and is untouched by gating: a silent toolbar refresh superseded by a non-silent filter-change reload (what case 3 always used). Not one assertion about the
finallyguard is weakened — same orderings, same flags, same outcomes — and thefinallyguard itself is not modified. The helper'stoBe(1)on mount is now this file's live control on the gate: a regression back to the duplicate query fails here loudly instead of silently restoring the old generator.Verification
All at
c5a46298c(git rev-parse --short HEADof the final commit), everything heavy through the shared verify lock.Tests —
pnpm exec vitest runfrom the repo root over the eight touched packages: 284 files / 2,865 tests, all passing. Type-check: eight packages,tsc --noEmit && tsc -p tsconfig.test.json, exit 0 with 0error TSlines over a freshly built dependency closure. The new test files are provably inside those programs (tsc -p tsconfig.test.json --listFiles: 2 hits in plugin-gantt, 1 in react, 1 in plugin-tree) — atypecheckthat excluded them would be a true sentence about nothing.Reverse verification / ablation — four legs, each with the mutation proved on disk before any run (anchored token counts plus blob hash against the HEAD blob), restored under a
trap … EXIT INT TERMwith absolute paths, and the restore proved by STATE (git diff HEAD,git status --shortempty, blob hash back to the HEAD blob) rather than by an exit code:$topceiling⭐ The third is the discrimination control this PR's "tests unchanged" rests on, and it reproduces the previous seat's 14 of 22 exactly — now on the migrated tree. That is what makes the green non-vacuous.
The fourth is a prediction miss, reported rather than adjusted (also recorded in the pin's own docblock). Direction as predicted, magnitude higher. The prediction assumed the second query came from
objectSchema's identity changing, so a definition settling asnullwould still produce one query. It does not: the second query comes fromobjectSchemaReadybeing in the effect's dependency list, which flips false to true on every path including both settle-with-nothing paths. The gate line and the dependency are two halves of one mechanism and the ablation removed only one.Gates — each run with output redirected before the exit code was read, never through a pipe:
check:i18n-keys,check:i18n-drift,check:i18n-dead-keys,check:control-bytes,check:phantom-deps,check:self-import,check:vi-mock-specifiers,check:vi-mock-inherit,check:side-effects-array,check:element-data-source-declaration,check:readme-exports,changeset:check,type-check:coverage,lint:coverage,check:sdui-registration-pins,check:dist-completeness,check:esm-specifiers,check:doc-types,check:doc-snippets,check:doc-fences— all exit 0.⛔
check:eager-closureis the one exception and it is RED, knowingly and unresolvably from inside this PR. See the section below: it is a fork for the maintainer, not an outstanding task.Lint is the full farm, not a narrowing:
turbo run lint— 47/47 tasks successful, exit 0 — pluslint:root, exit 0. Both warnings-only, all pre-existing. Control-byte self-scan over all changed files withgrep -naP: 0 hits.check:readme-exportsandcheck:sdui-registration-pinswere run against a fullturbo run build(43/43), not a partial one — on the first attempt readme-exports refused with "the population COLLAPSED — this run proves nothing" (17 packages read against a floor of 25), which is a prerequisite failure and not a colour. With everything built it reads 37 of 40 packages and 410 self-imports judged.⛔ BLOCKED, and it is a fork: the
frameworkper-chunk gzip ceiling cannot fit this ruling at allMeasured on one base (
a6e5f7050), control built by detaching this worktree toorigin/main:frameworkgzorigin/mainalone⭐ Read the third row. The two i18n keys across ten packs cost 423 bytes; the ceiling mechanism's code — constant, helper, note component, zero strings — costs 230. So even a completely untranslated footnote does not fit in 177 bytes. There is no version of ruling a′ that lands under the current ceiling, which is why the shaving stopped here rather than continuing.
⛔ The ceiling is not raised. The gate offers that route for intended growth, but raising a gate threshold is a maintainer decision, not this lane's.
What was already paid before concluding that, and is kept because it is right on its own merits: the copy tightened to the ruling's own form ("showing first N of M records; narrow the filter") across ten packs; the fallback default is read from the
enpack rather than retyped, so identical English no longer ships twice in one eagerly-loaded chunk; and two test-onlydata-attributes were dropped from a note that renders both numbers as text anyway. Those recovered ~600 bytes. They were not enough and could not be.The options, all of them the maintainer's:
framework— the gate's own documented route, withPER_CHUNK_BASELINEmoved alongside and the bytes justified. 653 bytes buys a ruled safety footnote in ten languages across four views.@object-ui/i18n's entry statically re-exports all ten (export { default as zh } …). Making that lazy would free far more than any footnote costs, and objectui#5324 / objectui#6795 already name payload-shrink candidates. That is an architectural change to a published entry — a separate ruled card, and out of scope under this dispatch's Clause-② "no".frameworkwent 510.8 KB → 511.5 KB onmainduring the ~90 minutes these measurements took, and objectui#7194's ruled refusal copy lands in the same packs — so it meets the same 177 bytes. Sequencing between the two is the PM's.How the number was measured, including the attempt that was void
The attribution row above is a real ablation, not arithmetic: the two keys were stripped from all ten packs, the console rebuilt, and the report re-read — mutation proved on disk (20 key lines → 0), restored under a
trap … EXIT INT TERMwith absolute paths, restore proved bygit diff HEADbeing empty.enpack — soturboexited 2, the script read the staleeager-closure.jsonfrom the previous build, and it reported the two keys as costing 0 bytes. A stale artifact next to a failed build reads exactly like a clean measurement. The script now refuses to read the report unless the build exited 0, and the module's pack reads are stubbed so the strip compiles.That same ablation then left a mutated
packages/i18n/diston disk after restoring the source, and the nexttype-checkfailed on it with twoerror TS2339s — a stale-distartifact, not a source defect, proved by rebuilding the closure from the restored source and re-running: 8 packages, exit 0, 0error TSlines.The earlier reading, kept for the record
The first build of this branch put
framework0.2 KB over its 511.7 KB per-chunk ceiling. A control build of plainorigin/main(1688986a3) in a second worktree settled whose bytes those were:frameworkorigin/mainalonec5a46298cA per-chunk diff of the two eager-closure reports attributed exactly 1,075 gzipped bytes to this branch (~227 in
@object-ui/react, the rest in eagerly-loaded locale packs). The ceiling is not raised. The gate offers that route for intended growth; the growth was real but the copy was simply longer than it needed to be, so it was paid for instead:framework(theenpack and the provider-less fallback map), so each edit counts double — the fallback map now says so, with the measured headroom, next to the strings;data-ceiling-drawn/data-ceiling-totalwere test-only attributes on a note that already renders both numbers as text; dropped, and the three pins that read them assert the text instead.1688986a3.mainhas moved several times since and the numbers above supersede it — it is kept because it shows the headroom collapsing in real time rather than being consumed by this branch alone.Not in this PR
ObjectGanttRendererforwards no host prop butschema— the one view wrapper that does not, soListView'sdata/onRowClicknever arrive and a live comment says the opposite #7222 —ObjectGanttRendererforwards no host prop. Untouched; forwardingdataremains the explicitly fenced-off wrong fix, since it caps the chart at one page, which is this ruling's forbidden direction by the back door.ObjectGantt's schema-resolution effect has exits that never settle — harmless today, and the exact trap whoever gates it will hit #7232 — see above: reported, its trap discharged for the gantt as a consequence of the ruled migration, no closing keyword.$expandat the remaining five build sites — calendar, gantt and record-detail expand EVERY declared relation with no column list at all #7230, plugin-gantt: the task list is capped at 320px and its Start/End columns take 160px of that, so task names get 53px and truncate to ~7 characters while 864px of chart sits empty #7204 / plugin-gantt: between 640px and 1023px the task-list rows carry NO dates at all — the Start/End columns are gated off and the date sublabel is display:none from 640px up #7224 / finding(plugin-gantt):columnWidthForContainerbranches on container width and returns 110 from all three arms — the breakpoints it documents do nothing #7228 — different defects, own rulings,GanttView.tsxuntouched.packages/coreandpackages/typesare not touched (the onlycorechange is removing three now-unusedextractRecordsimports), so there is no barrel collision with the sibling cards holding those this round.Out-of-scope finding, filed
Filed as #7390:
ObjectGallery(packages/plugin-list/src/ObjectGallery.tsx) issues the same unboundedfind— no$top, no ceiling, and no footnote either. It is a page-shaped surface underListView's paging chrome rather than one of the four the ruling names, and the honest fix for it is plausibly paging rather than this ceiling, so extending a ruled scope by inference was not done here.🤖 Generated with Claude Code
https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
Generated by Claude Code