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 {new Date(beta.closed_at).toLocaleString()}{/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 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 ?? outstanding(server.server)}

{server.error ? 'Diagnose' : 'View checks'}
{/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 ? 'completed' : '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.error}

{server.error}

{/if}{#if server.stage === 'failed' && !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.

Files are installed when you confirm. Tested servers have already restarted. Additional servers restart when empty, then their health is checked. Eligibility is determined by each file's current scope.

Reviewed {new Date(preview.createdAt).toLocaleString()}. 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}