play: old testing builds below production listed with their replace command (status, validate); 'Not live yet' instead of 'In review'; commit redone without changesNotSentForReview on the auto-send 400; pitfalls #129

This commit is contained in:
CRTkafa 2026-11-08 02:18:24 +07:00
parent 83d351cf42
commit 9c001d1ca9
13 changed files with 130 additions and 15 deletions

View file

@ -161,11 +161,15 @@ export function playReleases(data: unknown): StoreRelease[] {
return out;
}
/** A completed Play production release the store page does not show yet. The API has no review state: it may be in
* review, or blocked before review (an old build on another track with a policy issue, pitfall 129). Never "In review". */
export const PLAY_NOT_LIVE = 'Not live yet: in review or blocked before review (the API cannot tell; see Publishing overview)';
/** Plain words for a Play release's phase, decided from the store page (CLI text; the desktop has the same words in
* i18n, apps/desktop/src/ui/kit.tsx phaseLabel). */
export function playReleaseLabel(r: StoreRelease): string {
const base = ((): string => {
if (r.phase === 'review' || r.phase === 'sent') return r.managed ? 'In review / ready to publish (managed publishing)' : r.liveVersion ? `In review (live: ${r.liveVersion})` : 'In review';
if (r.phase === 'review' || r.phase === 'sent') return r.managed ? 'In review / ready to publish (managed publishing)' : r.liveVersion ? `${PLAY_NOT_LIVE} (live: ${r.liveVersion})` : PLAY_NOT_LIVE;
if (r.phase === 'released') return "Couldn't check the store page";
if (r.phase === 'live') return 'Live';
if (r.phase === 'rollout') return `Rolling out ${Math.round((r.fraction ?? 0) * 1000) / 10}%`;

View file

@ -1,6 +1,7 @@
// Store readiness rules for `storebound validate`. Pure: the command collects a snapshot from both APIs (read-only),
// these functions turn it into an ordered list of findings. Order = the order you would fix things in.
import { oldTrackBuilds } from '../play/old-builds';
import { consoleLink, consoleUrl } from './console-links';
import { describePending, type Pending, repairable } from '../apple/screenshot-health';
import { type FixAction, fixAppleListing, fixPlayListing, fixReviewDetails } from './fix-actions';
@ -409,6 +410,7 @@ export function playRules(s: PlaySnapshot): Finding[] {
if (r.status === 'halted') add('warn', 'tracks', `${t.track}: release ${r.versionCodes.join(',')} is halted`, 'storebound play rollout --resume (owner)');
if (r.status === 'inProgress') add('ok', 'tracks', `${t.track}: rollout ${Math.round((r.userFraction ?? 0) * 100)}% of ${r.versionCodes.join(',')}`);
}
for (const o of oldTrackBuilds(s.tracks)) add('warn', 'old-builds', `${o.track}: old build ${o.versionCodes.join(',')} (${o.status}) is still active below production ${o.productionCode}; Play reviews it with every submission and a policy issue in it (e.g. READ_MEDIA_IMAGES / READ_MEDIA_VIDEO) blocks Send changes for review (pitfall 129)`, `storebound play release --version-code ${o.productionCode} ${['internal','alpha','beta'].includes(o.track) ? '--' + o.track : '--track ' + o.track} completed`);
if (anyRelease && !f.some(x => x.code === 'tracks')) add('ok', 'tracks', s.tracks.filter(t => t.releases.length).map(t => `${t.track}: ${t.releases.map(r => r.status).join('/')}`).join(', '));
const prods = new Map(s.products.map(p => [p.productId, p] as const));