Skip to content

Review 5608

Cindy Zhang edited this page Aug 28, 2026 · 9 revisions

Review-5608

#5608 — fix(ci): keep accepted stable shots in the release gate · exact head 8aa506b243b99813ec995536051dd1b534f0a7ba
Verdict: HOLD — request changes

Problem and direction

The simplified design fixes the original false-removal path: ordinary and PR comparisons cannot infer removals, PR acceptance and promotion are add/update-only, and only a canonical stable-release capture may report a removal.

The contraction is substantial and correct in direction:

  • before: 23 files, +3164/−206
  • now: 10 files, +653/−221
  • removed: two ownership snapshots, the story-owner registry, copied built-index fixture, standalone metadata test, and caller-controlled removal authority

Architecture budget

Domain fact Intended source Finding
package release eligibility workspace package.json one source
stories that exist built Storybook index one source
complete release plan internal stable-release planner one source; caller scope refused
accepted baseline membership baseline no owner — membership is re-derived each run and cannot reconcile with the store

Complexity budget: one removal-reporting authority, one source for release membership, one readable verdict, zero new registries.
Actual burden: 10 files, about 430 runtime lines, one lane, one derived plan record, zero new registries.
Burden trend: sharply down from the prior 23-file design.
Reset trigger: not triggered; this is one model-level finding and its correction should continue the contraction rather than add another representation.

Blocking finding

The durable baseline records what a maintainer accepted, but the new release lane re-derives whether each accepted key belongs every run. The store cannot record or reconcile that membership.

Driven against the built index and live baseline:

  • deleting a real baseline story makes classification throw instead of producing a removal verdict;
  • 94 accepted keys fall outside the derived lane, including two Core-titled Layer stories whose file imports a Lab component;
  • a capture failure also throws before a verdict/report is written.

The consequence is the inverse of the intended contract: the only lane allowed to report deletions can end without publishing today's verdict, leaving the release cut with yesterday's answer.

Acceptance criteria:

  1. Deleting any currently accepted story produces a readable verdict, not a refusal.
  2. Every release-lane outcome, including capture failure, publishes a verdict the cut can identify as current.
  3. No accepted key is permanently both uncapturable and unprunable.
  4. A change to baseline membership is reported as a decision, never applied silently.

Contraction direction: let the baseline own its membership, and turn disagreement between the stored baseline and derived metadata into a readable verdict rather than another authority map.

Evidence

  • Exact-head CI, Lint, and CLI Smoke Test passed.
  • Visual-gate suite: 239 tests passed across 18 files.
  • Production resolver handled the built index; the canonical plan remained 884 shots.
  • PR comparison, acceptance, post-merge promotion, and explicit enumerated prune tests passed.
  • No component, visual, theme, accessibility, or internationalization surface changed.

Public review

Semantic verdict: request changes

Thanks — this is the right direction, and the contraction is real: the everyday lanes can no longer conclude a deletion, which was the whole bug.

What I'd like to change is where “which shots the release owns” lives. Today it is re-derived from the built Storybook index on every run and the baseline has no way to record or reconcile that answer, so the baseline is a truth nothing can converge. Two things follow: deleting any story makes the run refuse instead of report — the one deletion this authority exists to announce is the one it cannot — and 94 accepted keys now fall outside the lane, neither capturable nor removable.

Ideally I'd like the baseline to own its own membership, so a disagreement is a verdict the cut can read rather than a run that ends without one.

Where should that record live?

[Reviewed by Robohands]

Clone this wiki locally