The standalone Activity log splits history across overlapping entry points for fleet operators. Server jobs and maintenance/recovery already have dedicated pages; the remaining feed combines release and host-operation records that also have their own destinations.
Source checked on 2026-10-13 at 82e07ea33eedddd7b707f5e62c12d2e606a1e680:
src/routes/activity/+page.server.ts:6 excludes provisioning and maintenance from the standalone feed; src/routes/activity/+page.svelte:12 directs users to those separate histories.
src/lib/server/activity.ts:163 links the remaining records to Host operation history, Campaigns, and Betas.
src/lib/navigation.ts:52 exposes Activity log, its d shortcut, and active-state matching for /activity, /operations, and /hosts/operations.
src/routes/servers/[name]/+page.svelte:841 links server History back to Activity, while line 845 renders its own ActivityLog; src/routes/maintenance/+page.svelte:429 also uses the shared component.
src/routes/hosts/operations/+page.svelte:155 falls back to Activity for a selected operation; src/lib/navigation-context.ts:3,48,49 also recognizes and labels the legacy destinations.
src/routes/operations/+page.server.ts:4 redirects to /activity without preserving query parameters. src/lib/hosts.ts:265 defines the host/server scope supported by Host operation history.
src/routes/hosts/+page.svelte:88 has no fleet-wide history action in its header; src/routes/hosts/[id]/+page.svelte:197 already provides host-scoped history access.
Remove the standalone page and make Hosts the entry point for host-operation history. Keep Campaigns, Betas, server History, and Maintenance history available. This is navigation cleanup; no redesign of those history pages or changes to collected records are included.
Screenshots
Synthetic preview at the revision above, using the same fixture for both states. Desktop viewport: 1440×900; phone: 390×844. Images are cropped to the relevant navigation/header area. After images are DOM mockups, not implemented behavior. They show removal of the Activity log navigation item and a Host operation history action on Hosts; the Activity group still contains Provisioning and Maintenance.
Before — desktop:
After (mockup) — desktop:
Before — phone:
After (mockup) — phone:
Fix
Replace the /activity page with a compatibility redirect. Remove its navigation item, search/command entry, and keyboard shortcut; retain the Activity group's Provisioning and Maintenance entries.
Remove server History's “Open in Activity” link and retain its embedded history, filters, and pagination.
Add a “Host operation history” link on Hosts to /hosts/operations?filter=all, visible to users already permitted to view that history. Preserve existing host-scoped links and highlight Hosts on /hosts/operations.
Replace the selected host-operation fallback with /hosts. Update shared return-link handling so no breadcrumb/back link names or returns to the retired pages; preserve other validated return destinations and fall back to /hosts for retired or self-referential destinations.
Redirect both legacy routes directly with HTTP 308 according to the contract below. Do not chain /operations through /activity.
Keep /api/activity, src/lib/server/activity.ts, the shared query helpers, and ActivityLog; server History and Maintenance still depend on them. Preserve event collection, retained records, and retention behavior.
Update affected navigation, navigation-context, route, host-operation-history, and activity tests, plus docs/development/ui-patterns.md:93 to describe scoped history and its remaining entry points.
Legacy redirect contract
Both /activity and /operations use these destinations:
Validate each scope with the existing hostOperationScope rules and URL-encode its value. Keep valid historical identities even if the host/server was removed; absent records should yield the destination's normal empty state. Omit invalid scope values. Reset pagination and discard all other legacy parameters, including type, source, state, days, q, limit, offset, filter, and returnTo, rather than interpreting Activity filters as host-operation filters. The destination shows host operations; release histories remain under Campaigns and Betas.
Verification
Navigation, search, shortcuts, and internal links no longer lead to the retired page. Hosts exposes the new history action on desktop and phone without changing access permissions.
Tests cover both legacy paths with no scope, each scope, combined scopes, encoded identities, invalid/removed identities, unsupported filters, and old returnTo values; redirects have the specified destinations and no loops.
Server History and Maintenance history still load, filter, and paginate correctly, including contextual detail/back navigation.
Campaign, beta, and host-operation histories remain accessible. Selected host operations return to a valid originating page or Hosts; no stale “Back to Activity” links remain.
Historical records, event collection, and retention remain unchanged.
The standalone [Activity log](https://ec.thewrightserver.net/activity) splits history across overlapping entry points for fleet operators. Server jobs and maintenance/recovery already have dedicated pages; the remaining feed combines release and host-operation records that also have their own destinations.
Source checked on 2026-10-13 at `82e07ea33eedddd7b707f5e62c12d2e606a1e680`:
- `src/routes/activity/+page.server.ts:6` excludes provisioning and maintenance from the standalone feed; `src/routes/activity/+page.svelte:12` directs users to those separate histories.
- `src/lib/server/activity.ts:163` links the remaining records to Host operation history, Campaigns, and Betas.
- `src/lib/navigation.ts:52` exposes Activity log, its `d` shortcut, and active-state matching for `/activity`, `/operations`, and `/hosts/operations`.
- `src/routes/servers/[name]/+page.svelte:841` links server History back to Activity, while line 845 renders its own `ActivityLog`; `src/routes/maintenance/+page.svelte:429` also uses the shared component.
- `src/routes/hosts/operations/+page.svelte:155` falls back to Activity for a selected operation; `src/lib/navigation-context.ts:3,48,49` also recognizes and labels the legacy destinations.
- `src/routes/operations/+page.server.ts:4` redirects to `/activity` without preserving query parameters. `src/lib/hosts.ts:265` defines the host/server scope supported by Host operation history.
- `src/routes/hosts/+page.svelte:88` has no fleet-wide history action in its header; `src/routes/hosts/[id]/+page.svelte:197` already provides host-scoped history access.
Remove the standalone page and make Hosts the entry point for host-operation history. Keep Campaigns, Betas, server History, and Maintenance history available. This is navigation cleanup; no redesign of those history pages or changes to collected records are included.
**Screenshots**
Synthetic preview at the revision above, using the same fixture for both states. Desktop viewport: 1440×900; phone: 390×844. Images are cropped to the relevant navigation/header area. After images are DOM mockups, not implemented behavior. They show removal of the Activity log navigation item and a Host operation history action on Hosts; the Activity group still contains Provisioning and Maintenance.
Before — desktop:

After (mockup) — desktop:

Before — phone:

After (mockup) — phone:

**Fix**
- [ ] Replace the `/activity` page with a compatibility redirect. Remove its navigation item, search/command entry, and keyboard shortcut; retain the Activity group's Provisioning and Maintenance entries.
- [x] Remove server History's “Open in Activity” link and retain its embedded history, filters, and pagination.
- [ ] Add a “Host operation history” link on Hosts to `/hosts/operations?filter=all`, visible to users already permitted to view that history. Preserve existing host-scoped links and highlight Hosts on `/hosts/operations`.
- [ ] Replace the selected host-operation fallback with `/hosts`. Update shared return-link handling so no breadcrumb/back link names or returns to the retired pages; preserve other validated return destinations and fall back to `/hosts` for retired or self-referential destinations.
- [ ] Redirect both legacy routes directly with HTTP 308 according to the contract below. Do not chain `/operations` through `/activity`.
- [x] Keep `/api/activity`, `src/lib/server/activity.ts`, the shared query helpers, and `ActivityLog`; server History and Maintenance still depend on them. Preserve event collection, retained records, and retention behavior.
- [ ] Update affected navigation, navigation-context, route, host-operation-history, and activity tests, plus `docs/development/ui-patterns.md:93` to describe scoped history and its remaining entry points.
**Legacy redirect contract**
Both `/activity` and `/operations` use these destinations:
| Legacy query | Destination |
| --- | --- |
| No valid host/server scope | `/hosts/operations?filter=all` |
| `host=<id>` | `/hosts/operations?filter=all&host=<encoded-id>` |
| `server=<name>` | `/hosts/operations?filter=all&server=<encoded-name>` |
| Both | `/hosts/operations?filter=all&host=<encoded-id>&server=<encoded-name>` |
Validate each scope with the existing `hostOperationScope` rules and URL-encode its value. Keep valid historical identities even if the host/server was removed; absent records should yield the destination's normal empty state. Omit invalid scope values. Reset pagination and discard all other legacy parameters, including `type`, `source`, `state`, `days`, `q`, `limit`, `offset`, `filter`, and `returnTo`, rather than interpreting Activity filters as host-operation filters. The destination shows host operations; release histories remain under Campaigns and Betas.
**Verification**
- [x] Navigation, search, shortcuts, and internal links no longer lead to the retired page. Hosts exposes the new history action on desktop and phone without changing access permissions.
- [ ] Tests cover both legacy paths with no scope, each scope, combined scopes, encoded identities, invalid/removed identities, unsupported filters, and old `returnTo` values; redirects have the specified destinations and no loops.
- [x] Server History and Maintenance history still load, filter, and paginate correctly, including contextual detail/back navigation.
- [ ] Campaign, beta, and host-operation histories remain accessible. Selected host operations return to a valid originating page or Hosts; no stale “Back to Activity” links remain.
- [x] Historical records, event collection, and retention remain unchanged.
Reviewed eceb38a6bc against current upstream be7f6c77c1. The navigation removal is partly complete, but legacy redirects can return HTTP 500 and several explicit redirect/back-link requirements remain unmet, so this issue stays open.
Checklist
Compatibility redirect and navigation removal (Fix 1). The standalone component, navigation item, command entry and shortcut are removed, with Provisioning and Maintenance retained. The replacement redirect fails for server-scoped requests.
Embedded server History (Fix 2). “Open in Activity” is removed; embedded history, filtering and pagination remain.
Hosts entry point (Fix 3). The action is visible on desktop and phone and Hosts highlights operation history, but src/routes/hosts/+page.svelte:89 uses “Operation history” and /hosts/operations. It must use “Host operation history” and /hosts/operations?filter=all; the current loader otherwise defaults to Actions & errors.
Return-link handling (Fix 4). The selected-operation fallback at src/routes/hosts/operations/+page.svelte:155 still returns to history, not /hosts. safeReturnHref() rewrites retired destinations through the legacy redirect and accepts self-targeting selected-operation returns.
Legacy redirect contract (Fix 5). Both routes use direct 308 responses where execution succeeds, but the helper chooses Provisioning, server pages, Maintenance, Campaigns or Betas based on legacy filters, retains unsupported parameters, and does not validate identities using hostOperationScope.
Shared history and retention (Fix 6). The activity API, aggregation/query helpers, shared ActivityLog, event collection and retention remain available and unchanged by this commit.
Tests and documentation (Fix 7). Updated tests assert the differing redirect behavior and miss actual SvelteKit server URL handling. docs/development/ui-patterns.md:93 still describes the fleet timeline; the legacy-routing explanation in docs/guides/provisioning.md also needs alignment.
Navigation and responsive access (Verification 1). Navigation, command and shortcut tests pass. Chromium confirms the Hosts action is visible within both 1440×900 and 390×844 viewports; access policy is unchanged.
Redirect matrix (Verification 2). Required scopes, validation, discarded parameters and loop handling are incomplete; scoped routes can fail before redirecting.
Scoped histories (Verification 3). Server History and Maintenance load in Chromium. Shared filtering, pagination, scoped queries and valid contextual returns pass the relevant tests.
Remaining destinations and selected-operation returns (Verification 4). Campaign, beta and host-operation history pages load, but selected operations still accept self-targeting returns and do not use the required Hosts fallback.
Historical records (Verification 5). Record storage, collection and retention are unchanged; retained/expired history tests pass.
Review notes
Confirmed runtime failure: authenticated synthetic requests to /activity?server=deleted-server and /operations?host=deleted-host&server=deleted-server&state=failed&offset=25&returnTo=%2Factivity return HTTP 500. The server logs Cannot access event.url.hash at src/lib/activity-redirect.ts:21, called by the legacy server loader. The Maintenance/recovery branch repeats the same forbidden access at line 29. Plain URL objects in unit tests do not reproduce SvelteKit’s guarded server getter.
Confirmed invalid scope:/activity?host=host%0Ainvalid redirects to /hosts/operations?host=host%0Ainvalid; the contract requires /hosts/operations?filter=all with that invalid host omitted.
Confirmed self return: selecting retained-op with returnTo=/hosts/operations?operation=retained-op produces a back link to that same selected operation. With no origin it returns to operation history; with retired origin /activity?host=deleted-host it returns to host-filtered history. These cases require /hosts.
All 365 tests across 14 relevant files pass with no skips, including changed navigation/activity suites, host-operation history, Maintenance and permissions. The passing redirect tests currently encode behavior that conflicts with this ticket.
npm run lint and npm run check pass, with zero Svelte errors or warnings. Chromium checks used an isolated synthetic fixture; no production data or operations were changed.
Next steps
Make both legacy routes redirect directly to /hosts/operations?filter=all, copying only host/server identities accepted by hostOperationScope. Preserve valid removed identities, encode values, discard every other legacy parameter, and remove server-side hash access.
Set the Hosts action’s label and URL to the required values. Make absent, retired and self-referential selected-operation return destinations fall back to /hosts, while preserving other validated origins.
Align tests and documentation with the ticket’s contract. Add coverage using SvelteKit’s server URL behavior so the HTTP 500 regression is caught, plus the complete scope/filter and contextual-return matrix.
Reviewed eceb38a6bccbb7007a71ba0d33f18e50f2c1a21c against current upstream be7f6c77c1d7c33138e2adcdc49b28799b6d4d07. The navigation removal is partly complete, but legacy redirects can return HTTP 500 and several explicit redirect/back-link requirements remain unmet, so this issue stays open.
**Checklist**
- [ ] **Compatibility redirect and navigation removal (Fix 1).** The standalone component, navigation item, command entry and shortcut are removed, with Provisioning and Maintenance retained. The replacement redirect fails for server-scoped requests.
- [x] **Embedded server History (Fix 2).** “Open in Activity” is removed; embedded history, filtering and pagination remain.
- [ ] **Hosts entry point (Fix 3).** The action is visible on desktop and phone and Hosts highlights operation history, but `src/routes/hosts/+page.svelte:89` uses “Operation history” and `/hosts/operations`. It must use “Host operation history” and `/hosts/operations?filter=all`; the current loader otherwise defaults to Actions & errors.
- [ ] **Return-link handling (Fix 4).** The selected-operation fallback at `src/routes/hosts/operations/+page.svelte:155` still returns to history, not `/hosts`. `safeReturnHref()` rewrites retired destinations through the legacy redirect and accepts self-targeting selected-operation returns.
- [ ] **Legacy redirect contract (Fix 5).** Both routes use direct 308 responses where execution succeeds, but the helper chooses Provisioning, server pages, Maintenance, Campaigns or Betas based on legacy filters, retains unsupported parameters, and does not validate identities using `hostOperationScope`.
- [x] **Shared history and retention (Fix 6).** The activity API, aggregation/query helpers, shared `ActivityLog`, event collection and retention remain available and unchanged by this commit.
- [ ] **Tests and documentation (Fix 7).** Updated tests assert the differing redirect behavior and miss actual SvelteKit server URL handling. `docs/development/ui-patterns.md:93` still describes the fleet timeline; the legacy-routing explanation in `docs/guides/provisioning.md` also needs alignment.
- [x] **Navigation and responsive access (Verification 1).** Navigation, command and shortcut tests pass. Chromium confirms the Hosts action is visible within both 1440×900 and 390×844 viewports; access policy is unchanged.
- [ ] **Redirect matrix (Verification 2).** Required scopes, validation, discarded parameters and loop handling are incomplete; scoped routes can fail before redirecting.
- [x] **Scoped histories (Verification 3).** Server History and Maintenance load in Chromium. Shared filtering, pagination, scoped queries and valid contextual returns pass the relevant tests.
- [ ] **Remaining destinations and selected-operation returns (Verification 4).** Campaign, beta and host-operation history pages load, but selected operations still accept self-targeting returns and do not use the required Hosts fallback.
- [x] **Historical records (Verification 5).** Record storage, collection and retention are unchanged; retained/expired history tests pass.
**Review notes**
- **Confirmed runtime failure:** authenticated synthetic requests to `/activity?server=deleted-server` and `/operations?host=deleted-host&server=deleted-server&state=failed&offset=25&returnTo=%2Factivity` return HTTP 500. The server logs `Cannot access event.url.hash` at `src/lib/activity-redirect.ts:21`, called by the legacy server loader. The Maintenance/recovery branch repeats the same forbidden access at line 29. Plain `URL` objects in unit tests do not reproduce SvelteKit’s guarded server getter.
- **Confirmed invalid scope:** `/activity?host=host%0Ainvalid` redirects to `/hosts/operations?host=host%0Ainvalid`; the contract requires `/hosts/operations?filter=all` with that invalid host omitted.
- **Confirmed self return:** selecting `retained-op` with `returnTo=/hosts/operations?operation=retained-op` produces a back link to that same selected operation. With no origin it returns to operation history; with retired origin `/activity?host=deleted-host` it returns to host-filtered history. These cases require `/hosts`.
- All 365 tests across 14 relevant files pass with no skips, including changed navigation/activity suites, host-operation history, Maintenance and permissions. The passing redirect tests currently encode behavior that conflicts with this ticket.
- `npm run lint` and `npm run check` pass, with zero Svelte errors or warnings. Chromium checks used an isolated synthetic fixture; no production data or operations were changed.
**Next steps**
1. Make both legacy routes redirect directly to `/hosts/operations?filter=all`, copying only host/server identities accepted by `hostOperationScope`. Preserve valid removed identities, encode values, discard every other legacy parameter, and remove server-side hash access.
2. Set the Hosts action’s label and URL to the required values. Make absent, retired and self-referential selected-operation return destinations fall back to `/hosts`, while preserving other validated origins.
3. Align tests and documentation with the ticket’s contract. Add coverage using SvelteKit’s server URL behavior so the HTTP 500 regression is caught, plus the complete scope/filter and contextual-return matrix.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The standalone Activity log splits history across overlapping entry points for fleet operators. Server jobs and maintenance/recovery already have dedicated pages; the remaining feed combines release and host-operation records that also have their own destinations.
Source checked on 2026-10-13 at
82e07ea33eedddd7b707f5e62c12d2e606a1e680:src/routes/activity/+page.server.ts:6excludes provisioning and maintenance from the standalone feed;src/routes/activity/+page.svelte:12directs users to those separate histories.src/lib/server/activity.ts:163links the remaining records to Host operation history, Campaigns, and Betas.src/lib/navigation.ts:52exposes Activity log, itsdshortcut, and active-state matching for/activity,/operations, and/hosts/operations.src/routes/servers/[name]/+page.svelte:841links server History back to Activity, while line 845 renders its ownActivityLog;src/routes/maintenance/+page.svelte:429also uses the shared component.src/routes/hosts/operations/+page.svelte:155falls back to Activity for a selected operation;src/lib/navigation-context.ts:3,48,49also recognizes and labels the legacy destinations.src/routes/operations/+page.server.ts:4redirects to/activitywithout preserving query parameters.src/lib/hosts.ts:265defines the host/server scope supported by Host operation history.src/routes/hosts/+page.svelte:88has no fleet-wide history action in its header;src/routes/hosts/[id]/+page.svelte:197already provides host-scoped history access.Remove the standalone page and make Hosts the entry point for host-operation history. Keep Campaigns, Betas, server History, and Maintenance history available. This is navigation cleanup; no redesign of those history pages or changes to collected records are included.
Screenshots
Synthetic preview at the revision above, using the same fixture for both states. Desktop viewport: 1440×900; phone: 390×844. Images are cropped to the relevant navigation/header area. After images are DOM mockups, not implemented behavior. They show removal of the Activity log navigation item and a Host operation history action on Hosts; the Activity group still contains Provisioning and Maintenance.
Before — desktop:

After (mockup) — desktop:

Before — phone:

After (mockup) — phone:

Fix
/activitypage with a compatibility redirect. Remove its navigation item, search/command entry, and keyboard shortcut; retain the Activity group's Provisioning and Maintenance entries./hosts/operations?filter=all, visible to users already permitted to view that history. Preserve existing host-scoped links and highlight Hosts on/hosts/operations./hosts. Update shared return-link handling so no breadcrumb/back link names or returns to the retired pages; preserve other validated return destinations and fall back to/hostsfor retired or self-referential destinations./operationsthrough/activity./api/activity,src/lib/server/activity.ts, the shared query helpers, andActivityLog; server History and Maintenance still depend on them. Preserve event collection, retained records, and retention behavior.docs/development/ui-patterns.md:93to describe scoped history and its remaining entry points.Legacy redirect contract
Both
/activityand/operationsuse these destinations:/hosts/operations?filter=allhost=<id>/hosts/operations?filter=all&host=<encoded-id>server=<name>/hosts/operations?filter=all&server=<encoded-name>/hosts/operations?filter=all&host=<encoded-id>&server=<encoded-name>Validate each scope with the existing
hostOperationScoperules and URL-encode its value. Keep valid historical identities even if the host/server was removed; absent records should yield the destination's normal empty state. Omit invalid scope values. Reset pagination and discard all other legacy parameters, includingtype,source,state,days,q,limit,offset,filter, andreturnTo, rather than interpreting Activity filters as host-operation filters. The destination shows host operations; release histories remain under Campaigns and Betas.Verification
returnTovalues; redirects have the specified destinations and no loops.Reviewed
eceb38a6bcagainst current upstreambe7f6c77c1. The navigation removal is partly complete, but legacy redirects can return HTTP 500 and several explicit redirect/back-link requirements remain unmet, so this issue stays open.Checklist
src/routes/hosts/+page.svelte:89uses “Operation history” and/hosts/operations. It must use “Host operation history” and/hosts/operations?filter=all; the current loader otherwise defaults to Actions & errors.src/routes/hosts/operations/+page.svelte:155still returns to history, not/hosts.safeReturnHref()rewrites retired destinations through the legacy redirect and accepts self-targeting selected-operation returns.hostOperationScope.ActivityLog, event collection and retention remain available and unchanged by this commit.docs/development/ui-patterns.md:93still describes the fleet timeline; the legacy-routing explanation indocs/guides/provisioning.mdalso needs alignment.Review notes
/activity?server=deleted-serverand/operations?host=deleted-host&server=deleted-server&state=failed&offset=25&returnTo=%2Factivityreturn HTTP 500. The server logsCannot access event.url.hashatsrc/lib/activity-redirect.ts:21, called by the legacy server loader. The Maintenance/recovery branch repeats the same forbidden access at line 29. PlainURLobjects in unit tests do not reproduce SvelteKit’s guarded server getter./activity?host=host%0Ainvalidredirects to/hosts/operations?host=host%0Ainvalid; the contract requires/hosts/operations?filter=allwith that invalid host omitted.retained-opwithreturnTo=/hosts/operations?operation=retained-opproduces a back link to that same selected operation. With no origin it returns to operation history; with retired origin/activity?host=deleted-hostit returns to host-filtered history. These cases require/hosts.npm run lintandnpm run checkpass, with zero Svelte errors or warnings. Chromium checks used an isolated synthetic fixture; no production data or operations were changed.Next steps
/hosts/operations?filter=all, copying only host/server identities accepted byhostOperationScope. Preserve valid removed identities, encode values, discard every other legacy parameter, and remove server-side hash access./hosts, while preserving other validated origins.