From 8ac420fe614e69601ffe0cb9ba25f325ef934366 Mon Sep 17 00:00:00 2001 From: josh Date: Sat, 19 Sep 2026 21:34:34 -0400 Subject: [PATCH] Improve operational UX, recovery flows, and action safety Implement the approved UX review across Fleet, Betas, Library, deployments, and Settings. Add reviewed promotion and reconciliation plans, atomic queued-removal cancellation, recoverable beta drafts and launch inputs, accessible controls, and mobile improvements. Validated with 473 tests, a clean typecheck, production build, and isolated desktop/mobile browser walkthroughs. Include the review and implementation coverage notes. --- docs/ui-refresh.md | 2 + docs/ui-ux-implementation.md | 57 ++ docs/ui-ux-review.md | 359 +++++++++++ docs/ux-review-assets/beta-activity-first.png | Bin 0 -> 117318 bytes docs/ux-review-assets/fleet-stale-count.png | Bin 0 -> 123295 bytes docs/ux-review-assets/offline-server.png | Bin 0 -> 60984 bytes src/lib/beta-draft.ts | 27 + src/lib/beta-evidence.ts | 37 ++ src/lib/beta-plan.ts | 26 +- src/lib/beta-promotion.ts | 14 + src/lib/config-workbench.ts | 11 + src/lib/deployment-plan.ts | 3 +- src/lib/drift-plan.ts | 26 + src/lib/server/fleet/beta-tests.ts | 11 +- src/lib/server/fleet/beta.ts | 124 ++-- src/lib/server/fleet/collections.ts | 12 +- src/lib/server/fleet/create.ts | 10 +- src/lib/server/fleet/deployments.ts | 26 +- src/lib/server/fleet/drift.ts | 57 +- src/lib/server/fleet/overview.ts | 6 +- src/lib/system-status.ts | 15 + src/lib/ui/components/ArtifactDetail.svelte | 97 ++- src/lib/ui/components/BetaPlanBuilder.svelte | 60 +- src/lib/ui/components/BetaTestProgress.svelte | 150 +++-- src/lib/ui/components/BlueprintBuilder.svelte | 17 +- src/lib/ui/components/ConfigEditor.svelte | 6 +- src/lib/ui/components/ConfigInspector.svelte | 46 +- src/lib/ui/components/ConfigLibrary.svelte | 18 +- src/lib/ui/components/ConfigTextEditor.svelte | 20 +- .../components/DeployCollectionDialog.svelte | 47 +- .../ui/components/DeployServerDialog.svelte | 32 +- .../ui/components/DestroyServerModal.svelte | 8 +- src/lib/ui/components/HousePartyDialog.svelte | 4 +- src/lib/ui/components/LogPanel.svelte | 66 +- .../ui/components/NotificationHistory.svelte | 24 + src/lib/ui/components/OperationHistory.svelte | 29 +- .../ui/components/PluginGithubImport.svelte | 19 +- .../ui/components/ScriptUploadDrawer.svelte | 25 +- src/lib/ui/components/ServerCard.svelte | 12 +- .../ui/components/primitives/Button.svelte | 2 +- src/lib/ui/components/primitives/Field.svelte | 20 +- src/lib/ui/components/primitives/Input.svelte | 4 +- .../components/primitives/ListFooter.svelte | 4 +- .../ui/components/primitives/Select.svelte | 4 +- src/lib/ui/components/primitives/Tabs.svelte | 29 +- .../ui/components/primitives/Textarea.svelte | 4 +- src/lib/ui/library-context.ts | 17 + src/lib/ui/status.ts | 2 +- src/lib/ui/styles/components.css | 2 +- src/lib/ui/styles/tokens.css | 2 + src/lib/ui/toast.ts | 24 + src/routes/+layout.svelte | 41 +- src/routes/+page.svelte | 49 +- src/routes/api/betas/+server.ts | 6 +- src/routes/api/betas/[id]/+server.ts | 6 +- src/routes/api/betas/[id]/promote/+server.ts | 18 +- src/routes/api/configs/inspect/+server.ts | 2 +- .../api/deployments/[id]/cancel/+server.ts | 7 + src/routes/api/drift/+server.ts | 31 +- src/routes/api/scripts/[id]/+server.ts | 1 + src/routes/api/scripts/[id]/scope/+server.ts | 20 +- src/routes/api/system-status/+server.ts | 38 ++ src/routes/betas/+page.svelte | 26 +- src/routes/betas/[id]/+page.svelte | 492 +++++--------- src/routes/betas/new/+page.svelte | 603 ++++++------------ src/routes/campaigns/+page.svelte | 128 ++-- src/routes/campaigns/[id]/+page.svelte | 29 +- src/routes/deployments/+page.svelte | 62 +- src/routes/deployments/[id]/+page.svelte | 23 +- src/routes/leaderboard/+page.svelte | 20 +- src/routes/plugins/+page.svelte | 35 +- src/routes/scripts/+page.svelte | 42 +- src/routes/server-keys/+page.svelte | 57 +- src/routes/servers/[name]/+page.svelte | 38 +- src/routes/settings/+page.svelte | 52 ++ tests/unit/beta-promotion.test.ts | 78 +++ tests/unit/beta-setup.test.ts | 40 ++ tests/unit/config-inspect.test.ts | 13 +- tests/unit/config-workbench-api.test.ts | 1 + tests/unit/create-server.test.ts | 54 ++ tests/unit/drift-kinds.test.ts | 51 ++ tests/unit/library-scope-preview.test.ts | 35 + tests/unit/system-status.test.ts | 49 ++ 83 files changed, 2574 insertions(+), 1190 deletions(-) create mode 100644 docs/ui-ux-implementation.md create mode 100644 docs/ui-ux-review.md create mode 100644 docs/ux-review-assets/beta-activity-first.png create mode 100644 docs/ux-review-assets/fleet-stale-count.png create mode 100644 docs/ux-review-assets/offline-server.png create mode 100644 src/lib/beta-draft.ts create mode 100644 src/lib/beta-evidence.ts create mode 100644 src/lib/beta-promotion.ts create mode 100644 src/lib/drift-plan.ts create mode 100644 src/lib/system-status.ts create mode 100644 src/lib/ui/components/NotificationHistory.svelte create mode 100644 src/lib/ui/library-context.ts create mode 100644 src/routes/api/deployments/[id]/cancel/+server.ts create mode 100644 src/routes/api/system-status/+server.ts create mode 100644 src/routes/settings/+page.svelte create mode 100644 tests/unit/beta-promotion.test.ts create mode 100644 tests/unit/beta-setup.test.ts create mode 100644 tests/unit/library-scope-preview.test.ts create mode 100644 tests/unit/system-status.test.ts diff --git a/docs/ui-refresh.md b/docs/ui-refresh.md index c484305..aae49e4 100644 --- a/docs/ui-refresh.md +++ b/docs/ui-refresh.md @@ -2,6 +2,8 @@ The interface keeps the existing dark palette and blue accent, with shared controls and task-focused pages. +The follow-up [UI/UX review implementation](ui-ux-implementation.md) records the approved operational, recovery, accessibility, and mobile improvements, with recommendation coverage and validation. + 1. **Shared design system:** common headers, buttons, fields, dialogs, spacing, radii, and focus styles. Removed unused styles from retired layouts. 2. **Libraries:** Plugins opens on the searchable library. Add plugin opens Upload / GitHub tabs. Scripts uses compact status filters; Configs uses a compact summary and Library / Inspect tabs. 3. **Beta setup:** `/betas/new` guides Files → Servers → Test plan → Review. Exact versions, selected servers, and the plan survive Back / Continue. Existing beta selection links still redirect correctly. diff --git a/docs/ui-ux-implementation.md b/docs/ui-ux-implementation.md new file mode 100644 index 0000000..a373795 --- /dev/null +++ b/docs/ui-ux-implementation.md @@ -0,0 +1,57 @@ +# UI/UX review implementation + +Implemented September 19, 2026, following [the approved review](ui-ux-review.md). + +The changes prioritize clear operational outcomes, reviewed action scope, recoverable input, and usable small-screen layouts. Existing server, file, beta, and launch semantics remain visible in the interface rather than being implied by a successful request. + +## Recommendation coverage + +| Review | Implemented behavior | +| --- | --- | +| 1. Stale Fleet data | Stale cards explicitly show **Players unknown**, retain labeled last-known counts and rosters, and stop advancing live durations. Fleet shows snapshot age and refresh/reconnection status. | +| 2. Promotion impact | A promotion review lists exact versions, tested and additional servers, eligibility, staging, and restart policy. The backend checks a review token before writes; changed targets or composed config require a new review. Completion links to the resulting rollout. | +| 3. Reconciliation scope | Selected-server and entire-fleet reviews are separate actions. The plan includes scan time, file operations and restart policy. Execution checks target identities and before/after content fingerprints; changed plans return for review. | +| 4. Beta reading order | Outcome, blockers, deadline, actions, and server results precede evidence and activity. Shared activity history is collapsed, searchable, ordered, and progressively displayed. | +| 5. Beta recovery | Deadlines and pause/retry consequences are explicit. A fresh attempt confirms evidence reset and restarts; expired tests explain rollback and plan reuse. Sign-off availability follows test/run readiness. | +| 6. Launch input retention | Refreshing previews retains entered keys only for unchanged exact server IDs. Changed assignments are explained. Keys remain in memory; managing keys in another tab preserves the launch context. | +| 7. Removal cancellation | Waiting removals can be withdrawn from operation lists/details. A database transition competes atomically with the worker claim before external deletion. Once removal or confirmed-deletion cleanup begins, cancellation is unavailable. | +| 8. Partial outcomes | Reconciliation reports updated and skipped servers separately, with reasons and follow-up links. All-skipped work is an error outcome. Rollback feedback stays beside its initiating operation. | +| 9. Scope clarity | Scope editing previews added/removed eligible servers. Script/plugin unscoping explains retained live copies and tracking detachment; configs explain composition impact. Completion links to reconciliation. Eligibility, promoted versions, and installed inventory have separate labels. | +| 10. Accessible controls | Busy buttons retain their accessible names. Field labels focus the associated native control. Consequential errors use alert semantics; completion uses status semantics. Rollout server states have accessible descriptions. | +| 11. Server investigation | Offline/stale summaries offer Diagnostics and Logs. URL parameters retain the selected tab, RCON diagnosis precedes telemetry history, and removal is under Server actions. | +| 12. Beta drafts | Drafts retain exact versions, label, test plan, selected servers, and wizard step. Resume/discard is explicit, including returns through artifact links. Eligibility is rechecked and compatible selections retained. Unavailable browser storage triggers leave protection. | +| 13. Local validation | Blueprints display total capacity and duplicate-map errors. Beta requirements show field-specific errors and units, expand/focus invalid checks, and validate quorum against the selected cohort. | +| 14. Navigation context | Fleet views and library/operation filters are represented in URLs. Library loaded counts and appropriate selections survive detail navigation and Back. Server and log tabs have direct links. Explicit Fleet URL choices override saved personal defaults. | +| 15. System setup | Settings opens a read-only System status page with configured/unconfigured/unreachable/unverified states, prerequisite instructions, saved-key counts, and first-server guidance. Empty/unconfigured Fleet links directly to setup. | +| 16. Stable config preview | The last successful inspection remains visible during edits, with an updating state. Expanded keys survive refresh. Draft comparisons and ignored-content warnings remain near the editing task. | +| 17. Config composition | Inspection numbers composition layers, identifies winning sources and superseded assignments, and compares draft values with promoted values. Structured editing supports adding a setting without raw syntax. | +| 18. Beta target selection | Files show scope and eligible counts. Conflicts identify incompatible file scopes. Server picking supports search, game/map grouping, health/player context, selected counts and select-visible controls. | +| 19. Evidence interpretation | Requirements explain the next qualifying condition using current observations. Relevant-evidence links apply server/event filters; readable summaries precede raw payloads and telemetry diagnosis is directly linked. | +| 20. Artifact next action | The latest exact version and its test/active-beta action lead the detail page. Technical hashes/sizes are disclosures, version cards remain readable on phones, unscoped game filtering is consistent, and hidden selections are counted. | +| 21. Import continuity | GitHub import shares pending state with its parent dialog, prevents dismissal/tab switches during import, and keeps a completion panel with version/beta links. Script batches show aggregate progress and sticky actions. | +| 22. Key management | Game/map/lobby selectors generate the exact ID, with an expert raw-ID option. Rows show saved time, presence-versus-validation wording, deployment implications, and links to existing servers. Launch forms accept the exact missing/replacement key inline. | +| 23. Blueprint coverage | Existing/queued inventory is distinguished from healthy playable servers, with linked coverage details. Collections group assignments and show a sticky key count and jump-to-missing-key action. Creation remains limited to the target shortfall. | +| 24. Mobile overhead | Fleet avoids redundant headings/zero rollout summaries, empty libraries emphasize their next action, and Leaderboard totals collapse on phones with a compact selected-stat table. Long forms retain reachable actions and focus spacing. | +| 25. Consistent hierarchy | Editable controls use stronger dedicated boundaries. Routes have descriptive titles, operational language is clearer, keyboard shortcuts have a help panel, and selected overflow tabs scroll into view without moving the page. | +| 26. Investigation/handoffs | Logs support literal search/highlighting, copy, tail download, deep links, explicit follow/refresh state and jump-to-latest. A bounded recent-notifications panel retains results in the current browser tab. Beta rows include labels, age and blocker context. | + +The review explicitly made overlay-priority reordering and Leaderboard player history/recent-period views conditional on further design or operator demand. Those product extensions remain future discovery work; the composition explanations and mobile Leaderboard changes are implemented. + +## API and operational boundaries + +- Promotion uses `GET /api/betas/:id/promote` to review impact and `POST` with the returned token as `previewToken` to apply it. A changed plan returns HTTP 409 and needs renewed review. +- Reconciliation uses `POST /api/drift` with `dryRun: true` and optional `servers`, then executes with the returned `expectedFingerprint`. Omitted servers explicitly mean the entire fleet. A stale review returns HTTP 409; changes detected during application are reported as skipped files. +- `POST /api/deployments/:id/cancel` only withdraws a waiting removal. It does not restore a server after deletion has started. +- System status exposes no credential values. Its optional connection check verifies Komodo network reachability, not credential validity. Remote game-file volumes remain explicitly unverified. +- Drafts contain nonsecret beta setup. Launch keys are not stored in browser drafts. Recent notifications use tab-scoped session storage, capped at 50 entries, and do not imply background push delivery. +- Log search/export covers the loaded tail, not an entire remote file or a full diagnostic archive. + +## Validation + +- Full regression suite: **473 tests passed across 44 files**. Added coverage includes changed promotion scope/config, changed reconciliation bytes/targets, cancellation racing a worker, draft parsing/compatibility, scope previews, config comparison and system-status semantics. +- `npm run check`: **0 errors, 0 warnings**. +- `npm run build`: **passed**. The existing SvelteKit CSRF configuration deprecation remains a tooling notice. +- Local browser walkthroughs use an isolated database and synthetic populated API fixtures, with production integration credentials disabled. Fleet, server diagnostics, logs, Settings, Leaderboard, libraries, beta setup/progress, launches, keys, and reconciliation are exercised at desktop and phone widths. +- Browser checks include the loading button accessibility tree, clickable native labels, URL/Back restoration, retained previews/drafts, selected-tab visibility, pending import ownership, and horizontal overflow. These are targeted checks, not a claim of complete accessibility conformance. + +Live Komodo provisioning, real game-server restarts and removals were not executed during verification. Their boundary behavior is covered by regression tests and simulated UI flows. diff --git a/docs/ui-ux-review.md b/docs/ui-ux-review.md new file mode 100644 index 0000000..5b87f5f --- /dev/null +++ b/docs/ui-ux-review.md @@ -0,0 +1,359 @@ +# Electric Cherry UI/UX review + +Reviewed September 19, 2026. + +Implementation follow-up: [completed changes and validation](ui-ux-implementation.md). + +Electric Cherry has a coherent visual foundation and unusually capable operational workflows. The highest-value next investment is making operational decisions easier: what is known, what is waiting, what an action will affect, and how to recover. Preserve the existing dark palette, shared controls, friendly server identities, and guided setup while improving those decisions. + +## Scope and evidence + +This review combines source inspection with a local browser walkthrough. It covers Fleet, server details and diagnostics, Scripts, Configs, Plugins, beta creation and progress, server deployments, blueprints, rollouts, keys, and Leaderboard. Existing design notes and workflow documentation informed the review. + +Browser exploration used an isolated database with Komodo/RCON credentials disabled. Nine top-level pages were examined at 1440×1000 and 390×844. Populated Fleet, server details, and beta scenarios used synthetic API responses. Beta setup, blueprint validation, and the browser accessibility tree were also exercised. Navigation was checked around its responsive breakpoint. Production integrations, actual restarts, and destructive actions were not executed. + +**Evidence labels:** **Rendered** means reproduced in the local browser, sometimes with an explicitly synthetic populated state. **Source** means verified in UI/API implementation. **Opportunity** means a proposed capability or design direction, rather than a defect. Recommendations are expert judgments; they are not findings from end-user interviews or a complete accessibility conformance audit. + +No application code was changed for this review. The accompanying screenshots contain synthetic review data. + +## What to preserve + +- The shared tokens, restrained blue accent, readable text, friendly map/lobby identities, and separate navigation/action targets. +- The existing Fleet search, status filters, pins, card/table views, grouping, live freshness handling in aggregate counts, and lobby watches. +- The four-step beta setup, exact version selection, explicit server opt-in, readable test-plan summaries, and review step. +- Script batch intake, duplicate recognition, partial-success retry, and direct transfer into beta setup. +- Config draft recovery, unsaved-edit protection, effective-setting inspection, and override provenance. +- Deployment previews, shared-queue visibility, and separate recovery actions for health verification and filesystem cleanup. +- Native modal dialogs, keyboard-operated tabs, visible focus, reduced-motion support, retained snapshots after refresh errors, and progressive list rendering. + +Many generic dashboard recommendations are already implemented. The findings below build on them. + +## Recommended order + +P1 means address first because the issue affects trust, consequential actions, lost work, or basic access. P2 means a meaningful workflow improvement. P3 means refinement or a capability to validate with operators. Relative effort is directional: S is a localized UI change; M crosses several components or state flows; L requires a new backend operation or product capability. + +| First work | Recommendation | Priority | Relative effort | +| --- | --- | --- | --- | +| 1 | Label stale player data consistently | P1 | S | +| 2 | Preserve loading-button accessible names | P1 | S | +| 3 | Put beta results and decisions above the event log | P1 | S–M | +| 4 | Preview promotion targets and link the resulting rollout | P1 | M | +| 5 | Make reconciliation scope and partial results explicit | P1 | M | +| 6 | Preserve keys when launch previews refresh | P1 | M | +| 7 | Explain blueprint and test-plan validation locally | P1/P2 | S–M | +| 8 | Surface beta deadlines, reset consequences, and valid recovery actions | P1 | M | + +Cancellation of queued destruction is also important, but needs an explicit backend boundary and should be designed as a separate capability. + +## Recommendations + +### 1. Make stale Fleet cards unmistakable — P1 · Rendered + Source + +Fleet correctly excludes stale servers from live player totals, but passes their old player counts into cards. A stale card can still display a large blue player count, roster, and advancing match duration; its main distinction is an amber status dot and an older “Last seen” timestamp. In the synthetic review, the header reported **3 players online**, while an additional stale card prominently displayed **4**. + +Show **Players unknown** or an em dash as the primary value. Retain historical information under “Last known: 4 players, 3 minutes ago,” with an explicit **Stale** label. Apply the same current-versus-last-known distinction to roster and timing. Add the age of the last successful Fleet refresh and a reconnecting state when appropriate. + +Acceptance: when a fresh server ages into stale status, both card and table stop presenting its previous player count as current. Preserve historical context without requiring interpretation of color. + +Sources: [Fleet page](../src/routes/+page.svelte), lines 56, 62, 208; [ServerCard](../src/lib/ui/components/ServerCard.svelte), lines 72, 114, 150. [Screenshot](ux-review-assets/fleet-stale-count.png). + +### 2. Review the full impact of promotion — P1 · Source + +“Promote” immediately sends a request. The backend expands the tested files to all currently matching scope targets and queues restarts for additional servers. The UI does not show that expansion at the moment of approval. Afterward, it ignores the returned rollout ID. + +Add a concise promotion review with exact versions, tested servers, additional eligible servers, and restart behavior. Use a final label such as **Promote to 12 servers**. Explain eligibility, file staging, and activation separately. After submission, show **Promotion created — 9 servers awaiting activation** with **View rollout**. Keep “Promoted version” distinct from “Running everywhere.” + +Acceptance: an operator who tested one lobby can identify the entire affected set and follow remaining restarts without searching another section. + +Sources: [Beta detail](../src/routes/betas/[id]/+page.svelte), lines 72–79; [promotion implementation](../src/lib/server/fleet/beta.ts), lines 778, 1017, 1060. + +### 3. Make drift reconciliation match the reviewed scope — P1 · Source + +The drift list can be filtered by server, but Reconcile posts an empty body and affects the full fleet. The confirmation includes counts but omits automatic restarts. Execution rescans, so the action can also differ from the displayed scan. + +Separate **Reconcile selected servers** from **Reconcile entire fleet**. Show a file-level plan, scan time, affected servers, and activation policy. If the reviewed plan changes materially, show the updated plan before execution. The API already accepts `servers` and `dryRun`, providing a starting point. + +Acceptance: filtering or selecting one server never leaves the action scope ambiguous. An operator can explain which files will be restored or removed and when servers will restart. + +Sources: [Rollouts page](../src/routes/campaigns/+page.svelte), lines 118, 124, 203, 268; [drift API](../src/routes/api/drift/+server.ts), line 28; [drift implementation](../src/lib/server/fleet/drift.ts), line 265. + +### 4. Put beta outcome and next action above activity — P1 · Rendered + Source + +Beta detail renders up to 25 expanded activity events before files, requirements, per-server progress, and actions. In a synthetic three-server beta with three requirements per server and 25 events: + +| Content starts | Desktop 1440×1000 | Mobile 390×844 | +| --- | ---: | ---: | +| Activity | 436 px | 720 px | +| Test plan/results | 2,623 px | 3,590 px | +| Pending sign-off | 3,528 px | 4,846 px | +| Promote / Rollback | 4,011 px | 5,462 px | + +Place a compact outcome summary first: passed servers, outstanding conditions, deadline, and primary action. Follow with a failed/waiting-first server table. Put activity under a disclosure or separate tab. Keep the useful operation-flow steps, but reduce the oversized started/finished block. + +Acceptance: without scrolling through historical events, an operator can answer “What is blocking this beta, and what can I do?” + +Sources: [Beta detail](../src/routes/betas/[id]/+page.svelte), line 137; [OperationHistory](../src/lib/ui/components/OperationHistory.svelte), lines 21, 46. [Screenshot](ux-review-assets/beta-activity-first.png). + +### 5. Make beta time and recovery rules visible — P1 · Source + +Progress describes a testing window but does not show the actual expiry or time remaining. Waiting for empty servers consumes the window; pausing and retrying retain the original deadline. Starting a fresh attempt resets evidence and causes new restarts. Sign-off controls can appear in states where the API rejects them. + +Show **Ends tomorrow at 14:30 · 6h remaining**, plus **Pausing does not extend this deadline**. Explain evidence reset and restart consequences before a fresh attempt. Offer only valid actions, with a reason for unavailable sign-off. For deadline expiry, explain the required rollback/new-beta sequence and offer a way to reuse the plan. + +Acceptance: paused, failed, inconclusive, and passed tests each have an understandable next step; a retry never silently implies extra testing time. + +Sources: [BetaTestProgress](../src/lib/ui/components/BetaTestProgress.svelte), lines 29, 35, 53; [test action API](../src/routes/api/betas/[id]/test/+server.ts), lines 21, 48–53; [test-plan documentation](beta-test-plans.md). + +### 6. Preserve launch inputs through preview refresh — P1 · Source + +Refreshing a single-server preview clears its entered key. Refreshing a collection clears all entered keys. Preview expiry and capacity changes are normal recovery paths, so users can lose substantial input while doing what the UI requires. + +Keep entered keys in memory, indexed by exact server ID. Reuse a key only when that ID survives the refreshed allocation; flag changed assignments explicitly. Preserve nonsecret launch choices across a visit to Manage keys. Do not persist raw keys into local browser drafts. + +Acceptance: after entering five keys, an unchanged preview refresh retains all five. A new lobby assignment never inherits another server’s key. + +Sources: [DeployServerDialog](../src/lib/ui/components/DeployServerDialog.svelte), lines 41–45, 66, 123; [DeployCollectionDialog](../src/lib/ui/components/DeployCollectionDialog.svelte), line 27. + +### 7. Give queued destructive work a withdrawal window — P1 · Opportunity + +Server removal can wait for occupied or unreachable lobbies. Current detail pages provide resume actions but no cancellation before destruction starts. A delayed command can therefore outlive the operator’s original intention. + +Add **Cancel queued removal** while the operation is still waiting, with a precise backend transition after which cancellation is unavailable. For fleet removal, show per-server waiting/removing/completed states and cancellation eligibility. Clearly distinguish cancelling a request from restoring a server already removed. + +Acceptance: an operator can withdraw a waiting removal, and a race with worker execution cannot leave the UI claiming cancellation after removal has begun. + +Sources: [DestroyServerModal](../src/lib/ui/components/DestroyServerModal.svelte), lines 36–40; [HousePartyDialog](../src/lib/ui/components/HousePartyDialog.svelte), line 51; [deployment detail](../src/routes/deployments/[id]/+page.svelte), lines 110–123. Existing consequence confirmations should remain. + +### 8. Report partial success as a distinct outcome — P1 · Source + +Reconciliation returns per-server skipped reasons, but the UI reads aggregate changed-file counts. Errors and success messages also share a blue-toned flash container. Rollback feedback can appear in the drift card far from the row that initiated it. + +Use structured completion feedback: **7 servers updated, 2 skipped**, with reasons, relevant retry actions, and a rollout link. Place feedback beside the affected task. Keep success, partial success, and failure visually and programmatically distinct. + +Acceptance: a request that skipped every target cannot look like an uneventful successful run; the operator can find the unresolved servers immediately. + +Sources: [Rollouts page](../src/routes/campaigns/+page.svelte), lines 128–138, 181–184, 299, 508; [drift implementation](../src/lib/server/fleet/drift.ts), lines 349, 371, 383–410. + +### 9. Explain scope changes and distinguish eligibility from installation — P1 · Source + +The artifact scope dialog offers selectors and Save. Unscoping scripts/plugins detaches inventory tracking while leaving live copies; unscoping configs changes the intended composed configuration. Both can create reconciliation work. The UI discards the returned detach result for scripts/plugins. The detail label “Applies to” also represents matching scope, not verified installed versions. + +Preview added/removed eligible servers. Explain retained live files when unscoping, show the affected count afterward, and link to the relevant reconciliation view. Determine config impact from composition rather than the script/plugin detach count. Use separate labels for **Eligible servers**, **Promoted version**, and **Installed version**. + +Acceptance: changing eligibility never suggests that running servers have already changed. An operator knows when follow-up reconciliation is required. + +Sources: [ArtifactDetail](../src/lib/ui/components/ArtifactDetail.svelte), lines 183, 298, 380; [scope API](../src/routes/api/scripts/[id]/scope/+server.ts), lines 12, 30; [unscoping behavior](../src/lib/server/fleet/beta.ts), lines 1081–1108. + +### 10. Keep controls named and feedback accessible during actions — P1 · Rendered + Source + +The shared Button hides its label with `visibility: hidden` while its spinner is hidden from assistive technology. Browser accessibility inspection confirmed that **Refresh** becomes an unnamed button while busy. It retains `disabled` and `busy`, but loses its name. + +Preserve the accessible label during loading and announce meaningful progress separately. Audit action failures for alert semantics, and success messages for status semantics. Replace per-server status dots whose explanation exists only in hover text with visible or accessible text. Ensure Field labels focus their associated controls; current label context provides accessible naming, but many visible labels are divs. + +Acceptance: the same action has a stable accessible name before, during, and after execution; keyboard and touch users can identify which server failed without hovering. + +Sources: [Button](../src/lib/ui/components/primitives/Button.svelte), lines 63–71, 155; [Field](../src/lib/ui/components/primitives/Field.svelte), line 25; [rollout mini-pipelines](../src/routes/campaigns/+page.svelte), line 380. These recommendations follow W3C guidance on [Name, Role, Value](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html) and [Status Messages](https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html). + +### 11. Make server detail lead toward the likely next task — P2 · Rendered + Source + +An offline server still opens on Scoreboard. In the reviewed state this shows “Waiting for game data,” while the only header action is Destroy. The diagnostic view places telemetry request history before the RCON diagnostic, even when connectivity is the immediate issue. + +Keep a stable tab choice, but add an issue summary above it: **RCON has not answered for 1 hour — Diagnose connection · Open logs**. Put removal under a secondary Server actions menu. Allow direct URLs to Logs, Config, and Diagnostics so operation failures can link to the relevant place. Prioritize the diagnostic relevant to the reported failure. + +Acceptance: from an offline Fleet card, the operator can reach the relevant diagnostic in one clear action. Do not automatically switch tabs while someone is reading. + +Sources: [server detail](../src/routes/servers/[name]/+page.svelte), lines 103, 226, 331–337; [PlayerScoreboard](../src/lib/ui/components/PlayerScoreboard.svelte), line 37. [Screenshot](ux-review-assets/offline-server.png). + +### 12. Preserve beta drafts and compatible server selections — P2 · Source + +The wizard preserves Back/Continue state, but navigation or reload loses the draft. Changing or removing a file clears every selected server without explanation. + +Extend the Config editor’s existing draft pattern to beta setup: resume/discard an unfinished draft, retain exact version IDs, and revalidate availability when reopening. Preserve selected servers that still satisfy the new scope intersection; explain any removals. Warn before leaving a dirty draft when recovery is unavailable. + +Acceptance: visiting a file’s detail to check a version does not require rebuilding the test plan and server selection. + +Sources: [beta setup](../src/routes/betas/new/+page.svelte), lines 34, 114, 130, 139; [existing ConfigEditor pattern](../src/lib/ui/components/ConfigEditor.svelte), lines 27–79. + +### 13. Explain why a form cannot proceed — P1/P2 · Rendered + Source + +With six distinct blueprint maps set to 20 lobbies each, both Save actions are disabled with no explanation of the 100-server limit. This was reproduced in the browser. Duplicate maps can also pass client validation and fail on submission. Beta-plan errors can refer to internal names such as `timeoutHours` or an unspecified requirement target. + +Show **120 / 100 target lobbies — reduce the total by 20**. Prevent or merge duplicate maps. Associate errors with the relevant controls, expand a collapsed invalid requirement, and move focus to it. Use target units such as rounds, matches, minutes, or players. Validate quorum against selected servers before final submission. + +Acceptance: every disabled forward/save action has a discoverable reason, and a rejected submission points directly to the field needing correction. + +Sources: [BlueprintBuilder](../src/lib/ui/components/BlueprintBuilder.svelte), lines 18, 81–90; [blueprint validation](../src/lib/server/fleet/launch-recipes.ts), lines 57–63; [BetaPlanBuilder](../src/lib/ui/components/BetaPlanBuilder.svelte), line 123; [beta setup validation](../src/routes/betas/new/+page.svelte), line 68. + +### 14. Preserve task context in URLs and navigation — P2 · Source + +Library filters, sort, loaded count, and selection mostly live in component state. Server detail tabs also default locally. Moving among details and returning can force the operator to rebuild context; another person cannot open the same filtered working view. + +Put filter/sort/view/tab state in URL parameters. Preserve scroll and appropriate selection state across detail navigation. Keep Fleet display preferences in local storage, but distinguish personal defaults from an explicitly shared view. Reuse the Leaderboard’s existing URL-filter pattern. + +Acceptance: browser Back restores the operator’s working set, and a copied Diagnostics or filtered library URL opens the intended view. + +Sources: [Scripts](../src/routes/scripts/+page.svelte), lines 13–23; [Plugins](../src/routes/plugins/+page.svelte), lines 44–49; [ConfigLibrary](../src/lib/ui/components/ConfigLibrary.svelte), lines 24–29; [Leaderboard](../src/routes/leaderboard/+page.svelte). + +### 15. Add a setup and integration-health home — P2 · Opportunity + +Settings currently leads only to server keys. Integration information is available deep in server diagnostics; the empty Fleet encourages creation even when external services are not configured. The first-run user needs a short path from prerequisites to a functioning lobby. + +Add a read-only System status page and a contextual first-run checklist: Komodo configured/reachable, RCON configured, game files available where verifiable, keys available, and first server ready. Link directly to relevant setup instructions. Distinguish **not configured**, **unreachable**, and **server offline**. Avoid repeatedly displaying the full checklist after setup succeeds. + +Acceptance: someone with an empty installation can identify the next missing prerequisite without opening an unrelated server or reading the full README. + +Sources: [navigation](../src/routes/+layout.svelte), lines 80–96; [Fleet empty state](../src/routes/+page.svelte), line 177; [integration store](../src/lib/ui/stores/fleet.ts), line 13; [README setup](../README.md). + +### 16. Keep config previews stable while typing — P2 · Source + +ConfigInspector clears its current inspection immediately on an edit, then waits for its debounce and request. The effective settings disappear while typing, which can disrupt comparison and expanded setting details. + +Retain the last result with **Updating preview…**, replace it when the current request completes, and preserve expanded keys and scroll position. Identify values changed by the draft. Show ignored-content warnings near Save when they affect the submitted config. + +Acceptance: typing several characters does not repeatedly collapse the working preview or shift the editor layout. + +Sources: [ConfigInspector](../src/lib/ui/components/ConfigInspector.svelte), lines 35–54, 75–79; [ConfigTextEditor](../src/lib/ui/components/ConfigTextEditor.svelte). + +### 17. Make config composition easier to reason about — P2 · Opportunity + +The inspector already provides useful provenance, but overlay precedence depends on creation order. Understanding why a setting wins can require understanding historical ordering. + +Extend the existing final-value and winning-source summaries with a numbered composition sequence and per-layer overridden-setting counts. Consider explicit overlay priorities only with a before/after effective-value preview. Add an “Add setting” key/value row to the structured editor, while preserving raw text mode. + +Acceptance: an operator can explain a setting’s final value and add a basic assignment without reverse-engineering creation history or switching to raw syntax unnecessarily. + +Sources: [ConfigInspector](../src/lib/ui/components/ConfigInspector.svelte), lines 79–97; [ConfigTextEditor](../src/lib/ui/components/ConfigTextEditor.svelte), lines 19–35. + +### 18. Make beta compatibility and target selection visible — P2 · Source + +File picking exposes little scope context, while target eligibility is the intersection of all file scopes. An empty intersection produces a generic instruction to choose different scripts. Candidate servers then appear as a flat checkbox collection. + +Show scope and eligible count beside each file/version. Explain concrete conflicts, such as **This Origins script and Town config have no shared servers**. Add target search, map/game grouping, selected count, and current player/health context. Include select-visible for larger fleets while preserving explicit opt-in. + +Acceptance: users can resolve an incompatible bundle without trial and error, and can select a sensible test cohort without scanning every raw entry. + +Sources: [beta setup](../src/routes/betas/new/+page.svelte), lines 159, 237, 276–278. + +### 19. Explain what stalled requirements are waiting for — P2 · Source + +Counters such as `current / target` do not sufficiently distinguish missing telemetry, too few players, a pending game end, or the next report needed to credit gameplay time. Raw evidence JSON leaves that interpretation to the operator. + +Add a next-condition explanation per requirement: **Waiting for a completed match with at least 2 players; last report 4m ago**. Link to the relevant telemetry diagnostic. Summarize evidence in ordinary language, then offer raw JSON. Add server/event filters and “Show evidence for this check.” + +Acceptance: a requirement stuck at zero has a visible explanation and a direct investigation path. + +Sources: [BetaTestProgress](../src/lib/ui/components/BetaTestProgress.svelte), lines 46, 67; [evaluation](../src/lib/server/fleet/beta-evaluation.ts), line 79; [telemetry contract](beta-test-plans.md). + +### 20. Put the next release action at the top of artifact details — P2 · Source + +The header emphasizes Edit scope and Upload new version. Testing is lower in version history, and the “open a beta” link goes to the generic beta list. Version rows emphasize checksum, size, and timestamps; their grid also has fewer explicit columns than some rows have children. + +Add a latest-version summary even before first promotion, with **Test latest version**, **View active beta**, or **Review passed test** as appropriate. Put version, state, change notes, and action first. Move hash and byte size into technical details. Use deliberately labeled mobile version cards. + +Also standardize game-filter behavior for unscoped files across Scripts and Plugins, and show **3 selected · 1 hidden by filters** when selections are concealed. + +Acceptance: after uploading a first version, the next useful action is immediately visible and carries that exact version into setup. + +Sources: [ArtifactDetail](../src/lib/ui/components/ArtifactDetail.svelte), lines 269–278, 312–327, 347–359, 500; [Scripts filters](../src/routes/scripts/+page.svelte), lines 37, 135; [Plugins filters](../src/routes/plugins/+page.svelte), line 51. + +### 21. Own import progress at the dialog level — P2 · Source + +GitHub import tracks busy state inside its child component, while the parent dialog and source tabs only observe file-upload state. The import can continue after dismissal or a tab change, then complete with a navigation or modal-close callback. Import-only success content is immediately hidden when the parent closes. + +Share the pending operation state with the parent. Either keep the import visibly in progress, or allow dismissal with an explicit persistent completion notification. Avoid surprise navigation after the user has moved on. Show **Plugin imported — View version · Start beta** after success. + +For long script batches, add aggregate inspection/upload progress and a sticky action footer while preserving current partial-success retry. + +Acceptance: closing or switching import UI never makes the request’s outcome disappear or causes unexplained later navigation. + +Sources: [Plugins dialog](../src/routes/plugins/+page.svelte), lines 217–220; [PluginGithubImport](../src/lib/ui/components/PluginGithubImport.svelte), lines 18, 60–75, 141; [ScriptUploadDrawer](../src/lib/ui/components/ScriptUploadDrawer.svelte), lines 59, 101, 185. + +### 22. Complete key management within the launch journey — P2 · Source + Opportunity + +The standalone key form asks users to type a machine ID despite existing game/map catalogs. Key rows omit their available update timestamp. “Deployed” indicates that the server exists, not that it uses the latest saved key. + +Generate the exact ID from game/map/lobby selectors, retain a raw-ID option for experts, and link deployed rows to their server. Show **Saved on… · Used on next deployment**. Let the launch flow add or replace its exact missing key without losing launch context. Distinguish a stored key’s presence from credential validation. + +Acceptance: users can add the right key without manually constructing an identifier and can understand whether a running server is affected by an update. + +Sources: [server keys](../src/routes/server-keys/+page.svelte), lines 14, 81–105; [launch dialog](../src/lib/ui/components/DeployServerDialog.svelte), line 123. + +### 23. Separate blueprint coverage from playable capacity — P2 · Source + +A blueprint can be satisfied by existing stopped servers. Its “Existing / queued” identities are exposed through hover text, without an obvious path to inspect them. Meeting an inventory target does not establish that those lobbies are playable. + +Show **3 existing: 1 healthy, 1 stopped, 1 queued** with an expandable linked list. When no creation is needed, offer **Review existing servers**. Retain the current create-only-shortfall semantics, and say explicitly that excess servers remain and existing servers are not updated. + +For collections needing many keys, add a sticky summary, **12 of 20 keys ready**, grouping, and jump-to-next-missing-key. + +Acceptance: “Target satisfied” cannot be mistaken for “All lobbies ready to play.” + +Sources: [DeployCollectionDialog](../src/lib/ui/components/DeployCollectionDialog.svelte), lines 57–59, 72–84. + +### 24. Reduce mobile overhead before useful content — P2 · Rendered + Opportunity + +The inspected mobile pages generally fit the viewport, but some put substantial control and summary space ahead of the task. On the reviewed 390px Fleet, the first server card began around 614px down. The empty Scripts screen still shows zero-count filters, search, sorting, and select-visible controls. Leaderboard rankings begin below its filters and five summary metrics. + +On phones, prioritize one compact health summary, search, and the most useful status filter; keep display options in a small secondary control. Simplify true empty states to the relevant next action. Let Leaderboard summary metrics collapse and offer a compact player/selected-stat presentation while retaining the full scrollable table. Add sticky summaries/actions to long collection and batch forms, checking that they do not cover focused fields. + +Acceptance: a phone user reaches a real server, record, or first-run action quickly, without losing access to advanced controls. Validate sticky behavior with keyboard navigation and zoom, following [W3C focus visibility guidance](https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum). + +Sources: [Fleet layout](../src/routes/+page.svelte), lines 180–202, 334; [Scripts](../src/routes/scripts/+page.svelte); [Leaderboard layout](../src/routes/leaderboard/+page.svelte), lines 126–187. + +### 25. Sharpen visual hierarchy and vocabulary consistently — P2/P3 · Rendered + Source + +The visual language is coherent, but small controls, nested cards, repeated section headings, and technical metadata can compete with primary decisions. Input borders use the same very faint token family as passive surfaces. Some routes also retain the generic browser title “Electric Cherry,” making multiple open tabs hard to distinguish. + +Use a dedicated editable-control boundary token, reserve strong surfaces for actionable sections, and reduce repeated title/subtitle layers in builders. Keep body text and important form instructions comfortably readable; use compact metadata selectively. Add descriptive route titles, especially server name and lobby number. + +Use “server” consistently for the managed unit; introduce “lobby” as its player-facing meaning. Prefer **Preview missing servers** over “Conform fleet.” Use “Files” consistently for scripts/configs/plugins where a collective noun is needed. Keep raw IDs, RCON, Komodo, and hashes accessible in technical details. Expose the existing keyboard shortcuts through a small help panel. + +Acceptance: primary tasks are identifiable by placement and wording, and multiple browser tabs are distinguishable. Contrast should be measured before claiming a conformance result. + +Sources: [tokens](../src/lib/ui/styles/tokens.css), lines 57–71, 86–87; [BetaPlanBuilder](../src/lib/ui/components/BetaPlanBuilder.svelte); [navigation and shortcuts](../src/routes/+layout.svelte), lines 37–65; [deployment blueprint actions](../src/routes/deployments/+page.svelte), lines 125–132. + +### 26. Make investigation and handoffs easier over time — P3 · Opportunity + +Logs provide refresh, auto-follow behavior, and a useful tail, but no in-panel search or downloadable investigation bundle. Lobby watches work across navigation, while completed notifications are transient application state and are not a reviewable activity inbox. Beta list rows could also provide more timing and blocker context. + +Add log search/highlighting, copy/download, and a deep link preserving the selected server/log. Make the existing auto-refresh/follow state explicit and offer **Jump to latest**. Consider a small recent-notifications panel for completed watches and actions, without implying background push support. Add beta age, an operator label, and a one-line blocker to list rows. For Leaderboard, investigate player detail/history and recent-period views only after confirming operator demand; existing all-time statistics and counting explanations are a solid base. + +Acceptance: operators can return to a completed notification or share a precise diagnostic view without reconstructing the investigation. + +Sources: [LogPanel](../src/lib/ui/components/LogPanel.svelte); [notification store](../src/lib/ui/toast.ts); [watch handling](../src/lib/ui/stores/fleet.ts); [beta list](../src/routes/betas/+page.svelte); [Leaderboard](../src/routes/leaderboard/+page.svelte). + +## Suggested layout for operational detail pages + +Use the same reading order across beta, rollout, and server-deployment details: + +1. **Outcome and next action:** current state, elapsed/remaining time, blocker, primary recovery or completion action. +2. **Affected servers:** progress counts and a failed/waiting-first list with links to relevant diagnostics. +3. **Change summary:** exact files/versions or deployment recipe, including what is staged versus active. +4. **Evidence and activity:** searchable or collapsible history, with the latest meaningful event summarized near the top. + +This gives the existing shared components a consistent purpose without forcing every operation into identical controls. + +## Practical delivery sequence + +**First pass — clarity and trust:** address stale card values, unnamed loading buttons, silent blueprint limits, beta results placement, and misleading/remote action feedback. These are bounded changes with clear reproduction cases. + +**Second pass — complete action flows:** add promotion and reconciliation reviews, explicit beta timing/retry semantics, retained launch keys, beta drafts, import completion state, and links from outcomes to their rollout or recovery destination. + +**Third pass — scale and polish:** improve target pickers, library context restoration, mobile density, config composition, setup status, and evidence navigation. Design queued-operation cancellation separately with its backend guarantees. + +## Validation plan + +Use a fixture with online, occupied, empty, starting, stale, and unreachable servers; a library large enough to require filtering; an expired preview; an active beta with a long history; and partial deployment failures. Ask representative operators to perform these tasks without narration or hints: + +| Task | Observable success | +| --- | --- | +| Identify a safe empty lobby | User distinguishes confirmed empty from stale/unknown counts. | +| Promote a beta tested on one server | User correctly predicts the entire affected set and restart behavior. | +| Reconcile one selected server | User can name the scope and identify skipped or failed work afterward. | +| Recover a stalled beta | User finds the blocker, deadline, and valid next action without reading the event log. | +| Refresh a five-key launch preview | Unchanged server IDs retain their entered keys; changed IDs are clearly called out. | +| Fix an invalid blueprint | User finds the total/duplicate issue without guessing why Save is disabled. | +| Investigate an offline server on a phone | User reaches the relevant diagnostic promptly and keeps server context. | +| Complete a flow using keyboard/assistive technology | Actions keep names while loading; focus remains visible; errors and completion are announced. | + +Measure completion, errors, unnecessary backtracking, lost input, and time to identify the next action. Establish a baseline before setting numerical improvement targets. Source review and synthetic browser scenarios establish the issues above, but observed operator behavior should guide the final interaction details. diff --git a/docs/ux-review-assets/beta-activity-first.png b/docs/ux-review-assets/beta-activity-first.png new file mode 100644 index 0000000000000000000000000000000000000000..4e196ba95876b77e45f40a7251bd4da8592982e4 GIT binary patch literal 117318 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�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 literal 0 HcmV?d00001 diff --git a/src/lib/beta-draft.ts b/src/lib/beta-draft.ts new file mode 100644 index 0000000..e1ee635 --- /dev/null +++ b/src/lib/beta-draft.ts @@ -0,0 +1,27 @@ +import { requirementKinds, type BetaPlan } from './beta-plan.js'; + +export const betaDraftKey = 'electric-cherry:beta-draft:v1'; +export interface BetaDraft { + version: 1; savedAt: string; step: number; + picks: Array<{ scriptId: number | null; versionId: number | null }>; + servers: string[]; testPlan: BetaPlan; + label?: string; +} +/** Validate draft structure, preserving incomplete numeric fields for correction. */ +export function readBetaDraft(raw: string | null): BetaDraft | null { + if (!raw) return null; + try { + const d = JSON.parse(raw); + if (d?.version !== 1 || !Array.isArray(d.picks) || !d.picks.length || d.picks.length > 100 + || !d.picks.every((p: BetaDraft['picks'][number]) => p && [p.scriptId, p.versionId].every(v => v === null || Number.isSafeInteger(v) && v! > 0)) + || !Array.isArray(d.servers) || !d.servers.every((s: unknown) => typeof s === 'string') + || d.testPlan?.version !== 1 || !Array.isArray(d.testPlan.requirements) || d.testPlan.requirements.length > 30 + || !d.testPlan.requirements.every((r: BetaPlan['requirements'][number]) => r && requirementKinds.includes(r.kind) && typeof r.id === 'string' && /^[a-zA-Z0-9_-]{1,64}$/.test(r.id) && typeof r.label === 'string')) return null; + return { ...d, step: Math.max(0, Math.min(3, Number(d.step) || 0)) }; + } catch { return null; } +} + +export function compatibleBetaServers(selected: Iterable, candidates: readonly string[]): { kept: Set; removed: string[] } { + const allowed = new Set(candidates), names = [...selected]; + return { kept: new Set(names.filter(name => allowed.has(name))), removed: names.filter(name => !allowed.has(name)) }; +} diff --git a/src/lib/beta-evidence.ts b/src/lib/beta-evidence.ts new file mode 100644 index 0000000..7cb37b7 --- /dev/null +++ b/src/lib/beta-evidence.ts @@ -0,0 +1,37 @@ +import type { BetaRequirement, BetaTestView } from './beta-plan.js'; +import { needsGameTelemetry } from './beta-plan-summary.js'; + +export function betaWaitingCondition(requirement: BetaRequirement, observation?: BetaTestView['servers'][number]['observation']): string { + if (requirement.kind === 'manual') return 'Waiting for a tester to record their name and observation.'; + if (requirement.kind === 'recovery') return 'The other checks must pass before the next restart when empty; each cycle needs fresh evidence.'; + if (requirement.kind === 'healthy-minutes') return observation?.healthy === true + ? 'Collecting consecutive fresh healthy observations; an outage or monitoring gap resets this duration.' + : 'Waiting for fresh container and RCON health observations. Unhealthy or stale observations reset this duration.'; + if (requirement.kind === 'failure-budget') return 'An observed health outage exceeded the budget. Investigate before starting a fresh attempt.'; + if (needsGameTelemetry(requirement)) { + if (!observation?.lastGameplayAt) return 'No gameplay report received for this attempt. Check the game reporter and Telemetry API requests.'; + if (observation.gameEnded) return 'Waiting for the next game and its qualifying reports.'; + if (requirement.kind === 'population') return `Waiting for a game report containing at least ${requirement.target} players.`; + const players = `at least ${requirement.minPlayers} player${requirement.minPlayers === 1 ? '' : 's'}`; + if ((observation.players ?? 0) < requirement.minPlayers) return `The latest report has ${observation.players ?? 0} players; this check needs ${players}.`; + if (requirement.kind === 'matches') return requirement.minMinutes && !observation.matchStarted + ? 'This match has no game-start report, so its duration cannot qualify. Waiting for a new game start and game end.' + : `Waiting for game end${requirement.minRound ? ` after reaching round ${requirement.minRound}` : ''} with ${players}${requirement.minMinutes ? ` and at least ${requirement.minMinutes} minutes since game start` : ''}.`; + if (requirement.kind === 'round') return `Waiting for a round change or game end reporting round ${requirement.target} or higher with ${players}.`; + return `Time is credited when the next report arrives, with ${players} at both ends of the interval. It does not advance continuously between reports.`; + } + return 'Waiting for qualifying evidence.'; +} + +export function betaEvidenceSummary(event: BetaTestView['evidence'][number]): string { + let payload: Record; + try { payload = JSON.parse(event.payload); } catch { return event.kind.replaceAll('-', ' ').replaceAll('_', ' '); } + if (!payload || typeof payload !== 'object') return event.kind; + if (['game_start', 'round_change', 'game_end'].includes(event.kind)) { + const label = event.kind === 'game_start' ? 'Game started' : event.kind === 'game_end' ? 'Game ended' : 'Round changed'; + return `${label}${typeof payload.round === 'number' ? ` at round ${payload.round}` : ''}${Array.isArray(payload.players) ? ` with ${payload.players.length} players` : ''}${typeof payload.map === 'string' ? ` on ${payload.map}` : ''}.`; + } + if (event.kind === 'manual-sign-off') return `${payload.requirement ?? 'Checklist'}: ${payload.note ?? 'Signed off'}`; + if (event.kind === 'health' || event.kind === 'status-sample') return `${payload.healthy ? 'Healthy observation' : 'Unhealthy observation'}${payload.reason ? `: ${payload.reason}` : '.'}`; + return event.kind.replaceAll('-', ' ').replaceAll('_', ' '); +} diff --git a/src/lib/beta-plan.ts b/src/lib/beta-plan.ts index 65bd775..150a987 100644 --- a/src/lib/beta-plan.ts +++ b/src/lib/beta-plan.ts @@ -82,6 +82,30 @@ export interface BetaTestView { plan: BetaPlan; outcome: string; reason: string | null; - servers: Array<{ server: string; phase: number; passed: boolean; progress: RequirementProgress[] }>; + servers: Array<{ server: string; phase: number; passed: boolean; progress: RequirementProgress[]; observingAt?: string | null; + observation?: { lastGameplayAt: string | null; lastEvent: string | null; players: number | null; round: number | null; matchStarted: boolean; gameEnded: boolean; healthy: boolean | null; healthCheckedAt: string | null } }>; evidence: Array<{ id: number; server: string; received_at: string; kind: string; payload: string }>; } + +export interface BetaPlanIssue { field: string; message: string; requirementId?: string } +export function betaPlanIssues(plan: BetaPlan, serverCount?: number): BetaPlanIssue[] { + const issues: BetaPlanIssue[] = []; + const check = (field: string, value: number, min: number, max: number, integer: boolean, message: string, requirementId?: string) => { + if (typeof value !== 'number' || !Number.isFinite(value) || value < min || value > max || (integer && !Number.isInteger(value))) issues.push({ field, message, requirementId }); + }; + check('timeoutHours', plan.timeoutHours, .01, 8760, false, 'Enter a testing window between 0.01 and 8,760 hours.'); + check('waveSize', plan.waveSize, 0, 1000, true, 'Enter a whole number from 0 to 1,000; 0 deploys to all selected servers.'); + if (plan.scope === 'quorum') check('quorum', plan.quorum, 1, serverCount ?? 1000, true, `Choose between 1 and ${serverCount ?? 1000} qualifying servers.`); + if (!plan.requirements.length) issues.push({ field: 'requirements', message: 'Add at least one requirement to continue.' }); + for (const r of plan.requirements) { + if (!r.label?.trim()) issues.push({ field: `${r.id}-label`, message: 'Describe what this requirement checks.', requirementId: r.id }); + const integral = ['round', 'matches', 'population', 'failure-budget', 'recovery', 'manual'].includes(r.kind); + check(`${r.id}-target`, r.target, r.kind === 'failure-budget' ? 0 : .000001, 1_000_000, integral, `Enter ${integral ? 'a whole number' : 'a number'} ${r.kind === 'failure-budget' ? 'of zero or more' : 'greater than zero'} for ${requirementLabels[r.kind].toLowerCase()}.`, r.id); + if (['round', 'matches', 'populated-minutes', 'player-hours', 'sustained-population'].includes(r.kind)) check(`${r.id}-minPlayers`, r.minPlayers, 1, 1_000_000, true, 'Enter at least one player, using a whole number.', r.id); + if (r.kind === 'matches') { + check(`${r.id}-minRound`, r.minRound, 0, 1_000_000, true, 'Enter a whole round number; 0 allows any round.', r.id); + check(`${r.id}-minMinutes`, r.minMinutes, 0, 1_000_000, false, 'Enter a duration of zero or more minutes.', r.id); + } + } + return issues; +} diff --git a/src/lib/beta-promotion.ts b/src/lib/beta-promotion.ts new file mode 100644 index 0000000..b85df3a --- /dev/null +++ b/src/lib/beta-promotion.ts @@ -0,0 +1,14 @@ +export interface BetaPromotionPreview { + betaId: number; + token: string; + createdAt: string; + files: Array<{ + id: number; name: string; kind: string; path: string; versionId: number; + version: number; release_version: string | null; sha256: string; + scope: string; servers: string[]; + }>; + servers: Array<{ name: string; tested: boolean; game: string | null; map: string | null }>; + configWrites: Array<{ server: string; path: string; sha256: string | null; error: string | null }>; + blockers: string[]; + restartPolicy: 'additional-when-empty'; +} diff --git a/src/lib/config-workbench.ts b/src/lib/config-workbench.ts index bc0da8c..2e9919a 100644 --- a/src/lib/config-workbench.ts +++ b/src/lib/config-workbench.ts @@ -45,6 +45,17 @@ export function changeConfigValue(text: string, index: number, value: string): s return parts.join(''); } +/** Add one assignment without changing existing commands or line endings. */ +export function addConfigSetting(text: string, key: string, value: string): string { + key = key.trim(); value = value.trim(); + if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) throw new Error('Use a setting name containing letters, numbers, and underscores.'); + if (!value || /[\r\n]/.test(value) || value.startsWith('//')) throw new Error('Enter a value on one line.'); + if (configLines(text).some(entry => entry.key.toLowerCase() === key.toLowerCase())) throw new Error('This setting already exists. Find it above to edit its value.'); + const newline = text.includes('\r\n') ? '\r\n' : '\n'; + const formatted = /\s/.test(value) && !value.startsWith('"') ? JSON.stringify(value) : value; + return text + (text && !text.endsWith('\n') ? newline : '') + `set ${key} ${formatted}` + newline; +} + export function configWarnings(text: string, overlay: boolean): string[] { const warnings: string[] = []; const seen = new Map(); diff --git a/src/lib/deployment-plan.ts b/src/lib/deployment-plan.ts index 05f2618..c9c6572 100644 --- a/src/lib/deployment-plan.ts +++ b/src/lib/deployment-plan.ts @@ -37,7 +37,8 @@ export interface CollectionPreview { expiresAt: string; blueprintName: string; launchConcurrency: number; - entries: { count: number; existing: number; missing: number; existingServers: string[]; recipe: LaunchRecipeSummary }[]; + entries: { count: number; existing: number; missing: number; existingServers: string[]; + coverage: { name: string; health: string; href: string }[]; recipe: LaunchRecipeSummary }[]; servers: { entryIndex: number; name: string | null; port: number | null; hasSavedKey: boolean }[]; blockers: string[]; ready: boolean; diff --git a/src/lib/drift-plan.ts b/src/lib/drift-plan.ts new file mode 100644 index 0000000..eea1dd7 --- /dev/null +++ b/src/lib/drift-plan.ts @@ -0,0 +1,26 @@ +export interface DriftPlanFile { + server: string; + relPath: string; + kind: string; + driftKind: 'untracked' | 'missing' | 'replace'; + beforeSha256: string | null; + afterSha256: string | null; + beforeSize: number | null; + afterSize: number | null; +} + +export interface DriftPlan { + fingerprint: string; + scannedAt: string; + servers: string[]; + files: DriftPlanFile[]; +} + +export interface DriftResult { + deploymentId: string | null; + perServer: { server: string; removed: string[]; restored: string[]; skipped: string[] }[]; + totalRemoved: number; + totalRestored: number; + totalServers: number; + dryRun: boolean; +} diff --git a/src/lib/server/fleet/beta-tests.ts b/src/lib/server/fleet/beta-tests.ts index fb08fa0..07e72f4 100644 --- a/src/lib/server/fleet/beta-tests.ts +++ b/src/lib/server/fleet/beta-tests.ts @@ -73,8 +73,15 @@ export function testView(betaId: number): BetaTestView | null { const runs = db().prepare('SELECT * FROM beta_test_runs WHERE beta_id = ? AND retired_at IS NULL ORDER BY server').all(betaId) as TestRun[]; return { plan, outcome: stored.outcome, reason: stored.reason, servers: runs.map(run => { - const progress = evaluateRequirements(plan, readMetrics(run), run.phase); - return { server: run.server, phase: run.phase, passed: progress.every(r => r.passed), progress }; + const metrics = readMetrics(run); + const progress = evaluateRequirements(plan, metrics, run.phase); + const latest = db().prepare("SELECT received_at, kind, payload FROM beta_test_evidence WHERE run_id = ? AND kind IN ('game_start','round_change','game_end') ORDER BY id DESC LIMIT 1").get(run.id) as { received_at: string; kind: string; payload: string } | undefined; + const event = latest ? JSON.parse(latest.payload) : null; + return { server: run.server, phase: run.phase, passed: progress.every(r => r.passed), progress, observingAt: run.observing_at, + observation: { lastGameplayAt: latest?.received_at ?? null, lastEvent: latest?.kind ?? null, + players: metrics.match?.players ?? null, round: event?.round ?? null, + matchStarted: metrics.match?.started !== undefined, gameEnded: metrics.match?.ended ?? false, + healthy: metrics.wasHealthy ?? null, healthCheckedAt: metrics.lastSample ? new Date(metrics.lastSample).toISOString() : null } }; }), evidence: db().prepare(`SELECT e.id, r.server, e.received_at, e.kind, e.payload FROM beta_test_evidence e JOIN beta_test_runs r ON r.id = e.run_id WHERE r.beta_id = ? ORDER BY e.id DESC LIMIT 200`).all(betaId) as BetaTestView['evidence'] }; diff --git a/src/lib/server/fleet/beta.ts b/src/lib/server/fleet/beta.ts index 52dace0..d25760a 100644 --- a/src/lib/server/fleet/beta.ts +++ b/src/lib/server/fleet/beta.ts @@ -1,5 +1,6 @@ import { parseBetaPlan, type BetaPlan } from '../../beta-plan.js'; import { storedPlan } from './beta-tests.js'; +import type { BetaPromotionPreview } from '../../beta-promotion.js'; const operations = new Set(); export const betaOperationInFlight = (id: number) => operations.has(id); @@ -192,6 +193,7 @@ export class BetaError extends Error { | 'dest-fail' | 'invalid-state' | 'duplicate-script' + | 'preview-changed' | 'duplicate-target', public readonly details?: unknown ) { @@ -721,6 +723,54 @@ export interface PromoteResult { deploymentId: string; landed: string[]; // unique servers that received at least one file scriptIds: number[]; + awaitingActivation: number; + failedServers: string[]; +} + +/** Snapshot exactly the scope expansion and composed configuration reviewed by the operator. */ +function promotionPlan(betaId: number): { preview: BetaPromotionPreview; configContent: Map } { + const beta = getBeta(betaId); + if (!beta) throw new BetaError('This beta no longer exists.', 'no-such-beta'); + const bundle = listBetaScripts(betaId).map(row => { + const script = getScript(row.script_id), version = getVersion(row.script_version_id); + if (!script || !version) throw new BetaError('A selected file version is no longer available.', 'no-such-version'); + return { script, version }; + }); + if (!bundle.length) throw new BetaError('This beta has no files.', 'no-scripts'); + const tested = new Set(listBetaServers(betaId).map(row => row.server)); + const targets = (script: ScriptRow) => [...new Set([...tested, ...(script.scope_type && script.scope_value + ? serversMatchingScope(script.scope_type, script.scope_value) : [])])].sort(); + const files = bundle.map(({ script, version }) => ({ id: script.id, name: script.name, kind: script.kind, + path: script.target_rel_path, versionId: version.id, version: version.version, + release_version: version.release_version, sha256: version.sha256, + scope: script.scope_type ? `${script.scope_type}: ${script.scope_value}` : 'Selected test servers only', servers: targets(script) })); + const names = [...new Set(files.flatMap(file => file.servers))].sort(); + const blockers: string[] = []; + const servers = names.map(name => { + const server = getServer(name); + if (!server || server.destroyed_at) blockers.push(`${name}: server is no longer available.`); + return { name, tested: tested.has(name), game: server?.game ?? null, map: server?.map ?? null }; + }); + const collapsing = bundle.filter(({ script }) => isCollapsingKind(script.kind)); + const configContent = new Map(); + const configWrites = [...new Set(collapsing.flatMap(({ script }) => targets(script)))].sort().map(server => { + const row = getServer(server); + const composed = row && composeCfgForServer(server, row.game, row.map, { + inBetaBaseline: collapsing.find(({ script }) => script.kind === 'baseline')?.version, + inBetaOverlays: collapsing.filter(({ script }) => script.kind === 'config') + }); + const error = composed ? null : `${server}: no baseline is available to compose its configuration.`; + if (error) blockers.push(error); + const content = composed ? Buffer.from(composed.text, 'utf8') : null; + if (content) configContent.set(server, content); + return { server, path: configFileOf(server), sha256: content ? sha256Buffer(content) : null, error }; + }); + const impact = { betaId, files, servers, configWrites, blockers, restartPolicy: 'additional-when-empty' as const }; + return { preview: { ...impact, token: sha256Buffer(Buffer.from(JSON.stringify(impact))), createdAt: nowIso() }, configContent }; +} + +export function previewBetaPromotion(betaId: number): BetaPromotionPreview { + return promotionPlan(betaId).preview; } function promoteDeploymentId(betaId: number): string { @@ -728,14 +778,14 @@ function promoteDeploymentId(betaId: number): string { return `dep-${stamp}-promote-${betaId}`; } -export async function promoteBeta(betaId: number): Promise { +export async function promoteBeta(betaId: number, reviewedToken?: string): Promise { if (storedPlan(betaId)) { const { plannedBetaTick } = await import('../pipeline/beta-plan-runner.js'); await plannedBetaTick(); } - return exclusive(betaId, () => promoteBetaInternal(betaId)); + return exclusive(betaId, () => promoteBetaInternal(betaId, reviewedToken)); } -async function promoteBetaInternal(betaId: number): Promise { +async function promoteBetaInternal(betaId: number, reviewedToken?: string): Promise { const test = storedPlan(betaId); if (test && test.outcome !== 'passed') throw new BetaError('Test plan has not passed', 'not-ready-promote'); const beta = getBeta(betaId); @@ -743,6 +793,15 @@ async function promoteBetaInternal(betaId: number): Promise { if (beta.state !== 'ready-promote') { throw new BetaError(`beta must be ready-promote (is ${beta.state})`, 'not-ready-promote'); } + const reviewed = promotionPlan(betaId); + const checkReview = () => { + const current = previewBetaPromotion(betaId); + if (current.token !== (reviewedToken ?? reviewed.preview.token)) { + throw new BetaError('Promotion targets or versions changed. Review the updated plan before promoting.', 'preview-changed', current); + } + if (current.blockers.length) throw new BetaError(current.blockers.join(' '), 'invalid-state'); + }; + checkReview(); const bundleRows = listBetaScripts(betaId); if (bundleRows.length === 0) throw new BetaError('beta has no scripts', 'no-scripts'); const bundle = bundleRows.map((br) => ({ @@ -755,8 +814,6 @@ async function promoteBetaInternal(betaId: number): Promise { // Split bundle into non-collapsing (per-file) and collapsing (composed cfg). const nonCollapsing = bundle.filter((b) => !isCollapsingKind(b.script.kind)); const collapsing = bundle.filter((b) => isCollapsingKind(b.script.kind)); - const collapsingBaseline = collapsing.find((b) => b.script.kind === 'baseline'); - const collapsingOverlays = collapsing.filter((b) => b.script.kind === 'config'); // Build a per-(script, server) plan for non-collapsing artifacts. interface Plan { @@ -776,10 +833,7 @@ async function promoteBetaInternal(betaId: number): Promise { ); for (const { script, version } of nonCollapsing) { - const scopeServers = script.scope_type && script.scope_value - ? serversMatchingScope(script.scope_type, script.scope_value) - : []; - const targets = new Set([...betaServerSet, ...scopeServers]); + const targets = reviewed.preview.files.find(file => file.id === script.id)!.servers; for (const name of targets) { const dest = destOfKind(name, script.kind); @@ -830,23 +884,6 @@ async function promoteBetaInternal(betaId: number): Promise { // Write files. Track per-plan success and per-server first-error. const planWritten = new Map(); const serverErr = new Map(); - for (const p of plans) { - const dest = destOfKind(p.server, p.script.kind); - const targetPath = join(dest, p.script.target_rel_path); - try { - await mkdir(join(dest, dirname(p.script.target_rel_path)), { recursive: true }); - // Beta servers already have the version bytes at targetPath from - // openBeta; scope-expansion servers need the write. Idempotent - // either way — we just overwrite with the promoted content. - await writeFile(targetPath, p.version.content); - planWritten.set(p, true); - } catch (err) { - planWritten.set(p, false); - const msg = `${p.script.name}: ${(err as Error).message}`; - if (!serverErr.has(p.server)) serverErr.set(p.server, msg); - console.error(`[promote] ${p.server}/${p.script.name} failed:`, err); - } - } // Collapsing config layer: one composed cfg per server. Union of beta // servers + scope-matching servers for every collapsing artifact. @@ -860,29 +897,18 @@ async function promoteBetaInternal(betaId: number): Promise { } const cfgPlans: CfgPlan[] = []; if (collapsing.length > 0) { - const cfgTargets = new Set(betaServerSet); - for (const { script } of collapsing) { - if (script.scope_type && script.scope_value) { - for (const s of serversMatchingScope(script.scope_type, script.scope_value)) { - cfgTargets.add(s); - } - } - } + const cfgTargets = reviewed.preview.configWrites.map(write => write.server); for (const name of cfgTargets) { const srv = getServer(name); if (!srv) { serverErr.set(name, 'unknown server during config promote'); continue; } - const composedResult = composeCfgForServer(name, srv.game, srv.map, { - inBetaBaseline: collapsingBaseline?.version, - inBetaOverlays: collapsingOverlays - }); - if (!composedResult) { + const composedBuf = reviewed.configContent.get(name); + if (!composedBuf) { serverErr.set(name, `no baseline available for ${name} (game=${srv.game ?? '?'})`); continue; } - const composedBuf = Buffer.from(composedResult.text, 'utf8'); const composedSha = sha256Buffer(composedBuf); const dest = destOfKind(name, 'config'); const targetRel = configFileOf(name); @@ -913,6 +939,20 @@ async function promoteBetaInternal(betaId: number): Promise { } } + // Recheck after asynchronous snapshot reads, before any mutation. Execution uses + // the captured target lists/content so later membership changes never expand it. + checkReview(); + for (const p of plans) { + const dest = destOfKind(p.server, p.script.kind); + try { + await mkdir(join(dest, dirname(p.script.target_rel_path)), { recursive: true }); + await writeFile(join(dest, p.script.target_rel_path), p.version.content); + planWritten.set(p, true); + } catch (err) { + planWritten.set(p, false); + if (!serverErr.has(p.server)) serverErr.set(p.server, `${p.script.name}: ${(err as Error).message}`); + } + } // Write composed cfg to each target. const cfgWritten = new Map(); for (const cp of cfgPlans) { @@ -1061,7 +1101,9 @@ async function promoteBetaInternal(betaId: number): Promise { betaId, deploymentId: depId, landed, - scriptIds: bundle.map((b) => b.script.id) + scriptIds: bundle.map((b) => b.script.id), + awaitingActivation: reviewed.preview.servers.filter(server => !server.tested && !serverErr.has(server.name)).length, + failedServers: [...serverErr.keys()] }; } diff --git a/src/lib/server/fleet/collections.ts b/src/lib/server/fleet/collections.ts index 9434686..93331ae 100644 --- a/src/lib/server/fleet/collections.ts +++ b/src/lib/server/fleet/collections.ts @@ -5,6 +5,8 @@ import { config, komodoConfigured, rconConfigured } from '../config.js'; import { blueprintEntries, summarizeRecipe, type BlueprintEntry } from './launch-recipes.js'; import { creationQueue, nextAvailablePort, nextLobbyNumber, queueCreateServer } from './create.js'; import { getServerKey } from './server-keys.js'; +import { classifyHealth } from './health.js'; +import { getServer } from './servers.js'; import { parseServerName, zombieMapBySlug, zombieMaps } from './map-aliases.js'; function coverage(entries: BlueprintEntry[]) { @@ -29,7 +31,15 @@ function coverage(entries: BlueprintEntry[]) { const matches = zombieMaps(game).filter(map => map.canonical === server.map); return matches.length === 1 && matches[0].slug === entry.recipe.mapSlug; }).map(server => server.name).sort(); - return { existingServers, existing: existingServers.length, missing: Math.max(0, entry.count - existingServers.length) }; + const coverage = existingServers.map(name => { + const operation = db().prepare("SELECT id, state FROM server_deployments WHERE server = ? AND action = 'create' AND state IN ('queued', 'running', 'awaiting-health') ORDER BY rowid DESC LIMIT 1").get(name) as { id: string; state: string } | undefined; + const server = getServer(name); + return { name, health: operation ? operation.state === 'queued' ? 'queued' : 'starting' + : server?.container_state && !['running', 'starting', 'restarting'].includes(server.container_state) ? 'stopped' + : classifyHealth(server?.last_seen_at ?? null, server?.last_error ?? null, server?.container_state), + href: operation ? `/deployments/${encodeURIComponent(operation.id)}` : `/servers/${encodeURIComponent(name)}` }; + }); + return { existingServers, coverage, existing: existingServers.length, missing: Math.max(0, entry.count - existingServers.length) }; }); } diff --git a/src/lib/server/fleet/create.ts b/src/lib/server/fleet/create.ts index 9a980bf..b3857db 100644 --- a/src/lib/server/fleet/create.ts +++ b/src/lib/server/fleet/create.ts @@ -1,5 +1,5 @@ import { rconGetPlayerCount, rconStatusResult } from '../integrations/rcon.js'; -import { beginDeployment, deploymentStage, finishDeployment, recordDeploymentEvent, REMOVING_SERVER, resumeCleanup, resumeVerification } from './deployments.js'; +import { beginDeployment, deploymentStage, finishDeployment, recordDeploymentEvent, REMOVING_SERVER, resumeCleanup, resumeVerification, claimRemoval } from './deployments.js'; import { randomUUID } from 'node:crypto'; import type { LaunchPreview } from '$lib/deployment-plan.js'; import { blueprintRecipe, captureRecipe, recipeForDeployment, summarizeRecipe, type LaunchRecipe } from './launch-recipes.js'; @@ -461,6 +461,7 @@ async function runDestructions(): Promise { const queued = db().prepare("SELECT id, server, stage FROM server_deployments WHERE action = 'destroy' AND state = 'waiting' ORDER BY started_at").all() as { id: string; server: string; stage: string }[]; for (const operation of queued) { if (creating || destroying.has(operation.server)) continue; + if (!db().prepare("SELECT id FROM server_deployments WHERE id = ? AND state = 'waiting'").get(operation.id)) continue; destroying.add(operation.server); try { if (operation.stage === REMOVING_SERVER) { @@ -470,7 +471,7 @@ async function runDestructions(): Promise { finishDeployment(operation.id, { ok: false, message: 'A newer creation exists; local cleanup cannot safely resume.' }); continue; } - db().prepare("UPDATE server_deployments SET state = 'running' WHERE id = ?").run(operation.id); + if (!claimRemoval(operation.id)) continue; finishDeployment(operation.id, await cleanupDestroyedServer(operation.server, operation.id)); continue; } @@ -484,20 +485,21 @@ async function runDestructions(): Promise { } // A fresh successful zero is required; cached occupancy and timeouts are not evidence of emptiness. const players = await rconGetPlayerCount(operation.server); + if (!db().prepare("SELECT id FROM server_deployments WHERE id = ? AND state = 'waiting'").get(operation.id)) continue; if (players !== 0) { deploymentStage(operation.id, players === null ? 'Waiting for player count: server could not be reached' : 'Waiting for server to empty: ' + players + ' player(s) online'); continue; } + if (!claimRemoval(operation.id)) continue; deploymentStage(operation.id, 'Server is empty (0 players verified)'); - db().prepare("UPDATE server_deployments SET state = 'running' WHERE id = ?").run(operation.id); const result = await destroyServerUnlocked(operation.server, operation.id); finishDeployment(operation.id, result); } catch (err) { const row = db().prepare('SELECT state FROM server_deployments WHERE id = ?').get(operation.id) as { state: string }; if (row.state === 'waiting') deploymentStage(operation.id, 'Waiting for player count: ' + (err as Error).message); - else finishDeployment(operation.id, { ok: false, message: (err as Error).message }); + else if (row.state !== 'cancelled') finishDeployment(operation.id, { ok: false, message: (err as Error).message }); } finally { destroying.delete(operation.server); } } } diff --git a/src/lib/server/fleet/deployments.ts b/src/lib/server/fleet/deployments.ts index 7226401..3f19825 100644 --- a/src/lib/server/fleet/deployments.ts +++ b/src/lib/server/fleet/deployments.ts @@ -30,12 +30,31 @@ export function getDeployment(id: string) { const collection = db().prepare(`SELECT c.id, c.name FROM server_collection_members m JOIN server_launch_collections c ON c.id = m.collection_id WHERE m.deployment_id = ?`).get(id) ?? null; return { deployment, events, recipe: launch ? summarizeRecipe(launch.recipe) : null, blueprintName: launch?.blueprintName ?? null, - canResumeVerification: canResumeVerification(id), canResumeCleanup: canResumeCleanup(id), collection }; + canResumeVerification: canResumeVerification(id), canResumeCleanup: canResumeCleanup(id), canCancelRemoval: canCancelRemoval(id), collection }; } // This stage is written only after Komodo has confirmed deployment deletion. export const REMOVING_SERVER = 'Removing server files and registry'; +export function canCancelRemoval(id: string): boolean { + return !!db().prepare("SELECT id FROM server_deployments WHERE id = ? AND action = 'destroy' AND state = 'waiting' AND stage != ?").get(id, REMOVING_SERVER); +} + +/** Competes atomically with the worker's claim, before any external removal. */ +export function cancelRemoval(id: string): boolean { + return db().transaction(() => { + const result = db().prepare(`UPDATE server_deployments SET state = 'cancelled', stage = 'Removal cancelled', finished_at = ?, error = NULL + WHERE id = ? AND action = 'destroy' AND state = 'waiting' AND stage != ?`).run(new Date().toISOString(), id, REMOVING_SERVER); + if (!result.changes) return false; + recordDeploymentEvent(id, 'Queued removal cancelled. The server and its files were kept.'); + return true; + })(); +} + +export function claimRemoval(id: string): boolean { + return db().prepare("UPDATE server_deployments SET state = 'running' WHERE id = ? AND action = 'destroy' AND state = 'waiting'").run(id).changes > 0; +} + export function canResumeCleanup(id: string): boolean { return !!db().prepare(`SELECT d.id FROM server_deployments d WHERE d.id = ? AND d.action = 'destroy' AND d.state IN ('failed', 'interrupted') AND d.stage = ? @@ -81,8 +100,9 @@ export function finishDeployment(id: string, result: { ok: boolean; message?: st } export function listDeployments() { - return db().prepare(`SELECT d.*, EXISTS(SELECT 1 FROM servers s WHERE s.name = d.server) AS server_exists - FROM server_deployments d ORDER BY started_at DESC, rowid DESC`).all(); + return db().prepare(`SELECT d.*, EXISTS(SELECT 1 FROM servers s WHERE s.name = d.server) AS server_exists, + (d.action = 'destroy' AND d.state = 'waiting' AND d.stage != ?) AS canCancelRemoval + FROM server_deployments d ORDER BY started_at DESC, rowid DESC`).all(REMOVING_SERVER); } export function interruptDeployments(): void { diff --git a/src/lib/server/fleet/drift.ts b/src/lib/server/fleet/drift.ts index 25c42bb..52acf37 100644 --- a/src/lib/server/fleet/drift.ts +++ b/src/lib/server/fleet/drift.ts @@ -1,4 +1,6 @@ import { mkdir, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises'; +import { randomUUID } from 'node:crypto'; +import type { DriftPlan, DriftPlanFile } from '$lib/drift-plan.js'; import { existsSync } from 'node:fs'; import { dirname, join, posix, relative, sep } from 'node:path'; import { configFileOf, destOfKind, type ArtifactKind } from '../config.js'; @@ -244,6 +246,40 @@ export interface RunDriftInput { servers?: string[]; // if omitted, scans the whole fleet dryRun?: boolean; triggeredBy?: 'ui' | 'sweep' | 'cron'; + expectedFingerprint?: string; +} + +export class DriftPlanChanged extends Error { + constructor(public plan: DriftPlan) { super('The files or target servers changed. Nothing was changed. Review the updated plan before continuing.'); } +} + +function driftTargets(servers?: string[]): string[] { + const registered = listServers().map(server => server.name); + if (servers && (!servers.length || servers.some(name => !registered.includes(name)))) throw new Error('Select at least one registered server. Refresh the fleet if a server was removed.'); + return [...new Set(servers ?? registered)].sort(); +} + +async function describePlan(servers: string[], entries: DriftEntry[]): Promise { + const files: DriftPlanFile[] = []; + for (const entry of entries) { + const before = await readFile(join(destOfKind(entry.server, entry.kind), entry.relPath)).catch((error: NodeJS.ErrnoException) => { + if (error.code === 'ENOENT') return null; + throw error; + }); + const after = entry.driftKind === 'untracked' ? null : await resolveManagedEntry(entry.server, entry); + files.push({ server: entry.server, relPath: entry.relPath, kind: entry.kind, driftKind: entry.driftKind, + beforeSha256: before ? sha256Buffer(before) : null, afterSha256: after ? sha256Buffer(after) : null, + beforeSize: before?.byteLength ?? null, afterSize: after?.byteLength ?? null }); + } + files.sort((a, b) => `${a.server}:${a.kind}:${a.relPath}`.localeCompare(`${b.server}:${b.kind}:${b.relPath}`)); + return { servers, files, scannedAt: new Date().toISOString(), fingerprint: sha256Buffer(Buffer.from(JSON.stringify({ servers, files }))) }; +} + +export async function previewDrift(servers?: string[]): Promise { + const targets = driftTargets(servers); + const entries: DriftEntry[] = []; + for (const server of targets) entries.push(...await scanServerDrift(server)); + return describePlan(targets, entries); } export interface RunDriftResult { @@ -259,7 +295,7 @@ export interface RunDriftResult { function deploymentIdNow(): string { const stamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\.\d+Z$/, 'Z'); - return `dep-${stamp}-drift`; + return `dep-${stamp}-drift-${randomUUID().slice(0, 8)}`; } /** @@ -271,9 +307,7 @@ function deploymentIdNow(): string { export async function runDriftDeployment(input: RunDriftInput = {}): Promise { const { dryRun = false, triggeredBy = 'ui' } = input; - const scanTargets = input.servers && input.servers.length > 0 - ? input.servers - : listServers().map((s) => s.name); + const scanTargets = driftTargets(input.servers); const perServer: Array<{ server: string; @@ -287,6 +321,9 @@ export async function runDriftDeployment(input: RunDriftInput = {}): Promise server.entries)) : null; + if (plan && plan.fingerprint !== input.expectedFingerprint) throw new DriftPlanChanged(plan); const totalDrift = perServer.reduce((sum, s) => sum + s.entries.length, 0); if (totalDrift === 0 || dryRun) { return { @@ -335,6 +372,14 @@ export async function runDriftDeployment(input: RunDriftInput = {}): Promise file.server === s.server && file.kind === entry.kind && file.relPath === entry.relPath); + if (reviewed) { + const current = await readFile(abs).catch((error: NodeJS.ErrnoException) => { if (error.code === 'ENOENT') return null; throw error; }); + if ((current ? sha256Buffer(current) : null) !== reviewed.beforeSha256) { + s.skipped.push(`${entry.relPath}: changed after review; scan and review again`); + continue; + } + } if (entry.driftKind === 'untracked') { // Delete a file inventory doesn't know about. const content = await readFile(abs); @@ -349,6 +394,10 @@ export async function runDriftDeployment(input: RunDriftInput = {}): Promise { if (err.code === 'ENOENT') return null; throw err; diff --git a/src/lib/server/fleet/overview.ts b/src/lib/server/fleet/overview.ts index 747ef03..4248491 100644 --- a/src/lib/server/fleet/overview.ts +++ b/src/lib/server/fleet/overview.ts @@ -35,17 +35,17 @@ export function fleetOperations(now = Date.now()): FleetOperation[] { // Only the newest lifecycle operation can still require action on a server. const lifecycle = handle.prepare(`SELECT d.* FROM server_deployments d WHERE d.state IN ('queued', 'running', 'waiting', 'awaiting-health') - OR (d.state IN ('done', 'warning') AND d.finished_at >= ?) + OR (d.state IN ('done', 'warning', 'cancelled') AND d.finished_at >= ?) OR (d.state IN ('failed', 'interrupted', 'warning') AND NOT EXISTS (SELECT 1 FROM server_deployments n WHERE n.server = d.server AND n.rowid > d.rowid))`) .all(since) as { id: string; server: string; action: string; state: string; stage: string; error: string | null; started_at: string }[]; for (const row of lifecycle) { - const state = row.state === 'done' || row.state === 'warning' ? 'done' + const state = ['done', 'warning', 'cancelled'].includes(row.state) ? 'done' : ['failed', 'interrupted'].includes(row.state) ? 'attention' : 'active'; operations.push({ key: `deployment:${row.id}`, group: `deployment:${row.id}`, kind: 'deployment', server: row.server, state, startedAt: row.started_at, - label: state === 'done' ? row.state === 'warning' ? 'Completed with warnings' : 'Complete' + label: state === 'done' ? row.state === 'cancelled' ? 'Removal cancelled' : row.state === 'warning' ? 'Completed with warnings' : 'Complete' : state === 'attention' ? `${row.action === 'create' ? 'Launch' : 'Removal'} needs attention` : row.stage, detail: row.error ?? row.stage, href: `/deployments/${encodeURIComponent(row.id)}` }); } diff --git a/src/lib/system-status.ts b/src/lib/system-status.ts new file mode 100644 index 0000000..0645195 --- /dev/null +++ b/src/lib/system-status.ts @@ -0,0 +1,15 @@ +export interface SetupCheck { + id: string; + title: string; + state: 'ready' | 'attention' | 'unconfigured' | 'unverified'; + detail: string; + href?: string; + action?: string; +} +export interface SystemStatus { + checkedAt: string; + checks: SetupCheck[]; + readyServers: number; + totalServers: number; + savedKeys: number; +} diff --git a/src/lib/ui/components/ArtifactDetail.svelte b/src/lib/ui/components/ArtifactDetail.svelte index a9b37d4..5c79f0c 100644 --- a/src/lib/ui/components/ArtifactDetail.svelte +++ b/src/lib/ui/components/ArtifactDetail.svelte @@ -50,6 +50,13 @@ let artifact = $state(null); let versions = $state([]); let matchedServers = $state([]); + let installedVersions = $state>([]); + interface ScopeImpact { before: string[]; after: string[]; added: string[]; removed: string[]; affected: string[]; composed: boolean; detached: string[]; } + let scopeReviewOpen = $state(false); + let scopeImpact = $state(null); + let scopePreviewError = $state(''); + let scopePreviewLoading = $state(false); + let scopeComplete = $state<{ count: number; composed: boolean; detached: number; href: string } | null>(null); let runningBetaId = $state(null); let loading = $state(true); let flash = $state(null); @@ -84,9 +91,24 @@ : null ); const latestVersion = $derived(versions[0] ?? null); - const showLatestSeparately = $derived( - latestVersion !== null && currentVersion !== null && latestVersion.id !== currentVersion.id - ); + + $effect(() => { + const type = scopeType; const value = editedScopeValue; const artifactId = id; + if (!scopeReviewOpen) return; + scopeImpact = null; scopePreviewError = ''; + if (type !== 'none' && !value) { scopePreviewLoading = false; return; } + const controller = new AbortController(); scopePreviewLoading = true; + void (async () => { + try { + const response = await fetch(`/api/scripts/${artifactId}/scope?${new URLSearchParams({ type, value })}`, { signal: controller.signal }); + const body = await response.json(); + if (!response.ok) throw new Error(body.error ?? 'Could not preview scope.'); + if (!controller.signal.aborted) scopeImpact = body; + } catch (error) { if (!controller.signal.aborted) scopePreviewError = (error as Error).message; } + finally { if (!controller.signal.aborted) scopePreviewLoading = false; } + })(); + return () => controller.abort(); + }); function scopeLabel(s: Artifact): string { if (!s.scope_type) return 'unscoped'; @@ -105,7 +127,7 @@ const body = await detailRes.json(); const scopes = scopeRes?.ok ? await scopeRes.json() : null; if (requestedId !== id || current !== request) return; - artifact = body.script; versions = body.versions; matchedServers = body.matchedServers; runningBetaId = body.runningBetaId; + artifact = body.script; versions = body.versions; matchedServers = body.matchedServers; runningBetaId = body.runningBetaId; installedVersions = body.installedVersions ?? []; if (scopes) scopeOptions = scopes; if (seedForm) seedScopeForm(); loadError = ''; @@ -135,10 +157,12 @@ if (runningBetaId !== null) return; seedScopeForm(); flash = null; + scopeReviewOpen = true; scopeDialog?.showModal(); } function cancelScopeModal(): void { seedScopeForm(); + scopeReviewOpen = false; scopeDialog?.close(); } function openUploadModal(): void { @@ -192,7 +216,7 @@ async function saveScope(e: Event): Promise { e.preventDefault(); - if (updatingScope) return; + if (updatingScope || !scopeImpact || scopePreviewLoading) return; if (scopeType !== 'none' && !editedScopeValue) { flash = `Pick a ${scopeType}`; return; @@ -207,12 +231,13 @@ scopeValue: scopeType === 'none' ? null : editedScopeValue }) }); - const body = (await res.json()) as { ok: boolean; error?: string; kind?: string }; + const body = (await res.json()) as { ok: boolean; error?: string; kind?: string; detached?: string[] }; if (!res.ok || !body.ok) { flash = body.error ?? `HTTP ${res.status}`; return; } - scopeDialog?.close(); + scopeComplete = { count: scopeImpact.affected.length, composed: scopeImpact.composed, detached: body.detached?.length ?? 0, href: scopeImpact.affected.length === 1 ? '/campaigns?server=' + encodeURIComponent(scopeImpact.affected[0]) : '/campaigns' }; + scopeReviewOpen = false; scopeDialog?.close(); await load(); } catch (error) { flash = (error as Error).message; } finally { updatingScope = false; @@ -244,6 +269,8 @@ ]; +{artifact?.name ?? crumbLabel} · Electric Cherry + {#if loadError}{/if} {#if loading}
Loading…
@@ -258,6 +285,9 @@ {/snippet} + {#if scopeComplete}
Scope saved. {scopeComplete.composed ? `Intended configuration may change on ${scopeComplete.count} eligible servers.` : scopeComplete.detached ? `Inventory tracking detached on ${scopeComplete.detached} servers; live files remain.` : `${scopeComplete.count} servers are in the old or new scope.`} Running servers have not been changed. Review reconciliation →
{/if} + {#if latestVersion}

Latest {artifactVersionLabel(latestVersion)}

{latestVersion.notes || 'No version notes provided.'}

{#if runningBetaId !== null}{:else if latestVersion.id !== a.current_version_id}{:else}Latest version is promoted{/if}
{/if} + {#if runningBetaId}
Beta #{runningBetaId} is running for this {family}. @@ -278,7 +308,7 @@
-
+
Target file, scope, and eligible servers
Target file {a.target_rel_path} @@ -295,7 +325,7 @@
- Applies to + Eligible servers {#if !a.scope_type} Unscoped — deploy from a beta @@ -307,28 +337,21 @@
- Current version + Promoted version {#if currentVersion} {artifactVersionLabel(currentVersion)} · {currentVersion.sha256.slice(0, 8)} Promoted {:else} - Never promoted — open a beta + Never promoted — test a version first {/if}
- {#if showLatestSeparately && latestVersion} -
- Latest version - - {artifactVersionLabel(latestVersion)} · {latestVersion.sha256.slice(0, 8)} - - -
- {/if} -
+
+ {#if installedVersions.length}
Recorded installed files · {installedVersions.length} servers

Last recorded file writes, not a verification of the currently running process.

    {#each installedVersions as installed}
  • {installed.server} · v{installed.version} · {new Date(installed.recordedAt).toLocaleString()}
  • {/each}
{:else if family !== 'config'}

No installed file versions recorded. Eligibility does not mean a file is installed.

{/if} + {#if a.kind === 'config' || a.kind === 'baseline'} load({ seedForm: false })} /> @@ -346,8 +369,6 @@ {#each versions.slice(0,limit) as v (v.id)}
{artifactVersionLabel(v)} - {v.sha256.slice(0, 12)} - {v.size} B {v.notes ?? ''} {#if v.source}GitHub · {v.source.asset_name} ↗{/if} @@ -358,6 +379,7 @@ {#if runningBetaId === null}{/if} {/if} +
File detailsSHA-256: {v.sha256}Size: {v.size.toLocaleString()} bytes
{/each} @@ -374,10 +396,10 @@ - {#if flash}
{flash}
{/if} + {#if flash}{/if} - { if (updatingScope) event.preventDefault(); }} bind:this={scopeDialog} onclick={(e) => onDialogClick(scopeDialog, e)}> + scopeReviewOpen = false} oncancel={event => { if (updatingScope) event.preventDefault(); }} bind:this={scopeDialog} onclick={(e) => onDialogClick(scopeDialog, e)}>

Edit scope

@@ -387,20 +409,21 @@
+ {/if}
+ {#if scopePreviewLoading}

Reviewing eligible servers…

{:else if scopePreviewError}

{scopePreviewError}

{:else if scopeImpact}
{scopeImpact.after.length} eligible · {scopeImpact.added.length} added · {scopeImpact.removed.length} removed{#if scopeImpact.added.length}

Added: {scopeImpact.added.join(', ')}

{/if}{#if scopeImpact.removed.length}

Removed: {scopeImpact.removed.join(', ')}

{/if}

{scopeImpact.composed ? 'This changes intended configuration composition. Live configuration files remain unchanged until a deployment or reconciliation.' : scopeType === 'none' ? `${scopeImpact.detached.length} recorded installations will become untracked. Files remain on servers; review reconciliation to remove orphaned files.` : 'Scope describes eligibility. Saving does not install files or restart servers; review reconciliation for existing promoted files.'}

{/if}
-
- {#if flash}
{flash}
{/if} + {#if flash}{/if}
@@ -433,7 +456,7 @@ Upload version - {#if flash}
{flash}
{/if} + {#if flash}{/if}
@@ -499,7 +522,7 @@ .version-list { display: flex; flex-direction: column; gap: var(--space-1); } .version-row { display: grid; - grid-template-columns: minmax(100px, 1fr) 130px 80px 1fr 220px auto; + grid-template-columns: minmax(100px, auto) minmax(0, 1fr) auto auto auto; gap: var(--space-3); align-items: center; padding: var(--space-2) var(--space-3); @@ -514,7 +537,17 @@ background: rgba(124, 212, 255, 0.04); } .v-num { color: var(--text-primary); font-weight: var(--weight-semibold); overflow-wrap: anywhere; } - .v-sha, .v-size, .v-when { color: var(--text-tertiary); font-variant-numeric: tabular-nums; } + .v-when { color: var(--text-tertiary); font-variant-numeric: tabular-nums; } + .version-technical { grid-column: 1 / -1; color: var(--text-secondary); overflow-wrap: anywhere; } + .version-technical span { display: block; margin-top: 8px; } + .scope-complete { padding: 16px; border: 1px solid var(--state-online); border-radius: var(--radius-md); font-size: var(--text-sm); } + .release-summary { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px; } + .release-summary h2 { font-size: var(--text-lg); margin: 0 0 8px; } + .release-summary p, .installed p, .scope-impact p { color: var(--text-secondary); font-size: var(--text-sm); overflow-wrap: anywhere; } + .scope-impact { border: 1px solid var(--border-strong); border-radius: var(--radius-md); padding: 12px; font-size: var(--text-sm); } + .installed { font-size: var(--text-sm); } + .file-settings { font-size: var(--text-sm); } + .file-settings .kv-grid { margin-top: 16px; } .v-notes { color: var(--text-secondary); font-family: var(--font-body); font-size: var(--text-sm); } .v-notes { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 160px; overflow-y: auto; } .v-notes a { display: block; color: var(--accent-primary-hover); margin-top: var(--space-2); } diff --git a/src/lib/ui/components/BetaPlanBuilder.svelte b/src/lib/ui/components/BetaPlanBuilder.svelte index 824e28b..bc4dc4d 100644 --- a/src/lib/ui/components/BetaPlanBuilder.svelte +++ b/src/lib/ui/components/BetaPlanBuilder.svelte @@ -1,9 +1,23 @@
-

Test plan

- {#if test.reason}

{test.reason}

{/if} -

{coverageSummary(test.plan)} · {test.plan.timeoutHours}-hour testing window · Manual promotion

-
Test policy

{test.plan.waveSize ? test.plan.waveSize + ' servers per wave.' : 'All servers deployed together.'} {test.plan.failureAction === 'rollback' ? 'Failed checks trigger an automatic rollback.' : test.plan.failureAction === 'pause' ? 'Failed checks pause the test for investigation.' : 'Failed checks hold the test for review.'} {test.plan.rollbackRestart === 'when-empty' ? 'Rollback restarts wait for empty servers.' : 'Rollback restores files; servers must be restarted manually.'}

+

Test results

+

{coverageSummary(test.plan)} · Every requirement must pass on each qualifying server.

{#if !closed} -
- {#if test.outcome === 'paused'}{/if} - {#if ['active', 'passed'].includes(test.outcome)}{/if} - {#if ['paused', 'failed'].includes(test.outcome)}{/if} -
+
+ {#if test.outcome === 'paused' && !expired}{/if} + {#if ['active','passed'].includes(test.outcome)}{/if} + {#if ['paused','failed'].includes(test.outcome) && !expired}{/if} +
+ {#if retryBlocked && ['paused','failed'].includes(test.outcome)}

{retryBlocked}

{/if} + {#if expired}

The testing window ended. Roll back this beta first, then choose “Reuse files and test plan” to open a new beta with a longer window.

+ {:else if test.outcome === 'paused'}

Resume retains completed milestones; continuous health and in-progress timing intervals start fresh. Pausing does not extend the deadline.

{/if} {/if} {#if error}{/if} - {#if test.servers.length === 0}

Waiting for the first server restart. Evidence collection begins with that run.

{/if} - {#each test.servers as server (server.server)} -
-

Recovery cycles: {server.phase}

- {#each server.progress as progress (progress.id)} - {@const requirement = test.plan.requirements.find(r => r.id === progress.id)!} -
-
{progress.passed ? '✓' : progress.failed ? '✕' : '○'} {progress.label}{progress.detail}
- {#if ['round', 'matches', 'populated-minutes', 'player-hours', 'sustained-population'].includes(requirement.kind)} - Minimum {requirement.minPlayers} player(s){requirement.minRound ? `, round ${requirement.minRound} in the same game` : ''}{requirement.minMinutes ? `, ${requirement.minMinutes} minutes per match` : ''} - {/if} - {#if !['manual', 'failure-budget'].includes(requirement.kind)} - - {/if} - {#if requirement.kind === 'manual' && !progress.passed && !closed} -
- - -
- {/if} -
- {/each} -
- {/each} -
evidenceOpen = event.currentTarget.open}> - Evidence ({test.evidence.length}{test.evidence.length === 200 ? ' most recent' : ''}) - {#if evidenceOpen} - {#each test.evidence.slice(0,evidenceLimit) as event (event.id)} -
{event.server} · {event.kind}
{event.payload}
+ {#if message}

{message}

{/if} + {#if !test.servers.length}

Waiting for the first server restart. Evidence collection begins with that run. The testing window is already running.

{/if} + {#each ranked as server (server.server)} +
+ {server.progress.filter(p=>p.passed).length} / {server.progress.length} checks passed{#if test.plan.requirements.some(r=>r.kind==='recovery')}Recovery cycles: {server.phase}{/if} + {#if test.plan.requirements.some(needsGameTelemetry)}

{#if server.observation?.lastGameplayAt}Latest gameplay: {server.observation.lastEvent?.replaceAll('_',' ')} · · {server.observation.players ?? 'Unknown'} players{#if server.observation.round !== null} · Round {server.observation.round}{/if}{:else}No gameplay reports in this attempt yet.{/if} Telemetry diagnostics

{/if} + {#each server.progress as progress (progress.id)} + {@const requirement = test.plan.requirements.find(r=>r.id===progress.id)} + {#if requirement}
+
{progress.passed ? 'Passed' : progress.failed ? 'Failed' : 'Waiting'} {requirementSummary(requirement)}{progress.detail}
+ {#if !progress.passed && !closed}

{betaWaitingCondition(requirement,server.observation)}

{/if} + {#if !['manual','failure-budget'].includes(requirement.kind)}{/if} + {#if requirement.kind === 'manual' && !progress.passed && !closed} + {#if canSign && server.observingAt}
+ {:else if canSign}

Waiting for this server's restart and health verification to finish before tester sign-off.

+ {:else}

Sign-off is unavailable while this test is {test.outcome}. {test.outcome === 'paused' ? 'Resume testing first.' : 'Use the recovery instructions above.'}

{/if} + {/if} + +
{/if} {/each} - - {#if !test.evidence.length}

No evidence recorded yet.

{/if} +
+ {/each} +
Test policy

{test.plan.waveSize ? `${test.plan.waveSize} servers per wave.` : 'All selected servers deployed together.'} {test.plan.failureAction === 'rollback' ? 'Failed checks trigger automatic rollback.' : test.plan.failureAction === 'pause' ? 'Failed checks pause testing for investigation.' : 'Failed checks hold testing for review.'} {test.plan.rollbackRestart === 'when-empty' ? 'Rollback restarts wait for empty servers.' : 'Rollback restores files; restart servers manually.'} Health checks continue after passing until promotion.

+
+ Evidence ({test.evidence.length}{test.evidence.length===200 ? ' most recent' : ''}) + {#if evidenceOpen} +

Newest first. Includes retained evidence from earlier attempts and recovery cycles; current progress uses only the current attempt.

+
+ {#each filteredEvidence.slice(0,evidenceLimit) as event(event.id)}

{betaEvidenceSummary(event)}

Raw payload · {event.kind}
{event.payload}
{/each} + + {#if !filteredEvidence.length}

{test.evidence.length ? 'No evidence matches these filters.' : 'No evidence recorded yet. Check deployment progress and telemetry diagnostics.'}

{/if} {/if}
diff --git a/src/lib/ui/components/BlueprintBuilder.svelte b/src/lib/ui/components/BlueprintBuilder.svelte index 4254c2f..a215b22 100644 --- a/src/lib/ui/components/BlueprintBuilder.svelte +++ b/src/lib/ui/components/BlueprintBuilder.svelte @@ -15,7 +15,10 @@ let busy = $state(false); let error = $state(''); let total = $derived(rows.reduce((sum, row) => sum + (Number(row.count) || 0), 0)); - let valid = $derived(name.trim().length > 0 && rows.length > 0 && total <= 100 && rows.every(row => row.mapSlug && Number.isInteger(row.count) && row.count >= 1 && row.count <= 20)); + const duplicate = (row: typeof rows[number]) => rows.some(other => other.key !== row.key && other.game === row.game && other.mapSlug === row.mapSlug); + let valid = $derived(name.trim().length > 0 && rows.length > 0 && total <= 100 && rows.every(row => row.mapSlug && Number.isInteger(row.count) && row.count >= 1 && row.count <= 20 && !duplicate(row))); + let reason = $derived(!name.trim() ? 'Enter a blueprint name to save.' : total > 100 ? `Reduce the total by ${total - 100} to stay within 100 target lobbies.` : rows.some(duplicate) ? 'Choose each game and map once; increase its lobby count instead.' : !valid ? 'Choose a map and 1–20 target lobbies for every row.' : ''); + let canAdd = $derived((['t5', 't6'] as const).some(game => catalogs[game].some(map => !rows.some(row => row.game === game && row.mapSlug === map.slug)))); let wasOpen = false; let session = 0; let nextKey = 0; @@ -74,19 +77,20 @@
{ event.preventDefault(); void save(true); }}>
-

Your lineup

{total} server{total === 1 ? '' : 's'}
+

Your lineup

100} role="status">{total} / 100 target lobbies
{#each rows as row, index (row.key)}
{String(index + 1).padStart(2, '0')} - - + +
{/each} - +

Blueprints save your maps and target lobby counts. Every new server uses the latest promoted scripts, plugins, and configuration. Before launch, you’ll review every new server ID, port, and key.

+ {#if reason}

{reason}

{/if}
{/if} @@ -94,11 +98,12 @@ diff --git a/src/lib/ui/components/ConfigInspector.svelte b/src/lib/ui/components/ConfigInspector.svelte index bba290d..ff7c85a 100644 --- a/src/lib/ui/components/ConfigInspector.svelte +++ b/src/lib/ui/components/ConfigInspector.svelte @@ -3,10 +3,14 @@ import { serverTitle } from '$ui/server-labels.js'; import type { ConfigInspection, ConfigServer, ConfigSource } from '$lib/config-workbench.js'; import Button from './primitives/Button.svelte'; + import { saveLibraryContext } from '$ui/library-context.js'; let { artifactId, draftText, scopeType, scopeValue, fixedServer }: { fixedServer?: string; artifactId?: number; draftText?: string; scopeType?: string | null; scopeValue?: string | null } = $props(); let servers = $state([]); let selected = $state(''); let inspection = $state(null); + let promoted = $state(null); + let expanded = $state([]); + let inspectedServer = ''; let loading = $state(true); let error = $state(''); let query = $state(''); @@ -14,10 +18,15 @@ let raw = $state(false); let reload = $state(0); let ready = $state(false); + let desiredServer = ''; const eligible = $derived(servers.filter(s => (!fixedServer || s.name === fixedServer) && (!artifactId || (scopeType === 'game' ? s.game === scopeValue : scopeType === 'map' ? s.map === scopeValue : false)))); const settings = $derived((inspection?.settings ?? []).filter(s => (!onlyOverrides || s.history.length > 1) && `${s.key} ${s.value} ${s.source.name}`.toLowerCase().includes(query.toLowerCase()))); const overlaps = $derived(inspection?.settings.filter(s => s.history.length > 1).length ?? 0); + const previousValues = $derived(new Map((promoted?.settings ?? []).map(s => [s.key, s.value]))); + const changes = $derived(promoted && inspection ? inspection.settings.filter(s => previousValues.get(s.key) !== s.value) : []); + const removed = $derived(promoted?.settings.filter(s => inspection && !inspection.settings.some(current => current.key === s.key)) ?? []); function label(source: ConfigSource): string { return `${source.name}${source.draft ? ' · draft' : source.version ? ` · v${source.version}` : ''}`; } + function overriddenCount(source: ConfigSource) { return inspection?.settings.filter(s => (s.source.id !== source.id || s.source.kind !== source.kind) && s.history.some(h => h.source.id === source.id && h.source.kind === source.kind)).length ?? 0; } async function loadServers() { loading = true; error = ''; @@ -30,8 +39,9 @@ } catch (err) { error = (err as Error).message; } finally { loading = false; } } - onMount(loadServers); - $effect(() => { if (!eligible.some(s => s.name === selected)) selected = eligible[0]?.name ?? ''; }); + onMount(() => { desiredServer = new URLSearchParams(window.location.search).get('server') ?? ''; void loadServers(); }); + $effect(() => { if (!eligible.some(s => s.name === selected)) selected = eligible.find(s => s.name === desiredServer)?.name ?? eligible[0]?.name ?? ''; }); + $effect(() => { if (ready && selected && !fixedServer) saveLibraryContext({ server: selected }); }); $effect(() => { const server = selected; const text = draftText; @@ -39,7 +49,8 @@ const refresh = reload; if (!ready || !server) { inspection = null; if (ready) loading = false; return; } const controller = new AbortController(); - loading = true; error = ''; inspection = null; + loading = true; error = ''; + if (inspectedServer !== server) { inspection = null; promoted = null; expanded = []; inspectedServer = server; } const timer = setTimeout(async () => { try { const response = await fetch(id !== undefined && text !== undefined ? '/api/configs/inspect' : `/api/configs/inspect?server=${encodeURIComponent(server)}`, { @@ -48,7 +59,7 @@ }); const body = await response.json(); if (!response.ok) throw new Error(body.error ?? 'Could not inspect this config.'); - if (!controller.signal.aborted) inspection = body.inspection; + if (!controller.signal.aborted) { inspection = body.inspection; promoted = body.promoted ?? null; } } catch (err) { if (!controller.signal.aborted) error = (err as Error).message; } finally { if (!controller.signal.aborted) loading = false; } }, text === undefined ? 0 : 350); @@ -71,26 +82,26 @@ {#each eligible as server}{/each} {#if !eligible.length}{/if} - {#if error} - {:else if loading}

Composing configuration…

- {:else if !eligible.length}

{artifactId ? 'No registered servers match this scope.' : 'Register a server to inspect its configuration.'}

+ {#if error}{/if} +

{loading ? inspection ? 'Updating preview… Showing the last completed result.' : 'Composing configuration…' : inspection ? 'Preview up to date.' : ''}

+ {#if !eligible.length && !loading}

{artifactId ? 'No registered servers match this scope.' : 'Register a server to inspect its configuration.'}

{:else if inspection?.reason}

{inspection.reason}

{:else if inspection} -
+
    {#each inspection.sources as source, index} - {#if index}{/if} - {#if source.id}{label(source)} - {:else}{source.name}{/if} +
  1. {index + 1}.{#if source.id}{label(source)} + {:else}{source.name}{/if}{overriddenCount(source)} settings superseded later
  2. {/each} -
+

Overlays apply in creation order; later overlays win for the same key. The selected map takes precedence over map rotation.

+ {#if promoted}

Compared with promoted settings: {changes.length} changed or added, {removed.length} removed.

{#if removed.length}
Removed settings
    {#each removed as setting}
  • {setting.key} · previously {setting.value}
  • {/each}
{/if}{/if}
{#if raw} {:else}
{#each settings as setting (setting.key)} -
{setting.key}{setting.value}
{label(setting.source)} {#if setting.history.length > 1}{setting.history.length - 1} overridden{/if}
+
{ const open = event.currentTarget.open; expanded = open ? [...new Set([...expanded, setting.key])] : expanded.filter(key => key !== setting.key); }}>
{setting.key}{setting.value}
{label(setting.source)} {#if setting.history.length > 1}{setting.history.length - 1} overridden{/if}{#if promoted && previousValues.get(setting.key) !== setting.value}{previousValues.has(setting.key) ? `Changed from ${previousValues.get(setting.key)}` : 'Added by draft'}{/if}
    {#each setting.history as entry, index}
  1. {label(entry.source)}{entry.source.kind === 'map' ? 'Automatic' : `Line ${entry.line}`} · {index === setting.history.length - 1 ? 'Final value' : 'Overridden'}
    {entry.value}
  2. {/each}
{:else}

No matching settings.

{/each} @@ -110,10 +121,14 @@ .server-label { display: grid; gap: 8px; font-size: var(--text-xs); color: var(--text-secondary); } select, input:not([type='checkbox']) { width: 100%; box-sizing: border-box; background: var(--surface-sunken); color: var(--text-primary); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); padding: 10px 12px; font: var(--text-sm) var(--font-body); } select:focus-visible, input:focus-visible, button:focus-visible, summary:focus-visible, a:focus-visible, .composed:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; } - .sources { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 20px; font-size: var(--text-xs); } + .sources { display: grid; gap: 8px; margin: 20px 0 0; padding: 0; border: 0; font-size: var(--text-xs); list-style: none; } + .sources li { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 0; } + .layer-number { color: var(--text-primary); font-weight: 600; } + .preview-status { font-size: var(--text-xs); color: var(--text-secondary); min-height: 20px; } + .change-summary { display: block; font-size: var(--text-xs); color: var(--state-warning); margin-top: 8px; } .sources a, .map-source { background: var(--surface-raised); border-radius: 6px; padding: 6px 9px; text-decoration: none; } .sources a.draft { color: var(--state-warning); } - .map-source, .arrow { color: var(--text-secondary); } + .map-source { color: var(--text-secondary); } .hint { color: var(--text-secondary); font-size: var(--text-xs); line-height: 1.6; } .toolbar { border-top: 1px solid var(--border-subtle); padding-top: 12px; margin-top: 20px; } .switch { display: flex; gap: 4px; } @@ -142,4 +157,5 @@ .empty { color: var(--text-secondary); font-size: var(--text-sm); padding: 24px 0; } .error { color: var(--state-danger); margin-top: 16px; font-size: var(--text-sm); } @media (max-width: 600px) { .inspector { padding: 16px; } } + input:not([type='checkbox']):not([type='file']), select, textarea { border-color: var(--border-control); } diff --git a/src/lib/ui/components/ConfigLibrary.svelte b/src/lib/ui/components/ConfigLibrary.svelte index a2eac6c..7faee00 100644 --- a/src/lib/ui/components/ConfigLibrary.svelte +++ b/src/lib/ui/components/ConfigLibrary.svelte @@ -3,13 +3,14 @@ import Tabs from './primitives/Tabs.svelte'; import ListFooter from './primitives/ListFooter.svelte'; import { mapLabel } from '$lib/script-library.js'; - import { goto } from '$app/navigation'; + import { afterNavigate, goto } from '$app/navigation'; import SectionHeader from './primitives/SectionHeader.svelte'; import Button from './primitives/Button.svelte'; import Badge from './primitives/Badge.svelte'; import EmptyState from './primitives/EmptyState.svelte'; import ConfigTextEditor from './ConfigTextEditor.svelte'; import ConfigInspector from './ConfigInspector.svelte'; + import { libraryLimit, saveLibraryContext } from '$ui/library-context.js'; interface Version { id: number; version: number; state: 'untested' | 'tested' | 'test-failed'; uploaded_at: string; } interface Artifact { @@ -27,7 +28,11 @@ let status = $state(''); let view = $state('library'); let limit = $state(25); - $effect(() => { query; game; scope; status; limit = 25; }); + let mounted = $state(false); + afterNavigate(() => { mounted = true; }); + let lastFilters = ''; + $effect(() => { const key = JSON.stringify([query, game, scope, status]); if (!mounted) return; if (lastFilters && lastFilters !== key) limit = 25; lastFilters = key; }); + $effect(() => { if (mounted) saveLibraryContext({ q: query, game, scope, status, view, limit }, { view: 'library', limit: 25 }); }); let dialog: HTMLDialogElement; let kind = $state<'baseline' | 'config'>('config'); let name = $state(''); @@ -67,7 +72,7 @@ } catch (err) { error = (err as Error).message; } finally { loading = false; } } - onMount(load); + onMount(() => { const params = new URLSearchParams(window.location.search); query = params.get('q') ?? ''; game = params.get('game') ?? ''; scope = params.get('scope') ?? ''; status = params.get('status') ?? ''; view = params.get('view') === 'inspect' ? 'inspect' : 'library'; limit = libraryLimit(params); void load(); }); function openCreate(type: 'config' | 'baseline' = 'config') { kind = type; createError = ''; dialog.showModal(); } function resetFilters() { query = ''; game = ''; scope = ''; status = ''; } async function importFile(event: Event) { @@ -102,20 +107,20 @@ {#snippet actions()}{/snippet} -
{baselines.length} baselines{overlays.length} overlays{pending} awaiting promotion
+ {#if artifacts.length}
{baselines.length} baselines{overlays.length} overlays{pending} awaiting promotion
{/if}
{#if error}{/if} {#if view === 'inspect'} {:else} -
+ {#if loading || artifacts.length || error}
{#if query || game || scope || status}{/if} -
+
{/if} {#if loading}
Loading your config library…
{:else if !artifacts.length && !error}
Start with a foundation

Your fleet, configured your way.

Add a baseline for each game, then layer on small, focused changes for a game or map. Every change gets its own version.

@@ -218,4 +223,5 @@ .card-footer { padding-top:12px; margin-top:12px; } .welcome { padding:24px; } .loading { padding:24px 0; } + input:not([type='checkbox']):not([type='file']), select { border-color: var(--border-control); } diff --git a/src/lib/ui/components/ConfigTextEditor.svelte b/src/lib/ui/components/ConfigTextEditor.svelte index 627cd1f..dafae18 100644 --- a/src/lib/ui/components/ConfigTextEditor.svelte +++ b/src/lib/ui/components/ConfigTextEditor.svelte @@ -1,8 +1,17 @@ { if (isDialogBackdrop(event, dialog) && !busy) open = false; }} oncancel={event => { if (busy) event.preventDefault(); }} onclose={() => open = false}> @@ -54,9 +73,12 @@ {#if error}{/if} {#if !preview}

{busy ? 'Finding a lobby and port for every server…' : 'Refresh to prepare another preview.'}

{#if !busy}{/if} {:else} + {#if keyNotice}

{keyNotice}

{/if} + {#if expired}

This preview expired. Refresh before launch; keys remain entered for unchanged IDs.

{/if}
{preview.servers.length ? `${preview.servers.length} missing server${preview.servers.length === 1 ? '' : 's'} to create` : 'Blueprint already satisfied'} {#each preview.entries as entry}{/each}
MapTargetExisting / queuedTo create
{entry.recipe.mapName} {entry.recipe.game.toUpperCase()}{entry.count}{entry.existing}{entry.missing}
-

Existing and queued servers count toward each map’s target, including stopped servers. Extra servers are kept. Servers awaiting removal do not count.

+

Targets count inventory, including stopped servers; they do not mean every server is ready to play. Only missing servers are created. Extra servers remain and existing servers are not updated.

+ {#if preview.entries.some(entry => entry.existing)}
Review existing servers{#each preview.entries.filter(entry => entry.existing) as entry}
{entry.recipe.mapName}: {entry.existing} existing

{[...new Set((entry.coverage ?? []).map(server => server.health))].map(health => `${entry.coverage.filter(server => server.health === health).length} ${health}`).join(', ')}

    {#each entry.coverage ?? [] as server}
  • {server.health === 'online' ? 'Healthy' : server.health}
  • {/each}
{/each}
{/if}
{#if preview.servers.length}
@@ -70,15 +92,15 @@

Add a key for each new lobby below, or reuse its saved key. Fleet counts and available slots are checked again when you queue the launch.

{ event.preventDefault(); void launch(); }}>
    - {#each preview.servers as server, index} + {#each preview.servers as server, index (server.name ?? `unavailable-${index}`)}
  1. -
    {#if server.name}{:else}{preview.entries[server.entryIndex].recipe.mapName}{/if}{server.name ?? 'No available lobby'} · {server.port === null ? 'No available port' : `Port ${server.port}`}
    - {#if server.name}{/if} +
    {#if index === 0 || preview.servers[index - 1].entryIndex !== server.entryIndex}{preview.entries[server.entryIndex].recipe.game.toUpperCase()} · {preview.entries[server.entryIndex].recipe.mapName}{/if}{#if server.name}{:else}{preview.entries[server.entryIndex].recipe.mapName}{/if}{server.name ?? 'No available lobby'} · {server.port === null ? 'No available port' : `Port ${server.port}`}
    + {#if server.name}{/if}
  2. {/each}
- +
{:else}

Your fleet already meets or exceeds every target in this blueprint. No servers will be created or removed.

{/if}
Setup and launch requirements

Each server uses the latest promoted setup when its turn begins. The host must have the selected games and DLC. This preview checks settings and capacity; it does not probe game files, images, credentials, or network access.

{#each preview.entries as entry}
{/each}
@@ -87,10 +109,15 @@
diff --git a/src/lib/ui/components/DeployServerDialog.svelte b/src/lib/ui/components/DeployServerDialog.svelte index 8edfd1d..3f48ca1 100644 --- a/src/lib/ui/components/DeployServerDialog.svelte +++ b/src/lib/ui/components/DeployServerDialog.svelte @@ -1,4 +1,5 @@
- ({id:t.key,label:t.label}))} bind:value={active} idPrefix={uid} panelId={uid + '-panel'} ariaLabel="Log files" size="sm" /> + ({id:t.key,label:t.label}))} value={active} onchange={chooseLog} idPrefix={uid} panelId={uid + '-panel'} ariaLabel="Log files" size="sm" />
{#if current?.mtime} {fmtBytes(current.size)} · updated {ago(current.mtime)} {/if}
+
+
{#if refreshError}{/if} @@ -142,7 +176,9 @@ {:else if current && (!current.lines || current.lines.length === 0)}
log is empty
{:else if current?.lines} -
{current.lines.join('\n')}
+ +
{#each visibleLines as line}{#each highlight(line) as part}{#if part.match}{part.text}{:else}{part.text}{/if}{/each}{'\n'}{/each}
+ {#if query && !visibleLines.length}

No matches in the loaded tail. Try another search or download the tail.

{/if} {#if current.truncated}
showing last {current.lines.length} lines (file is larger)
{:else} @@ -153,6 +189,12 @@
diff --git a/src/lib/ui/components/OperationHistory.svelte b/src/lib/ui/components/OperationHistory.svelte index efdd132..25c1b58 100644 --- a/src/lib/ui/components/OperationHistory.svelte +++ b/src/lib/ui/components/OperationHistory.svelte @@ -3,6 +3,11 @@ import Button from './primitives/Button.svelte'; let { steps, events, active = false }: { steps: OperationStep[]; events: ActivityEvent[]; active?: boolean } = $props(); let limit = $state(25); + let query = $state(''); + let newestFirst = $state(true); + const latest = $derived(events.at(-1)); + const matching = $derived(events.filter(event => event.message.toLowerCase().includes(query.toLowerCase()))); + const visible = $derived(newestFirst ? matching.slice(-limit).reverse() : matching.slice(0, limit));
@@ -17,23 +22,37 @@
-

Activity

{#if active}Updates automatically{/if}
- {#if events.length} - {#if events.length > limit}{/if} + {#if latest}

Latest update {latest.message}

{/if} +
+ Activity history · {events.length} events{active ? ' · updates automatically' : ''} + {#if events.length} +
    - {#each events.slice(-limit) as event (event.id)} + {#each visible as event (event.id)}
  1. {event.message}

  2. {/each}
+ {#if !matching.length}

No matching activity.

{/if} + {#if matching.length > limit}{/if} {:else}

This operation predates detailed activity tracking. Its recorded status and timestamps are shown on this page.

{/if} +
diff --git a/src/lib/ui/components/ScriptUploadDrawer.svelte b/src/lib/ui/components/ScriptUploadDrawer.svelte index cd5e9a2..87f95d5 100644 --- a/src/lib/ui/components/ScriptUploadDrawer.svelte +++ b/src/lib/ui/components/ScriptUploadDrawer.svelte @@ -24,6 +24,8 @@ let message = $state(''); let preferredTarget = $state(null); let nextKey = 0; + let activeFile = $state(''); + const checkedCount = $derived(queue.filter(q => q.inspected).length); const pending = $derived(queue.filter(q => !q.result)); const inspecting = $derived(queue.some(q => q.inspecting)); const hasNew = $derived(pending.some(q => q.target === 'new')); @@ -56,19 +58,20 @@ return scripts.filter(s => s.target_rel_path.replaceAll('\\', '/').split('/').pop()?.toLowerCase() === file.name.toLowerCase()); } export async function addFiles(files: File[]) { - if (busy || !files.length) return; + if (busy || inspecting || !files.length) return; if (!dialog.open) open(); - for (const file of files) { + const items = files.map(file => { const matches = matchingScripts(file); const item: Upload = { key: nextKey++, file, target: preferredTarget ?? (matches.length === 1 ? matches[0].id : matches.length > 1 ? '' : 'new'), name: file.name.replace(/\.[^.]+$/, ''), duplicates: [], inspecting: true, inspected: false, error: '', result: null }; - queue = [...queue, item]; - // Work with the reactive proxy, rather than the original object. - await inspect(queue.find(q => q.key === item.key)!); - } + return item; + }); + queue = [...queue, ...items]; + for (const item of items) await inspect(queue.find(q => q.key === item.key)!); preferredTarget = null; } async function inspect(item: Upload) { + activeFile = item.file.name; item.inspecting = true; item.error = ''; try { const form = new FormData(); form.append('content', item.file); @@ -77,7 +80,7 @@ if (!res.ok) throw new Error(body.error ?? 'Could not inspect this file.'); item.duplicates = body.duplicates; item.inspected = true; } catch (e) { item.error = (e as Error).message; } - finally { item.inspecting = false; } + finally { item.inspecting = false; activeFile = ''; } } function duplicate(item: Upload) { return item.duplicates.find(d => d.scriptId === item.target); } function validation(item: Upload): string { @@ -99,6 +102,7 @@ busy = true; message = ''; try { for (const item of queue.filter(q => !q.result)) { + activeFile = item.file.name; item.error = ''; try { const form = new FormData(); @@ -126,7 +130,7 @@ if (prepareBeta && testable.length === results.length && testable.length) { dialog.close(); await goto(betaSelectionHref(testable)); } } } catch (e) { message = (e as Error).message; } - finally { busy = false; } + finally { busy = false; activeFile = ''; } } function close(event?: Event) { if (busy || inspecting) { event?.preventDefault(); return; } dialog.close(); } @@ -183,6 +187,7 @@ {/if} {#if message}

{message}

{/if}
+ {#if inspecting || busy}

{inspecting ? `Checked ${checkedCount} of ${queue.length} files` : `Uploaded ${results.length} of ${queue.length} files`}{activeFile ? ` · ${activeFile}` : ''}

{:else if queue.length}

{results.length} saved · {pending.length} remaining{queue.some(q => q.error) ? ` · ${queue.filter(q => q.error).length} need attention` : ''}

{/if} {#if pending.length} {:else if testable.length}{/if}
@@ -205,6 +210,8 @@ input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; } .success, .warning, .error { margin: 0; font-size: var(--text-sm); line-height: 1.5; } .success { color: var(--state-online); } .warning { color: var(--state-warning); } .error { color: var(--state-danger); } a { color: inherit; } .notice { padding: 14px; background: var(--surface-raised); border-radius: var(--radius-md); font-size: var(--text-sm); line-height: 1.6; } - footer { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: auto; padding-top: 20px; border-top: 1px solid var(--border-subtle); } + footer { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: auto; padding: 16px 0; border-top: 1px solid var(--border-subtle); position: sticky; bottom: 0; z-index: 3; background: var(--surface); } + .batch-progress { flex-basis: 100%; margin: 0; color: var(--text-secondary); font-size: var(--text-sm); overflow-wrap: anywhere; } @media (max-width: 640px) { .drawer { padding: 20px; } } + input:not([type='checkbox']):not([type='file']), select, textarea { border-color: var(--border-control); } diff --git a/src/lib/ui/components/ServerCard.svelte b/src/lib/ui/components/ServerCard.svelte index b14d5e5..154c61c 100644 --- a/src/lib/ui/components/ServerCard.svelte +++ b/src/lib/ui/components/ServerCard.svelte @@ -80,7 +80,7 @@ let gameInProgress = $derived(!!gameStartedAt && !gameEndedAt && !!activeSince); let gameElapsed = $derived(gameInProgress ? elapsedSince(gameStartedAt, $uiNow) : null); let showTiming = $derived( - showRoster && (activeElapsed !== null || inactiveElapsed !== null || gameElapsed !== null) + health === 'online' && (activeElapsed !== null || inactiveElapsed !== null || gameElapsed !== null) ); // Shared-element transition to /servers/{name} — Chromium only, others @@ -109,6 +109,8 @@ Starting {:else if health === 'offline'} offline + {:else if health === 'stale'} + Stale {:else}
{#if showMap}{health === 'online' ? 'Current map' : 'Last map'}: {mapLabel}{/if}{#if gtLabel}{gtLabel}{/if}
{/if} + {#if health === 'stale'} +
Players unknownLast known: {players ?? 'unknown'}{players !== null ? ' players' : ''}{lastSeenAt ? ` · ${ago(lastSeenAt, $uiNow)}` : ''}
+ {#if topRoster.length}
Last reported players
{/if} + {/if} + {#if health === 'online' && players !== null && players > 0 && gameInProgress}{/if} {#if showTiming && !(compactEmpty && players === 0)} @@ -185,6 +192,9 @@ diff --git a/src/lib/ui/components/primitives/Select.svelte b/src/lib/ui/components/primitives/Select.svelte index 2dc4f4d..4e67d6c 100644 --- a/src/lib/ui/components/primitives/Select.svelte +++ b/src/lib/ui/components/primitives/Select.svelte @@ -69,7 +69,7 @@ appearance: none; padding: 9px 32px 9px 12px; background: var(--surface-sunken); - border: 1px solid var(--border-subtle); + border: 1px solid var(--border-control); border-radius: var(--radius-md); color: var(--text-primary); font-family: var(--font-body); @@ -81,7 +81,7 @@ background-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard); } - .select:hover { border-color: var(--border-strong); } + .select:hover { border-color: var(--border-control-hover); } .select:focus { outline: none; border-color: var(--accent-primary); diff --git a/src/lib/ui/components/primitives/Tabs.svelte b/src/lib/ui/components/primitives/Tabs.svelte index 167469d..04d6499 100644 --- a/src/lib/ui/components/primitives/Tabs.svelte +++ b/src/lib/ui/components/primitives/Tabs.svelte @@ -1,4 +1,5 @@ -
+
{#each tabs as t (t.id)}
- + {#if secondary.length}{/if}
@@ -127,6 +142,10 @@
+ + +
{#each [['g f','Fleet'],['g s','Scripts'],['g c','Configs'],['g p','Plugins'],['g d','Server deployments'],['g a','Rollouts'],['g b','Betas'],['g h','System status'],['g k','Server keys'],['g l','Leaderboard'],['?','This help']] as [keys,label]}
{keys}
{label}
{/each}
+
diff --git a/src/routes/betas/[id]/+page.svelte b/src/routes/betas/[id]/+page.svelte index 47552d9..8b41d78 100644 --- a/src/routes/betas/[id]/+page.svelte +++ b/src/routes/betas/[id]/+page.svelte @@ -1,375 +1,187 @@ Beta #{id} | Electric Cherry -{#if loadError}{/if} - -{#if loading} -
Loading…
-{:else if !beta} - -{:else} - {@const b = beta} -
- - {#snippet crumbs()} - - {/snippet} - {#snippet actions()} - - {/snippet} - - - -
-
Started{new Date(b.opened_at).toLocaleString()}
-
Finished{b.closed_at ? new Date(b.closed_at).toLocaleString() : 'In progress'}
-
-
- - - - - -
-

Artifacts

- {scripts.length} -
- {#if scripts.length === 0} - - {:else} -
- {#each scripts as s (s.id)} -
- {s.kind} - {s.name} - {s.target_rel_path} - {artifactVersionLabel(s.version)} - {s.version?.sha256.slice(0, 8) ?? ''} -
- {/each} -
- {/if} -
- - {#if test} - - {:else} - - -

Options

-
-
- Wait for health - {b.wait_for_health ? 'Yes' : 'No'} -
-
- Wait for match - {b.wait_for_match ? 'Yes' : 'No'} -
-
-
- - {/if} - - - -
-

Server progress

- {servers.length} -
-
- {#each servers as bs (bs.server)} -
- - -
- Deploy - Empty - Restart - {#if b.wait_for_health}Healthy{/if} - {#if b.wait_for_match} - Match - {/if} -
- {#if bs.error} - {bs.error} - {/if} - {#if bs.stage === 'failed' && !test} - - {/if} -
- {/each} -
-
- - - -

Actions

-
- - -
- {#if flash}
{flash}
{/if} -
-
+{#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} +
+ diff --git a/src/routes/betas/new/+page.svelte b/src/routes/betas/new/+page.svelte index 2c53c85..9e5fe86 100644 --- a/src/routes/betas/new/+page.svelte +++ b/src/routes/betas/new/+page.svelte @@ -1,422 +1,225 @@ +New beta | Electric Cherry
- - {#snippet actions()}{/snippet} - - {#if flash}{/if} + {#snippet actions()}{/snippet} + {#if flash}{/if} {#if $fleetError}{/if} - {#if loading} - {:else if eligibleScripts.length === 0 && !flash} + {#if notice}

{notice}

{/if} + {#if loading} + {:else if availableDraft}

Resume unfinished beta?

Saved {new Date(availableDraft.savedAt).toLocaleString()} · {availableDraft.picks.filter(p=>p.scriptId!==null).length} files · {availableDraft.servers.length} selected servers. Versions and eligibility will be rechecked.

+ {:else if !eligibleFiles.length && !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} -
- +
    {#each steps as label,index}
  1. {index+1}{label}
  2. {/each}
+
{#if storageUnavailable}Draft saving is unavailable in this browser. Keep this page open to preserve your work.{:else}Unfinished changes save in this browser.{/if}{#if dirty}{/if}
+
+

{steps[step]}

+ {#if step===0} + +
{#each picks as pick,index(pick.key)}
+ + + + {#if pick.scriptId!==null}{@const file=detailById[pick.scriptId]?.script}{#if file}

{scopeText(file)} · {scopeCount(file)} eligible servers · Inspect file and versions{#if !loadingVersions.has(pick.key)&&!versionsFor(pick).length}
No unpromoted versions. Upload a new version from the file page.{/if}

{/if}{/if} +
{/each}
+ +

Test servers must match every file's scope. Changing a file retains compatible server selections.

+ {:else if step===1} +

{pickedServers.size} selected · {candidateServers.length} compatible servers. Restarts wait for confirmed empty lobbies.

+
Selected file scopes
    {#each picks as pick}{#if pick.scriptId!==null}{@const file=detailById[pick.scriptId]?.script}{#if file}
  • {file.name}: {scopeText(file)} · {scopeCount(file)} eligible servers
  • {/if}{/if}{/each}
+ {#if !candidateServers.length}
The selected file scopes have no servers in common. Review the scopes above, then go Back to replace or remove a conflicting file.
+ {:else} +
+
{visibleServers.length} visible
+ {#each groups as group}
{fleetIdentity(group.servers[0]).map} · {group.servers[0].game==='t5'?'Black Ops I':'Black Ops II'}
{#each group.servers as server}{/each}
{/each} + {#if !visibleServers.length}

No servers match these filters.

{/if} + {/if} + {:else if step===2} + {:else}

Files and exact versions

    {#each picks as pick}
  • {scripts.find(file=>file.id===pick.scriptId)?.name} · {artifactVersionLabel(versionsFor(pick).find(v=>v.id===pick.versionId))} · {versionsFor(pick).find(v=>v.id===pick.versionId)?.sha256.slice(0,12)}
  • {/each}

Test servers ({pickedServers.size})

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

Pass criteria

{coverageSummary(testPlan)} · {testPlan.timeoutHours}-hour window, starting when this beta opens.

    {#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 automatic rollback.':testPlan.failureAction==='pause'?'Failed checks pause testing.':'Failed checks hold the beta for review.'} {testPlan.rollbackRestart==='when-empty'?'Rollback restarts wait for empty servers.':'Rollback restores files; restart servers manually.'}

Starting installs the selected versions and restarts test servers when empty. Waiting, pausing, and retrying use the original testing window. Promotion is a separate reviewed action after testing.

{/if} +

{forwardReason}

{#if step<3}{:else}{/if}
+ {/if}
+ diff --git a/src/routes/campaigns/+page.svelte b/src/routes/campaigns/+page.svelte index 2ddb466..5269e04 100644 --- a/src/routes/campaigns/+page.svelte +++ b/src/routes/campaigns/+page.svelte @@ -1,5 +1,9 @@ +Rollouts | Electric Cherry +
reviewDrift(false)} + disabled={running || scanning || reviewing || !selected.length} loading={running} > - Reconcile + Review {selected.length} selected +
{#if driftOpen}
+ {#if drift}

Scanned {new Date(drift.scannedAt).toLocaleString()}. Selection controls the action scope; search only changes the visible list.

{/if} {#if drift && drift.totalDrift > 0} { driftFilter = event.currentTarget.value; saveContext(); }} /> +
{selected.length} selected
{#each filteredDriftServers.slice(0,driftLimit) as s (s.server)}
- + {s.files.length} entr{s.files.length === 1 ? 'y' : 'ies'}
@@ -296,9 +322,13 @@
{/if} - {#if flash} -
{flash}
- {/if} + {#if result}
0} role={skipped.length ? 'alert' : 'status'}> + {result.totalServers} server{result.totalServers === 1 ? '' : 's'} updated{skipped.length ? `, ${skipped.length} with skipped files` : ''} +

{result.totalRemoved} files removed; {result.totalRestored} installed. {result.totalServers ? 'Affected servers restart when empty, then health is verified.' : skipped.length ? 'No changes could be applied. Review the reasons below.' : 'The reviewed servers already match the intended files.'}

+ {#if result.deploymentId}View rollout →{/if} + {#each skipped as server}
    {#each server.skipped as reason}
  • {reason}
  • {/each}
{/each} + {#if skipped.length}{/if} +
{/if} @@ -345,12 +375,25 @@ {/each} {/if} - + {/if}
+ + {#if planError}{/if} + {#if reviewing}

Comparing current files with their intended versions…

+ {:else if plan} +

{reviewAll ? 'Entire fleet' : 'Selected servers'}: {plan.servers.length} server{plan.servers.length === 1 ? '' : 's'}, {plan.files.length} file change{plan.files.length === 1 ? '' : 's'}.

+

Files change immediately. Each affected server restarts after a fresh check confirms it is empty, then waits for health verification. Untracked files will be removed.

+

Reviewed {new Date(plan.scannedAt).toLocaleString()}. Changes to this plan require another review.

+
{#each plan.servers as server}{@const files = plan.files.filter(file => file.server === server)}{#if files.length}

{#each files as file}
{file.driftKind === 'untracked' ? 'Remove' : file.driftKind === 'missing' ? 'Restore' : 'Replace'} {file.relPath}{file.beforeSize === null ? 'Absent' : `${file.beforeSize} bytes`} → {file.afterSize === null ? 'Removed' : `${file.afterSize} bytes`}
File fingerprints

Before: {file.beforeSha256 ?? 'Absent'}
After: {file.afterSha256 ?? 'Removed'}

{/each}
{/if}{/each}
+ {/if} + {#snippet actions()}{/snippet} +
+ {#snippet deployRow(d: Deployment)}
+ {#if flash && flashId === d.id}
{flash}
{/if}
{d.action} rollout {d.id} @@ -384,7 +427,7 @@ title="{s.server}: {s.restart_state}{s.error ? ' — ' + s.error : ''}" > - {serverTitle(s.server)}{s.players !== null && s.players > 0 ? ` (${s.players}p)` : ''} + {serverTitle(s.server)}{s.players !== null && s.players > 0 ? ` (${s.players} players at last check)` : ''} {/each}
@@ -403,6 +446,16 @@ {/snippet} diff --git a/src/routes/server-keys/+page.svelte b/src/routes/server-keys/+page.svelte index 8a2183f..baa7edd 100644 --- a/src/routes/server-keys/+page.svelte +++ b/src/routes/server-keys/+page.svelte @@ -1,5 +1,8 @@ +{serverTitle(name)} · {activeTab.charAt(0).toUpperCase() + activeTab.slice(1)} · Electric Cherry {#if server} @@ -223,9 +231,7 @@ {/snippet} {#snippet actions()} - +
Server actions
{/snippet} @@ -280,9 +286,15 @@ {#if $fleetError}{/if} + {#if hasDiagnosticIssue} +
+
{effectiveHealth === 'stale' ? 'Server report is outdated' : 'Server is not responding'}

Player count is unknown. {effectiveSeen ? `Last successful report ${ago(effectiveSeen, $uiNow)}.` : 'No successful report has been received.'} {integrations && !integrations.rcon ? 'RCON is not configured.' : ''}

+
{#if integrations && (!integrations.rcon || !integrations.komodo)}{/if}
+
+ {/if} {#if operations.length}

Current operations

{#each operations as operation (operation.key)}{operation.label}{operation.detail}{/each}
{/if}
- +
@@ -329,9 +341,6 @@ {:else if activeTab === 'diagnostics'} - {#key name} - - {/key}

RCON diagnostic

@@ -493,6 +502,7 @@ {/if}
+
{#key name}{/key}
{:else if activeTab === 'history'}
@@ -537,6 +547,12 @@ {/if} diff --git a/tests/unit/beta-promotion.test.ts b/tests/unit/beta-promotion.test.ts new file mode 100644 index 0000000..8764063 --- /dev/null +++ b/tests/unit/beta-promotion.test.ts @@ -0,0 +1,78 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { existsSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { newFixture, type Fixture } from '../helpers/fixture.js'; + +let fixture: Fixture; +const servers = ['t5_zombie_theater_1', 't5_zombie_cosmodrome_1']; +beforeEach(async () => { + vi.resetModules(); fixture = await newFixture(servers); + vi.stubEnv('KOMODO_ADDRESS', ''); vi.stubEnv('RCON_PASSWORD', ''); + const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js'); + await seedServerRegistry(); +}); +afterEach(async () => { await fixture.cleanup(); vi.unstubAllEnvs(); }); + +async function ready(kind: 'script' | 'baseline' = 'script', scope: 'game' | 'map' = 'game') { + const { createScript, getLatestVersion } = await import('../../src/lib/server/fleet/scripts.js'); + const { openBeta } = await import('../../src/lib/server/fleet/beta.js'); + const { db } = await import('../../src/lib/server/db/index.js'); + const { script } = createScript({ name: 'Review test', kind, targetRelPath: kind === 'script' ? 'review.gsc' : undefined, + scopeType: scope, scopeValue: scope === 'game' ? 't5' : 'zombie_theater', content: Buffer.from(kind === 'script' ? 'main(){}' : 'set sv_voice "1"\n') }); + const version = getLatestVersion(script.id)!; + const { betaId } = await openBeta({ scripts: [{ scriptId: script.id, scriptVersionId: version.id }], servers: [servers[0]], waitForHealth: false, waitForMatch: false }); + db().prepare("UPDATE betas SET state = 'ready-promote' WHERE id = ?").run(betaId); + db().prepare("UPDATE beta_servers SET stage = 'ready', restarted_at = ? WHERE beta_id = ?").run(new Date().toISOString(), betaId); + return { betaId, script, version }; +} +const destination = () => join(fixture.t5, servers[1], 'runtime/plutonium/storage/t5/raw/scripts/sp/review.gsc'); + +describe('reviewed beta promotion', () => { + it('previews exact versions and additional targets without writing, then links the activation rollout', async () => { + const { betaId, script, version } = await ready(); + const { previewBetaPromotion, promoteBeta } = await import('../../src/lib/server/fleet/beta.js'); + const preview = previewBetaPromotion(betaId); + expect(preview.files[0]).toMatchObject({ id: script.id, versionId: version.id, sha256: version.sha256, servers: [...servers].sort() }); + expect(preview.servers).toEqual(expect.arrayContaining([expect.objectContaining({ name: servers[0], tested: true }), expect.objectContaining({ name: servers[1], tested: false })])); + expect(previewBetaPromotion(betaId).token).toBe(preview.token); + expect(existsSync(destination())).toBe(false); + const result = await promoteBeta(betaId, preview.token); + expect(result).toMatchObject({ awaitingActivation: 1, failedServers: [] }); + expect(result.deploymentId).toContain('promote'); + expect(await readFile(destination(), 'utf8')).toBe('main(){}'); + }); + it('rejects changed scope membership before creating a rollout or writing extra files', async () => { + const { betaId } = await ready('script', 'map'); + const { previewBetaPromotion, promoteBeta, getBeta } = await import('../../src/lib/server/fleet/beta.js'); + const { db } = await import('../../src/lib/server/db/index.js'); + const preview = previewBetaPromotion(betaId); + expect(preview.servers).toHaveLength(1); + db().prepare('UPDATE servers SET map = ? WHERE name = ?').run('zombie_theater', servers[1]); + await expect(promoteBeta(betaId, preview.token)).rejects.toMatchObject({ kind: 'preview-changed', details: expect.objectContaining({ servers: expect.arrayContaining([expect.objectContaining({ name: servers[1] })]) }) }); + expect(existsSync(destination())).toBe(false); + expect(getBeta(betaId)?.state).toBe('ready-promote'); + expect(db().prepare('SELECT COUNT(*) n FROM deployments').get()).toEqual({ n: 0 }); + await expect(promoteBeta(betaId, previewBetaPromotion(betaId).token)).resolves.toMatchObject({ awaitingActivation: 1 }); + }); + it('includes effective config contents in the guard, including map-specific composition', async () => { + const { betaId } = await ready('baseline'); + const { previewBetaPromotion, promoteBeta } = await import('../../src/lib/server/fleet/beta.js'); + const { db } = await import('../../src/lib/server/db/index.js'); + const preview = previewBetaPromotion(betaId); + expect(preview.configWrites).toHaveLength(2); + expect(new Set(preview.configWrites.map(write => write.sha256)).size).toBe(2); + db().prepare('UPDATE servers SET map = ?, map_slug = ? WHERE name = ?').run('zombie_moon', 'moon', servers[1]); + await expect(promoteBeta(betaId, preview.token)).rejects.toMatchObject({ kind: 'preview-changed' }); + expect(db().prepare('SELECT COUNT(*) n FROM deployments').get()).toEqual({ n: 0 }); + }); + it('requires the reviewed token at the HTTP boundary', async () => { + const { betaId } = await ready(); + const { POST, GET } = await import('../../src/routes/api/betas/[id]/promote/+server.js'); + const response = await POST({ params: { id: String(betaId) }, request: new Request('http://localhost/promote', { method: 'POST', body: '{}' }) }); + expect(response.status).toBe(400); + const preview = await GET({ params: { id: String(betaId) } }); + expect(preview.headers.get('cache-control')).toBe('no-store'); + expect((await preview.json()).preview.token).toHaveLength(64); + }); +}); diff --git a/tests/unit/beta-setup.test.ts b/tests/unit/beta-setup.test.ts new file mode 100644 index 0000000..7ac5ca5 --- /dev/null +++ b/tests/unit/beta-setup.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, it } from 'vitest'; +import { defaultPlan, betaPlanIssues, requirement } from '../../src/lib/beta-plan.js'; +import { readBetaDraft, compatibleBetaServers } from '../../src/lib/beta-draft.js'; +import { betaWaitingCondition, betaEvidenceSummary } from '../../src/lib/beta-evidence.js'; + +describe('beta draft and plan recovery', () => { + it('retains exact version IDs and incomplete plan fields in a recoverable draft', () => { + const plan = defaultPlan(); + const raw = JSON.stringify({ version: 1, savedAt: new Date().toISOString(), step: 2, picks: [{ scriptId: 12, versionId: 45 }], servers: ['town'], testPlan: { ...plan, timeoutHours: null } }); + const draft = readBetaDraft(raw)!; + expect(draft.picks).toEqual([{ scriptId: 12, versionId: 45 }]); + expect(betaPlanIssues(draft.testPlan, 1)).toContainEqual(expect.objectContaining({ field: 'timeoutHours' })); + expect(readBetaDraft('{bad')).toBeNull(); + expect(readBetaDraft(JSON.stringify({ version: 1, picks: [{ scriptId: '12', versionId: 45 }] }))).toBeNull(); + }); + it('keeps compatible explicit selections without selecting newly eligible servers', () => { + const result = compatibleBetaServers(['town1', 'town2'], ['town2', 'town3']); + expect([...result.kept]).toEqual(['town2']); + expect(result.removed).toEqual(['town1']); + }); + it('identifies the precise requirement and rejects an impossible quorum before review', () => { + const plan = { ...defaultPlan(), scope: 'quorum' as const, quorum: 3, requirements: [{ ...requirement('matches', 'matches'), target: 1.5, minPlayers: 0 }] }; + expect(betaPlanIssues(plan, 2).map(issue => issue.field)).toEqual(['quorum', 'matches-target', 'matches-minPlayers']); + expect(betaPlanIssues(plan, 2).find(issue => issue.field === 'matches-target')?.requirementId).toBe('matches'); + }); +}); +describe('beta evidence explanations', () => { + const observation = { lastGameplayAt: new Date().toISOString(), lastEvent: 'round_change', players: 2, round: 12, matchStarted: true, gameEnded: false, healthy: true, healthCheckedAt: new Date().toISOString() }; + it('distinguishes missing reports, insufficient population, and report-driven time', () => { + const r = { ...requirement('populated-minutes', 'play'), minPlayers: 3 }; + expect(betaWaitingCondition(r)).toContain('No gameplay report'); + expect(betaWaitingCondition(r, observation)).toContain('latest report has 2 players'); + expect(betaWaitingCondition(r, { ...observation, players: 3 })).toContain('next report arrives'); + }); + it('summarizes telemetry while keeping arbitrary or legacy payloads readable', () => { + const event = { id: 1, server: 'town', received_at: '', kind: 'game_end', payload: JSON.stringify({ round: 25, players: [{ name: 'A' }], map: 'zm_transit' }) }; + expect(betaEvidenceSummary(event)).toBe('Game ended at round 25 with 1 players on zm_transit.'); + expect(betaEvidenceSummary({ ...event, kind: 'old-event', payload: 'invalid' })).toBe('old event'); + }); +}); diff --git a/tests/unit/config-inspect.test.ts b/tests/unit/config-inspect.test.ts index 4cf9b5d..5c92ac5 100644 --- a/tests/unit/config-inspect.test.ts +++ b/tests/unit/config-inspect.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; import { inspectConfig, type ConfigLayer } from '../../src/lib/server/fleet/config-inspect.js'; import { composeServerCfg } from '../../src/lib/server/fleet/config-compose.js'; -import { changeConfigValue, configWarnings } from '../../src/lib/config-workbench.js'; +import { addConfigSetting, changeConfigValue, configWarnings } from '../../src/lib/config-workbench.js'; const base = (text: string): ConfigLayer => ({ text, source: { id: 1, name: 'Base', version: 2, kind: 'baseline' } }); const overlay = (id: number, text: string): ConfigLayer => ({ text, source: { id, name: `Overlay ${id}`, version: 3, kind: 'config' } }); @@ -63,6 +63,17 @@ describe('config source inspection', () => { }); describe('config settings editor', () => { + it('adds a structured value without altering existing content or line endings', () => { + expect(addConfigSetting('// comment\r\nset x 1', 'sv_hostname', 'Cherry lobby')).toBe('// comment\r\nset x 1\r\nset sv_hostname "Cherry lobby"\r\n'); + expect(addConfigSetting('', 'g_inactivity', '0')).toBe('set g_inactivity 0\n'); + }); + + it('rejects duplicate keys, missing values, and multiline assignments', () => { + expect(() => addConfigSetting('set FOO 1', 'foo', '2')).toThrow('already exists'); + expect(() => addConfigSetting('', 'bad key', '1')).toThrow('setting name'); + expect(() => addConfigSetting('', 'key', '// no value')).toThrow('value'); + expect(() => addConfigSetting('', 'key', '1\nset other 2')).toThrow('one line'); + }); it('changes only the selected assignment, preserving CRLF, spacing and raw commands', () => { const text = '// note\r\n set a "1" // original\r\nexec other.cfg\r\nset a 5\n'; expect(changeConfigValue(text, 1, '"2" // changed')).toBe('// note\r\n set a "2" // changed\r\nexec other.cfg\r\nset a 5\n'); diff --git a/tests/unit/config-workbench-api.test.ts b/tests/unit/config-workbench-api.test.ts index 23bd940..2e720ba 100644 --- a/tests/unit/config-workbench-api.test.ts +++ b/tests/unit/config-workbench-api.test.ts @@ -29,6 +29,7 @@ describe('config workbench API', () => { expect(response.status).toBe(200); const result = await response.json(); expect(result.inspection.settings.find((s: { key: string }) => s.key === 'g_inactivity')).toMatchObject({ value: '60', source: { id: overlay.script.id, draft: true } }); + expect(result.promoted.settings.find((s: { key: string }) => s.key === 'g_inactivity').value).toBe('190'); expect(listVersions(overlay.script.id)).toHaveLength(1); expect(getScript(baseline.script.id)?.current_version_id).toBe(baseline.version.id); const { getPromotedServerConfig } = await import('../../src/lib/server/fleet/server-config.js'); diff --git a/tests/unit/create-server.test.ts b/tests/unit/create-server.test.ts index 10e73df..5b3255e 100644 --- a/tests/unit/create-server.test.ts +++ b/tests/unit/create-server.test.ts @@ -48,6 +48,60 @@ afterEach(async () => { vi.unstubAllEnvs(); }); +describe('queued removal cancellation', () => { + it('lets cancellation win while the worker awaits a player count, and never removes the server', async () => { + const { createServer, destroyServer, processDestructions } = await import('../../src/lib/server/fleet/create.js'); + const { getDeployment } = await import('../../src/lib/server/fleet/deployments.js'); + const { POST } = await import('../../src/routes/api/deployments/[id]/cancel/+server.js'); + const { rconGetPlayerCount } = await import('../../src/lib/server/integrations/rcon.js'); + const { komodoDestroyDeployment } = await import('../../src/lib/server/integrations/komodo.js'); + await createServer(input); + let resolveCount!: (players: number) => void; + vi.mocked(rconGetPlayerCount).mockImplementationOnce(() => new Promise(resolve => { resolveCount = resolve; })); + const queued = destroyServer(serverName); + const work = processDestructions(); + await vi.waitFor(() => expect(resolveCount).toBeTypeOf('function')); + expect((await POST({ params: { id: queued.deploymentId! } })).status).toBe(200); + resolveCount(0); + await work; + expect(komodoDestroyDeployment).not.toHaveBeenCalled(); + expect(getDeployment(queued.deploymentId!)?.deployment).toMatchObject({ state: 'cancelled', server_exists: 1, stage: 'Removal cancelled' }); + expect(getDeployment(queued.deploymentId!)?.canCancelRemoval).toBe(false); + expect((await POST({ params: { id: queued.deploymentId! } })).status).toBe(409); + }); + + it('does not overwrite cancellation when the in-flight player check rejects', async () => { + const { createServer, destroyServer, processDestructions } = await import('../../src/lib/server/fleet/create.js'); + const { cancelRemoval, getDeployment } = await import('../../src/lib/server/fleet/deployments.js'); + const { rconGetPlayerCount } = await import('../../src/lib/server/integrations/rcon.js'); + await createServer(input); + let rejectCount!: (error: Error) => void; + vi.mocked(rconGetPlayerCount).mockImplementationOnce(() => new Promise((_resolve, reject) => { rejectCount = reject; })); + const queued = destroyServer(serverName); + const work = processDestructions(); + await vi.waitFor(() => expect(rejectCount).toBeTypeOf('function')); + expect(cancelRemoval(queued.deploymentId!)).toBe(true); + rejectCount(new Error('RCON unavailable')); + await work; + expect(getDeployment(queued.deploymentId!)?.deployment).toMatchObject({ state: 'cancelled', error: null }); + }); + + it('refuses cancellation after an atomic removal claim and for cleanup checkpoints', async () => { + const { createServer, destroyServer } = await import('../../src/lib/server/fleet/create.js'); + const { cancelRemoval, claimRemoval, canCancelRemoval, deploymentStage, REMOVING_SERVER } = await import('../../src/lib/server/fleet/deployments.js'); + const { db } = await import('../../src/lib/server/db/index.js'); + await createServer(input); + const queued = destroyServer(serverName); + expect(claimRemoval(queued.deploymentId!)).toBe(true); + expect(cancelRemoval(queued.deploymentId!)).toBe(false); + expect(claimRemoval(queued.deploymentId!)).toBe(false); + deploymentStage(queued.deploymentId!, REMOVING_SERVER); + db().prepare("UPDATE server_deployments SET state = 'waiting' WHERE id = ?").run(queued.deploymentId); + expect(canCancelRemoval(queued.deploymentId!)).toBe(false); + expect(cancelRemoval(queued.deploymentId!)).toBe(false); + }); +}); + describe('destruction cleanup recovery', () => { it('removes T6 servers with beta test runs and their dependent evidence', async () => { const { createServer, destroyServer, processDestructions } = await import('../../src/lib/server/fleet/create.js'); diff --git a/tests/unit/drift-kinds.test.ts b/tests/unit/drift-kinds.test.ts index 8818ea7..0963332 100644 --- a/tests/unit/drift-kinds.test.ts +++ b/tests/unit/drift-kinds.test.ts @@ -21,6 +21,57 @@ afterEach(async () => { await fixture.cleanup(); }); +describe('reviewed drift plans', () => { + it('rejects changed file bytes before any deletion and returns a fresh review', async () => { + const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js'); + const { previewDrift, runDriftDeployment, DriftPlanChanged } = await import('../../src/lib/server/fleet/drift.js'); + const { db } = await import('../../src/lib/server/db/index.js'); + await seedServerRegistry(); + const path = join(fixture.t5, 't5_zombie_theater_1', 'configs', 'stray.cfg'); + await writeFile(path, 'original'); + const plan = await previewDrift(['t5_zombie_theater_1']); + await writeFile(path, 'changed'); + await expect(runDriftDeployment({ servers: plan.servers, expectedFingerprint: plan.fingerprint })).rejects.toBeInstanceOf(DriftPlanChanged); + expect(await readFile(path, 'utf8')).toBe('changed'); + expect(db().prepare('SELECT * FROM deployments').all()).toEqual([]); + const refreshed = await previewDrift(plan.servers); + expect(refreshed.fingerprint).not.toBe(plan.fingerprint); + expect((await runDriftDeployment({ servers: refreshed.servers, expectedFingerprint: refreshed.fingerprint })).totalRemoved).toBe(1); + }); + + it('rejects changed replacement bytes and preserves the reviewed existing file', async () => { + const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js'); + const { createScript } = await import('../../src/lib/server/fleet/scripts.js'); + const { previewDrift, runDriftDeployment, DriftPlanChanged } = await import('../../src/lib/server/fleet/drift.js'); + const { db } = await import('../../src/lib/server/db/index.js'); + await seedServerRegistry(); + const { script, version } = createScript({ name: 'Managed config', kind: 'baseline', scopeType: 'game', scopeValue: 't5', content: Buffer.from('set sv_voice "1"\n') }); + db().prepare('UPDATE scripts SET current_version_id = ? WHERE id = ?').run(version.id, script.id); + const path = join(fixture.t5, 't5_zombie_theater_1', 'configs', 'dedicated_sp.cfg'); + await writeFile(path, 'existing settings'); + const plan = await previewDrift(['t5_zombie_theater_1']); + db().prepare('UPDATE script_versions SET content = ? WHERE id = ?').run(Buffer.from('set sv_voice "0"\n'), version.id); + await expect(runDriftDeployment({ servers: plan.servers, expectedFingerprint: plan.fingerprint })).rejects.toBeInstanceOf(DriftPlanChanged); + expect(await readFile(path, 'utf8')).toBe('existing settings'); + }); + + it('keeps selected reconciliation within its reviewed server identities', async () => { + const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js'); + const { previewDrift, runDriftDeployment, DriftPlanChanged } = await import('../../src/lib/server/fleet/drift.js'); + const second = join(fixture.t5, 't5_zombie_theater_2', 'configs'); + await mkdir(second, { recursive: true }); + await seedServerRegistry(); + const firstPath = join(fixture.t5, 't5_zombie_theater_1', 'configs', 'stray.cfg'); + await writeFile(firstPath, 'one'); + await writeFile(join(second, 'stray.cfg'), 'two'); + const plan = await previewDrift(['t5_zombie_theater_1']); + await expect(runDriftDeployment({ expectedFingerprint: plan.fingerprint })).rejects.toBeInstanceOf(DriftPlanChanged); + await runDriftDeployment({ servers: plan.servers, expectedFingerprint: plan.fingerprint }); + expect(existsSync(firstPath)).toBe(false); + expect(await readFile(join(second, 'stray.cfg'), 'utf8')).toBe('two'); + }); +}); + describe('drift scanning', () => { it('replaces a seeded config once instead of planning both removal and installation', async () => { const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js'); diff --git a/tests/unit/library-scope-preview.test.ts b/tests/unit/library-scope-preview.test.ts new file mode 100644 index 0000000..f53b4c2 --- /dev/null +++ b/tests/unit/library-scope-preview.test.ts @@ -0,0 +1,35 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { newFixture, type Fixture } from '../helpers/fixture.js'; + +let fixture: Fixture; +const server = 't5_zombie_theater_1'; +beforeEach(async () => { + vi.resetModules(); fixture = await newFixture([server]); + const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js'); + await seedServerRegistry(); +}); +afterEach(async () => { await fixture.cleanup(); }); + +describe('scope impact preview', () => { + it('reports unscoping tracked script copies without changing scope or inventory', async () => { + const { createScript, getScript } = await import('../../src/lib/server/fleet/scripts.js'); + const { recordScript, listServerScripts } = await import('../../src/lib/server/fleet/inventory.js'); + const { GET } = await import('../../src/routes/api/scripts/[id]/scope/+server.js'); + const script = createScript({ name: 'Example', scopeType: 'game', scopeValue: 't5', targetRelPath: 'example.gsc', content: Buffer.from('example') }); + recordScript(server, 'example.gsc', script.version.id, script.version.sha256, script.version.size, 'test'); + const response = await GET({ params: { id: String(script.script.id) }, url: new URL('http://localhost/?type=none') }); + expect(await response.json()).toMatchObject({ before: [server], after: [], removed: [server], detached: [server], affected: [server], composed: false }); + expect(getScript(script.script.id)?.scope_type).toBe('game'); + expect(listServerScripts(server)).toHaveLength(1); + }); + + it('reports config composition impact separately from detached inventory', async () => { + const { createScript } = await import('../../src/lib/server/fleet/scripts.js'); + const { GET } = await import('../../src/routes/api/scripts/[id]/scope/+server.js'); + const config = createScript({ name: 'Overlay', kind: 'config', scopeType: 'game', scopeValue: 't5', content: Buffer.from('set g_inactivity 0') }); + const response = await GET({ params: { id: String(config.script.id) }, url: new URL('http://localhost/?type=none') }); + expect(await response.json()).toMatchObject({ composed: true, detached: [], affected: [server], removed: [server] }); + const invalid = await GET({ params: { id: String(config.script.id) }, url: new URL('http://localhost/?type=invalid&value=t5') }); + expect(invalid.status).toBe(400); + }); +}); diff --git a/tests/unit/system-status.test.ts b/tests/unit/system-status.test.ts new file mode 100644 index 0000000..8f05a74 --- /dev/null +++ b/tests/unit/system-status.test.ts @@ -0,0 +1,49 @@ +import { afterEach, beforeEach, expect, it, vi } from 'vitest'; +import { newFixture, type Fixture } from '../helpers/fixture.js'; + +let fixture: Fixture; +beforeEach(async () => { + vi.resetModules(); + fixture = await newFixture([]); + vi.stubEnv('KOMODO_ADDRESS', ''); + vi.stubEnv('KOMODO_API_KEY', ''); + vi.stubEnv('KOMODO_API_SECRET', ''); + vi.stubEnv('KOMODO_TARGET_SERVER', ''); + vi.stubEnv('RCON_PASSWORD', ''); +}); +afterEach(async () => { await fixture.cleanup(); vi.unstubAllEnvs(); vi.restoreAllMocks(); }); + +it('distinguishes missing setup from an unverifiable host volume without probing', async () => { + const probe = vi.spyOn(await import('../../src/lib/server/integrations/netProbe.js'), 'tcpProbe'); + const { GET } = await import('../../src/routes/api/system-status/+server.js'); + const response = await GET({ url: new URL('http://localhost/api/system-status') }); + const body = await response.json(); + expect(response.headers.get('cache-control')).toBe('no-store'); + expect(body.checks.find((check: { id: string }) => check.id === 'komodo').state).toBe('unconfigured'); + expect(body.checks.find((check: { id: string }) => check.id === 'game-files').state).toBe('unverified'); + expect(body.readyServers).toBe(0); + expect(probe).not.toHaveBeenCalled(); +}); + +it('never exposes credentials or claims that network reachability validates them', async () => { + vi.stubEnv('KOMODO_ADDRESS', 'https://komodo.example.test'); + vi.stubEnv('KOMODO_API_KEY', 'fixture-private-key'); + vi.stubEnv('KOMODO_API_SECRET', 'fixture-private-secret'); + vi.stubEnv('RCON_PASSWORD', 'fixture-rcon-secret'); + vi.spyOn(await import('../../src/lib/server/integrations/netProbe.js'), 'tcpProbe').mockResolvedValue({ label: 'Komodo', host: 'komodo.example.test', port: 443, resolvedIp: '192.0.2.1', outcome: 'connected', elapsedMs: 1 }); + const { GET } = await import('../../src/routes/api/system-status/+server.js'); + const text = await (await GET({ url: new URL('http://localhost/api/system-status?probe=1') })).text(); + for (const secret of ['fixture-private-key', 'fixture-private-secret', 'fixture-rcon-secret']) expect(text).not.toContain(secret); + const connection = JSON.parse(text).checks.find((check: { id: string }) => check.id === 'komodo'); + expect(connection.state).toBe('ready'); + expect(connection.detail).toContain('does not validate API credentials'); +}); + +it('reports a configured unreachable host as needing attention', async () => { + vi.stubEnv('KOMODO_ADDRESS', 'http://komodo.example.test:9120'); + vi.stubEnv('KOMODO_API_KEY', 'key'); vi.stubEnv('KOMODO_API_SECRET', 'secret'); + vi.spyOn(await import('../../src/lib/server/integrations/netProbe.js'), 'tcpProbe').mockResolvedValue({ label: 'Komodo', host: 'komodo.example.test', port: 9120, resolvedIp: null, outcome: 'dns-fail', elapsedMs: 1 }); + const { GET } = await import('../../src/routes/api/system-status/+server.js'); + const body = await (await GET({ url: new URL('http://localhost/api/system-status?probe=1') })).json(); + expect(body.checks.find((check: { id: string }) => check.id === 'komodo').state).toBe('attention'); +});