Skip to content

seed-loader resolveSoleOrganizationId swallows every sys_organization read failure behind a comment naming one benign cause, so a transient outage silently seeds org-less rows #12852

Description

@claude

Found while triaging the parameterless-catch read seams for #12753 (see PR #12851 for the full 11-site triage). Filed unassigned, and ⛔ with no domain:* — that is triage's single-producer field, per the convention recorded on #8901.

⛔ Not repaired in #12851: that PR's scope is a gate-header record, and this is a source fix in another package.

The seam

packages/metadata-protocol/src/seed-loader.ts, resolveSoleOrganizationId():

try{constrows=awaitthis.engine.find('sys_organization',{fields: ['id'],limit: 2,context: {isSystem: true}}asany);if(Array.isArray(rows)&&rows.length===1){ ... returnid ? String(id) : undefined;}}catch{// sys_organization may not exist (single-tenant runtime) - ignore.}returnundefined;

Why it is wrong

The comment names ONE benign cause and the catch swallows every cause. This is the #4728 shape verbatim: a real outage, a permission refusal or a driver fault is answered exactly like "this runtime has no sys_organization table".

The method's own JSDoc states the consequence: the value is used "to stamp business seed rows when the caller pinned no config.organizationId", and without it the seeds land "org-less (→ invisible under strict org-scoping)". So a transient read failure during seeding writes rows that are silently invisible afterwards, and nothing in the run says so — the seed report has an errors field, and this path does not touch it.

Note the asymmetry that makes this cheap to justify: the sibling probe on the objectql side, probeInstallOrganizations, had the SAME shape and was repaired by PR #9817 to bind the parameter and ask the declared predicate. This one was not.

The fix, which is the declared one

}catch(error){if(!isMissingTableError(error))throwerror;// packages/metadata/src/errors.ts}

isMissingTableError is the single entry in READ_FAILURE_DISCRIMINATORS in scripts/check-durability-degradation-log-level.mjs and is exactly the benign class the comment already names, so the discrimination costs nothing and the JSDoc's "or when sys_organization is absent" stays true — while every other cause stops being answered as an emptiness.

Measurement context

This seam is 1 of 11 read seams with a parameterless catch on origin/main @ 6f0fec3d0, and 1 of only 2 of those 11 graded genuinely wrong rather than correct-but-undeclared. It is not covered by #8901's cohort (no accumulator above the try), and not by #8896 / #8906 / #8895, all closed and none naming it.


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions