fix(react)!: dataSource at the renderer seam is the published DataSource contract - #9310
Conversation
…rce contract
`SchemaRendererProvider`'s `dataSource` prop and the context type every
`useSchemaContext()` consumer reads back were both declared `any`, so a bare
string passed where the host's adapter belongs raised nothing at compile time
and failed at runtime on the first `find()`. Both are now
`DataSource | null | undefined` — the spelling `useSettledSchema` in this same
package already used — so the two absences that really occur stay expressible
and everything that is not an adapter is refused.
Red call sites are repaired by typing, never by casting at the seam:
- `useClientNotifications` declares `getClient` as the adapter CAPABILITY it is
and probes it with a type guard, instead of reaching through `any`.
- `useDataScope`'s path walk annotates its accumulator; its published return
type is unchanged.
- `ObjectGallery` drops a hand-rolled `{ find }` stand-in for the real contract,
and the now-redundant cast at its `useSettledSchema` call.
- the `kind:'react'` page stops passing a truthy empty object as its "no
adapter yet" stand-in, so the `if (!dataSource)` guards written for that state
fire; the memo identity the module constant existed for is kept, because the
absent adapter is itself render-stable.
- calendar, gantt and kanban collapse a null context adapter to the single
spelling their widget prop declares.
- five redundant `as any` reads of this context in `@object-ui/fields` are gone,
along with `LookupField`'s local re-declaration of the imported context as a
`Context` of `any`, which laundered its `dataSource` read while looking typed.
Test doubles keep every injected value byte-for-byte and mark the crossing, so
no assertion moves: a double that stubs only the members its path calls is not a
host, and completing them would change which capability probes fire.
Both directions are pinned against the real compiler, with controls that fire if
the harness ever stops resolving the real types. The documentation probe from
the card — a bare string in this package's README provider example — now fails
`check:doc-snippets`, where it used to exit 0 with zero diagnostics; the same
gate caught the quick-start guide teaching an empty object, which is repaired.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
✅ 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
|
CI's "Build Docs" job caught the one injection site the type-check union in the previous commit did not cover: `apps/site` was excluded from that filter, and `LiveSplitDemo` handed the provider a truthy empty object as its "no adapter" stand-in — the same shape already corrected in the `kind:'react'` page. Every preset this component renders is a static schema; the object-bound examples live in `InteractiveDemo` and `SchemaThumbnail`, which inject the docs gallery adapter. So this surface has no adapter, and `undefined` is what that is. Still a module constant, because the memo below keys on its identity. The union is corrected with it: dropping `--filter='!@object-ui/site'` puts the site's own `type-check` back in scope, which is where this would have surfaced locally. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
✅ 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
|
Bring the branch up to date with `main` (19 commits behind) so CI runs against the current tree. No source change of this branch's own is touched. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
✅ 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
|
…ng it is `Type Check` went red on this branch only after `main` merged in: objectui#8021's `guide-schema-rendering-data-context-8021.test.tsx` injects a plain scope bag as `SchemaRendererProvider.dataSource`, and legs A/C/D exist to measure exactly that — the renderer binds the context's `dataSource` as the expression `data` root. The file landed after this branch's own sweep, so it is the one injection site the sweep could not have marked. Same treatment as the other 33 test files here: an explicit `as unknown as DataSource` at the injection, with the file's own note naming the second meaning. The injected value is byte-for-byte what it was, all six assertions are unchanged, and the declaration is untouched — nothing widens, nothing is skipped. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
✅ 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
|
✅ 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
|
Contract reviewHead judged: ① Derived judgments
1 & 2 — read off the diff, not the body. Both sites are literally 3 — the absences are the contract, not a hole in it. A Studio preview, a 4 — and this is the judgement I most want on the record. Completing the doubles into full adapters would change which capability probes fire ( 5 — the ② Semver
③ Boundary flags — the two reds, ruled
Nine required contexts and a live merge queue. The seat re-measured this independently and was right; I was wrong. It matters here because I had been treating "nothing is required, so I must hold everything by hand" as the operating rule.
|
| flag | disposition |
|---|---|
useCascadingOptions.ts:45 keeps its binding-level as any |
accepted. Its only reads are the formValues / data tail objectui#7206 explicitly leaves undecided; narrowing the binding would red exactly those two reads. Declared, not silent. |
FieldWidgetProps.dataSource?: unknown still launders four read sites |
accepted. Another package's own declared choice; this card does not move it, and each of the four names it in a comment. |
ObjectGallery's envelope-sniffing block |
accepted. The widening is stated in place and the question it raises is about the adapters, not about this seam. |
objectui#9309 (ObjectGallerySchema.filter typed unknown) |
accepted, filed. It is why the one $filter forward had to be asserted; the assertion names the card. |
objectui#7483 (ObjectView props typed any) |
accepted. Same direction, deliberately untouched, with a note owed there after this lands. |
Verified by this seat on the merged head
origin/main had moved under the branch. Merged in as a merge commit — ⛔ no rebase, no force-push — and re-ran the check the required set turns on:
pnpm exec turbo run type-check --concurrency=2
Tasks: 81 successful, 81 total
os-verify-lock: VERDICT command-exit 0 · held the lock 438s
⭐ Whole workspace, no --filter exclusion. The previous round's declared narrowing (--filter='!@object-ui/site') turned out to be the load-bearing one — apps/site is a dependent of @object-ui/react and has a real type-check — and that exclusion is what let a red through to CI. It is gone, and the membership read behind it is now measured rather than declared.
Independence
Implemented-by: claude/issue-7912-datasource-contract (mode:subagent — a subagent has no session of its own)
Reviewed-by: session_01UzHd6hDYatoDn17BuwKxnZ (domain:ui PM seat)
⛔ Stated plainly: for this lane a clause-② review is default-tier self-review plus the gates, not an independence-qualified ruling — the independence clause and the downgrade fuse bind the spec seat, not this one. What carries the verdict is the readings above, not this seat's confidence.
Verdict
PASS, with the two reds ruled rather than waived: Doc Snippet Type Check lands red under option B at a named cost with objectui#9346 holding the measurement, and Skill Example Check is dispatched as objectui#9311.
Arming waits on the nine required contexts going green on this head — ⛔ not on "no red anywhere", which is the standard I was wrongly applying, and ⛔ not on a subset I pick by eye.
Generated by Claude Code
⛔ Correction to this PR's contract review — the ruling in ③ was against the written protocolMy review above ( That ruling was wrong, and not as a matter of judgement — it contradicts a written landing pre-check I should have re-read before overriding. ⭐ Where that leaves itI tried to disarm auto-merge on noticing; the route answered ⇒ The remedy is to close both reds, and both now need the maintainer:
|
Fixes #7912
Implements decision batch #68's ruling (comment 5565350616, maintainer verbatim 「同意」):
SchemaRendererProvider'sdataSourceprop andSchemaRendererContextType.dataSourceare the published
DataSourcecontract, notany. "Keepanyand document that the hostadapter's shape is not TypeScript's job" was refused.
tag-shaped fragment does not survive a GitHub body, and the subject here is a JSX attribute,
so "the SchemaRendererProvider element" is written out rather than drawn.
Execution note 1 — the two blast radii, measured separately
Posted on the card before this PR was opened (comment 5647354308), with the method and the
caveats. The short version, measured on
origin/mainat243fc8317over the 33 packages thatdepend on
@object-ui/react, both tiers per package, with only@object-ui/react'sdistre-emitted so no build cascade enters the reading (baseline: 66 tasks, 0 diagnostics):
SchemaRendererContextType.dataSource(everyuseSchemaContext()reader)⭐ The ordering is the reverse of the card's prediction, by 7.4x. ① was expected to be the
expensive half because it infects the whole tree; it is the cheap half, because every reader
in the tree already guarded (
ctx?.dataSource,if (!dataSource)) and none of them everreached past
find/getObjectSchema. ② is the expensive half, because the injection pointsare overwhelmingly test doubles that were never complete adapters. Of ②'s 52, exactly one
is production code.
Two caveats that belong with the numbers, both recorded on the card: under ① the react and
plugin-list test tiers are NOT MEASURED (a package's
type-checkistsc --noEmit && tsc -p tsconfig.test.json, and the first leg failing short-circuits thesecond); and ① additionally produced 6 TS7016 diagnostics in three packages that are a build
cascade from plugin-list being unable to emit its own
.d.ts, not call sites — they areexcluded from the 7.
The shipped type
Both sites are
DataSource | null | undefined— the spellinguseSettledSchemain this samepackage already used, which the card itself cites as the precedent. The absences are part of
the contract, not a weakening of it: a Studio preview, a
kind:'react'page rendered beforethe host's adapter connects, and a widget probe driving
apiFetchalone all render withnothing bound, and every reader already guards for it. What the union refuses is everything
that is not an adapter — a string, an empty object, a data bag, a partial adapter missing a
required member. All five refusals are pinned.
Against ②'s reading, the union clears the 8 sites that legitimately pass
undefinedornulland adds 3 production sites where a nullable context adapter meets a widget prop that declares
only
dataSource?: DataSource.Execution note 2 — every red site repaired by typing, none by casting at the seam
useClientNotificationsdeclaresgetClientas the adapter capability it is(
DataSourcedoes not promise it) and probes it with a type guard.useDataScope's path walk annotates its accumulator; the hook's published return type isunchanged,
anybefore and after.ObjectGallerydrops a hand-rolled{ find }stand-in for the real contract, and the castat its
useSettledSchemacall, which the honest seam made redundant.as anyreads of this context in@object-ui/fieldsare gone — and so isLookupField's local re-declaration of the imported context as aContextofany, whichlaundered its
dataSourceread while every read site looked perfectly typed.prop declares.
Test doubles keep every injected value byte-for-byte and mark the crossing with the
repo-idiomatic
as unknown as DataSource, one explanatory note per file: 65 marked sites in 33files. A double that stubs only the members its path calls is not a host, and completing
those doubles would change which capability probes fire (
typeof ds.getObjectSchema === 'function') and therefore change what the tests measure. That population is now greppable,which is what objectui#9308 needed.
Two runtime behaviour changes, both toward "no adapter"
@object-ui/components'kind:'react'page passed a truthy empty object as its "no adapteryet" stand-in, so it walked past every
if (!dataSource)guard written for exactly thatstate and failed later, at the call. It now hands over the absent adapter itself. The memo
identity the module constant existed for (objectui#2954) is preserved:
nullis aprimitive, so the provider's memo is unaffected.
nulltoundefinedat the context read.Nothing else moves: no value flowing through this key changes.
Instruments
The type pin —
packages/react/src/context/__tests__/SchemaRendererContext.dataSourceType.pin.test.ts,the same tsc-driven harness as objectui#9197's
RecordContext.dataSourceType.pin.test.ts. Itgoes through the PUBLISHED surface —
ParametersOFtypeof SchemaRendererProvideratindex 0, and
ReturnTypeOFtypeof useSchemaContext(generic parameters are written aswords here because a GitHub body eats bracket-shaped fragments even inside backticks) —
rather than the internal interface, because "no
consumer can be told anything about it" is the defect. 14 rows: 6 accepted, 5 breaking,
3 controls.
Reverse verification (prediction written down before the run: exactly the 5 BREAKING rows
flip, and the 3 CONTROLs must stay refused). Ablating both declarations back to
anyon thecommitted tree, with the mutation proved on disk (typed declarations 2 to 0,
anydeclarations 0 to 2, blob hash changed) and restored by a trap:
Exactly the 5, and the 3 controls (a misspelled prop key, a missing required prop, and
DataSource's required members being visible) stayed refused — which is what makes the flipattributable to the declaration rather than to the harness degrading types to
any. Restoredbyte-identically (blob equals the HEAD blob); the pin is green again at
c3e363b5c.--reporter=basic, which vitest 4 does not have.That was a harness startup error and NOT MEASURED — re-run with the default reporter for
the reading above.
Execution note 4 — the documentation probe now has something to say. The card's planted
probe is the provider example in
packages/react/README.mdwithdataSource={adapter}replaced by
dataSource={'not-an-adapter'}. Planted first, on the untouched base tree, so the"unmodified" arm is the real base:
The gate was running and had nothing to say; it now says it. The probe is not committed —
both plants were restored byte-identically (blob equals the HEAD blob).
⭐ The same gate caught a real red that is not the probe:
content/docs/guide/quick-start.mdtaught the empty object (TS2740). Repaired in the contract's own terms — that example renders
inline
data, so it has no adapter and now says so — and the surrounding prose updated(AGENTS.md #2).
pnpm check:doc-snippetsis back to exit 0, 646/646, 0 failed atc3e363b5c.Verification, at
c3e363b5cEverything below ran through
../objectstack/scripts/pm/os-verify-lock.shwhere it is heavyverification, and the verdicts are that wrapper's VERDICT line, not a bare exit status.
turbo run type-checkover...@object-ui/reactminus@object-ui/site, i.e. 33 packages, builds included, both tierseach: 66 tasks successful, 66 total, 0 diagnostics (
VERDICT command-exit 0).examples/schema-catalog(objectui#9273: a package-scoped run is not the blast radius), intwo locked runs from the repo root: 350 files / 4882 tests and 770 files / 8845
tests, all passed, both
VERDICT command-exit 0. Union: 1120 files, 13727 tests.package.jsonplus.github/workflows(this repo has noscripts/pm/dispatch-gates.mjs), all exit 0:check:doc-snippets,check:doc-types,check:doc-fences,check:doc-example-ids,check:readme-exports,check:new-line-citations,check:phantom-deps,check:unused-deps,check:self-import,check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:test-path-roots,check:element-data-source-declaration,check:unreferenced-sources,check:lockfile-integrity,check:control-bytes,check:changeset-claims,node scripts/check-changeset-presence.mjs, andpnpm changeset:check(the real spelling — there is nono-majorscript; the file runsinside that one).
pnpm lint:coveragereports 46/46 packages linted with 0 outstanding errors.check:*farm and the repo-wide ESLintscan are CI's runs (
lint.yml), and full-repopnpm testis CI's. CI convergence and theready/queue flip are left to the PM seat.
Clause-② — the published TS accept set narrows
needs:contract-reviewis hung on both limbs (this PR and the card). The changeset states thetype change with a FROM/TO, shaped after objectui#8604 / objectui#9187: 41 packages sit in one
fixedgroup somajoris unavailable, and the breaking half ships asminorcarrying aBREAKING marker. ⛔ Neither limb's carrier is cleared by this seat.
In-flight overlap
PR objectui#9144 touches
packages/react/src/__tests__/SchemaRenderer.predicateEnvelopeConfigBag.test.tsx,which this PR also touches. The overlap is textually tiny and the union is mechanical: #9144
changes what that probe asserts about the legacy
propsconfig bag; this PR adds a note blockafter the imports and one
as unknown as DataSourceon the context value handed to theprovider element. Take both — the cast is required for that file to compile against the
narrowed context no matter which assertions #9144 lands. If the merge queue rebuilds #9144
after this, its new provider-element lines need the same cast, and the pin test names the
reason.
Also checked and clear: objectui#9289 (landed;
RecordContext.tsx, a different file in thesame directory — its two residual
useRecordContext() as anybindings are objectui#9304 andare deliberately NOT in this PR), objectui#9138 (
plugin-calendar/src/ObjectCalendar.tsx, adifferent file from the
index.tsxthis touches), objectui#8021 (a different guide, alreadylanded), objectui#7561 (
filter-builder.tsx, untouched here).⛔
packages/components/src/ui/**is untouched (AGENTS.md #7).Acceptance notes
ObjectView's props typedany) follows the same direction and isdeliberately untouched. Execution note 5 asks for a note there once this lands; that note is
posted after this PR opens, not before.
useCascadingOptions.ts:45keeps its binding-levelas any(
useContext(SchemaRendererContext) as any) on purpose: its only reads are theformValues/datatail that objectui#7206 explicitly leaves undecided, and narrowing thebinding would red exactly those two reads. Declared rather than silent.
FieldWidgetProps.dataSource?: unknownis now the only thing laundering the mergedvalue at four of the five repaired
@object-ui/fieldsread sites — the context leg is typedand cast-free at all five, and each of the four names that upstream declaration in a
comment. That declaration is a deliberate choice in another package's own surface
("Left structural (
unknown)"), so this card does not move it.SchemaRenderer.tsx's reader-side empty-object stand-in (the one that feeds theexpression scope when no adapter is bound) is unchanged and not red: it substitutes a value
downstream of the seam rather than injecting one through it.
ObjectGalleryenvelope-sniffing block now has a realQueryResultOFanydeclaration above three branches, two of which read undeclared envelopes(
records, a bare array). Every branch is kept and the widening is stated in place, becausewhether any adapter really answers with those two is a question about the adapters. No PR
will touch that block before someone asks that question; successor: none.
Out-of-scope findings, filed and not repaired here
that
bindpaths anddata.*predicates resolve against (useDataScopewalks the injectedvalue;
SchemaRendererbinds it asdata; five production widgets read it that way). Thisruling declares the adapter meaning, so the bag meaning is no longer expressible by a
conformant host without a cast. That is the one thing this narrowing costs, it is measured
(65 sites / 33 files), and the choice between giving the data scope its own key, retiring it,
or declaring a union is a second published-surface decision that is not taken here.
ObjectGallerySchema.filteris typedunknownwhile its own docblocksays it is forwarded verbatim as
$filter, and it is the one view schema of six in@object-ui/typesthat is notany[]. It is why the single$filterforward inObjectGalleryhad to be asserted rather than declared; that assertion carries a commentnaming the card.
Dedup for both ran against the repo-scoped open-issue list, paginated to exhaustion (450 open
issues, last page short) with two known-hit controls (#7912 and #7483 both present), then
grepped over titles and bodies: zero prior cards for either.
Follow-up after CI — the two gates the union did not cover, now measured
CI went red twice on
c3e363b5ca, both inside the one surface the type-check union aboveexcluded. The exclusion was declared, not hidden — and it turned out to be the load-bearing
one, so the 66/68 green did not cover the two surfaces CI failed on.
apps/siteHAS its owntype-checkscript and IS a dependent of@object-ui/react, so--filter='!@object-ui/site'is exactly what let the first one through. The union is corrected: the exclusion is gone.
RED 1 — "Build Docs". Cost: one injection site.
apps/site/app/components/LiveSplitDemo.tsxhanded the provider{ dataSource: {} }— thesame truthy empty-object stand-in already corrected in the
kind:'react'page, and the samecorrection applies: every preset that component renders is a static schema (the object-bound
demos live in
InteractiveDemoandSchemaThumbnail, which inject the docs gallery adapter),so it has no adapter and now says
undefined. Still a module constant, because the memo belowit keys on identity. Fixed in
64c05fdbf. Verified two ways:turbo run build --filter='@object-ui/site'— 35 tasks successful, VERDICT command-exit 0,with
@object-ui/site:builda cache miss that really executed (next build).turbo run type-check --filter='...@object-ui/react' --concurrency=2 --continuewith no exclusion — 68 tasks successful, 68 total, 0 diagnostics, and@object-ui/site:type-checklikewise a cache miss that executed. That is where this wouldhave surfaced locally.
RED 2 — "Skill Example Check". Cost: one marked skill example, and it is NOT repaired here.
Reproduced locally (the job-log blob host is refused by this container's egress, so the
assertion below is a local reproduction, not a quote of the CI annotation):
The marked example, under "Via DataSource methods (in plugin code)", destructures
dataSourcefromuseSchemaContext()and calls.findon it with no guard.It is a true positive, not collateral. A provider with no adapter bound is a real state —
this PR's own repairs are two instances of it — and
useSchemaContext()throws only whenthere is no PROVIDER, not when the adapter is absent. So that guidance, copied into a plugin
mounted on such a surface, throws at the first call. The compiler now says so, which is the
signal this card exists to buy.
Why it is not repaired in this PR. The file is published
skills/**, a governed surface,and the repository's own authority agrees —
node scripts/check-governed-queue-guard.mjs --test:Folding a one-line guard into this PR would convert an ordinary PR into one that cannot land
without a maintainer approval. It is reported for routing to the skills seat instead.
The minimal repair, for whoever takes it: guard before use inside that fence — one line,
if (!dataSource) return [];or equivalent. ⛔ The other option the gate names (drop theos:checkmarker) would be the wrong one here: the example is meant to compile, it simplyneeds the guard the contract now requires.
⛔ Not an option: narrowing the declaration so that
{}, or an unguarded read, becomesassignable again. That undoes the card. It was also measured: strict
DataSourcewithout thetwo absences forces casts at the 8 internal sites that legitimately inject
undefinedornull, thekind:'react'page's "no adapter yet" window among them.Status of the two gates as of
64c05fdbf: Build Docs green locally, both ways. SkillExample Check still red on that single fence, by design, until the skills-side guard lands —
its self-test is green, so the harness itself is sound.
Fix-the-red round at
e2c31aa1d—Type Checkgreen, the other two reportedThe three red contexts on
373c1c8e4carried no file-anchored annotation on the pull requestpage and the Actions job-log blob host is refused by this container's egress policy, so they
were NOT MEASURED remotely. Every reading below is a local reproduction, and each verdict
is the one the command printed for itself.
Type Check— reproduced, repaired, greenReproduced first,
pnpm exec turbo run type-check --filter=@object-ui/componentsthrough theverify lock:
(The generic parameter is written as a word — a bracket-shaped fragment does not survive a
GitHub body.)
⭐ It is this branch's red, and it is new. The file is objectui#8021's, landed on
mainafter this branch's own sweep and merged in at
373c1c8e4. It injects a plain scope bag as theprovider's
dataSourceon purpose — legs A, C and D exist to measure exactly that, becausethe renderer binds the context's
dataSourceas the expressiondataroot. It is the oneinjection site the sweep could not have marked, so it gets the same treatment as the other 33
files here: an explicit
as unknown as DataSourceat the injection with the file's own note,naming objectui#9308. 65 marked sites becomes 66, in 34 files.
⛔ Nothing widened, nothing cast at the seam, nothing skipped: the declaration is untouched, the
injected value is byte-for-byte what it was, and all six assertions in the file are unchanged
and passing.
Doc Snippet Type Check— still red; the reason is measured, and it is not repairable hereThe gate's own controls all fired in that run —
⚠️ The gate returns exit 2 = PRECONDITION NOT MET on an
@object-ui/typesresolved to the builtdist/index.d.ts, the sentinel produced TS2305, the positive produced 0 — so these arereadings, not a degraded harness.
unbuilt tree, which is NOT MEASURED rather than a failure; the closure named by
--build-filter(34 packages) was built first, both times.All three blocks are objectui#8021's, and all three arrived with the same merge: this branch was
at 646/646 judged, 0 failed before it and is at 649/649 judged, 3 failed after it. Each teaches
the SECOND meaning of this key — the page's own values published through
dataSourceand readback under the
data.path prefix. objectui#9308 is the open card on that very question.⛔ There is no repair available inside this PR. A cast inside a published fence teaches the
reader to defeat the contract this PR establishes (execution note 2); widening the declaration
is the card itself; declaring the blocks in the gate's ledger is a quarantine. What is left is
rewriting what the pages teach — and
content/docs/guide/schema-rendering.mdis PINNED to thecurrent teaching by objectui#8021's own leg A, which reads the Data Context fence off the page,
branches on whether it carries a provider
dataSource=attribute, and asserts the AccessingData fence renders
Welcome, John!. Moving the page off meaning 2 moves a landed card's pin.⇒ Measured and filed as objectui#9346, blocked on objectui#9308. ⛔ Deliberately not
repaired here.
Skill Example Check— unchanged, objectui#9311One finding, the same one, byte-for-byte:
skills/objectui/guides/data-integration.md:304:26,TS18049.Semantic phase: 14 of 14 ts fence(s) judged, 1 failed. Publishedskills/**is agoverned surface; ⛔ untouched.
The membership read the previous round's declared narrowing needed
turbo ls --filter='...@object-ui/react'names 33 packages, and@object-ui/siteis amember of that set — it has a real
type-checkscript (fumadocs-mdx && next typegen && tsc --noEmit), so the requiredType Checkjob runs it. The earlier round excluded it. It is nowmeasured and green (31 tasks successful,
VERDICT command-exit 0), and so is the wholeworkspace.
Verification at
e2c31aa1dHeavy runs went through
../objectstack/scripts/pm/os-verify-lock.sh; the verdicts are thatwrapper's VERDICT line, never a bare exit status.
turbo run type-checkover the WHOLE workspace (what the requiredType Checkjob runs):81 tasks successful, 81 total,
VERDICT command-exit 0.of a test-only edit —
packages/components: 270 files / 2603 tests passed,VERDICT command-exit 0.turbo run lint --filter=@object-ui/components— 2 tasks successful, 0 errors,956 pre-existing warnings, exit 0; the edited file itself reports 0 errors and 0 warnings.
and this repo's
lintisturbo run lint(per-packageeslint .), with no type-awarelinting configured, so this diff cannot move the verdict on a file it did not touch. The
repo-wide scan is CI's run.
check:control-bytes,check:phantom-deps,check:self-import,check:test-path-roots,check:new-line-citations,check:vi-mock-specifiers,check:doc-fences,check:doc-example-ids,check:changeset-claims.no published surface.
check:*farm, the repo-wide ESLint scanand full-repo
pnpm testare CI's runs; CI convergence and the ready/queue flip are the PMseat's.
GET /repos/objectstack-ai/objectui/rules/branches/mainat 2026-09-13:
Lint,Type Check,Build & E2E,Test (shard 1/4)throughTest (shard 4/4),Build Docs,Changeset Declaration.Doc Snippet Type CheckandSkill Example Checkare not in that set, so the two remaining reds are reported contexts rather than queue
blockers — they are still real findings, and each has a card.
This PR was produced by an ObjectUI development agent seat in Claude Code; the session is
https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ.🤖 Generated with Claude Code
https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
Generated by Claude Code
Generated by Claude Code