Uh oh!
There was an error while loading. Please reload this page.
fix(plugin-detail): stop the loading-frame record is not defined noise on record:alert - #5797
Merged
os-zhuang merged 1 commit intoAug 23, 2026
Conversation
…ise on record:alert
`record:alert`'s bare/`${…}` `visible` predicate is evaluated on every render
(Rules of Hooks), including the frame before `useRecordContext().data` loads.
In that frame `usePredicateRecordContext` binds an empty context bag by
design (no `record` key), so a predicate referencing `record.*` faults with
`record is not defined` — logged on every load, including working ones,
since the same predicate resolves fine one frame later. The banner already
hides unconditionally while unloaded, so the verdict in that frame was never
consulted. Skip evaluating the predicate while `record` hasn't loaded (same
condition the early-return already used); a genuinely-broken predicate still
faults and still logs once `record` is populated.
Fixes#5776
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EuPCi56cnGyykygi3z9w4mContributor
✅ 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-zhuang
marked this pull request as ready for review
August 23, 2026 11:39
Uh oh!
There was an error while loading. Please reload this page.
os-zhuang
deleted the
claude/issue-5776-record-not-defined-loading-frame
branch
August 23, 2026 11:40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#5776
What was wrong
record:alert'svisiblepredicate (usePredicateRecordContext+useCondition) is evaluated on every render — Rules of Hooks means the hook must run even in the frame beforeuseRecordContext().datahas loaded. In that framerecordisundefined, andusePredicateRecordContextdeliberately binds an empty context bag then (its own doc: "No row → bind NOTHING", so a host-supplied ambientrecordisn't shadowed by a record that merely hasn't loaded yet).A bare-string (or
${…}-wrapped) predicate referencingrecord.*against that empty bag faults with a bareReferenceError: record is not defined, whichExpressionEvaluator.evaluate's catch logs viaconsole.warnon every page load — including the correct, working ones, since the exact same predicate resolves fine one frame later oncerecordpopulates. The banner's own visibility was never wrong (it already hides unconditionally while!record); only the diagnostic was permanently misleading.Re-measured on today's
origin/main(cd6a328fe, post@objectstack/*17.2.0 refresh) — the mechanism and message are unchanged from the objectstack#11247 evidence at the old pin.The fix
record-alert.tsxnow derives onerecordLoadedflag and uses it in two places that used to diverge slightly (!record || Object.keys(record).length === 0vs. no gate at all):useConditionisrecordLoaded ? predicateInput : undefined—evaluateCondition(undefined)short-circuits totruewithout ever touching the evaluator, so nothing is evaluated (and nothing can fault) in a frame whose banner is hidden regardless.!recordLoaded— the exact same expression, not a re-derived one, so the two can never drift apart.A predicate that is genuinely broken (bad field, bad syntax) is not touched by this change — once
recordis populated it's evaluated for real, faults for real, and still logs for real. That pairing is pinned directly (see tests below).Tests
New file
packages/plugin-detail/src/renderers/__tests__/record-alert.loadingFrameDiagnostic.test.tsx, realtoPredicateInput/useConditionpipeline (objectui#3941 doubling convention — only the data layer is mocked):record.*predicate loggedFailed to evaluate expression: ${record.status == 'in_review'}/record is not defined, for both eventual polarities.recordpopulates.bogus_unbound_field.status == 'x') against an already-loaded record still logsFailed to evaluate expression— proving this isn't the diagnostic silenced outright.Full existing
record:alertsuites (record-alert.test.tsx,.rowBinding.test.tsx,.visibleWhen.evidence.test.tsx) plus the new file: 39/39 passed. Fullplugin-detailpackage: 868/868 passed (pnpm exec vitest run packages/plugin-detail/, from repo root per this repo's invocation guard).pnpm --filter @object-ui/plugin-detail run type-check: clean. Targetedeslint --no-inline-configon both touched files: 0 errors (pre-existingno-explicit-anywarnings only, matching this file's existing style).node scripts/check-changeset-presence.mjs/check-changeset-no-major.mjs: both pass with the addedpatchchangeset.Scope
Deliberately narrow to
record:alert's bare-string/legacy-${…}path — the sizing datum on the source card measured this as the only surface currently authoring bare-string predicates (all 6 othervisibleWhenvalues across 34 pages are{dialect:'cel'}envelopes). No behavior change to any predicate verdict; diagnostic hygiene only.Generated by Claude Code