Uh oh!
There was an error while loading. Please reload this page.
fix(plugin-form): decline to fetch a detail collection with no child object - #6191
Merged
yinlianghui-tw merged 1 commit intoAug 25, 2026
Merged
Conversation
…object `object-master-detail-form`'s detail resolve effect called `getObjectSchema(d.childObject)` with no guard on the key being resolved. A malformed detail entry therefore made the block ask the data layer for an object literally named `undefined` — a real backend receives that query and whatever it returns becomes the console's problem. The effect now skips such an entry and warns, leaving it in place so the grid card shows its config hint and the row-state array stays index-matched. This is the choice `RelatedList` already makes for the same class of missing key, and the sibling child-schema-cache effect in this same component already spelled it `.filter(Boolean)`. The binding-reach probe's generic array sample left `details` as `['name']`, which the declared entry shape (`MasterDetailDetailConfig.childObject` is required) rules out as a publishable configuration; the sample is corrected on that reading, not on the bad call going away. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
Contributor
✅ 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
|
yinlianghui-tw
marked this pull request as ready for review
August 24, 2026 23:52
yinlianghui-tw
enabled auto-merge
August 24, 2026 23:52
This was referenced Aug 24, 2026
Uh oh!
There was an error while loading. Please reload this page.
yinlianghui-tw
deleted the
claude/issue-5940-detail-collection-decline-to-fetch
branch
August 25, 2026 00:12
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#5940
object-master-detail-formcalledgetObjectSchema(d.childObject)with no guard on the key being resolved, so a malformed detail entry made the block ask the data layer for an object literally namedundefined.The discriminating step the card asked for
The card left both of its halves open and named the measurement that decides the second. Both readings, taken from the source rather than from the sample:
1. Which key does the renderer read the child object off? Neither
.objectnor.objectName— it ischildObject, atMasterDetailForm.tsx:341(pre-fix numbering):2. What is a
detailsentry declared to be? An object with a required child-object key — not a bare string.MasterDetailFormSchema.detailsisMasterDetailDetailConfig[], and that interface opens with a non-optionalchildObject: string("Child object name, e.g.'expense_line'"). Every other key on the entry is optional and derived from the child's metadata. It is what all three downstream reads are keyed on:deriveDetail(d.childObject, …), the child-schema cache, and each child fetch's FK scope.So the fixture half is taken:
['name']is not a detail collection any author could publish, and the probe's sample table is corrected — on the declared shape, not on the bad call going away (the #3840 discriminator).The fix, and the precedent it follows
The resolve effect now skips an entry whose
childObjectis unresolved and warns, leaving the entry in place — exactly what the adjacentcatchalready does, so the grid card still shows its config hint anddetailsstays length-matched torawDetails(the row-state array is indexed against it).This is the decline
RelatedListalready makes for the same class of missing key — "has no referenceField/parentId — refusing to fetch all rows" (RelatedList.tsx:498), whose schema fetch is likewise gatedif (api && dataSource?.getObjectSchema). The sibling effect in this same component, the child-schema cache, already spelled it.filter(Boolean). The three now agree rather than failing three ways.What was measured, each direction predicted before running
Verified at
fd8df8399, root vitest (objectui#3378), against the #3840 binding-reach fixture with a call-recording Proxy data source of the same shape as the probe's.Before — predicted two calls, second
getObjectSchema(undefined). Reproduced exactly:After — predicted the second absent and the first still made. Both hold:
⭐ Both halves are asserted, because a "fix" that declined to fetch everything would also make the bad call vanish and would pass an absence-only test. The regression test pins the exact call list, and a second test independently proves a well-formed
{ childObject: 'invoice_line' }still fetches.Reverse verification. The fix was committed first, then reverted alone (
git checkout HEAD~1 -- MasterDetailForm.tsx) under a restoretrap. Mutation confirmed on disk by grepping the text intended to be removed (if (!d.childObject)→ 0 occurrences, the warn string → 0), not by the edit tool's exit code. Predicted red on test 1 only; observed exactly that:Test 2 stayed green, which is correct — a well-formed detail was always fetched, so it does not depend on the guard. The restore leg was confirmed byte-identical (
git statusempty against the commit).Note this call is invisible to the binding-reach probe's assertions: that probe asks whether any call carried the object name, and the first, correct call already satisfies it. The probe was green for as long as the defect was live, so its green is not evidence for this fix — hence an assertion that reads the full call list.
Gates
Each quoted from the gate's own verdict line; exit codes captured by redirect before any pipe.
pnpm lint(full repo,eslint . --no-inline-config) —Tasks: 47 successful, 47 total,0 errors. Run in full under the shared verify lock (VERDICT command-exit 0 · held the lock 178s), so no narrowing is claimed.pnpm --filter @object-ui/plugin-form type-check— exit 0 (tsc --noEmit && tsc -p tsconfig.test.json), after building the dependency closure.pnpm --filter @object-ui/console type-check—VERDICT command-exit 0.packages/plugin-form—Test Files 61 passed (61),Tests 615 passed (615).fd8df8399: plugin-form + both reach probes —Test Files 63 passed (63),Tests 644 passed (644).public-block-binding-reachafter the sample change —Tests 16 passed (16).record-block-record-reach,registry-inputs-spec-parity,masterDetailFormTypeManifest,public-contract,catalog-gallery-render) —Tests 672 passed (672).pnpm check:control-bytes—OK (scanned 5110 tracked text file(s)).pnpm changeset:check— all three checks OK.Branched from today's
origin/main(b37d3f0), which already carries #6177; theformTypeenum it landed was read from the file as it stands, not quoted from before 22:58Z.Scope
The renderer's detail-collection resolution, its test, and the probe's sample table. The sweep turned up one same-family site left untouched and filed instead: #6188 —
record:line_items(LineItemsPanel.tsx:114) readsschema.childObjectthrough the identical unguarded path. That card is out of scope here and #3838 is not addressed here.Generated by Claude Code