Beta #{id} | Electric Cherry {#if loadError}{/if} {#if loading} {:else if !beta && !loadError} {:else if beta}
{#snippet crumbs()}{/snippet} {#snippet actions()}{/snippet}

{closed ? beta.state === 'promoted' ? 'Version promoted' : 'Beta rolled back' : `${passed} / ${servers.length} servers passed`}

{#if test}{coverageSummary(test.plan)}{/if}

{nextAction}

{#if test?.reason}

{test.reason}

{/if}
Started {#if deadline && !closed}Ends · {deadlineText}{/if} {#if beta.closed_at}Finished {$timeFormat.dateTime(beta.closed_at)}{/if}
{#if !closed && test}

Waiting for empty servers uses this window. Pausing or retrying does not extend the deadline.

{/if}
{#if !closed}{/if} {#if closed}{/if} {#if promotion}{/if} {#if rollbackCampaign}{/if}
{#if promotion}

{promotion.pending} servers awaiting activation · {promotion.failed} need attention. Promoting a version does not mean it is already running everywhere.

{/if} {#if flash}{/if} {#if success}

{success}

{/if}
{#if !closed && waiting.length}

Outstanding conditions

{#each waiting as server}

{server.error ?? (server.server_deleted_at ? 'This server was deleted. Recorded progress is retained.' : outstanding(server.server))}

{#if server.error && !server.server_deleted_at}Diagnose{:else if test}View checks{/if}
{/each}
{/if} {#if test}
server.error?.startsWith('deploy:')) ? 'Deployment was incomplete. Roll back before opening a fresh beta.' : undefined} onUpdate={load} />
{/if}
Files and versions ({scripts.length})
{#each scripts as file}
{file.name}{artifactVersionLabel(file.version)}{file.target_rel_path}{file.version?.sha256.slice(0,12)}
{/each}
Deployment progress ({servers.length} servers)
{#each ranked as server}

Files {server.deployed_at ? 'installed' : 'pending'} · Restart {server.restarted_at ? 'submitted' : 'pending'}{#if beta.wait_for_health} · Health {server.healthy_at ? 'verified' : 'pending'}{/if}{#if beta.wait_for_match} · Match {server.match_seen_at ? 'observed' : 'pending'}{/if}

{#if server.provisioning_id}View provisioning{/if}{#if server.error}

{server.error}

{/if}{#if server.stage === 'failed' && !server.server_deleted_at && !test && !closed}{/if}
{/each}
{/if} {#if acting === 'preview'}

Preparing promotion impact…

{/if} {#if reviewError}{/if} {#if preview}

{preview.servers.filter(server => server.tested).length} tested servers and {preview.servers.filter(server => !server.tested).length} additional eligible servers.

Confirming queues the file changes. Each server waits until empty and restart capacity is available, then installs its files and restarts. Tested servers only need another activation if their configuration changed or earlier queued work could replace the tested files. Eligibility follows each file's current scope.

Reviewed {$timeFormat.dateTime(preview.createdAt)}. If targets, versions, or composed settings change, you must review again.

{#each preview.blockers as blocker}{/each}
{#each preview.files as file}
{file.name} · {artifactVersionLabel(file)} · {file.servers.length} servers

{file.path} · {file.scope} · SHA {file.sha256.slice(0,12)}

    {#each file.servers as name}
  • {preview.servers.find(server => server.name === name)?.tested ? 'Already tested' : 'Additional target · restart when empty'}
  • {/each}
{/each}
{#if preview.configWrites.length}
Composed configuration files ({preview.configWrites.length}){#each preview.configWrites as write}

{write.server} · {write.path} · {write.sha256?.slice(0,12) ?? write.error}

{/each}
{/if} {:else if acting !== 'preview'}{/if} {#snippet actions()}{#if preview}{/if}{/snippet}