Blocked-by: #7814
Filed by the domain:metadata PM seat as the third card in the organization_id-strict-equality family, following the same fence #7705 → #7779 used: the dev that held the file measured a mechanism implicating further sites, was instructed to report rather than grow the diff on a serialized file, and did exactly that. #7779's dev reported two of the four sites below; the PM seat grepped the file face at the merge base and found two more.
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 and #7779.
The four remaining sites
Measured on origin/main at 098b62914 (also PR #7814's base). ⚠️ These line numbers will be stale before you read them — #7814 adds 36 lines inside listCommits at :12117, so everything below it shifts by roughly +35, and this file took six merges in one day. #7779's dev found the card's anchor already 15 lines off. Re-measure on your branch point; anchor on the enclosing method name, not the line.
| # |
line |
enclosing method |
table |
where before the org predicate |
| 1 |
12180 |
revertCommit |
sys_metadata_commit |
{ id: request.commitId } |
| 2 |
12455 |
rollbackToPackageCommit (target lookup) |
sys_metadata_commit |
{ id: request.commitId } |
| 3 |
11792 |
duplicatePackage |
sys_metadata |
{ package_id: request.sourcePackageId, state: 'active' } |
| 4 |
11981 |
reassignOrphanedMetadata |
sys_metadata |
{} |
All four carry the byte-identical predicate that #7705 (PR #7771) and #7779 (PR #7814) each replaced one site at a time:
if (request.organizationId) where.organization_id = request.organizationId;
For reference, the two already fixed in this family are deletePackage (:11655, $or landed) and listCommits (:12117, $or landed in #7814).
The evidence is NOT uniform across the four — treat the tiers differently
This is the most important thing on the card. Two sites are measured; two are a grep match with a plausible mechanism and nothing more. Do not let the measured half launder the unverified half.
Tier 1 — sites 1 and 2 are MEASURED, and the symptom is already observable today
#7779's suite drives it: with listCommits fixed, the rollback planner now sees an env-wide commit and asks revertCommit to undo it, and that lookup still cannot resolve an env-wide row. packages/runtime/src/package-list-commits-org-scope.integration.test.ts asserts the current state explicitly:
const rollback = await p.rollbackToPackageCommit({ commitId: c1, organizationId: ACTIVE_ORG });
expect(rollback.success).toBe(false);
expect(rollback.failed.map((f) => f.commitId)).toEqual([c2]);
That assertion is the handoff. It is pinning a known-incomplete state, not a desired one — closing this card means changing those two lines, and if your fix does not make that suite demand an update, you have not reached the site.
Note the direction of travel: #7814 already converted this failure from silent to loud. Pre-#7814 an org-scoped rollback past an env-wide commit answered {success: true, revertedCommits: []} with the changes still live; today it answers success: false naming the commit. So this card is not a regression risk sitting in production unannounced — it is a loud, attributable, non-destructive failure that still blocks a legitimate operation. Fix it on that basis, not on urgency.
Tier 2 — sites 3 and 4 are UNVERIFIED. Step one is to measure, exactly as #7779's step one was
Different table (sys_metadata, not sys_metadata_commit), different callers, and no one has driven them. The mechanism transfers on paper; whether the state is reachable does not. Projected symptoms, offered as hypotheses to falsify:
duplicatePackage — an org-scoped duplicate would copy only the source package's org-scoped rows and silently skip its env-wide ones, yielding a partial copy that reports success.
reassignOrphanedMetadata — an org-scoped reassign would never see env-wide orphans. Since finding orphans is the entire purpose of the function, a class of orphan it structurally cannot see is the sharper version of the defect.
"Latent, not live" is a complete and valuable outcome for either. If nothing reaches these states — no org-scoped caller, no env-wide rows in that table by the time these run — say so with the measurement and leave the code alone. A fix for an unreachable state is worse than no fix: it is untestable weight on the repo's hottest file. #7779's step one came back live and that is why it shipped; do not assume yours will.
The open design question — do NOT reflexively mirror the $or
Sites 1 and 2 differ from every previous member of this family in a way that changes the remedy, and this is the judgment the card is asking for:
where is keyed on id. These are primary-key lookups, so the org predicate is not scoping a scan — it is an authorization filter layered on a unique key, and it fails by answering COMMIT_NOT_FOUND (404) for a row that demonstrably exists. Three candidate remedies, and the card does not pick one for you:
- Mirror the
$or (org or env-wide), consistent with the rest of the family.
- Drop the org predicate entirely — an id lookup does not need it — and let the authorization live where authorization lives.
- Keep it as a genuine authz check, but distinguish "no such commit" from "not yours" instead of collapsing both into 404.
The in-repo evidence favors treating env-wide rows as legitimately reachable by an org caller: #7559 already changed revertCommit to resolve each item's scope from the row rather than from the request, with the in-code rationale that "a batch legitimately mixes an env-wide artifact with an org overlay." The design already accepts this; a target lookup that refuses the same row is inconsistent with the body that would process it. That is an argument, not a verdict — state which option you took and why. If the choice turns on product intent you cannot read out of the code, stop and say so rather than guessing; that is a needs-user-decision, not a coin flip.
Do not copy half the shape — the hazard is live on all four
Every previous card in this family left its no-org branch alone, deliberately. Narrowing it to organization_id IS NULL re-creates the same bug pointed the other way, and the exposure is worst at site 4, where where starts as {}: a no-org reassignOrphanedMetadata already scans every organization's rows. Check what that door is supposed to do before you touch its predicate.
⚠️ Related but out of scope: #7780 is the open product question about a no-org uninstall deleting every organization's rows. It is a maintainer call and it is not this card's to make. If your work on site 4 produces evidence bearing on it, comment on #7780 — do not act on it here.
Pin
Assert the consequence, not the call, on a real engine over a real driver. Both deletePackage suites and the ADR-0067 commit-history suites stub engine.find, which is precisely why none of them could see any member of this family: the question is whether organization_id = 'org' matches a NULL column, which is a property of the driver's SQL and not of a stub's filter().
The worked example is packages/runtime/src/package-list-commits-org-scope.integration.test.ts from #7814 — including why it lives in packages/runtime (metadata-protocol cannot import objectql, dependency cycle) and how it seeds through the real publish path. Required cases per site fixed: the positive, both negative directions (another org's rows, another package's rows), and the no-org door. Plus, for sites 1–2, the updated version of the handoff assertion quoted above.
Sequencing
⛔ packages/metadata-protocol/src/protocol.ts is serialized. PR #7814 must land before this is dispatched — Blocked-by: #7814 above is what the unlock sweep reads.
Whether this is one dispatch or two is the dispatching PM's call, and the tiers are the seam: sites 1–2 share a table, a symptom and a single design decision, and belong together. Sites 3–4 are a different table and start from an unanswered "is it even live". Bundling all four risks the Tier 1 evidence carrying the Tier 2 sites through review unmeasured — which is the specific failure #7779 was written to prevent.
Blocked-by: #7814
Filed by the
domain:metadataPM seat as the third card in theorganization_id-strict-equality family, following the same fence #7705 → #7779 used: the dev that held the file measured a mechanism implicating further sites, was instructed to report rather than grow the diff on a serialized file, and did exactly that. #7779's dev reported two of the four sites below; the PM seat grepped the file face at the merge base and found two more.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 and #7779.The four remaining sites
Measured on⚠️ These line numbers will be stale before you read them — #7814 adds 36 lines inside
origin/mainat098b62914(also PR #7814's base).listCommitsat:12117, so everything below it shifts by roughly+35, and this file took six merges in one day. #7779's dev found the card's anchor already 15 lines off. Re-measure on your branch point; anchor on the enclosing method name, not the line.wherebefore the org predicaterevertCommitsys_metadata_commit{ id: request.commitId }rollbackToPackageCommit(target lookup)sys_metadata_commit{ id: request.commitId }duplicatePackagesys_metadata{ package_id: request.sourcePackageId, state: 'active' }reassignOrphanedMetadatasys_metadata{}All four carry the byte-identical predicate that #7705 (PR #7771) and #7779 (PR #7814) each replaced one site at a time:
For reference, the two already fixed in this family are
deletePackage(:11655,$orlanded) andlistCommits(:12117,$orlanded in #7814).The evidence is NOT uniform across the four — treat the tiers differently
This is the most important thing on the card. Two sites are measured; two are a grep match with a plausible mechanism and nothing more. Do not let the measured half launder the unverified half.
Tier 1 — sites 1 and 2 are MEASURED, and the symptom is already observable today
#7779's suite drives it: with
listCommitsfixed, the rollback planner now sees an env-wide commit and asksrevertCommitto undo it, and that lookup still cannot resolve an env-wide row.packages/runtime/src/package-list-commits-org-scope.integration.test.tsasserts the current state explicitly:That assertion is the handoff. It is pinning a known-incomplete state, not a desired one — closing this card means changing those two lines, and if your fix does not make that suite demand an update, you have not reached the site.
Note the direction of travel: #7814 already converted this failure from silent to loud. Pre-#7814 an org-scoped rollback past an env-wide commit answered
{success: true, revertedCommits: []}with the changes still live; today it answerssuccess: falsenaming the commit. So this card is not a regression risk sitting in production unannounced — it is a loud, attributable, non-destructive failure that still blocks a legitimate operation. Fix it on that basis, not on urgency.Tier 2 — sites 3 and 4 are UNVERIFIED. Step one is to measure, exactly as #7779's step one was
Different table (
sys_metadata, notsys_metadata_commit), different callers, and no one has driven them. The mechanism transfers on paper; whether the state is reachable does not. Projected symptoms, offered as hypotheses to falsify:duplicatePackage— an org-scoped duplicate would copy only the source package's org-scoped rows and silently skip its env-wide ones, yielding a partial copy that reports success.reassignOrphanedMetadata— an org-scoped reassign would never see env-wide orphans. Since finding orphans is the entire purpose of the function, a class of orphan it structurally cannot see is the sharper version of the defect."Latent, not live" is a complete and valuable outcome for either. If nothing reaches these states — no org-scoped caller, no env-wide rows in that table by the time these run — say so with the measurement and leave the code alone. A fix for an unreachable state is worse than no fix: it is untestable weight on the repo's hottest file. #7779's step one came back live and that is why it shipped; do not assume yours will.
The open design question — do NOT reflexively mirror the
$orSites 1 and 2 differ from every previous member of this family in a way that changes the remedy, and this is the judgment the card is asking for:
whereis keyed onid. These are primary-key lookups, so the org predicate is not scoping a scan — it is an authorization filter layered on a unique key, and it fails by answeringCOMMIT_NOT_FOUND(404) for a row that demonstrably exists. Three candidate remedies, and the card does not pick one for you:$or(org or env-wide), consistent with the rest of the family.The in-repo evidence favors treating env-wide rows as legitimately reachable by an org caller: #7559 already changed
revertCommitto resolve each item's scope from the row rather than from the request, with the in-code rationale that "a batch legitimately mixes an env-wide artifact with an org overlay." The design already accepts this; a target lookup that refuses the same row is inconsistent with the body that would process it. That is an argument, not a verdict — state which option you took and why. If the choice turns on product intent you cannot read out of the code, stop and say so rather than guessing; that is aneeds-user-decision, not a coin flip.Do not copy half the shape — the hazard is live on all four
Every previous card in this family left its no-org branch alone, deliberately. Narrowing it to
organization_id IS NULLre-creates the same bug pointed the other way, and the exposure is worst at site 4, wherewherestarts as{}: a no-orgreassignOrphanedMetadataalready scans every organization's rows. Check what that door is supposed to do before you touch its predicate.Pin
Assert the consequence, not the call, on a real engine over a real driver. Both
deletePackagesuites and the ADR-0067 commit-history suites stubengine.find, which is precisely why none of them could see any member of this family: the question is whetherorganization_id = 'org'matches a NULL column, which is a property of the driver's SQL and not of a stub'sfilter().The worked example is
packages/runtime/src/package-list-commits-org-scope.integration.test.tsfrom #7814 — including why it lives inpackages/runtime(metadata-protocolcannot importobjectql, dependency cycle) and how it seeds through the real publish path. Required cases per site fixed: the positive, both negative directions (another org's rows, another package's rows), and the no-org door. Plus, for sites 1–2, the updated version of the handoff assertion quoted above.Sequencing
⛔
packages/metadata-protocol/src/protocol.tsis serialized. PR #7814 must land before this is dispatched —Blocked-by: #7814above is what the unlock sweep reads.Whether this is one dispatch or two is the dispatching PM's call, and the tiers are the seam: sites 1–2 share a table, a symptom and a single design decision, and belong together. Sites 3–4 are a different table and start from an unanswered "is it even live". Bundling all four risks the Tier 1 evidence carrying the Tier 2 sites through review unmeasured — which is the specific failure #7779 was written to prevent.