Commit Graph

11 Commits

Author SHA1 Message Date
Anso d113004359 feat: add confirmed Take down stack action with optional volume removal (#1599)
* feat: add confirmed Take down stack action with optional volume removal

Expose Take down in the stack header and sidebar with a confirmation dialog
that runs compose down while keeping the stack definition on disk. Optional
volume removal is gated by node capability and stack:deploy permission, with
remote gateway preflight before proxying removeVolumes requests.

Closes #1582

* fix: reset take-down volume checkbox when dialog closes

* test: align getStackMenuVisibility assertions with showTakeDown key

getStackMenuVisibility now returns a fifth lifecycle flag, showTakeDown,
but three exhaustive toEqual assertions still listed only the prior four
keys and failed. Add the expected showTakeDown value to each: true for
the partial and exited running-stack cases, false for the self stack.

* test: cover Take down visibility for running non-self stacks

The getStackMenuVisibility assertions exercised the partial and exited
branches and the self-stack guard, but not the raw === 'running' literal
that drives showTakeDown for a normal running stack. Add a case so a
regression dropping 'running' from that check is caught.

* fix: drop Take down from header overflow and wire activity shortcut

Remove duplicate Take down from More actions.

Keep inline button when running, sidebar menu, and Cmd+ArrowDown.

Record stack_taken_down in activity on successful POST /down.
2026-07-09 12:20:13 -04:00
Anso 9ff678a7bb docs: v1 docs refresh (batch 5) (#1395)
* docs(introduction): refresh for the redesigned UI and replace screenshots

Bring the Getting Started Introduction page in line with the current
product:

- Add the Security top-level view to the navigation list and a
  dedicated Security section with a new screenshot.
- Correct the Fleet tab names (Snapshots, Status, Map, Deployments,
  Routing, Federation, Actions, Secrets).
- Split Settings out from security and list the current nine setting
  groups (Security graduated to its own view).
- Refine the navigation paragraph so role, tier, and local-vs-remote
  context read accurately.

Replace all four existing screenshots (Home, stack workspace, Fleet,
Resources) with fresh captures of the redesigned UI and add a Security
overview screenshot.

* docs(configuration): document advanced env vars and clarify deployment vs runtime config

Add an Advanced environment variables section (TRIVY_BIN, SENCHO_MESH_SUBNET,
GITSOURCE_MAX_CLONE_BYTES, SENCHO_PUBLIC_URL, SENCHO_COMPOSE_STALL_TIMEOUT_MS) and
reframe the intro to separate deployment-time configuration from the runtime
settings that live in the in-app Settings Hub. Cross-link the pilot-agent
variables to the Pilot Agent page instead of duplicating them.

* docs(sso): refresh SSO Setup Guide and SSO & LDAP reference for the redesigned UI

Refresh both SSO documentation pages against the current product and the
redesigned settings UI.

- Correct the navigation path to Settings -> Access -> SSO on both pages.
- Fix the "Require 2FA on SSO sign-in" toggle location to
  Settings -> Personal -> Account.
- Describe the login-page experience (the Local / LDAP toggle and the
  branded OIDC buttons under the "Or continue with" divider) and the SSO
  panel masthead (SCOPE, PROVIDERS, ENABLED).
- Replace all six SSO screenshots with fresh captures of the redesigned UI.

* docs(features): refresh the Features Overview page for the redesigned UI

Rewrite docs/features/overview.mdx to mirror the current Features
navigation grouping (Stacks, Deployment, Resources, Observability,
Fleet, Automation, Security & Identity) and add the recently shipped
capabilities surfaced in the redesign: Stack Dossier, Drift Detection,
Compose Doctor, Compose Networking, Environment & secrets guardrails,
Storage portability, Health-Gated Updates, Fleet Dossier, and the
dedicated Security page.

Correct stale claims (the file explorer now gates writes on stack edit
permission, not an admin role; downloads are a read action; bulk label
assign now spans nodes) and standardize the tier callouts so partly
paid features read as "Admiral adds X". Replace the three pre-redesign
screenshots and add a Security overview banner, all captured from a
populated fleet.

* docs(features): refresh the Appearance page for the redesigned UI

Add fresh screenshots and a troubleshooting section to the Appearance
page, verified against the live product.

- Add four screenshots: the Theme card (live preview, mode, accent, and
  fine-tune sliders), the top-bar quick switcher, the Typography card,
  and the Display card.
- Refresh the Density screenshot used by the Settings reference page.
- State that the quick switcher also covers text size, and that the
  contrast, border, and glow sliders stay in Settings.
- Add a Troubleshooting accordion covering per-browser persistence,
  resets to defaults, cross-operator scope, and the quick-switcher
  versus full-Settings split.

* docs(introduction): refresh screenshots and correct stale content

* docs(reference): refresh the Settings Reference page for the redesigned UI

Replace all seven stale screenshots with fresh 1920x1080 captures.
Add five new screenshots for the sections that previously had none.

Content changes:
- Sidebar table: rename Infrastructure "Fleet Mesh" entry to "Fleet";
  add "Image update checks" to the Automation group list
- Fleet section: rename heading to match registry label; add the
  Documentation snapshots subsection (snapshot_documentation toggle)
- Container Alerts: add screenshot
- Image update checks: add the full section (Registry checks table,
  scheduling mode, interval presets, cron expression support)
- Stacks / Deploy Guardrails: add screenshot
- Recovery: add the full section (System health snapshot, Environment
  preflight checks, Safe actions, Command-line recovery table)

* docs(sso): refresh screenshots for SSO quickstart and feature pages

* docs: refresh Features Overview screenshots and content

Replace all 4 hero screenshots with fresh 1920x1080 production captures.
Correct security posture state names (Action needed / Monitoring / Secure),
add the Policies tab to the Security section tab list, mention the Simple
mode in Scheduled operations, and update all alt text to match the new
screenshots.

* docs: refresh Appearance page screenshots and correct quick-switcher scope

Replace all four Appearance screenshots with fresh production captures.
Fix the quick-switcher control list: remove fonts (not present in the
popover), add visual style and readability which are. Add Log chip color
to the Display section. Update all screenshot alt text to match new
captures.

* docs: refresh stack management page with current UI and anatomy tabs

* docs: fix convert-tab-error screenshot with fully visible error toast

* docs: convert troubleshooting section to AccordionGroup format

* docs(quickstart): refresh screenshots and align dashboard description

Replace all three first-boot and dashboard screenshots with current UI.
Add Security to the top navigation list, update gauge and Stack health
descriptions to reflect sparklines and column detail, and align
Configuration Status wording with the Introduction page.

* docs(editor): rewrite anatomy panel, replace all screenshots

- Correct the anatomy panel tab inventory: the panel has eight tabs
  (Anatomy, Activity, Dossier, Drift always; Environment, Networking,
  Doctor, Storage when the node advertises the matching capability), not
  three as previously documented
- Add table describing all eight tabs with capability gates and links to
  dedicated feature pages
- Add anatomy-tabs.png screenshot showing the scrollable tab row
- Note the Doctor severity dot (red for blocker, amber for high-risk)
- Remove the stale Markdown-export subsection; Dossier and Activity are
  now covered in the tab table
- Replace all six stale screenshots with fresh 1920x1080 captures
- Replace the compose diff preview screenshot

* docs(files): refresh Files & Volumes screenshots and fix context-menu alt text

Replace all 9 stale screenshots on the Files & Volumes page with fresh
captures from the production node. Fix three alt-text strings that did
not match the live UI: removed hardcoded octal value 644, and added the
Duplicate, Copy to, and Move to entries missing from the context-menu
alt text.

* docs: rewrite Stack Activity page with full event categories and fresh screenshots

Expands the event category table from 5 to 10 entries to cover drift
detected, drift resolved, update started, health gate passed, and health
gate failed. Adds a live-disconnected-state section, a background-actor
attribution table, and a corrected troubleshooting accordion covering the
WebSocket reconnect case. Replaces both stale screenshots with fresh
1920x1080 captures from the production node.

* docs(drift): rewrite drift detection page with screenshots and full coverage

Full rewrite of the Drift Detection feature page. Adds two previously
undocumented finding types (network-undeclared, network-missing), expands
the temporal section to distinguish the raw-file hash from the parsed-model
hash, documents the two-layer spatial-engine and ledger architecture,
explains when the ledger is reconciled (post-deploy vs manual re-check vs
tab open), adds Activity timeline integration note, introduces a Limitations
section (no background scanner, port-range caveat, history cap, advisory-only
enforcement), expands Troubleshooting from five entries to seven using the
AccordionGroup convention, and adds four production screenshots.

* docs(drift): use CardGroup for Related section

* docs(dossier): rewrite Stack Dossier page with full feature coverage

* docs(networking): rewrite Compose Networking page with full feature coverage

* docs(doctor): rewrite Compose Doctor with full 30-rule reference, screenshots, and cross-links

* docs(networking): add production screenshots and correct alt text

Adds 7 production screenshots for all sections of the Compose Networking
page and updates the four placeholder alt texts written before screenshots
were taken to match what the actual images show (arr-net external badge,
swag service with 443/tcp and 80/tcp, single-service exposure intent row).
Also adds the full-panel overview image at the top of the page.

* docs(environment-guardrails): rewrite with project env file, env file status, and screenshots

* docs(storage): rewrite Storage Portability page with screenshots and full coverage

Rewrites compose-storage.mdx from a 61-line sketch into a complete
reference page. Key additions: Where to find it section with screenshot,
full storage inventory section documenting all mount type/access/status
chips and the Linux owner display, expanded portability verdict section
with per-reason detail and edge-case caveats (read-only binds, symlink
escapes, anonymous volume risks), snapshot coverage section with admin
scope and remote-node behavior, Findings in Doctor cross-reference, and
six troubleshooting accordions covering tab visibility, bind status,
external named volumes, render errors, and snapshot coverage states.
Adds two production screenshots: storage-tab.png and storage-node-bound.png.

* docs(stack-labels): rewrite with accurate permissions, capability gate, dry run, live preview, and color conflict docs

* docs: rewrite Stack Sidebar page with accurate feature coverage

Rewrites the Stack Sidebar documentation page to match the current UI.

Key changes:
- Fix branding header description (shows logo + version, not just version)
- Fix bulk mode icon description (stacked-rows, not square)
- Add cross-node search section (fan-out behavior, Other nodes section,
  unreachable-node warnings, click-to-switch navigation)
- Update Labels submenu description (inline New label creation, Manage labels link)
- Note that Delete only appears when the user has delete permission
- Remove the auto-update implication from Schedule task description
- Rewrite the Activity ticker section with the full 6-state priority cascade
  table; remove the non-existent IDLE state; correct pulsing-dot behavior
- Replace all 7 stale screenshots with fresh production screenshots
- Add new sidebar-cross-node-search.png screenshot

* docs(atomic-deployments): refresh screenshot and document project env files, rollback readiness, and recovery actions

* docs(atomic-deployments): fix rollback permission visibility and banner string accuracy

The Rollback menu entry is hidden by the frontend when the user lacks
stack:deploy; it never appears and does not 403. Fixed the step-4
narrative and troubleshooting accordion to match.

The rollback-failure banner emitted by ComposeService is
'=== Rollback failed. Manual intervention may be required ==='
(period, capital M). Fixed both occurrences in the page.

Updated the Settings navigation path from the nonexistent
'Roles & Access' to the real 'Access'.

* docs(deploy-progress): rewrite with health gate, inline style, and 9 fresh screenshots

Add health gate section covering all four states (observing, passed, failed,
unknown) with exact UI banner text and the configurable observation window.
Expand the inline style section with full band content, 4s auto-dismiss, and
pill handoff. Add Scanning as a supported entry point. Replace all 6 existing
screenshots and add 3 new ones (modal-health-gate, inline-banner, setting-style).
Add two health gate troubleshooting accordions. Add Related CardGroup linking to
health-gated-updates, stack-activity, deploy-enforcement, and atomic-deployments.

* docs(health-gated-updates): refresh screenshots and correct signal row order and label

* docs(deploy-enforcement): rewrite with fleet replication, honor suppressions location, scan-failed dialog state, and fresh screenshots

Adds the Fleet policy replication section covering control/replica behavior,
Managed by control node banner, and Demote to control. Documents the exact
location of the Honor suppressions toggle (bottom of Policies tab). Expands
the block dialog section with the scan-failed row state. Updates all three
screenshots to the current visual design. Restores the Admiral license note
and corrects the policy-card scope description.

* docs(app-store): rewrite with mobile layout, fresh screenshots, and registry admin note

- Replace all 5 stale screenshots with 1920x1080 production captures
- Add app-store-mobile.png showing the status masthead layout
- Document mobile single-column layout in a new Mobile subsection
- Note that the featured hero has its own Deploy button
- Mark the category rail as desktop only with a cross-link to Mobile
- Add admin-account requirement to the custom registry section
- Add Related CardGroup linking vulnerability scanning, deploy progress, deploy enforcement, and resources
2026-06-29 01:29:03 -04:00
Anso ebf66fd92a feat(settings): add Stacks section for stack workflow preferences (#1366)
Move the browser-local Deploy progress, Progress style, and Diff preview
before save controls out of Appearance into a new Stacks section under the
Infrastructure group. These are stack lifecycle and editor workflow
preferences, not visual style, so Settings now groups them where operators
expect to find them.

Add a browser-local masthead scope so these localStorage-backed sections read
SCOPE browser instead of the misleading global, and apply it to both
Appearance and Stacks. Control behavior, storage keys, and backing hooks are
unchanged; this is an information-architecture move only.
2026-06-12 18:40:53 -04:00
Anso e20f1fe415 feat: add an inline deploy-progress style for the stack detail (#1355)
* feat: add an inline deploy-progress style for the stack detail

Deploy progress gains a presentation choice under Settings > Appearance >
Display: Modal (the default centered overlay) or Inline. In Inline style a
compact status band on the stack detail shows the running operation, its
elapsed time, the live phase, the latest output line, and the post-update
health gate result. A "View output" button opens the full log modal on
demand, a dismiss control clears the band, and the band auto-clears a few
seconds after a clean completion.

The live progress socket is lifted to an always-mounted owner so the band
streams without the modal; the default Modal style is unchanged. Operations
carry their node so a band never bleeds onto a same-named stack on another
node.

The stack detail's redundant "CONTAINERS" section heading is removed; the
band reserves that vertical space.

* fix: keep inline deploy progress reachable off the stack detail

Review of the inline presentation found a gap: a failed operation, an App
Store install, or navigating away leaves the inline session with no visible
surface, since the band only renders on the operation's own stack detail.
Restore the minimized pill as the inline fallback, shown only when the band
is not covering the session, so there is always a click-through to the log
without ever overlapping the band. Closing the modal for a failed op now
ends the session (the band has stepped aside) instead of only hiding it.

Also document the unsupported mid-operation style switch, and refresh the
deploy-progress, settings, appearance, and app-store docs for the renamed
"Deploy progress" setting and the Modal/Inline choice.
2026-06-11 10:33:57 -04:00
Anso 38aabe7064 feat: health-gated updates and rollback readiness (#1354)
* feat: classify stack deploy and update failures with suggested next actions

Failed deploy and update responses now carry a failure classification
(cause category, headline, and suggested next step) derived from the
compose error output. The recovery panel and chip render the
classification and include it in copied diagnostics, and gateway-style
failures surface as a node-unreachable cause.

* feat: add update and rollback readiness reports for stacks

Before a manual update, Sencho now shows an advisory readiness verdict
computed from the stored preflight result, open drift findings, live
container health, the pending image change, the rollback backup slot,
and node disk headroom. The Stack Dossier gains a rollback readiness
section that states what a rollback can restore and explicitly
discloses that volume and bind-mounted data are not covered. Toolbar
and sidebar updates now share one update path, and admins can create a
fleet snapshot from the readiness dialog before updating. Nodes that do
not advertise the capability keep the direct update flow.

* feat: observe stack health after updates with a post-deploy health gate

After a deploy or update succeeds, Sencho now watches the stack for a
configurable observation window and records a passed, failed, or
unknown verdict: containers must stay running, healthchecks must report
healthy, and restart loops or disappearing containers fail the gate.
The deploy panel shows the observation live and holds off auto-closing
until the verdict lands, a failed gate surfaces the existing recovery
actions including rollback, and the stack timeline records update
started and gate verdict events. Scheduled, webhook, bulk, and
git-source updates are gated the same way; rollbacks and installs are
deliberately not. The gate is observational only and can be tuned or
disabled per node under host alert settings.

* docs: document health-gated updates and rollback readiness

New operator page covering the update readiness dialog, the post-update
health gate and its settings, the rollback readiness disclosure, and
classified failures, with cross-links from the atomic deployments and
deploy progress pages. The API reference gains the readiness and
health-gate endpoints, the healthGateId success field, and the failure
classification schema on deploy and update error responses.

* feat: withhold the success verdict while the health gate observes

An update used to show a green Succeeded that a failed health gate then
contradicted moments later. The deploy modal now reports Verifying
health while the gate observes, shows success only when the gate
passes, and makes a failed or unknown gate the headline result; success
toasts soften to a verifying message while a gate runs. The mobile
recovery card groups its actions behind one bottom-right Take action
menu so it stays compact on a phone, with the classified cause still
visible on the card. A successful image update now also counts as the
last known-good marker in rollback readiness, and the docs gain
screenshots of the readiness dialog, gate states, dossier section, and
settings.

* fix: harden log format strings and the env existence path check

Log calls that interpolated the stack name into the console format
string now use constant format strings with placeholder arguments, and
envExists validates path containment inline at its filesystem access,
matching the established patterns used elsewhere in the same files.

* test: adapt deploy modal success specs to the post-deploy health gate

The deploy feedback modal now withholds its success verdict while the
health gate observes the new containers, showing "Verifying health"
until the gate passes. The two success-path E2E tests waited for
"Succeeded" within the gate's 90s default window and timed out.

Shorten the observation window to the 15s minimum for these tests via
the settings API, assert the verify-then-succeed sequence the modal
actually renders, and restore the default window afterward so the test
value does not leak into later runs.

* fix: serialize health gate polling and harden gate observation

Address race conditions in the post-update health gate found in review.

Backend: the gate poller used setInterval, so a Docker observe slower
than the 5s tick could overlap the next poll and corrupt the restart and
missing-container accounting, and a wedged socket could leave a poll
pending forever. Polling is now single-flight: each cycle self-schedules
the next only after it settles, and the observe is bounded by an 8s
timeout so a hung probe counts as a poll error and resolves the gate
unknown after three in a row.

Frontend: the gate poller could overlap requests, letting a slow earlier
"observing" response overwrite an already-applied terminal verdict. It is
now single-flight with a terminal latch, so a late response can never
roll the UI back from passed or failed.

Also reject a non-digit nodeId on the snapshot coverage route instead of
letting parseInt coerce it, document that turning off the deploy progress
panel opts out of the live gate UI while the gate still runs server-side,
and add gate-coverage tests for the webhook, git source, and auto-update
apply paths plus the new single-flight, observe-timeout, and recovery
cases.
2026-06-11 00:26:26 -04:00
Anso d369b03a38 feat: detect stalled stack updates and add in-app recovery actions (#1347)
* feat: detect stalled stack updates and add in-app recovery actions

Add a backend idle-output backstop that stops a deploy/update compose step
that has gone silent (SENCHO_COMPOSE_STALL_TIMEOUT_MS, default 10m), so a
hung image pull surfaces a fast failure instead of spinning indefinitely.

Surface failed, timed-out, and stalled operations with recovery actions on
the stack page: a desktop chip plus popover menu and an inline mobile card
offering retry, restart, roll back (when a backup exists), refresh state,
and copy diagnostics, all gated by deploy permission. The streaming
deploy/update progress modal is now on by default and warns when output
goes quiet. Container state is refreshed after a failed or stalled
operation, and the UI never sits in an indefinite spinner.

* fix: harden rollback against policy-blocked file mutation and refine recovery

Address review findings on the stalled-update recovery work:

- The rollback route restored backup files before running the policy gate, so
  a policy-blocked rollback could leave the on-disk config rolled back while the
  deployed containers were unchanged. Snapshot the current files first and
  revert them when the gate blocks; if that revert itself fails, escalate it on
  the persistent alert feed since the 409 is already sent.
- Refresh container state after a successful manual rollback (rollback
  redeploys), without mis-recording a refetch failure as a rollback failure.
- Suppress the stalled-output warning once live progress is unavailable.

* test: mock snapshotStackFiles in the atomic-deploy rollback route tests

The rollback route now snapshots stack files before restoring a backup, so its
FileSystemService mock needs snapshotStackFiles. Without it the mocked call
threw and the route returned 500, failing the success-path rollback assertions.
2026-06-10 10:12:24 -04:00
Anso ce08a593d7 feat(settings): reorganize the settings hub into domain groups (#1321)
* refactor(settings): split System Limits and regroup the hub

System Limits had grown into a grab-bag of host alert thresholds, Docker
cleanup, and mesh data-plane controls under one mislabeled section. Split it
into Host Alerts, Docker & Storage, and Fleet Mesh, and split Developer into
Developer Diagnostics and Data Retention. Reorganize the sidebar into ten
domain groups: Personal, Access, Infrastructure, Monitoring, Notifications,
Automation, Organization, Security, Operations, Help.

Each section now saves only its own keys, so a concurrent edit in one section
no longer clobbers another. Data Retention sends the audit-log window only on
a paid plan, matching the field's existing visibility, so a Community save no
longer fails on a key the operator cannot set. NumberChip moves to a shared
module and the toggle reuses the existing shared component. The /settings API
is unchanged.

* test(settings): cover registry structure and per-section save payloads

Add structural invariants for the ten-group registry (every item maps to a
real group, ids are unique, the System Limits and Developer splits land in the
right groups with the right gates, renamed labels and the Registries paid gate
hold) and per-section payload tests asserting each split section patches only
its own keys, including the Community path where Data Retention omits the paid
audit-log key.

* docs(settings): document the regrouped settings hub

Rewrite the settings reference for the ten-group layout, replace the System
Limits page with Host Alerts, Docker & Storage, and Fleet Mesh, and document
the prune-on-update, reclaimable-space banner, and mesh auto-recreate settings
that were previously undocumented. Update the Settings navigation breadcrumbs
across the feature docs and refresh the affected screenshots.

* fix(settings): show Access sections as instance-global, not operator-scoped

License, Users, SSO, and API Tokens are instance-global settings but the
masthead scope label rendered them as operator-scoped because it keyed off the
old Identity group. Only Personal sections (account, appearance) are
operator/browser-scoped now; everything else reads as global.

Also add a compile-time exhaustiveness guard to the section switch so a future
SectionId added without a matching case fails the build instead of silently
rendering a blank panel.

* docs(settings): remap remaining settings breadcrumbs to the new groups

Update the navigation breadcrumbs that still pointed at the removed Identity,
Alerts, and Advanced groups: API Tokens and Users now sit under Access, Webhooks
under Automation, Labels under Organization, App Store under Infrastructure,
Appearance under Personal, and scan policies under Security > Vulnerability
Scanning. Correct the settings reference scope note so Access reads as global.

* docs(settings): remap renamed-section breadcrumbs across feature docs

Sweep every feature, operations, getting-started, and reference page for
navigation paths that still named the renamed settings sections, and point them
at the current ones: Security becomes Security > Vulnerability Scanning,
Notifications becomes Notifications > Channels, Routing becomes Notifications >
Notification Routing, and Developer becomes Operations > Developer Diagnostics
(with its retention windows under Operations > Data Retention). App Store moves
under Infrastructure and the four-group overview in the getting-started intro is
rewritten to the ten groups. Separators each page already used are preserved.
2026-06-05 23:01:37 -04:00
Anso 5dea040ec8 fix(deploy-progress): decouple deploys from the live progress stream (#1246)
* fix(deploy-progress): decouple deploys from the live progress stream

The deploy progress modal streamed compose output over a WebSocket, but
the deploy itself was coupled to that socket in two ways that could break
or silently abort a deploy:

- The deploy request was gated on the progress socket connecting, so any
  upgrade failure (a reverse proxy blocking WebSocket upgrades, or the
  admin-only stream rejecting a scoped deployer) left the modal stuck on
  "Connecting..." and the deploy never fired.
- The backend terminated the running compose process when that socket
  closed, so minimizing the modal, navigating away, or a network blip
  aborted an in-flight deploy.

Make the progress socket output-only: the deploy is owned by its request
and runs to completion (or the existing command timeout) regardless of
the stream. The modal now degrades to a "Live progress unavailable" state
and still reports success or failure from the request result. Connect
failures, drops, and a connect timeout all release the deploy instead of
blocking it.

Also route progress output per deploy: the frontend sends a correlation
id on both the connectTerminal message and the deploy request header, and
the backend keys progress sockets by that id so concurrent deploys from
different tabs or users no longer cross-stream each other's output.

Cap the in-memory parsed log rows so a very long deploy cannot grow the
modal's state unbounded.

* fix(deploy-progress): generate the deploy session id with a CSPRNG

The per-deploy correlation id keys which WebSocket receives a deploy's
live output, so a guessable id lets one authenticated client register a
victim's id and read its compose output. It was built from Math.random()
plus a timestamp, which is not cryptographically secure.

Generate it with crypto.getRandomValues (128 bits, hex). That is the one
Crypto member available in insecure contexts, so it still works over LAN
HTTP where crypto.randomUUID is unavailable.

* fix(deploy-progress): stop headerless ops bleeding into a keyed progress modal

Address review findings on the progress-stream routing:

- Only an id-less connectTerminal registration may become the id-less
  fallback socket. Previously every connectTerminal (including keyed deploy
  modals) set the fallback, so a headerless operation (bulk update, rollback,
  or a legacy client) resolved via getTerminalWs() into another user's keyed
  deploy modal. Keyed sockets are now excluded from the fallback, and a socket
  that adopts a session id is removed from it.
- The connect-timeout fallback now also flags the modal as "Live progress
  unavailable" instead of leaving it on "Connecting..." while the deploy runs.
- Log only a short prefix of the deploy session id in developer diagnostics,
  not the full capability value.
2026-05-28 20:51:45 -04:00
Anso 5f7a887ed6 docs: reorganize navigation for feature discoverability (#1147)
Restructures the Documentation tab so each group answers one operator
question.

- Split the 12-page "Stacks & Deployments" into Stacks (per-stack work)
  and Deployment (the act of deploying); promote Resources Hub to a
  standalone item.
- Dissolve the 2-page "Platform" junk drawer: Sidebar moves to Stacks,
  Host Console moves to Fleet.
- Rename "Fleet & Multi-Node" to "Fleet"; absorb Node Compatibility
  from Reference. Move Scheduled Operations from Fleet to Automation
  (now a 4-page group covering Scheduled Ops, Auto-Update, Auto-Heal,
  Webhooks).
- Clean up the Reference tab: drop misplaced node-compatibility, move
  root-level security.mdx into reference/, delete the orphan
  reference/verifying-images.mdx after porting its Available Tags
  table into operations/verifying-images.mdx.
- Reorder top-level groups: Operations moves above Reference.
- Rename two misleading page titles: "Deploy Progress Modal" becomes
  "Deploy Progress" (drops the UI implementation leak); "Auto-Update
  Readiness" becomes "Auto-Update Policies" (matches filename and
  sibling "Auto-Heal Policies").

Verified: docs.json parses as valid JSON, 59 disk .mdx files match
59 nav entries with zero orphans and zero broken refs.
2026-05-21 21:25:23 -04:00
Anso 0be479100c docs: v1 docs refresh (#966)
* docs(introduction): rewrite intro page and refresh screenshots

Rewrite the Getting Started introduction to reflect the current product:
adds the Mesh, Blueprints, Pilot, Fleet, Resources concepts up front;
restructures capability sections around Stacks, Fleet (now including
Fleet Actions), Mesh, Blueprints, Monitoring, Resources, Security,
Automation, and Pilot/Remote ops; cross-links every claim to the
matching feature page.

Replaces the dashboard hero shot with a fresh capture against the
redesigned cockpit chrome and adds three inline shots (running stack
with anatomy and logs, fleet command deck, resources hub with
reclaim header). All screenshots taken at 1920x900, dark theme,
with node names, usernames, IPs, and home paths neutralized.

Drops outdated claims: stale "190+ templates" count, the
"viewer accounts" RBAC summary, and the "atomic" deployment label
that did not match the actual rollback mechanism.

* docs(introduction): add Federation and Fleet Secrets

Federation has shipped (Admiral) with cordon and pin policy as
operator overrides on the blueprint reconciler. Fleet Secrets is
landing as a Skipper+ tab for versioned env-var bundles encrypted
at rest, with diff preview and target push.

Mirror those in the Run-one-machine-or-many bullet list and in the
Tiers paragraph so the introduction matches the current product.

* docs(introduction): re-shoot screenshots against v0.72.0 production

Re-capture all four introduction screenshots from the upgraded
production node so the fleet view shows the current full tab strip
(Overview / Snapshots / Status / Deployments / Traffic / Federation
/ Fleet Actions / Secrets) instead of the older Overview / Snapshots
/ Status only. Same 1920x900 dark-theme capture and the same PII
scrub applied (node names, usernames, IPs, home paths neutralized).

* docs(quickstart): rewrite around v0.72.0 cockpit and add screenshots

Replaces the bare install snippet with a five-minute walkthrough that
matches the redesigned UI. Leads with a docker-compose.yml block (the
bare docker run command is collapsed in an Accordion), keeps the 1:1
path rule, and adds two new sections that show the user what happens
on first boot.

Adds two screenshots at 1920x900 dark theme:
- setup-cold-start.png: the Cold start card with Username, Password,
  Confirm password fields, and the Initialize console button.
- dashboard.png: the post-sign-in dashboard captured against v0.72.0
  with the full top nav (Home, Fleet, Resources, App Store, Logs,
  Auto-Update, Console, Audit, Schedules) and the populated Stack
  health table sorted by load.

Where-to-next now uses CardGroup cols=2 to match the introduction
page's pattern.

* docs(configuration): align env var reference with current backend

Bring docs/getting-started/configuration.mdx up to date with the
v0.72.0 backend:

- Remove PORT from the optional env vars table. The listen port is
  hardcoded to 1852 in backend/src/helpers/constants.ts and is never
  read from the environment. Replace it with a Listen port section
  that explains the fixed port and host-port remapping.
- Document API_RATE_LIMIT (default 200) and API_POLLING_RATE_LIMIT
  (default 300), both applied in production only.
- Note the /app/compose fallback default for COMPOSE_DIR while still
  pointing readers at the 1:1 path rule.
- Point the SSO env var section at the new SSO Quickstart page and
  keep the SSO feature reference as the deeper dive.
- Tighten First boot and cross-link to Quickstart so the screenshot
  is not duplicated.
- Add a Where to next CardGroup matching the refreshed Introduction
  and Quickstart pages.

Drop stale PORT=1852 and JWT_SECRET=your-secure-jwt-secret-here
lines from .env.example so the example no longer contradicts the
docs (PORT is hardcoded, JWT_SECRET is auto-generated and persisted
to the database during initial setup).

* docs(configuration): replace em-dash-substitute hyphens in prose

Three sentences used ` - ` (space-hyphen-space) as an em-dash
substitute. Replaced with the punctuation that fits each case:

- "How Sencho organizes your compose directory": semicolon between
  the two related clauses.
- Data directory Warning: parentheses around the parenthetical
  insertion.
- 1:1 path rule explanation: comma before the contrastive clause.

Heading slugs and YAML code-block comments are unchanged.

* docs(sso): refresh setup guide and drop misleading "one-click" wording

Brings the SSO Setup Guide in line with how SSO actually works in the
current build, and corrects misleading copy across both SSO docs pages.

- Setup Guide: explains the env-var-seeds-once / DB-is-authoritative
  config model up front, replacing per-section "Restart Sencho"
  wording that implied a restart was always required.
- Setup Guide: promotes the per-provider Test Connection button out
  of the LDAP-only paragraph into a generic intro callout, and adds
  a self-signed LDAPS tip.
- Setup Guide: notes that all OIDC providers accept a *_DISPLAY_NAME
  override for the login button label, and adds a commented LDAP TLS
  toggle to the full compose example.
- Setup Guide: adds two screenshots of the redesigned Settings > SSO
  panel (overview + LDAP card expanded with form).
- Both pages: replaces "one-click presets" / "one-click configuration"
  with "preset providers". The Skipper-tier presets still require an
  OAuth app provisioned in the provider's console; what they actually
  buy is provider-aware defaults and a branded login button. The old
  wording overpromised.

* docs(features-overview): regroup catalog and add 17 missing features

Restructure the Features Overview into the same six groups the docs
sidebar uses (Stacks & Deployments, Observability, Fleet & Multi-Node,
Security & Identity, Automation, Platform) plus a short Reference tail.

Add catalog entries for 17 shipped features that the previous overview
never mentioned: Stack Activity, Stack File Explorer, Deploy Progress,
Deploy Enforcement, Blueprints, Git Sources, Global Search, Pilot Agent,
Sencho Mesh, Fleet Federation, Fleet Actions, Fleet Sync, Fleet Secrets,
Two-Factor Authentication, CVE Suppressions, Auto-Heal Policies, Stack
Sidebar.

Fix two factual inaccuracies:
- Fleet View blurb wrongly gated search, sort, filter, and stack
  drill-down behind Skipper. The deep-dive is explicit that those are
  available on every tier; only the bulk Update All action inside the
  Node Updates modal is paid.
- Auto-update entry was titled and described as a scheduling system.
  The deep-dive page is the Auto-Update Readiness board (risk tags,
  changelog previews, rollback targets); the scheduler lives under
  Scheduled Operations.

Add three hero screenshots captured from production at 1920x900,
illustrating the redesigned cockpit visual language: Home dashboard,
stack anatomy, and fleet topology.

* docs(stack-management): refresh page around v0.72.0 cockpit and add screenshots

Updates the Stack Management page to match the current UI: sidebar with
filter chips and label groups, bulk mode, restructured kebab menu,
two-tab anatomy panel, and three-source New stack dialog (Empty, From
Git, From Docker Run).

Adds sections for Filter chips, Pinned and label groups, and Bulk mode.
Restructures the Stack context menu around the inspect, organize,
lifecycle, and destructive groups with their keyboard shortcuts.
Documents the From Git tab and cross-links Git Sources for the full
sync flow.

Replaces every existing screenshot with fresh captures from the current
UI and adds eight new captures for the new sections. Cross-links Stack
Activity, Stack Labels, Stack File Explorer, Compose Editor, Atomic
Deployments, Scheduled Operations, Auto-Heal Policies, Auto-Update
Policies, and Alerts and Notifications for features documented on
their own pages.

* docs(stack-activity): refresh page around v1 cockpit and recapture screenshots

Realign the page with the current Anatomy panel tab strip and the
StackActivityTimeline component:

- Frame the Activity tab as a sibling of Anatomy under the right-hand
  panel, with files/edit actions belonging to the strip.
- Expand the category guidance: list the five iconized categories and
  call out that other stack-scoped notifications (deploy failure,
  available image updates, auto-heal triggers, monitor alerts, scan
  findings) flow into the timeline with a generic icon.
- Tighten the actor-attribution rule to match the component: omitted
  for events without an actor and for system-driven events.
- Add the day-format example to the relative-time row.
- Recapture both screenshots from a populated stack (Today + Yesterday
  + Earlier with three distinct icons) and an empty stack.
- Convert troubleshooting blurbs to H3 for anchor links and consistency
  with the v1-refresh sibling pages.

* docs(stack-activity): wrap troubleshooting entries in Accordion blocks

Match the foldable troubleshooting pattern established by
docs/features/deploy-progress.mdx so the page stays compact and
readers can scan to their issue. This is the canonical formatting
for the /features section's troubleshooting blurbs going forward.

* docs(editor): refresh page around v1 cockpit and recapture screenshots

Rewrites the page around the dual-mode right panel (Anatomy by default,
Monaco when the user clicks edit), the redesigned Command Center action
bar, the new container row layout with status badges and live stats, the
Structured / Raw terminal logs toggle, the Git Source toolbar button, and
the opt-in diff preview. Drops the obsolete persistent embedded terminal
section. Preserves the #diff-preview-before-save and #log-viewer anchors
referenced from settings.mdx and global-observability.mdx. Replaces
editor-overview.png and container-exec-modal.png with fresh captures
against v0.72.0 production at 1920x900 dark theme; renames container
-actions.png to containers-list.png; adds command-center.png and
editor-edit-mode.png. PII scrubbed (host paths normalized) and the
compose-diff-preview/diff-modal.png shared asset is left untouched after
visual diff against the live UI showed no chrome change.

* docs(features): wrap troubleshooting accordions in AccordionGroup

Wraps the loose <Accordion> blocks in editor.mdx and stack-activity.mdx
in a single <AccordionGroup> to match the troubleshooting design used
by fleet-federation.mdx. Structural only; no content changes.

* docs(stack-file-explorer): refresh page around v1 explorer and add screenshots

Full rewrite to match the live two-pane Files tab. Replaces the false
'Edit' toolbar flow with the read-only chip + always-on Save model,
fixes the protected-files list (5 names) and dedicated-tab redirect
list (3 names), drops the fabricated 100 MB download cap, and corrects
the upload claim to single file at a time.

Adds sections for New File, Rename, Permissions, the type-to-confirm
protected-file delete flow, the non-empty folder delete confirmation,
the 500-entry tree display cap, and the symlink rendering. Restructures
troubleshooting around <AccordionGroup> + <Accordion> to match
fleet-federation.mdx, and adds two new entries (display cap, 403 on
Community admin write).

Ships nine screenshots captured against v0.72.0 production at 1920x900
in dark theme: overview, two-pane layout, protected-tree-marker,
viewer-edit-mode, new-file-dialog, context-menu-folder, context-menu-file,
permissions-dialog, delete-protected-confirm.

* docs(deploy-progress): rewrite around current modal + capture v1 screenshots

Aligns the page with the v0.72.0 implementation and standardizes the
troubleshooting layout with the rest of the docs refresh.

Setting and gating
- Renames the Settings field to "Deploy progress modal" and quotes the
  current helper text verbatim. Documents that the toggle is off by
  default, lives under Settings > Appearance > Display, is stored in
  localStorage, and syncs across tabs in the same browser.

Modal anatomy
- Names every visible UI string: header verbs, status indicator (with
  the "closes in <n>s" countdown that was previously undocumented),
  empty-body strings, footer toggle that flips between "Raw output" and
  "Hide raw", and the destructive border on ERR rows vs the softer warn
  tint on WARN rows.
- Replaces the vague "after a few seconds" with the actual 4-second
  auto-close timer; documents hover-to-pause and the
  leave-hover-restarts-the-countdown behavior.
- Documents the truncated error message in the failed-state header and
  the manual close-only requirement.
- Notes that the pill is portal-mounted and survives navigation.

Stage badges
- Keeps the 9-badge table but adds an honest note that most lines render
  as LOG because the badges are gated on Compose's "[+]" progress
  prefix, which Compose only emits in TTY mode and Sencho spawns it
  without one.

Entry points
- Splits the supported actions into the four that produce a populated
  structured-log body (Deploy, Update, Install, Git Apply) and the two
  that bypass compose and finish with 0 lines (Restart, Stop). Drops the
  "Down" claim from the user-facing list since no UI control currently
  triggers it; mentions the down route as an automation surface only.

Troubleshooting
- Wraps the existing accordions in an <AccordionGroup> matching the
  pattern used by the editor and stack-activity refreshes. Adds two new
  entries: one explaining the Restart/Stop "0 lines" outcome, one
  explaining the LOG-everywhere case for non-TTY compose output.

Screenshots (six PNGs in docs/images/deploy-progress/, 1920x900, dark
theme, captured against the upgraded production node)
- setting-toggle.png: the Display section with the toggle enabled.
- modal-streaming.png: a real update in flight at 19s, 554 lines.
- modal-succeeded.png: succeeded state with the live closes-in
  countdown visible.
- modal-raw-output.png: structured rows with the Raw output panel
  expanded beneath.
- pill.png: minimized pill anchored bottom-center on a stack editor
  view.
- modal-failed.png: failed state with the truncated error in the
  header and ERR rows highlighted.

* docs(resources): refresh Resources Hub page for v1 redesign and feature additions

Rewrite the page to match the shipping UI and replace stale screenshots
with fresh captures of the redesigned chrome.

- Document the admin-only Reclaim hero and clarify the per-tile Sencho-only
  vs. All Docker (includes external) split in Quick Clean.
- Add coverage of the Scan history toolbar button and the per-row severity
  badge plus shield-icon scan dropdown in the Images tab; cross-link to the
  vulnerability scanning page.
- Correct the Volumes column list (no Size column; size lives on the Largest
  5 landing card) and call out admin gates on browse and delete.
- Spell out the List/Topology view-mode toggle and that Create Network is
  admin-only and List-mode only.
- Rewrite the Unmanaged tab section around the project-grouped layout, the
  Select all + Purge Selected (N) admin-only multi-select, and the empty
  state copy.
- Replace screenshots: resources-reclaim, networks-list, create-network,
  network-inspect, network-topology, network-topology-toggle. Add fresh
  resources-volumes-tab and resources-unmanaged-tab captures.

* docs(app-store): refresh page around v1 deploy sheet, scan integration, and registry settings

Rewrites the App Store reference to match the current cockpit:

- Documents the weekly-rotated featured banner picked from the top-5 by GitHub stars and the star-descending grid sort.
- Adds the deploy-sheet structure (breadcrumb, meta line, About panel with Read more) and splits the Advanced tab into Ports, Volumes, Environment variables, Custom variables, and Security subsections.
- Documents the Trivy-gated Security checkbox, atomic vs non-atomic deploys by tier, and the rollback semantics driven by error class.
- Adds a Watching the deploy section linking to the deploy-progress modal.
- Rewrites the Custom registry section against the new two-panel settings layout (Default + Custom) with the URL validation rule and the using default / using custom hint.
- Adds a four-entry Accordion troubleshooting block in the house style.
- Replaces three screenshots and adds two (Advanced tab, Settings registry panel) captured against the production node.

Permissions wording aligns with current backend (admin only); the broader stack:create gate will land in a follow-up fix branch.

* docs(app-store): describe inline port-conflict messaging on deploy sheet

Update the deploy-sheet section to match the visible port-conflict
behavior: the Essentials tab surfaces a Port-conflict warning that
replaces the defaults hint when any default port is already bound, and
the Advanced tab shows an inline "in use by {stack}" message next to
the container port instead of a hover-only tooltip. Refresh the
screenshot alt-text and the troubleshooting Accordion to match.

* docs(app-store): align permissions note with stack:create gate

Pairs with the backend gate swap in fix/templates-deploy-rbac (#986)
which moves POST /api/templates/deploy from requireAdmin to
requirePermission('stack:create'). Updates the Note block under
'Watching the deploy' so the docs match the new behavior: admin and
node-admin can deploy templates from the App Store; viewer, deployer,
and auditor cannot.
2026-05-07 23:44:13 -04:00
Anso dd9d33813b feat(deploy-logs): opt-in deploy progress modal with structured log rows (#779)
* feat(notifications): dispatch deploy_failure alert on stack action errors

* feat(terminal): add onReady and onMessage callback props

* feat(deploy-logs): add DeployLogContext with runWithLog API

* feat(deploy-logs): add DeployLogPanel bottom drawer with resize and minimize

* feat(deploy-logs): wire DeployLogContext to App and EditorLayout action runners

* test(deploy-logs): add E2E test for deploy log panel open, failure, and minimize

* docs(deploy-logs): add user-facing and internal architecture docs

* feat(deploy-logs): redesign as opt-in modal with structured log rows

Replace the full-width bottom drawer (DeployLogPanel) with a centered
modal that streams structured log output for deploy, stop, restart,
update, install, and Git apply operations. The modal is disabled by
default; users opt in from Settings -> Appearance.

Core changes:
- New DeployFeedbackContext with runWithLog() API: if opt-in is off,
  silently bypasses the UI so all call sites degrade to the existing
  toast behavior without code changes.
- composeLogParser.ts: pure parser that strips ANSI escapes and
  classifies compose output into stage badges (PULL, BUILD, CREATE,
  START, STOP, DOWN, WARN, ERR, LOG). 15 unit tests.
- StructuredLogRow.tsx: memoized row with timestamp, stage badge, and
  message. Error rows get a rose left rail; warn rows get a tinted bg.
- DeployFeedbackModal: Dialog-based, max-w-640px/max-h-70vh, elapsed
  timer, auto-close 4s on success (hover cancels), persistent on
  failure. Raw xterm output collapsible in footer.
- DeployFeedbackPill: minimized state anchored top-right, survives
  navigation, click restores modal.
- Wires App Store install (action: install), Git apply (action: deploy),
  and Git pull (action: update) in addition to the existing EditorLayout
  actions.
- Fixes Terminal.tsx WS URL in generic mode (was connecting to root path
  not proxied by Vite; now uses /ws).
- Settings: adds "Show deploy progress modal" checkbox to Appearance.
- Docs: renames deploy-logs.mdx to deploy-progress.mdx; updates
  internal architecture doc.

* fix(deploy-logs): connect Terminal in generic mode and move pill to bottom-center

Terminal was passed stackName which routes it to the stack logs WS
(container stdout). In that mode onReady is never called, so the
deployStarted gate never resolves and the compose command never runs.
Remove stackName so Terminal uses generic WS mode, which calls onReady
on open and streams compose output.

Also reposition the minimized pill from top-right to bottom-center
(fixed bottom-6 left-1/2 -translate-x-1/2) per UX feedback.

* docs(deploy-logs): update pill position to bottom center

* test(deploy-logs): rewrite E2E spec for deploy feedback modal

The old spec targeted the removed bottom-drawer DeployLogPanel and used
the wrong field name when calling POST /api/stacks (sent 'name' but the
endpoint reads 'stackName'), causing every test to fail with a 400 before
any UI assertions ran.

Fixes:
- POST /api/stacks body now uses 'stackName' matching the API contract
- All locators updated to target the new DeployFeedbackModal and
  DeployFeedbackPill components (data-testid attributes added)
- Added enableDeployFeedback helper to opt-in via localStorage before
  each test that expects the modal (feature is off by default)
- Added opt-in OFF test to confirm the modal is suppressed when disabled
- Minimize/expand test now asserts the pill appears and contains the
  stack name before clicking to restore the modal

* test(deploy-logs): fix compose file write endpoint in E2E helper

createStackViaApi was calling PUT /api/stacks/:name/files/docker-compose.yml
which does not exist. The correct endpoint is PUT /api/stacks/:name with
{ content } in the body.

* test(deploy-logs): use addInitScript to persist opt-in across reloads

The opt-in flag was set via page.evaluate before setupDeployStack, which
calls page.reload() and loginAs (a second navigation). Although localStorage
should persist across same-origin reloads, the React tree was reading
'false' on remount in CI. Switching to addInitScript guarantees the
localStorage value is set before any page script on every navigation, so
useDeployFeedbackEnabled's useState initializer always sees the right
value when React mounts.

* test(deploy-logs): verify localStorage and re-dispatch event before deploy

Adds syncDeployFeedbackState() called right before each deploy click in
the ON tests. It both verifies localStorage is set (failing the test
loudly with a clear message if not) and re-dispatches the
SENCHO_SETTINGS_CHANGED event to defeat any stale React state after
navigation. If the modal still does not appear with the assertion green,
the issue is downstream of localStorage and we have a clear signal.

* test(deploy-logs): wait for React re-render after dispatching opt-in event

After syncDeployFeedbackState dispatches SENCHO_SETTINGS_CHANGED, React
schedules the state update but does not flush it synchronously. The
click that follows can fire against the stale closure where isEnabled is
still false, so runWithLog takes its early-return path and the modal
never opens. A 200ms wait is enough to let React commit the new state
before the next interaction.

* test(deploy-logs): wait for stack file fetch before clicking deploy

deployStack() in EditorLayout returns early at 'if (!selectedFile)'
without calling runWithLog. selectedFile is set inside loadFile() after
GET /api/stacks/:name resolves. The previous setup clicked the stack in
the sidebar and immediately asked the test to click Deploy, racing the
fetch. CI backend logs confirmed no deploy POST ever fired for the ON
tests, while the OFF test passed only because it asserts non-existence.

Now setup awaits both the stack click and the file response together,
then verifies the action bar's deploy button is visible before returning.

* test(deploy-logs): wait for network idle and capture browser logs

Adds a networkidle wait plus a 500ms settle after the stack click so
React commits selectedFile and any follow-up env/container/backup
fetches drain before the deploy click. Also mirrors browser console
errors and pageerrors into the Playwright output so the next failure
ships with the React stack trace instead of just a 'modal not visible'
message.

* test(deploy-logs): temporary debug logging in runWithLog

Adds a console.log at the entry of runWithLog so we can see in CI logs
whether it is being called and what isEnabled value the closure has.
Also widens the test's console capture to include these debug lines.

This is diagnostic only and will be removed once the root cause of the
modal-not-opening-in-CI failure is identified.

* test(deploy-logs): debug log at deployStack entry to trace click path

Adds console.log at the first line of deployStack handler so we can
confirm in CI whether the click is reaching it at all and what
selectedFile/isStackBusy resolve to. Combined with the existing
runWithLog debug logs, this isolates whether the modal failure is in
deployStack guarding out, runWithLog early-returning, or something
else entirely.

* test(deploy-logs): drop filter, log every browser console msg

The previous filter only emitted error/warning plus the deploy-feedback
substring. The deploy-feedback debug logs never appeared, so we don't
yet know whether the log itself is firing. Remove the filter so the
full console stream shows up in CI.

* test(deploy-logs): app-level console log to verify capture pipeline

If even an unconditional log at App component render time does not
appear in CI browser logs, then the console capture listener is broken
or the dispatched logs are being filtered upstream of Playwright. This
isolates whether the issue is in the production code or the test
harness.

* test(deploy-logs): use testid locator for stack action button

Replaces the regex-based getByRole locator (/Deploy|Start/i) with
getByTestId('stack-deploy-button'). The regex matched something other
than the actual deploy button: backend logs proved no deploy POST ever
fired, and instrumentation confirmed neither deployStack nor runWithLog
ran on click despite the test claiming success.

Adds data-testid='stack-deploy-button' to both the Restart and Start
button branches in EditorLayout's action bar so the same locator works
whether the stack is running or not.

Also drops the temporary debug console.log entries in deployStack,
runWithLog, and App, and restores the test's console listener filter
to only emit error and warning messages.

* test(deploy-logs): park cursor in corner so auto-close countdown fires

After clicking the deploy button, the cursor lands inside the centered
modal. The modal pauses its 4s auto-close countdown on hover, so the
HAPPY test was waiting for a close that never happened. page.mouse.move
to (0,0) parks the cursor outside the modal before the success banner
appears, letting the countdown complete.

* test(deploy-logs): drop redundant loginAs after page.reload

page.reload preserves auth cookies, so the page lands back on the
dashboard without needing a fresh login. The loginAs call after reload
was racing on isLoginPage(): a transient login-page state during page
load made loginAs commit to filling #username, then the dashboard
committed and #username never came back. Playwright's auto-wait then
hung the fill until the test's 120s timeout, which also dragged later
stacks.spec tests down with collateral timeouts.

waitForStacksLoaded is enough to confirm we're on the dashboard with
the sidebar populated before clicking the new stack.

* test(e2e): make loginAs race-safe when login page is a false positive

isLoginPage() reports the page as a login screen if the Login button
locator reports visible at the moment of the check. Under CI load (more
real container deploys from the deploy-log-panel suite), the auth
context can render the login form for one paint, then redirect to the
dashboard. The original code committed to filling #username and hung
until the test timeout when the field was no longer there.

Now the login branch waits up to 2s for #username to actually appear
before filling. If it never appears, we fall through to the dashboard
check instead of hanging.
2026-04-26 00:43:54 -04:00