Found while fixing #10789 (PR #10964), by sweeping the repo for the same conflation class. Not fixed there — different package, different blast radius, and the consequence here is a PRODUCT answer rather than a reported status, so it wants its own triage.
The defect
packages/services/service-package/src/index.ts carries its own local
normalizeRows (:177-181), the same three-dialect flattener
metadata-protocol exports:
functionnormalizeRows(result: any): any[]{if(Array.isArray(result))returnresult;if(result&&Array.isArray(result.rows))returnresult.rows;return[];}Its two consumers both run raw SQL through the engine seam and then read
emptiness as a fact about the data:
get(packageId, version) (:290) — normalizeRows(result), then
if (rows.length === 0) return null; ⇒ "this package is not installed".list() (:324) — normalizeRows(result).map(...) ⇒ "no packages are installed".
A seam that cannot answer returns null rather than throwing —
InMemoryDriver.execute() logs Raw execution not supported in InMemory driver
and returns null, which is the shape pinned on a real booted driver by
packages/cli/src/commands/migrate/duplicates.null-seam.test.ts (#10677). Both
call sites therefore flatten it to [] and report an absence they never
measured.
This is the third instance of one class: a seam that cannot answer is absent,
not empty.#10677 / PR #10788 fixed it for os migrate duplicates, #10789 /
PR #10964 for backfillSeedTenancy. Both landed the same consumer-side shape —
judge the seam by whether it returns a RESULT SET, not by whether execute
exists.
Why this one may be worse than its two siblings
The other two report a status an operator reads. These return product
values that callers act on: get() returning null is indistinguishable from
"not installed", and list() returning [] from "nothing installed". Whether
anything downstream then writes on that reading (a re-install, a hydration
skip) is exactly what triage should establish — I did not measure it, and it is
the difference between a cosmetic report and data loss.
Not measured here
- Which hosts actually reach these two methods on a non-answering seam.
service-package is a devDependency of packages/runtime and its
sys_packages rehydration path is driven by app-plugin.disabled-seed.test.ts
against a real driver. Whether the DevPlugin zero-install stack (a real
InMemoryDriver, plugin-dev/src/dev-plugin.ts:473-482) reaches
get()/list() at boot is unverified — I only established the conflation by
reading, not by booting. - The mongodb driver, for the same reason it is out of scope on the two
sibling cards: not loaded, not measured. - Whether the right fix is the shared predicate or a local one. Note that
metadata-protocol deliberately does not publish its isResultSet from
the package index (no consumer outside its own module, and its index comment
names a test-only export as the shape to catch before it ships), and the CLI
keeps its own copy — so a third consumer arriving is the first real evidence
that unifying them is worth doing, which is itself a decision rather than a
drive-by.
Refs
#10677 · PR #10788 · #10789 · PR #10964
Found while fixing #10789 (PR #10964), by sweeping the repo for the same conflation class. Not fixed there — different package, different blast radius, and the consequence here is a PRODUCT answer rather than a reported status, so it wants its own triage.
The defect
packages/services/service-package/src/index.tscarries its own localnormalizeRows(:177-181), the same three-dialect flattenermetadata-protocolexports:Its two consumers both run raw SQL through the engine seam and then read
emptiness as a fact about the data:
get(packageId, version)(:290) —normalizeRows(result), thenif (rows.length === 0) return null;⇒ "this package is not installed".list()(:324) —normalizeRows(result).map(...)⇒ "no packages are installed".A seam that cannot answer returns
nullrather than throwing —InMemoryDriver.execute()logsRaw execution not supported in InMemory driverand returns
null, which is the shape pinned on a real booted driver bypackages/cli/src/commands/migrate/duplicates.null-seam.test.ts(#10677). Bothcall sites therefore flatten it to
[]and report an absence they nevermeasured.
This is the third instance of one class: a seam that cannot answer is absent,
not empty.#10677 / PR #10788 fixed it for
os migrate duplicates, #10789 /PR #10964 for
backfillSeedTenancy. Both landed the same consumer-side shape —judge the seam by whether it returns a RESULT SET, not by whether
executeexists.
Why this one may be worse than its two siblings
The other two report a status an operator reads. These return product
values that callers act on:
get()returningnullis indistinguishable from"not installed", and
list()returning[]from "nothing installed". Whetheranything downstream then writes on that reading (a re-install, a hydration
skip) is exactly what triage should establish — I did not measure it, and it is
the difference between a cosmetic report and data loss.
Not measured here
service-packageis a devDependency ofpackages/runtimeand itssys_packagesrehydration path is driven byapp-plugin.disabled-seed.test.tsagainst a real driver. Whether the DevPlugin zero-install stack (a real
InMemoryDriver,plugin-dev/src/dev-plugin.ts:473-482) reachesget()/list()at boot is unverified — I only established the conflation byreading, not by booting.
sibling cards: not loaded, not measured.
metadata-protocoldeliberately does not publish itsisResultSetfromthe package index (no consumer outside its own module, and its index comment
names a test-only export as the shape to catch before it ships), and the CLI
keeps its own copy — so a third consumer arriving is the first real evidence
that unifying them is worth doing, which is itself a decision rather than a
drive-by.
Refs
#10677 · PR #10788 · #10789 · PR #10964