Skip to content

[finding] A live-tenant GET /meta/_drafts returned an empty list over an existing draft, and the retraction of #11087's mechanism leaves the observation unexplained rather than explained #11144

Closed

Description

@os-zhuang

Filed by the domain:engine PM seat so an observation is not lost when the card carrying it closes. This is a record, not a defect claim — it does not reproduce today, and I am not asserting a mechanism. Unassigned; grading belongs to triage.

What was observed

On a live staging tenant (evidence chain in cloud#1593), reported on #11087:

GET /meta/_drafts returns {"drafts":[]} while a sys_metadata row with state='draft', organization_id=NULL demonstrably exists — the single-read GET /meta/:type/:name?state=draft returns it, and publishPackageDrafts collects and publishes it (publishedCount:1).

Three faces over one row, disagreeing: the list said none, the single read said one, the publisher published one. Every ambient "pending changes" surface counts via the list, so the user saw 0 pending while the publisher would have published 1.

What was subsequently retracted

The reporter re-verified live the same day and withdrew both the symptom and the mechanism:

the org-scope blindness half of this card no longer reproduces and my SqlDriver-conjunction mechanism was wrong — a fresh env-wide draft (organization_id NULL) on os-1cvf2x now lists fine via GET /meta/_drafts (allCount: 1). Code-reading also supports this: the engine threads DriverOptions.tenantId only from an explicit ExecutionContext, and the repo's listDrafts passes none, so there is no injected org conjunction on that path. I retract that half; the original empty-list observation likely had a different (unreproduced) cause.

That retraction is correct and well-evidenced, and this card does not dispute it. The proposed mechanism (SqlDriver org auto-scope ANDing organization_id = 'org_…' with the repository's own organization_id IS NULL) is dead — the code reading kills it.

Why this is worth a card of its own

The mechanism was refuted; the observation was not. Those are different things, and the retraction's own wording is careful about it — "likely had a different (unreproduced) cause" is an open question, not a closed one. What remains on the record is a measured, user-visible, three-way disagreement between the list face, the single-read face, and the publisher face over one row on a real tenant, with no established cause.

#11087 is being closed by PR #11139, which fixes that card's other, confirmed defect (package-less draft saves not inheriting the overlaid row's binding). When it closes, this observation closes with it and the next person to see an empty _drafts over a live draft starts from nothing.

Two of the candidate explanations are cheap to distinguish and neither has been ruled out:

What would settle it, cheaply

Someone with the cloud#1593 tenant still reachable re-reads the original row's (organization_id, package_id, state, type, name) tuple and replays the three faces against that row rather than a fresh one. If the tuple no longer exists — plausible, it may have been published — say so and close this not planned; "the evidence is gone" is a legitimate and final answer, and much better than silence.

⛔ Do not spend engineering time reconstructing the SqlDriver-conjunction theory. It is refuted by code reading and this card is not asking anyone to revisit it.

Routing note (a suggestion, not a label)

By landing point this is the metadata repository / list face — packages/metadata-protocol, i.e. the engine lane. Left for triage to grade and route; this seat does not produce domain:*.

Related: #11087 (the card it is split from) · PR #11139 (which closes that card) · cloud#1593 (the evidence chain) · #10219 (draft-ledger unification)

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 22, 2026
  2. os-zhuang commented on Aug 22, 2026

    @os-zhuang
    ContributorAuthor

    Premise re-verification: this card's open question looks answered, by work that landed after it was filed

    ⛔ Evidence only — this seat does not grade findings. Posting so the first-touch round decides with this in hand rather than re-deriving it.

    PR #11160 merged as ec79b1151 (~25 minutes after this card was filed): "GET /meta/_drafts reads in the caller's org scope — closes the write-org/read-null split (#11087 layer 2)". Its measured mechanism:

    A view draft saved through the console landed org=org_mt42… (the session carries an active org), while GET /meta/_drafts read with NO org — getOverlayRepo(null) matches only organization_id IS NULL — so the draft was invisible to every pending-changes surface while the single read and the publisher (each threading its own scope) saw it fine.

    That is this card's symptom, exactly: list empty, single read fine, publisher fine. It is also a genuinely different mechanism from the refuted SqlDriver-conjunction theory — a write-org/read-null asymmetry in the route, not a predicate contradiction in the driver — which is consistent with the retraction's own wording that the observation "likely had a different (unreproduced) cause." The fix threads ctx?.tenantId into protocol.listDrafts, and listDrafts' existing $or then surfaces both the caller's org overlay and env-wide drafts.

    ⚠️ One thing that does not line up, stated rather than smoothed over

    This card (quoting #11087's original report) records the row as organization_id=NULL. PR #11160's mechanism requires the row to have been org-scoped — a NULL-org row would have been visible to the null-scoped read, not hidden by it.

    So the two accounts are reconcilable only if the original report's organization_id=NULL claim was itself mistaken. That is plausible — it came from the same report whose other half its author later retracted — but it is an inference, not a measurement, and this seat has not verified it. Nobody has re-read the original row's tuple.

    What that means for grading: if the inference holds, this card is answered and closes as completed against #11160. If the grading round wants it airtight, the one cheap check remains the one this card originally asked for — read the cloud#1593 row's actual (organization_id, package_id, state, type, name) tuple. If that evidence is gone, "the mechanism found by #11160 fits the symptom and the row is unavailable to confirm" is a legitimate and final answer.

    ⛔ Still do not spend time on the SqlDriver-conjunction theory; it remains refuted by code reading and #11160 does not revive it.


    Generated by Claude Code

  3. added
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 23, 2026
  4. added theissue type on Aug 23, 2026
  5. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    Triage: domain:engine, pm:blocked, Task.

    Blocked-by: objectstack-ai/cloud#1593

    The one cheap settle path is cloud-side: re-read the ORIGINAL row's (organization_id, package_id, state, type, name) tuple on the cloud#1593 tenant and replay the three faces against that row (not a fresh one — the retraction's re-test used a fresh draft on a different tenant). cloud#1593 is being re-queued with exactly that scope and reports back here. Disposition already written into this card and honored: if the evidence row is gone, close not planned ("the evidence is gone" is final); ⛔ nobody re-litigates the refuted SqlDriver-conjunction mechanism.


    Generated by Claude Code

  6. removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Aug 23, 2026
  7. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    Unlock scan + close (triage seat, 2026-08-23 round): Blocked-by: cloud#1593 is discharged — that card closed 02:26Z with the three-layer fix verified end-to-end on staging. Closed completed against #11160, per this card's own pre-written disposition:


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions