diff --git a/docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene.md b/docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene.md
new file mode 100644
index 00000000..39ce5da3
--- /dev/null
+++ b/docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene.md
@@ -0,0 +1,415 @@
+# Hosts per-driver rows + AbCip nested-struct + Galaxy hygiene — Implementation Plan
+
+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers-extended-cc:subagent-driven-development to implement this plan task-by-task.
+
+**Goal:** Ship three disjoint backlog items — a `/hosts` cluster-grouped Driver Instances section (#8),
+AbCip nested-struct member expansion (#6), and Galaxy stale-comment hygiene + reconcile (#3/#13/#10).
+
+**Architecture:** Reuse the existing driver-health DPS pipeline (add only an AdminUI-internal store
+`GetAll()` + a pure view-model builder) so no Commons/interface/EF change is needed. AbCip stops discarding
+the nested template id the member block already carries. Galaxy comments rewritten to shipped reality.
+
+**Tech Stack:** .NET 10, Blazor Server (AdminUI), EF Core (ConfigDB read), xUnit + Shouldly. No bUnit.
+
+**Base:** branch `feat/hosts-rows-abcip-nested-hygiene` off master `f59680fa`; design committed `fec08915`.
+
+**Execution note:** implementers dispatched **serially** on this branch (avoids the shared-tree git-race
+lesson); per-task classification-driven review. T3 depends on T2.
+
+---
+
+### Task 1: AbCip nested-struct template-id threading
+
+**Classification:** standard
+**Estimated implement time:** ~5 min
+**Parallelizable with:** none (serial dispatch)
+
+**Files:**
+- Modify: `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/AbCipTemplateCache.cs:57` (`AbCipUdtMember` record)
+- Modify: `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/CipTemplateObjectDecoder.cs:85-96`
+- Modify: `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/AbCipDriver.cs:~1179` (the nested recursion call)
+- Test: `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/AbCipFetchUdtShapeTests.cs` (or a new
+ `AbCipNestedTemplateTests.cs` in the same project)
+
+**Context:** Top-level controller-discovered UDT members are addressable (`4e141402`/`4a7b0fde`), but a
+nested struct member's sub-shape can't be fetched because the prior fix passed `templateInstanceId: null`
+when recursing. The member-info `u16` actually carries the nested template id (bit 15 = struct flag, lower
+12 bits = template instance id — see the decoder's own remarks block, lines 26-27). Stop discarding it.
+
+**Step 1: Extend `AbCipUdtMember` (optional trailing param — preserves existing 4-arg call sites)**
+
+```csharp
+/// One member of a Logix UDT.
+/// Member name.
+/// Byte offset from the struct start.
+/// Member CIP data type (Structure for a nested UDT).
+/// Element count (1 for a scalar member).
+/// For a member, the nested UDT's
+/// template instance id decoded from the member-info low 12 bits; null for a scalar member.
+public sealed record AbCipUdtMember(
+ string Name,
+ int Offset,
+ AbCipDataType DataType,
+ int ArrayLength,
+ uint? NestedTemplateId = null);
+```
+
+**Step 2: Decode the nested template id in `CipTemplateObjectDecoder.Decode` (struct members only)**
+
+In the member loop (after computing `isStruct`/`typeCode`, ~line 85), use the **full 12-bit mask** (not the
+byte-cast `typeCode`) for the nested id, and thread it into the member:
+
+```csharp
+var isStruct = (info & MemberInfoStructFlag) != 0;
+var typeCode = (byte)(info & MemberInfoTypeCodeMask);
+var dataType = isStruct
+ ? AbCipDataType.Structure
+ : (CipSymbolObjectDecoder.MapTypeCode(typeCode) ?? AbCipDataType.Structure);
+// For a struct member the low 12 bits are the nested UDT's template instance id (same encoding as
+// the Symbol Object), NOT a primitive type code — capture it so the nested shape can be fetched.
+var nestedTemplateId = isStruct ? (uint?)(info & MemberInfoTypeCodeMask) : null;
+
+var memberName = i < memberNames.Length ? memberNames[i] : $"";
+members.Add(new AbCipUdtMember(
+ Name: memberName,
+ Offset: offset,
+ DataType: dataType,
+ ArrayLength: arraySize == 0 ? 1 : arraySize,
+ NestedTemplateId: nestedTemplateId));
+```
+
+**Step 3: Thread the id at the recursion site (`AbCipDriver.cs:~1179`)**
+
+Change `templateInstanceId: null` → `templateInstanceId: member.NestedTemplateId`:
+
+```csharp
+var nested = await ResolveDiscoveredUdtShapeAsync(
+ deviceHostAddress, member.Name, templateInstanceId: member.NestedTemplateId, cancellationToken)
+ .ConfigureAwait(false);
+```
+
+`ResolveDiscoveredUdtShapeAsync` still consults the name-keyed seeded shapes (the `SeedDiscoveredUdtShapeForTest`
+seam) first, then falls back to `FetchUdtShapeAsync(deviceHostAddress, id, ct)` — which reads `@udt/{id}` and
+decodes — when an id is now present. Deep nesting works recursively (each level decodes its own members'
+`NestedTemplateId`), bounded by the existing `MaxUdtDepth` + `visited` cycle guard.
+
+**Step 4: Tests (offline, via `FakeTemplateReader`)**
+
+- **Decoder test:** build a minimal Template Object blob (header + one struct member with
+ `info = 0x8000 | 0x123`, plus a scalar member) using the same byte layout the existing tests use; assert
+ the struct member decodes `DataType == Structure` AND `NestedTemplateId == 0x123u`, and the scalar member
+ decodes `NestedTemplateId == null`.
+- **Threading test:** drive the discovery/fan-out path for a top-level UDT whose member is a nested struct;
+ configure the `FakeTemplateReader` to return the nested template's blob for the nested id; assert the nested
+ struct's leaf members become addressable (emitted) — i.e. the nested id now drives a real fetch rather than
+ yielding `null`. Reuse the existing discovery test harness pattern in this project; do NOT use
+ `SeedDiscoveredUdtShapeForTest` for the nested shape (that would bypass what we're testing).
+
+**Step 5: Run + commit**
+
+```bash
+dotnet test tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests --filter "FullyQualifiedName~Udt" -v minimal
+git add src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/AbCipTemplateCache.cs \
+ src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/CipTemplateObjectDecoder.cs \
+ src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/AbCipDriver.cs \
+ tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/.cs
+git commit -m "feat(abcip): thread nested-struct template id so nested UDT members are addressable (#6)"
+```
+
+---
+
+### Task 2: `/hosts` driver-snapshot store enumeration + pure grouping view-model
+
+**Classification:** standard
+**Estimated implement time:** ~5 min
+**Parallelizable with:** none (serial; T3 depends on this)
+
+**Files:**
+- Modify: `src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/IDriverStatusSnapshotStore.cs`
+- Modify: `src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/InMemoryDriverStatusSnapshotStore.cs`
+- Create: `src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hosts/HostsDriverView.cs` (pure builder + view-model records)
+- Test: `tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Hosts/HostsDriverViewTests.cs` (confirm the AdminUI
+ test project path; create the file)
+
+**Step 1: Add `GetAll()` to the store interface**
+
+```csharp
+/// Returns a point-in-time snapshot of every driver instance's last-known health.
+IReadOnlyCollection GetAll();
+```
+
+**Step 2: Implement in `InMemoryDriverStatusSnapshotStore`**
+
+```csharp
+///
+public IReadOnlyCollection GetAll() => _byInstance.Values.ToArray();
+```
+
+**Step 3: Pure grouping view-model `HostsDriverView`**
+
+Define plain input/output records (no EF types) so it unit-tests offline. Group by `ClusterId`, union of
+cluster ids from nodes + snapshots; enrich each snapshot with `Name`/`DriverType` by joining instances on
+`DriverInstanceId`; unknown driver (snapshot with no matching instance) → null Name/DriverType fallback.
+
+```csharp
+namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hosts;
+
+using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers;
+
+/// A cluster node as needed for the Hosts driver view (subset of the ConfigDB ClusterNode row).
+public sealed record HostsNodeInfo(string ClusterId, string NodeId, string Host, int OpcUaPort);
+
+/// A driver instance as needed for enrichment (subset of the ConfigDB DriverInstance row).
+public sealed record HostsDriverInstanceInfo(string DriverInstanceId, string ClusterId, string Name, string DriverType);
+
+/// One driver row in a cluster group: live health enriched with the configured name + type.
+public sealed record HostsDriverRow(
+ string DriverInstanceId,
+ string? Name,
+ string? DriverType,
+ string State,
+ DateTime? LastSuccessfulReadUtc,
+ string? LastError,
+ int ErrorCount5Min,
+ DateTime PublishedUtc);
+
+/// One cluster group: the cluster's nodes + the cluster's live driver rows.
+public sealed record HostsClusterGroup(
+ string ClusterId,
+ IReadOnlyList Nodes,
+ IReadOnlyList Drivers);
+
+/// Pure builder for the Hosts page Driver-Instances section — DB-agnostic + unit-testable.
+public static class HostsDriverView
+{
+ /// Builds the cluster-grouped driver view from live snapshots + cached ConfigDB rows.
+ /// Live driver-health snapshots from the snapshot store.
+ /// ConfigDB cluster nodes (for the per-cluster node list).
+ /// ConfigDB driver instances (for Name/DriverType enrichment).
+ /// Cluster groups ordered by ClusterId; drivers ordered by Name ?? DriverInstanceId.
+ public static IReadOnlyList Build(
+ IEnumerable snapshots,
+ IEnumerable nodes,
+ IEnumerable instances)
+ {
+ var snapList = snapshots?.ToList() ?? new();
+ var nodeList = nodes?.ToList() ?? new();
+ var instById = (instances ?? Enumerable.Empty())
+ .GroupBy(i => i.DriverInstanceId)
+ .ToDictionary(g => g.Key, g => g.First());
+
+ var clusterIds = snapList.Select(s => s.ClusterId)
+ .Concat(nodeList.Select(n => n.ClusterId))
+ .Where(id => !string.IsNullOrEmpty(id))
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .OrderBy(id => id, StringComparer.OrdinalIgnoreCase);
+
+ var groups = new List();
+ foreach (var clusterId in clusterIds)
+ {
+ var clusterNodes = nodeList
+ .Where(n => string.Equals(n.ClusterId, clusterId, StringComparison.OrdinalIgnoreCase))
+ .OrderBy(n => n.NodeId, StringComparer.OrdinalIgnoreCase)
+ .ToList();
+
+ var drivers = snapList
+ .Where(s => string.Equals(s.ClusterId, clusterId, StringComparison.OrdinalIgnoreCase))
+ .Select(s =>
+ {
+ instById.TryGetValue(s.DriverInstanceId, out var inst);
+ return new HostsDriverRow(
+ s.DriverInstanceId, inst?.Name, inst?.DriverType, s.State,
+ s.LastSuccessfulReadUtc, s.LastError, s.ErrorCount5Min, s.PublishedUtc);
+ })
+ .OrderBy(d => d.Name ?? d.DriverInstanceId, StringComparer.OrdinalIgnoreCase)
+ .ToList();
+
+ groups.Add(new HostsClusterGroup(clusterId, clusterNodes, drivers));
+ }
+ return groups;
+ }
+}
+```
+
+**Step 4: Tests (xUnit + Shouldly)** in `HostsDriverViewTests.cs`:
+- two clusters with nodes + snapshots → two groups, correct nodes + drivers per cluster;
+- enrichment: a snapshot whose `DriverInstanceId` matches an instance → Name + DriverType filled;
+- unknown-driver fallback: a snapshot with no matching instance → row present with null Name/DriverType;
+- a cluster with nodes but no snapshots → group present, empty Drivers;
+- empty inputs → empty list;
+- driver ordering by Name then DriverInstanceId.
+
+**Step 5: Run + commit**
+
+```bash
+dotnet test tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests --filter "FullyQualifiedName~HostsDriverView" -v minimal
+git add src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/IDriverStatusSnapshotStore.cs \
+ src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hubs/InMemoryDriverStatusSnapshotStore.cs \
+ src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Hosts/HostsDriverView.cs \
+ tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Hosts/HostsDriverViewTests.cs
+git commit -m "feat(adminui): driver-snapshot GetAll() + pure Hosts driver-view builder (#8)"
+```
+
+---
+
+### Task 3: `/hosts` "Driver Instances" Razor section
+
+**Classification:** standard
+**Estimated implement time:** ~5 min
+**Parallelizable with:** none (depends on Task 2)
+
+**Files:**
+- Modify: `src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Hosts.razor`
+
+**Context:** Add a new section below the existing Members section. Keep the Akka member rows untouched.
+Pattern after `DriverStatusPanel` for the live subscription (in-process store read, marshal via InvokeAsync —
+dodges the Traefik self-hub trap) and after `Fleet.razor` for the ConfigDB read.
+
+**Step 1: Injects + usings** (top of Hosts.razor)
+
+```razor
+@using ZB.MOM.WW.OtOpcUa.AdminUI.Hosts
+@using ZB.MOM.WW.OtOpcUa.AdminUI.Hubs
+@using ZB.MOM.WW.OtOpcUa.Configuration
+@using Microsoft.EntityFrameworkCore
+@inject IDriverStatusSnapshotStore DriverStore
+@inject IDbContextFactory DbFactory
+```
+(Confirm the ConfigDbContext type name + namespace from `Fleet.razor`.)
+
+**Step 2: State + lifecycle (in `@code`)**
+
+- Fields: `IReadOnlyList? _driverGroups;` plus cached
+ `List _nodes`, `List _instances`.
+- `OnInitializedAsync`: `await LoadConfigAsync();` then `RebuildDriverGroups();` then
+ `DriverStore.SnapshotChanged += OnSnapshotChanged;`
+- `LoadConfigAsync()`: `await using var db = await DbFactory.CreateDbContextAsync();` read `ClusterNodes`
+ → `HostsNodeInfo(ClusterId, NodeId, Host, OpcUaPort)`; read `DriverInstances` →
+ `HostsDriverInstanceInfo(DriverInstanceId, ClusterId, Name, DriverType)`. (Confirm DbSet + property names.)
+- `RebuildDriverGroups()`: `_driverGroups = HostsDriverView.Build(DriverStore.GetAll(), _nodes, _instances);`
+- `OnSnapshotChanged(DriverHealthChanged _)`: `InvokeAsync(() => { RebuildDriverGroups(); StateHasChanged(); });`
+ (cheap — reuses cached config; a brand-new driver shows by id until the 5 s timer/Refresh re-reads config).
+- Extend the existing `Refresh`/timer + `RefreshAsync` to also `await LoadConfigAsync(); RebuildDriverGroups();`
+ so configured names stay current. (The timer callback is sync — make a small async path or call
+ `LoadConfigAsync()` fire-and-forget-with-InvokeAsync; keep it simple and correct.)
+- `Dispose()`: add `DriverStore.SnapshotChanged -= OnSnapshotChanged;` alongside the existing `_timer?.Dispose()`.
+
+**Step 3: Markup — new section below the Members ``**
+
+A panel "Driver instances" with a small notice that rows are **cluster-scoped** (health is per driver
+instance across the cluster, not per Akka member). For each `HostsClusterGroup`: a sub-head
+`Cluster ` + node chips (` (:)`) + a table of drivers:
+columns Driver (Name ?? DriverInstanceId, with the id in `.mono` small if a name exists), Type, Status
+(chip via the mapping below), Last read, Last error, Errors/5 min. Handle `_driverGroups is null` (Loading)
+and empty (a notice "No driver instances reporting yet").
+
+**Step 4: Local chip mapping (mirror `DriverStatusPanel.ChipClass`)**
+
+```csharp
+private static string DriverChipClass(string? state) => state switch
+{
+ "Healthy" => "chip-ok",
+ "Degraded" => "chip-warn",
+ "Connecting" => "chip-warn",
+ "Reconnecting" => "chip-warn",
+ "Faulted" => "chip-bad",
+ _ => "chip-idle",
+};
+```
+
+**Step 5: Build + commit** (no bUnit — proven live in Task 6)
+
+```bash
+dotnet build src/Server/ZB.MOM.WW.OtOpcUa.AdminUI -v minimal
+git add src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Hosts.razor
+git commit -m "feat(adminui): /hosts cluster-grouped Driver Instances section (#8)"
+```
+Also update the page's stale top-of-file comment (lines 2-5: "there are no per-driver host rows yet") to
+reflect the shipped section.
+
+---
+
+### Task 4: Galaxy stale-comment hygiene
+
+**Classification:** trivial
+**Estimated implement time:** ~4 min
+**Parallelizable with:** none (serial)
+
+**Files:**
+- Modify: `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/GalaxyDriver.cs` (~lines 52, 92, 669)
+- Modify: `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/GalaxyDriverFactoryExtensions.cs` (~line 19)
+- Modify: `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Health/HostStatusAggregator.cs` (~line 21)
+
+**Comment-only.** Verify each claim against the current code BEFORE rewriting (e.g. confirm `_ownedMxSession`
+is built in `InitializeAsync`, the probe-watcher membership refresh after `DiscoverAsync` is wired,
+`HostStatusAggregator.OnHostStatusChanged` is re-raised by the driver). Rewrite to shipped reality:
+- Drop "PR 4.W" / "PR 4.4 supplies the production implementation; until then…" / "legacy-host backend
+ handles reads in production" — Galaxy is the standard Equipment-kind driver now; reads ARE supported in
+ production; the legacy Galaxy.Host/Proxy/Shared were retired in PR 7.2.
+- `GalaxyDriverFactoryExtensions`: drop "PR 4.W will add a server-side `Galaxy:Backend` switch … parity
+ testing (Phase 5)" — never landed and won't (only `GalaxyMxGateway` exists; the legacy `Galaxy` proxy
+ type is retired). State the shipped reality (the distinct type name is historical; no backend switch).
+- Convert any genuinely-still-future note to a real `TODO`, else delete the forward-ref.
+
+Do NOT change any code — comments/XML-doc only.
+
+**Build + commit:**
+```bash
+dotnet build src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy -v minimal
+git add src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/GalaxyDriver.cs \
+ src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/GalaxyDriverFactoryExtensions.cs \
+ src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Health/HostStatusAggregator.cs
+git commit -m "docs(galaxy): rewrite stale PR-4.W/legacy-host forward-ref comments to shipped reality (#13)"
+```
+
+---
+
+### Task 5: Reconcile stillpending + memory (never-staged for stillpending)
+
+**Classification:** trivial
+**Estimated implement time:** ~3 min
+**Parallelizable with:** none
+
+**Files:**
+- Modify: `stillpending.md` (**never staged** — local working copy only)
+- Modify: `/Users/dohertj2/.claude/projects/-Users-dohertj2-Desktop-OtOpcUa/memory/MEMORY.md`
+- Modify: `/Users/dohertj2/.claude/projects/-Users-dohertj2-Desktop-OtOpcUa/memory/project_stillpending_backlog.md`
+
+- `stillpending.md`: mark item #10 SHIPPED (the `ctx`-receiver guard is in `ScriptAnalysisService.cs:224`,
+ `70e1bde9`); strike #8 (this phase) + #6 (this phase) SHIPPED with the commit refs once known; note the
+ AbCip finding (id was already in the member block, not a new query) + the Hosts cluster-scoped framing +
+ the deferred per-member-nesting follow-up.
+- Memory: update `project_stillpending_backlog.md` + the `MEMORY.md` one-liner. Keep `MEMORY.md` entries
+ short (the index is already near its size cap).
+
+**Commit (memory files only — stillpending.md stays unstaged):**
+```bash
+git add docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene.md.tasks.json
+git commit -m "docs(plans): mark hosts/abcip/hygiene tasks complete + reconcile"
+```
+(Memory files live outside the repo; they are written, not committed.)
+
+---
+
+### Task 6: Build + tests + live `/run` + finish
+
+**Classification:** small
+**Estimated implement time:** ~5 min (+ live-verify)
+**Parallelizable with:** none
+
+**Step 1: Full build + the three affected test projects**
+```bash
+dotnet build ZB.MOM.WW.OtOpcUa.slnx -v minimal
+dotnet test tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests -v minimal
+dotnet test tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests -v minimal
+dotnet test tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests -v minimal
+```
+Expected: build clean; all green (AbCip + AdminUI + Galaxy). Note any pre-existing unrelated failures.
+
+**Step 2: Component A live `/run` (docker-dev)** — rebuild **BOTH** central-1 AND central-2 (the `:9200`
+AdminUI round-robins across both; a half-deploy serves stale code). Deploy a Modbus driver, open
+`http://localhost:9200/hosts`, confirm the Driver Instances section lists the deployed driver(s) grouped by
+cluster with a live status chip; drive a Reconnect from a driver page and confirm the chip updates. Record
+the result honestly (login is disabled on the local rig — drive it yourself; do not defer to user sign-in).
+
+**Step 3: Finish** — superpowers-extended-cc:finishing-a-development-branch → merge to master + push.
diff --git a/docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene.md.tasks.json b/docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene.md.tasks.json
new file mode 100644
index 00000000..a3ec684b
--- /dev/null
+++ b/docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene.md.tasks.json
@@ -0,0 +1,17 @@
+{
+ "planPath": "docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene.md",
+ "designPath": "docs/plans/2026-06-18-hosts-rows-abcip-nested-hygiene-design.md",
+ "branch": "feat/hosts-rows-abcip-nested-hygiene",
+ "baseSha": "f59680fa",
+ "designCommit": "fec08915",
+ "executionState": "IN_PROGRESS",
+ "tasks": [
+ {"id": 1, "subject": "Task 1: AbCip nested-struct template-id threading (decoder + record + driver + tests)", "classification": "standard", "status": "pending"},
+ {"id": 2, "subject": "Task 2: /hosts store GetAll() + pure HostsDriverView grouping builder + tests", "classification": "standard", "status": "pending"},
+ {"id": 3, "subject": "Task 3: /hosts cluster-grouped Driver Instances Razor section", "classification": "standard", "status": "pending", "blockedBy": [2]},
+ {"id": 4, "subject": "Task 4: Galaxy stale-comment hygiene (PR-4.W / legacy-host forward-refs)", "classification": "trivial", "status": "pending"},
+ {"id": 5, "subject": "Task 5: Reconcile stillpending #10/#6/#8 + memory", "classification": "trivial", "status": "pending"},
+ {"id": 6, "subject": "Task 6: Build + AbCip/AdminUI/Galaxy tests + Component A live /run + finish (merge+push)", "classification": "small", "status": "pending"}
+ ],
+ "lastUpdated": "2026-06-18"
+}