{#snippet actions()}{/snippet} {#if flash}{/if} {#if $fleetError}{/if} {#if loading} {:else if eligibleScripts.length === 0 && !flash} {:else if scripts.length}
    {#each steps as label, index}
  1. {index + 1}{label}
  2. {/each}

{steps[step]}

{#if step === 0}
{#each picks as row, idx (row.key)}
▾
▾
{/each}
{:else if step === 1}
{#if candidateServers.length === 0} No server satisfies all selected scopes — pick different scripts. {:else} {#each candidateServers as name (name)} {/each} {/if}
{:else if step === 2} {:else}

Files and versions

    {#each picks as pick}
  • {scripts.find(s => s.id === pick.scriptId)?.name} · {artifactVersionLabel(versionsForRow(pick).find(v => v.id === pick.versionId))}
  • {/each}

Test servers ({pickedServers.size})

    {#each [...pickedServers] as name}
  • {/each}

Pass criteria

{coverageSummary(testPlan)} · {testPlan.timeoutHours}-hour testing window

    {#each testPlan.requirements as requirement}
  • {requirementSummary(requirement)}
  • {/each}

Rollout and failure handling

{testPlan.waveSize ? `${testPlan.waveSize} servers per wave.` : 'Deploy to all selected servers.'} {testPlan.failureAction === 'rollback' ? 'Failed checks trigger an automatic rollback.' : testPlan.failureAction === 'pause' ? 'Failed checks pause testing for investigation.' : 'Failed checks hold the beta for review.'} {testPlan.rollbackRestart === 'when-empty' ? 'Rollback restarts wait for empty servers.' : 'Rollback restores files; restart the servers manually.'}

Starting installs these versions and restarts the selected servers. Promotion to the rest of the fleet is a separate action after testing.

{/if}
{#if step < 3} {:else}{/if}
{/if}