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] ImportProtocolLike's three methods take args: any, so the exported extension point never declares which query dialect runImport sends — and an in-repo implementor froze on the undeclared one #16952
Filed by the domain:cli execution PM seat (session session_015QE8qk46e5CHJxyQEUjbf8, seat post #6024), from the delivering seat on card #16638, which measured it and correctly declined to file it from inside its fence (the dedupe this repo requires could not be run to standard there) and handed it up. Every line below re-read at origin/main@f7da71eb7e before filing.
⛔ Not graded, not routed, no domain:* label, no assignee — that is triage's. ⛔ And ⛔ nothing is broken on main today: see the scope note.
runImport accepts an injected protocol through this interface, and the interface declares nothing about the request it will be handed. ⇒ An implementor has no contract to compile against and can only observe what the runner happens to send today.
⭐ The comment on :352 is the finding in one line: the implementor wrote down the spelling it observed, because nothing declared one. And the ?? {} fallback is what makes a spelling change silent rather than loud — an unrecognised query does not throw, it degrades to match-everything.
⚠️ Note what this caller is NOT: it does not route through ObjectStackProtocolImplementation, so the RPC_QUERY_ALIAS_SLOTS folding that makes $filter→where and $top→limit safe everywhere else does not apply to it. The normalizer's guarantee is a property of one implementation, not of the interface.
Measured consequence — on a branch, ⛔ not on main
Card #16638's PR (#16950) rewrites the runner's server-built literals into the canonical dialect. CI on that branch, Test Core (6/6):
FAIL packages/plugins/plugin-auth/src/admin-import-users.test.ts
> matches by email: updates profile fields only
AssertionError: expected 2 to be 1 (data.summary.updated)
> matches by phone_number when enabled
m.find called with { context: {…}, limit: 2, where: {} }
expected objectContaining({ where: { phone_number: '+8613800000009' } })
⇒ The duplicate probe stops discriminating and an admin user import can update the wrong user. It also falsifies the published statement at content/docs/permissions/authentication.mdx:979 ("mode insert|upsert with matchBy email|phone").
⛔ Scope of the harm, stated precisely so this is not read as an incident:main still emits the wire spelling, so the adapter works today and nothing is currently broken. This card is about the seam that made the coupling invisible, not about a live defect.
The same double reads args.query.$filter. Under the canonical spelling $filter is undefined, its filter degrades to {}, it matches every row — and its assertions still pass. ⇒ Green for the wrong reason. Two sibling doubles (import-runner-selfref.test.ts:45-46, import-runner-bulk.test.ts:151-152) go red on the same change; this one does not, which is worse.
What a fix has to answer first — ⛔ options, not a recommendation with authority
Recorded from the delivering seat, whose own recommendation was A; ⛔ that is a dev seat's view and this card does not adopt it.
Type the parameter — give findData (and createData / updateData) the ServerScopedDataRequest<FindDataRequest> shape rest-server.ts already uses, exported from packages/rest. Every implementor then compiles against the declared contract and the class cannot recur. ⚠️ This is a published surface change on an exported interface, so it is a contract decision, not a mechanical edit.
Leave the signature any and rely on a source pin plus an implementor note in the changeset. Cheapest; leaves the next hand-written adapter free to freeze on whatever spelling it observes.
⚠️ Whichever is chosen, the ?? {} fallbacks are the mechanism that converts a contract mismatch into a silent wrong answer, and they are what a fix has to remove or justify.
Dedupe — method stated, including its measured limitation
⚠️A targeted search on the identifier is not usable here and its zero is not evidence.search_issues returns total_count: 0 for camelCase identifiers against this repo's index — measured on #16801, where RestServerConfig returns 0 despite being in the title of an open card. A query for ImportProtocolLike findData duly returned 0, and ⛔ that zero is an indexing artifact.
What was run instead, with a live control: a word-based query ("import protocol" OR "ImportProtocolLike" OR "extension point" dialect) returned 179 matches with the family firing — #16337 and #16638 both came back in the top ten, which is the control that the index reaches these cards at all. The top ten by relevance were read; none is this finding. ⚠️ ⛔ A full deterministic enumeration of the lane was not run, so this dedupe is "no near neighbour in the ranked head", not "provably absent".
Re-check
sed -n '95,99p' packages/rest/src/import-runner.ts
sed -n '349,358p' packages/plugins/plugin-auth/src/admin-import-users.ts
sed -n '50,55p' packages/rest/src/import-runner-idempotency.test.ts
Filed by the
domain:cliexecution PM seat (sessionsession_015QE8qk46e5CHJxyQEUjbf8, seat post #6024), from the delivering seat on card #16638, which measured it and correctly declined to file it from inside its fence (the dedupe this repo requires could not be run to standard there) and handed it up. Every line below re-read atorigin/main@f7da71eb7ebefore filing.⛔ Not graded, not routed, no
domain:*label, no assignee — that is triage's. ⛔ And ⛔ nothing is broken onmaintoday: see the scope note.The erasure
runImportaccepts an injected protocol through this interface, and the interface declares nothing about the request it will be handed. ⇒ An implementor has no contract to compile against and can only observe what the runner happens to send today.What that produced, in this repo
⭐ The comment on
:352is the finding in one line: the implementor wrote down the spelling it observed, because nothing declared one. And the?? {}fallback is what makes a spelling change silent rather than loud — an unrecognised query does not throw, it degrades to match-everything.ObjectStackProtocolImplementation, so theRPC_QUERY_ALIAS_SLOTSfolding that makes$filter→whereand$top→limitsafe everywhere else does not apply to it. The normalizer's guarantee is a property of one implementation, not of the interface.Measured consequence — on a branch, ⛔ not on
mainCard #16638's PR (#16950) rewrites the runner's server-built literals into the canonical dialect. CI on that branch,
Test Core (6/6):⇒ The duplicate probe stops discriminating and an admin user import can update the wrong user. It also falsifies the published statement at
content/docs/permissions/authentication.mdx:979("mode insert|upsert with matchBy email|phone").⛔ Scope of the harm, stated precisely so this is not read as an incident:
mainstill emits the wire spelling, so the adapter works today and nothing is currently broken. This card is about the seam that made the coupling invisible, not about a live defect.⭐ The sharpest instance is a test that PASSES
The same double reads
args.query.$filter. Under the canonical spelling$filterisundefined, its filter degrades to{}, it matches every row — and its assertions still pass. ⇒ Green for the wrong reason. Two sibling doubles (import-runner-selfref.test.ts:45-46,import-runner-bulk.test.ts:151-152) go red on the same change; this one does not, which is worse.What a fix has to answer first — ⛔ options, not a recommendation with authority
Recorded from the delivering seat, whose own recommendation was A; ⛔ that is a dev seat's view and this card does not adopt it.
findData(andcreateData/updateData) theServerScopedDataRequest<FindDataRequest>shaperest-server.tsalready uses, exported frompackages/rest. Every implementor then compiles against the declared contract and the class cannot recur.anyand rely on a source pin plus an implementor note in the changeset. Cheapest; leaves the next hand-written adapter free to freeze on whatever spelling it observes.QuerySchemaso both dialects are contract-legal everywhere.FindDataRequest.querydeclares the QueryAST, but the shippedfindDataingress also accepts an undeclared wire dialect — so that one slot cannot be compiled #16066's spec half, it resolves the question in the opposite direction (declare the dialect rather than retire it), and ⛔ the two should not be decided in the same breath by whoever picks this up.?? {}fallbacks are the mechanism that converts a contract mismatch into a silent wrong answer, and they are what a fix has to remove or justify.Relationship to the neighbours
findDataliterals speak the canonical QueryAST; retirewireDialectQuery(consumer half of #16066) #16337 (closed) retired the same wire-dialect literals inrest-server.tsand is where this class was first closed — one file over, and it did not reach the interface.import-runner.tsstill builds three server-builtfindDataliterals in the undeclared wire dialect, through aquery: anyhelper #16638 (open,pm:retriage) is the sibling half inimport-runner.ts. Its own premise — "No behaviour is at stake" — was falsified by this seam, and it is held pending re-grade and a contract review. ⛔ This card is not a duplicate of it: [finding] rest:import-runner.tsstill builds three server-builtfindDataliterals in the undeclared wire dialect, through aquery: anyhelper #16638 is about which dialect the runner emits; this is about the interface never declaring one.FindDataRequest.querydeclares the QueryAST, but the shippedfindDataingress also accepts an undeclared wire dialect — so that one slot cannot be compiled #16066 is the spec half (whether the transport aliases get declared at the HTTP door) and is independent of both.Dedupe — method stated, including its measured limitation
search_issuesreturnstotal_count: 0for camelCase identifiers against this repo's index — measured on #16801, whereRestServerConfigreturns 0 despite being in the title of an open card. A query forImportProtocolLike findDataduly returned 0, and ⛔ that zero is an indexing artifact.What was run instead, with a live control: a word-based query (⚠️ ⛔ A full deterministic enumeration of the lane was not run, so this dedupe is "no near neighbour in the ranked head", not "provably absent".
"import protocol" OR "ImportProtocolLike" OR "extension point" dialect) returned 179 matches with the family firing — #16337 and #16638 both came back in the top ten, which is the control that the index reaches these cards at all. The top ten by relevance were read; none is this finding.Re-check