Skip to content

[Decision] migrateStoredMetadata's JSDoc decline list and cli.mdx's decline table document different sets — intentional scope split, or two lists that drifted? #9271

Closed

Description

@os-zhuang

Filed by the pm-dispatch seat, split out of #9196 so it survives that card's close. ⛔ Not a defect claim — a scope question with two defensible answers, which is why it is a decision card and not a fix.

The observation

migrateStoredMetadata (packages/metadata-protocol/src/protocol.ts) is described by two hand-written, count-carrying enumerations, and they are not the same enumeration:

JSDoc header ("## What it declines to touch, and says so") content/docs/deployment/cli.mdx ("Three things it deliberately declines")
flow rows with no reachable automation engine (outcome: 'skipped') ✅ bullet ❌ no row
Types with no repository write path (neither allowOrgOverride nor allowRuntimeCreate) ✅ ✅
Rows that still fail the current schema after conversion ✅ ✅
A flow whose rename the conflict guard refused (outcome: 'failed', real conflicts.length > 0) ❌ no bullet ✅ row
Row stored under a non-canonical metadata type (#8957, PR #9059 b740440bd) ✅ (added by PR #9270) ✅ (added by #9175's PR)

So each list has exactly one member the other lacks, and the two gaps point in opposite directions.

Why it is plausibly intentional

The JSDoc documents the function's full internal surface, including a path no CLI caller can reach: os migrate meta --stored always supplies a live automation engine (the JSDoc's own canonicalizeFlow parameter doc says so, and cli.mdx's "Flows are covered, and cost one extra plugin" section confirms the CLI boots an inert engine specifically so that skip path is never observed from that door). The docs page documents only what an operator running the actual command can observe. Under that reading both lists are correct for their own audience and the difference is a feature.

The flow-conflict row cuts the other way, though — that path is internal to the function, so if the JSDoc's remit is "the full internal surface", its absence there is a genuine omission rather than a scope choice. That asymmetry is what makes this worth asking rather than assuming.

Why it matters beyond these two files

This is the third instance this shift of a hand-written, count-carrying list with nothing enforcing the count:

The pattern is the finding. Two prose lists describing one function will drift again whichever way this question is answered; the answer determines whether the fix is "keep them in sync" or "state their different remits so nobody tries to".

The decision

  • A — intentional scope split. Add one explicit sentence to each list naming its remit (JSDoc: full internal surface; cli.mdx: operator-observable surface), and add the flow-conflict bullet to the JSDoc, since that path is internal and its absence is not explained by the split. The two lists then legitimately differ by exactly one member, for a stated reason.
  • B — drift. Reconcile both to the same set (5 members each), and accept that cli.mdx then documents a path an operator cannot reach.
  • C — something else, e.g. derive one from the other, or collapse to a single source with the docs page transcluding it.

PM's read: A. The two audiences are real and the CLI page documenting an unreachable path would be a small lie of its own; but the flow-conflict omission is not explained by the split and should be closed either way. ⚠️ Stated as a recommendation, not a measurement — I have not verified that the flow-conflict path is unreachable from any non-CLI caller, and if it is reachable only from the CLI then A's second half is wrong and the lists differ correctly by one member in each direction.

Backlinks

#9196 (the JSDoc's fourth bullet, closed by PR #9270) · #9175 (the cli.mdx fix) · #8957 / PR #9059 b740440bd (the fourth decline itself) · #9190, #8908 (the hand-curated-list pattern)

Activity

  1. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 17, 2026
  2. os-zhuang commented on Aug 17, 2026

    @os-zhuang
    ContributorAuthor

    Maintainer ruling (2026-08-17, recorded by PM session session_01NYgmGheCzM6NrHZN436Cxf). The maintainer accepted the decision-inbox report's recommendations in full, verbatim: 「其他接受你的所有建议」. For this card:

    Ruled: Option A — intentional scope split, made explicit.

    • Each list gains one sentence naming its remit: the JSDoc documents the function's full internal surface; cli.mdx documents the operator-observable surface of os migrate meta --stored.
    • The flow-conflict bullet is added to the JSDoc — that path is internal, so its absence is not explained by the split.
    • Falsifiable premise carried into the dispatch (per the PM's own caveat): verify the flow-conflict path is reachable from a non-CLI caller. If it turns out CLI-only, the correct end-state is the two lists differing by exactly one member in each direction — report the fork, don't force the bullet.
    • Option C (derive/transclude) is not taken — two audiences, two documents, each now self-describing.

    Label flipped needs-user-decision → pm:queue in the same stroke (domain:* left for triage — docs/JSDoc surface reads as devx).


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 17, 2026
  4. os-zhuang commented on Aug 17, 2026

    @os-zhuang
    ContributorAuthor

    Triage routing: domain:metadata added (the ruling — Option A — is already recorded on-card; state was flipped to pm:queue by the recorder, domain deliberately left to triage).

    Anchor: the operative diff lands in packages/metadata-protocol/src/protocol.ts (the remit sentence + the flow-conflict bullet in the JSDoc) with a one-sentence rider in content/docs/deployment/cli.mdx. Per the anchoring rule the primary landing package decides, and #9196 — the same JSDoc block — ran as domain:metadata. The recorder's devx suggestion noted, not adopted, for that reason.

    Dispatch notes for the metadata seat:

    • Same-day churn: PR docs(metadata-protocol): add the #8957 fourth decline bullet to migrateStoredMetadata's JSDoc #9270 rewrote this JSDoc block today — take the bullet list from current main, not from the card's table.
    • Carry the ruling's falsifiable premise verbatim: verify the flow-conflict path is reachable from a non-CLI caller; if it turns out CLI-only, report the fork — don't force the bullet.
    • protocol.ts is a hot file — name in-flight siblings in the claim comment's serial-constraints line.

    This comment is from the triage seat Routine — session session_01Y6RnGGr6eNirCHrU7QmFRd.


    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

    pm:dispatchedDispatched to a dev agent by /pm-dispatch

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions