Filed by the domain:metadata PM seat, as the fence promised on #7705: that card's dev measured a mechanism that implicates this second site, was instructed to report rather than grow the diff on the repo's hottest file, and did exactly that. This is the follow-up card, not a duplicate.
No domain:* label applied — routing labels are the triage seat's territory. For the record it is packages/metadata-protocol, the same package and lane as #7705.
The defect
packages/metadata-protocol/src/protocol.ts:12085 (in listCommits, against sys_metadata_commit) carries the byte-identical predicate #7705 just fixed one function away:
const where: Record<string, unknown> = { package_id: request.packageId };
if (request.organizationId) where.organization_id = request.organizationId;
An org-scoped listCommits therefore misses every commit row stored env-wide (organization_id IS NULL) — the same NULL semantics, the same engine, the same strict equality.
Why this is not speculative
#7705's dev did the diagnostic work that makes this a measured inference rather than a grep match, and both halves of its fork were settled there:
- The engine is not the variable.
findData — the GET /api/v1/data/... path — issues this.engine.find(object, options) at protocol.ts:6803 on the same engine instance. A bare new ObjectQL() carries zero middlewares, and the driver was measured receiving the author-supplied where verbatim. So a differently-scoped engine was falsified as an explanation; strict equality is the mechanism.
- The equality demonstrably drops env-wide rows. On a real engine over a real SQLite driver,
deletePackage with {packageId, organizationId} selected 1 of 4 rows and left 3 env-wide rows behind.
Nothing about that reasoning is specific to sys_metadata. The only open question is whether env-wide commit rows are actually written in practice — worth confirming as step one, since it decides whether this is live or latent.
Different table, different symptom — do not treat it as #7705 part two
#7705's symptom was orphaned rows after uninstall (a data-lifecycle defect). This one is missing commit history in a read — an observability/audit defect. Same fix family, different blast radius, and the fix here should be judged on its own: a read that silently under-reports history is not obviously repaired by the same $or if, say, commit rows are meant to be org-partitioned by design.
Fix sketch, to be verified not assumed
The #3115 shape, as applied in #7705 (PR #7771):
if (request.organizationId) {
where.$or = [
{ organization_id: request.organizationId },
{ organization_id: null },
];
}
Note what #7705 deliberately did not do, because it applies here too: it did not narrow the no-org branch to organization_id IS NULL. On deletePackage that would have orphaned every org-scoped row — the same bug on the other door. Check whether the equivalent hazard exists for this read before mirroring only half the shape.
The in-package precedent is packages/metadata-protocol/src/sys-metadata-repository.ts:896-899 (#3115, the "orphaned draft" bug). ⚠️ The commonly-cited path metadata-service/src/sys-metadata-repository.ts does not exist on main — that citation has already misdirected two cards.
Pin
Assert the consequence, not the call: seed commit rows in both scopes, call listCommits with an org id, and assert the env-wide rows are returned — plus the negative direction, that another org's commit rows are not. Both existing deletePackage suites stubbed engine.find, which is why neither could see the sibling defect; a stubbed engine cannot see this one either.
Sequencing
⛔ Do not dispatch this while another card holds packages/metadata-protocol/src/protocol.ts — that file is serialized and took five merges in one day. #7705 / PR #7771 must land first.
Filed by the
domain:metadataPM seat, as the fence promised on #7705: that card's dev measured a mechanism that implicates this second site, was instructed to report rather than grow the diff on the repo's hottest file, and did exactly that. This is the follow-up card, not a duplicate.No
domain:*label applied — routing labels are the triage seat's territory. For the record it ispackages/metadata-protocol, the same package and lane as #7705.The defect
packages/metadata-protocol/src/protocol.ts:12085(inlistCommits, againstsys_metadata_commit) carries the byte-identical predicate #7705 just fixed one function away:An org-scoped
listCommitstherefore misses every commit row stored env-wide (organization_id IS NULL) — the same NULL semantics, the same engine, the same strict equality.Why this is not speculative
#7705's dev did the diagnostic work that makes this a measured inference rather than a grep match, and both halves of its fork were settled there:
findData— theGET /api/v1/data/...path — issuesthis.engine.find(object, options)atprotocol.ts:6803on the same engine instance. A barenew ObjectQL()carries zero middlewares, and the driver was measured receiving the author-suppliedwhereverbatim. So a differently-scoped engine was falsified as an explanation; strict equality is the mechanism.deletePackagewith{packageId, organizationId}selected 1 of 4 rows and left 3 env-wide rows behind.Nothing about that reasoning is specific to
sys_metadata. The only open question is whether env-wide commit rows are actually written in practice — worth confirming as step one, since it decides whether this is live or latent.Different table, different symptom — do not treat it as #7705 part two
#7705's symptom was orphaned rows after uninstall (a data-lifecycle defect). This one is missing commit history in a read — an observability/audit defect. Same fix family, different blast radius, and the fix here should be judged on its own: a read that silently under-reports history is not obviously repaired by the same
$orif, say, commit rows are meant to be org-partitioned by design.Fix sketch, to be verified not assumed
The #3115 shape, as applied in #7705 (PR #7771):
Note what #7705 deliberately did not do, because it applies here too: it did not narrow the no-org branch to
organization_id IS NULL. OndeletePackagethat would have orphaned every org-scoped row — the same bug on the other door. Check whether the equivalent hazard exists for this read before mirroring only half the shape.The in-package precedent is⚠️ The commonly-cited path
packages/metadata-protocol/src/sys-metadata-repository.ts:896-899(#3115, the "orphaned draft" bug).metadata-service/src/sys-metadata-repository.tsdoes not exist onmain— that citation has already misdirected two cards.Pin
Assert the consequence, not the call: seed commit rows in both scopes, call
listCommitswith an org id, and assert the env-wide rows are returned — plus the negative direction, that another org's commit rows are not. Both existingdeletePackagesuites stubbedengine.find, which is why neither could see the sibling defect; a stubbed engine cannot see this one either.Sequencing
⛔ Do not dispatch this while another card holds
packages/metadata-protocol/src/protocol.ts— that file is serialized and took five merges in one day. #7705 / PR #7771 must land first.