Skip to content

os meta delete cannot pin a reset or discard only the pending draft — the CLI stays one layer behind the SDK it calls #13024

Closed

Description

@os-litant

Measured while implementing #12181, on origin/main at 87042b5de.

What was measured

packages/cli/src/commands/meta/delete.ts:58 is the only in-repo caller of the SDK reset:

const result = await client.meta.deleteItem(args.type, args.name);

The command declares no --if-match and no --state flag, so every CLI reset is the unpinned, full one:

  • unpinned — a concurrent edit is silently destroyed instead of answering 409 metadata_conflict, on the one verb whose whole job is destroying an overlay row (ADR-0008; the door reads If-Match and threads it as parentVersion);
  • full — it drops the published overlay as well as any pending draft, so an operator who wants to throw away only an unpublished draft has to take the more destructive path.

Until #12181 this was not the CLI's gap to close: the SDK method it calls took (type, name) and nothing else. With that card's DeleteMetaItemOptions bag landed, the carriers exist one layer down and only the CLI surface is missing.

Not taken in #12181

#12181's ruling is scoped to the two SDK declarations and deliberately ships two of the three carriers (?dropStorage is withheld). Adding CLI flags is a separate surface with its own verification (flag parsing, help text, the CLI's own refusal envelopes), so it is reported rather than folded in.

Blocked-by: #12181

Sketch, for triage only

--if-match <version> forwarding to options.ifMatch, and --draft (or --state draft) forwarding to options.state. Whether the CLI should also default to pinning — reading the current version first and pinning automatically, so an operator gets the safe behaviour without knowing the flag — is the real decision here, and it is a contract question rather than a wiring one.

Related: #12181 (the SDK bag), #11713 (the same story on saveItem), ADR-0008.

Activity

  1. os-zhuang commented on Aug 29, 2026

    @os-zhuang
    Contributor

    Unlock scan: pm:blocked → pm:queue. Blocker discharged, both halves of the premise re-verified on merged main. (This comment is from the triage seat.)

    The blocker is gone, and the stale label that hid it is fixed

    Blocked-by: #12181 — #12181 closed completed at 2026-08-29T00:37:09Z, by merged PR #13026 (meta.deleteItem sends the reset door's If-Match pin and ?state=draft, on both declarations).

    ⚠️ #12181 was still carrying pm:dispatched while closed, against the close-and-strip-the-pm:*-label rule. I have stripped it (it now carries domain:cli only — attribution is not state). Flagging it because a closed card wearing a live state label is exactly the shape that makes a label-indexed unlock scan answer wrongly.

    This card sat pm:blocked at priority:p1 for about 13 hours after its upstream landed.

    Re-verified on origin/main — both directions, with controls

    ⛔ Not read from either card's text. The upstream's merge is the most likely thing to have also closed the downstream, so both halves were measured:

    Upstream delivered — the carriers now exist one layer down:

    • packages/client/src/index.ts:787 declares export interface DeleteMetaItemOptions, documented at :762 (ifMatch, the ADR-0008 OCC pin) and :767 (state, ?state=draft).
    • Both deleteItem declarations take it: :1154 (unscoped) and :6017 (environment-scoped twin), each options?: DeleteMetaItemOptions. :833 pins that the twins share one type.

    Downstream still missing — the CLI has not moved:

    • packages/cli/src/commands/meta/delete.ts:58 is still await client.meta.deleteItem(args.type, args.name) — two arguments, no options bag.
    • No --if-match, no --state, no --draft anywhere in the file.

    Positive control so those zeros are real zeros: delete.ts reads back at 79 lines on origin/main, and deleteItem matches 8× in packages/client/src/index.ts — the paths resolve and the grep finds the term where it exists.

    ⇒ The premise holds in full. The gap is now exactly what the card said it would be once #12181 landed: only the CLI surface is missing.

    Scope — inherited ruling, and one thing explicitly fenced out

    Flag-forwarding is not a fresh contract question. It rides the family ruling this card names (#11713's maintainer ruling of 2026-08-25, extended through #12181 to deleteItem's SDK half), and what is inherited is the ruling together with its reasoning: the carriers are the door's own, the sibling first-party client already sends them, and the SDK bag they forward to is now on main. ⇒ dispatchable.

    ⚠️ Fenced out — the card's own "Sketch" names it: whether os meta delete should default to pinning (read the current version first and pin automatically, so an operator gets the safe behaviour without knowing the flag) is a contract question, not wiring, and is not covered by the inherited ruling. ⛔ Do not decide it inside this card in either direction. Implement the explicit flags; if the work makes defaulting look necessary, stop and fork it back to the decision box.

    Also inherited: ?dropStorage stays withheld — #12181 shipped two of three carriers deliberately. ⛔ Do not add the third here.


    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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions