diff --git a/PROBLEMS.md b/PROBLEMS.md index bbe7225..c508e06 100644 --- a/PROBLEMS.md +++ b/PROBLEMS.md @@ -1,10 +1,10 @@ -# PROBLEMS.md +# PROBLEMS.md Open issues only. Fixed items removed. Last sweep: 2026-06-07. ## No open code issues -Automatable gaps are closed; remaining items below are by-design limits, architecture deferrals, manual/live P2, or test noise. Regression tables and counts live in `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 **797**, agent **612**, Vitest **791**, Playwright **25** — see `tests/README.md`. ## By design / safety @@ -22,11 +22,11 @@ Automatable gaps are closed; remaining items below are by-design limits, archite | Area | Notes | |------|-------| -| **Subnet grouping** | Derived from `agents.ip` /24 prefix at query time; no `agents.subnet` column — hundreds of subnets OK via `LIKE` filter + dropdown (not chips). | +| **Subnet grouping** | Derived from `agents.ip` /24 prefix at query time; no `agents.subnet` column - hundreds of subnets OK via `LIKE` filter + dropdown (not chips). | | **Per-agent subnet scan** | Capped at 128 hosts (`MaxSubnetScanHosts`); syscheck uses 20 (`SyscheckSubnetScanCap`); spread sem=16 (`SpreadConcurrencyCap`). Fleet discovery is incremental (ARP + capped sweep), not full /16. | | **`stats_batch` WS** | Server coalesces stats every 250ms (`StatsBatchCoalesceInterval`) into one frame; client applies in single `setAgents` pass with `agentStatsUnchanged` skip. | -| **Hashrate samples** | One `INSERT` per agent stats tick — dominant DB write at scale. Automated purge via `StartRetentionJobs` (default 168h, `stats_retention_hours`). | -| **Stale-agent sweep** | Every 45s (`StaleAgentSweepInterval`) queries `status='online' AND last_seen < cutoff` (`ListStaleOnlineAgents`, composite index) — not a full-table scan. Still O(stale-online) broadcasts per sweep. | +| **Hashrate samples** | One `INSERT` per agent stats tick - dominant DB write at scale. Automated purge via `StartRetentionJobs` (default 168h, `stats_retention_hours`). | +| **Stale-agent sweep** | Every 45s (`StaleAgentSweepInterval`) queries `status='online' AND last_seen < cutoff` (`ListStaleOnlineAgents`, composite index) - not a full-table scan. Still O(stale-online) broadcasts per sweep. | ## Container Mining @@ -34,7 +34,7 @@ Automatable gaps are closed; remaining items below are by-design limits, archite |-------|-------| | **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. | -| **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. | | **Worker image** | `aetherforge/agent-worker:latest` (override `AETHERFORGE_MINER_IMAGE`). Build from `docker/Dockerfile.agent`; Forge live notice + `FieldHint` on Miner Execution. | | **Container hashrate** | Host relays container worker H/s via `MINER_STATS_FILE` + `ProbeHashrate()` when `hostMiningDisabled` (dashboard no longer stuck at 0). | @@ -64,25 +64,13 @@ Automatable gaps are closed; remaining items below are by-design limits, archite | **Terminal virtualization** | 400-line DOM cap only; full virtual scrollback deferred. | | **Vite chunk weight** | `three` + vendor warnings; FleetTopologyMap lazy but heavy first open. | -## Test gaps / noise +## Manual / live / honest partial | Item | Notes | |------|-------| -| **P1 covered (2026-06-07)** | 14-tier spread chain, triple-onion gates, fleet recon, Fleet AI control, personas, phenotype, failure atlas, court, clearance L0–L4 — Go server **793** + agent **608** `Test*` + Vitest **791**; see `tests/README.md` | -| **Fleet evolution covered (2026-06-07)** | Seeder/miner split, atlas gossip, genetic breeding, BGP spread router, genealogy telemetry (non-blocking auth), court retry L4, hashrate/subnet gates, APK scout, persona temperament, WSUS mimic, erasure foundation — Go **793+608** + Vitest **791** + Playwright **25** (phase 8); master table in `tests/README.md` | -| **P2 covered (2026-06-07)** | Mock `MiningChainRunner` lifecycle (`mining_chain_lifecycle_test.go`); spread lane templates + dispatch (`spread_lanes_test.go`, `winrm_spread_test.go`, staging/BITS mocks); Path Forge API + Forge UI incl. cancel/batch race (`pathforge_test.go`, `BuilderPage.test.tsx`); WS/beacon + file upload round-trips (`ws_beacon_integration_test.go` server+agent); pathtracer stub + `wg_setup` routing (`pathtracer_stub_test.go`, `aggressive_commands_test.go`); Path Tracer UI poll coverage (`PathTracerPage.test.tsx`); Emberwake WS-only war room (`EmberwakePage.test.tsx`); SystemStatusBar WS fleet count (`components.test.tsx`); flaky WS/spread-gate tests stabilized (`ed9c90a`); Playwright LOTL onion + discover→spread stub E2E (`lotl-timeline.spec.ts`, `discover-spread.spec.ts`); mock container/podman exec + runtime probe (`container_launcher_test.go`, `runtime_detect_test.go`); BITS/curl `HiddenRun` mocks (`bits_windows_test.go`, `staging_chain_test.go`); WinRM/GPO/systemd deploy-plan httptest + mock execute (`deploy_plan_integration_test.go`, `discover_join_test.go`); 3-hop discover→spread Playwright stub chain (`discover-spread-stub.ts`, `discover-spread.spec.ts`, `d18c591`); Vitest **791** + Playwright **25** — see `tests/README.md` § P2 | -| **Erasure-coded multi-lane propagation (foundation 2026-06-07)** | **Partial / honest foundation** — server `internal/erasure/` Reed–Solomon 4+2 encode + in-memory shard store + `/api/v1/public/erasure-shard/{token}/{index}`; signed 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; BGP `spread_route_hint` + Path Tracer show `erasure_lanes_enabled`. **Not shipped:** live parallel lane orchestration, seeder-side shard fan-out, or erasure-first (non-fallback) spread E2E. | -| **P2 remaining (manual only)** | Live Docker/Podman container start on operator host; real WinRM/GPO/systemd/crontab execution on remote owned hosts; live BITS/curl against non-mock C2 endpoints; live multi-hop discover→spread without Playwright stub; live TLS/mesh beacon; full `wg_setup` on real Windows hosts | - -## Scrubbed 2026-06-07 (prod garbage removed) - -| Item | Action | -|------|--------| -| `agent/config/builtin.go` XMR/RVN wallets | Cleared — dev builtin no longer ships third-party addresses | -| `server/config.go` builtin Cloudflare token | Removed — connector requires env/config/`cloudflared-token.txt` | -| `data-e2e/`, `music/`, `scratch/` in repo | Untracked + `.gitignore` (E2E wallet stays in `docker/` + `e2e-validate.ps1` only) | -| Mission Deck forge bar | Replaced client-side stage timer with server `GET /builder/progress/{token}` poll | +| **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. **Not shipped:** live parallel lane orchestration, seeder-side shard fan-out, or erasure-first (non-fallback) spread E2E. | +| **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. | ## Do not commit -- `data/login-credentials.json`, `data/users.json`, and other local secrets. \ No newline at end of file +- `data/login-credentials.json`, `data/users.json`, and other local secrets. diff --git a/server/web/e2e/crucible-command.spec.ts b/server/web/e2e/crucible-command.spec.ts index cc9f2df..66710f5 100644 --- a/server/web/e2e/crucible-command.spec.ts +++ b/server/web/e2e/crucible-command.spec.ts @@ -21,9 +21,9 @@ test.describe('Crucible remote command', () => { test('whoami on selected online node shows terminal output', async ({ page }) => { await page.getByText(E2E_STUB_AGENT_HOSTNAME).click(); - await expect( - page.locator('.crucible-actions-card').getByText(new RegExp(`→ ${E2E_STUB_AGENT_HOSTNAME}`)), - ).toBeVisible(); + await expect(page.locator('.crucible-actions-card')).toContainText(E2E_STUB_AGENT_HOSTNAME, { + timeout: 10_000, + }); await page.getByRole('button', { name: 'CMD', exact: true }).click(); const input = page.locator('.crucible-term-input'); diff --git a/server/web/e2e/path-tracer.spec.ts b/server/web/e2e/path-tracer.spec.ts index 657e26f..09e0acc 100644 --- a/server/web/e2e/path-tracer.spec.ts +++ b/server/web/e2e/path-tracer.spec.ts @@ -56,7 +56,9 @@ test.describe('Path Tracer E2E', () => { const card = page.locator('.pt-agent-card').filter({ hasText: E2E_STUB_AGENT_HOSTNAME }); await expect(card).toBeVisible({ timeout: 15_000 }); await card.click(); - await card.getByRole('button', { name: /TRACE/i }).click(); + const traceBtn = page.locator('.pt-actions').getByRole('button', { name: /TRACE/i }); + await expect(traceBtn).toBeEnabled({ timeout: 10_000 }); + await traceBtn.click(); await expect(page.getByText('Spread Routes')).toBeVisible({ timeout: 15_000 }); await expect(page.getByText(/192\.168\.1\.0\/24/)).toBeVisible(); diff --git a/tests/README.md b/tests/README.md index 06ab8bf..6280783 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,6 @@ -# AetherForge Test Suite +# AetherForge Test Suite -**Current counts (2026-06-07):** Go server **793** `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 **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`. ## Master validation (operator commands) @@ -833,3 +833,5 @@ Unit tests cover `AgentRemoteActions` offline gating and mining live-stats in `c 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. + +