You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] the #10288 react-page adapter-contract guard sweeps only app-showcase pages, so the same .records read survived a third time in content/docs #10751
Found while fixing #10469. Recording the mechanism, not proposing a rush: this is the reason that card existed at all.
What happened
One wrong read — result.records off an ObjectStackAdapter.find() result, where the normalized QueryResult only ever declares data — has now been fixed three separate times:
#10288 did the right thing and left a guard behind so there would not be a fourth: examples/app-showcase/test/react-page-adapter-query-contract.test.ts, which sweeps react pages for both traps — recordsOnlyReads() (a .records read with no .data beside it) and unprefixedQueryKeys() (a query option missing its $).
The guard works. Its population is the gap:
constREACT_PAGES=Object.values(pagesasRecord<string,unknown>).filter((p): p is {name: string;kind?: string;source?: string}=>!!p&&typeofp==='object'&&(pas{kind?: string}).kind==='react').filter((p)=>typeofp.source==='string');
pages is the app-showcase page registry. The sweep therefore covers kind: "react" pages inside examples/app-showcase and nothing else. The react-page samples in content/docs are not page modules, so they are invisible to it — which is precisely why instance 3 survived the two code fixes and stayed live in the copy a customer starts from.
The gate derivation agrees: node scripts/pm/dispatch-gates.mjs for a content/docs/ui/react-pages.mdx change names 13 families, and none of them reads a jsx sample for this contract.
The shape of a fix
Extend the guard's population to the react-page samples in content/docs, rather than adding a second scanner. The two detectors are already written, already have a positive control (the scanners fire on a known-bad source) and a census control against a vacuously-green empty sweep; what they need is the docs corpus as an additional source of source strings — the fenced jsx blocks under content/docs/ui/ that call adapter.find(...).
That closes the whole class instead of the one line, which is the reason this is worth filing rather than remembering.
Two things to decide when it is picked up, hence finding rather than a queued fix:
Where it should live. The guard currently sits in examples/app-showcase/test/, and a test in an example app reaching into content/docs would need a check:cross-package-test-inputs declaration. A scripts/check-*.mjs gate in the docs family may be the better home.
How to select blocks. Every jsx fence is not a page source; keying on fences that mention adapter.find( is the obvious narrow start, and the census control has to be re-pointed so an empty docs sweep cannot pass.
Found while fixing #10469. Recording the mechanism, not proposing a rush: this is the reason that card existed at all.
What happened
One wrong read —
result.recordsoff anObjectStackAdapter.find()result, where the normalizedQueryResultonly ever declaresdata— has now been fixed three separate times:examples/app-showcase/src/ui/pages/crm-workbench.page.tsexamples/app-showcase/src/ui/pages/renewals-pipeline.page.ts(examples: the showcase renewals react page passestop: 500toadapter.find, which is not a query option — the rollup silently reads only the first page #10288)content/docs/ui/react-pages.mdx(docs(ui): the react-pages live-data sample readsresult.records, which is always undefined — and its Callout misstates what a dropped option does #10469)#10288 did the right thing and left a guard behind so there would not be a fourth:
examples/app-showcase/test/react-page-adapter-query-contract.test.ts, which sweeps react pages for both traps —recordsOnlyReads()(a.recordsread with no.databeside it) andunprefixedQueryKeys()(a query option missing its$).The guard works. Its population is the gap:
pagesis the app-showcase page registry. The sweep therefore coverskind: "react"pages insideexamples/app-showcaseand nothing else. The react-page samples incontent/docsare not page modules, so they are invisible to it — which is precisely why instance 3 survived the two code fixes and stayed live in the copy a customer starts from.The gate derivation agrees:
node scripts/pm/dispatch-gates.mjsfor acontent/docs/ui/react-pages.mdxchange names 13 families, and none of them reads ajsxsample for this contract.The shape of a fix
Extend the guard's population to the react-page samples in
content/docs, rather than adding a second scanner. The two detectors are already written, already have a positive control (the scanners fire on a known-bad source) and a census control against a vacuously-green empty sweep; what they need is the docs corpus as an additional source ofsourcestrings — the fencedjsxblocks undercontent/docs/ui/that calladapter.find(...).That closes the whole class instead of the one line, which is the reason this is worth filing rather than remembering.
Two things to decide when it is picked up, hence
findingrather than a queued fix:examples/app-showcase/test/, and a test in an example app reaching intocontent/docswould need acheck:cross-package-test-inputsdeclaration. Ascripts/check-*.mjsgate in the docs family may be the better home.jsxfence is not a page source; keying on fences that mentionadapter.find(is the obvious narrow start, and the census control has to be re-pointed so an empty docs sweep cannot pass.Generated by Claude Code
Generated by Claude Code