# Architecture Map

This document explains **what the system does**, **why it exists**, and **how the pieces connect**. It is written for human developers and AI assistants onboarding to the codebase.

---

## Problem and objective

### Problem

US secretary-of-state and business registries are inconsistently reachable from shared hosting:

- **Florida Sunbiz** — Cloudflare blocks many datacenter IPs
- **Mississippi, Louisiana, North Carolina, California, West Virginia, Tennessee** — Akamai, Cloudflare, Imperva, or reCAPTCHA require a real browser session (Edge/WebView2 on a Windows PC)
- **Georgia, Alabama, South Carolina, Texas, Kentucky** — HTTP registries (Florida modal); production still routes through the worker queue for a single integration path
- **Virginia** — Windows agent + Edge (invisible reCAPTCHA); see `sunbiz-agent-cpp/docs/VIRGINIA_SCC_EDGE.md`
- **Florida DBPR** (`myfloridalicense.com`) — Usually reachable directly from the server; no agent needed

### Objective

Provide a **reusable, real-time multi-state verification library** that:

1. Verifies registry entities by document/control number, name search, and best-match name verification
2. Optionally verifies Florida DBPR professional licenses (server-side PHP only)
3. Works from **x10 shared hosting** without Redis, a database, or long-running PHP
4. Supports **multiple Windows worker PCs** with configurable parallel worker pools
5. Returns structured JSON suitable for web applications
6. Completes most queued lookups in **~3–15 seconds** end-to-end

### Solution pattern

**Split execution by network reachability and deployment mode:**

| Workload | Where it runs | Why |
|----------|---------------|-----|
| Registry jobs (production) | Windows home agent(s) via file queue | Residential IP + Edge for protected sites |
| Registry jobs (dev / direct mode) | PHP on current machine | When `sunbiz_queue_url` is not set |
| Florida DBPR licenses | Web server (PHP) | Datacenter IP is fine |
| Coordination | Web server (file queue + JSON APIs) | Bridge between app and agents |

---

## Supported states

Defined in `lib/StateCodes.php`. Catalog exposed to `index.html` via `api.php?action=status`.

| Code | Label | Agent required (Edge) | Identifier examples |
|------|-------|----------------------|---------------------|
| FL | Florida (Sunbiz) | No* | Document number `M22000004323` |
| GA | Georgia (SOS) | No* | Control number |
| AL | Alabama (SOS) | No* | Entity ID |
| SC | South Carolina (SOS) | No* | Profile UUID |
| MS | Mississippi (SOS) | **Yes** | Business ID |
| LA | Louisiana (SOS) | **Yes** | Charter number |
| NC | North Carolina (SOS) | **Yes** | SOS ID |
| CA | California (BizFile) | **Yes** | File number |
| TX | Texas (Comptroller) | No* | SOS file / taxpayer number |
| WV | West Virginia (SOS) | **Yes** | Organization number (e.g. `623474`) |
| TN | Tennessee (SOS) | **Yes** | Control number |
| KY | Kentucky (SOS) | No* | Organization number (e.g. `1065987`) |
| VA | Virginia (SCC) | **Yes** | Entity ID (8 digits, e.g. `07265010`) |

\*In **production queue mode**, all states still flow through `businessverifier_agent.exe` even if PHP could scrape them directly.

### HTTP vs Edge tiers (implementation)

| Tier | States | Notes |
|------|--------|-------|
| **HTTP** | FL, GA, AL, SC, TX, KY | Plain `HttpClient` + cookie jar; no Edge session scripts |
| **Edge** | MS, LA, NC, CA, WV, TN, VA | Hidden Edge + CDP; required for bot protection / reCAPTCHA |

**Kentucky:** ASP.NET UpdatePanel search works over HTTP. Profile GETs for `sosbes.sos.ky.gov` use system **`curl.exe`** (libcurl alone was unreliable). Single-match redirects must fetch the full profile page.

**West Virginia:** SOS at `apps.wv.gov/SOS/BusinessEntitySearch/` — **Edge-only** on Windows. Organization **name** search only (org number is posted as a name query). Invisible reCAPTCHA on ASP.NET WebForms POST; browser fills `#hiddenRecpatcha` before submit. **No 2captcha.** Setup search **`Hale House`**. Cookies: `data/cookies/westvirginia_cookies.txt`. Reference: `westvirginiamappingfile.txt` in Release.

**Virginia:** SCC CIS at `cis.scc.virginia.gov` — **Edge-only** on Windows. Login-page search uses invisible reCAPTCHA Enterprise; automation uses **`reCaptchaValidate('Entity')` → `getPerformEntitySearch()`** via CDP (**trigger + poll**, not one long async evaluate). **No 2captcha.** Setup search entity ID **`07265010`**. Cookies: `data/cookies/virginia_cookies.txt`. Full guide: `sunbiz-agent-cpp/docs/VIRGINIA_SCC_EDGE.md`. Reference: `virginiamappingfile.txt` in Release.

**Louisiana** is the only state that optionally uses `http.recaptcha_solver_api_key` for Edge reCAPTCHA v3. Do not add solver keys for WV or VA. LA setup timing, worker parking, and invoke hot path: `sunbiz-agent-cpp/docs/LOUISIANA_SOS_EDGE.md`.

See `sunbiz-agent-cpp/docs/STATE_IMPLEMENTATION_RULES.md` when adding states from a `*mappingfile.txt`.

### Edge pool (shared browser slots)

Edge-backed states no longer each own a fixed profile under `data/profile/`. The agent runs a **pool of N hidden Edge slots** (default **4**) under `data/edge_pool/slot_{N}/`, managed by `EdgePoolManager` in the C++ agent.

| Concept | Behavior |
|---------|----------|
| Slot layout | `profile/`, `temp/`, `meta.json` (`parked_state`), `edge.pid`, `edge.port` |
| Assignment | Canonical order LA → NC → MS → CA → TN → VA → WV; slot `i` gets `edgeStates[i]` when enough states are enabled |
| Job flow | Worker calls `acquire(state)` → optional **migrate** → run verifier with slot context → `release` |
| Pre-warm | On startup or `enabled_states` change, pool pre-warms slots (coalesced restart reads current states at execution time) |
| Config | `config.json` → `edge_pool.size`, `pre_warm_on_startup`, `acquire_timeout_seconds`, `state_switch_timeout_seconds` |

Full design: **`sunbiz-agent-cpp/docs/EDGE_POOL.md`**.

### Verify vs search (HTTP and Edge optimizations)

`verify_name` with entity details must not perform a second HTTP/Edge round-trip when the search response already includes detail HTML.

| State | Tier | Optimization |
|-------|------|--------------|
| **MS** | Edge | Combined `BusinessNameSearchAndDetail` invoke; verify uses `exact` / `startingwith` (not `matchany`); log step `verify_detail_reused` |
| **SC** | HTTP | Combined `postNameSearchAndDetail` (same path as `search_name` limit=1 + details); log step `verify_detail_reused` |

Benchmark CLI: `--test-ms-benchmark`, `--test-sc-benchmark` on `businessverifier_agent.exe`.

---

## System topology

```mermaid
flowchart TB
    subgraph Browser["Browser / Your web app"]
        UI[index.html test console]
        APP[Your production PHP app]
    end

    subgraph Server["Shared host (Linux, PHP 8.x)"]
        API[api.php]
        FBV[FloridaBusinessVerifier.php]
        SC[StateCodes.php]
        QSV[QueuedSunbizVerifier.php]
        DLV[DbprLicenseVerifier.php]
        STATE_PHP[api/ga, api/al, api/ms, ...]
        QAPI[sunbiz_queue_api.php]
        FVQ[FileVerificationQueue.php]
        AR[AgentRegistry.php]
        STORE[(storage/verification_queue/)]
    end

    subgraph HomePC["Windows PC(s)"]
        SVC[businessverifier_agent.exe --service]
        GUI[Monitor GUI]
        CTRL[Control API :17821]
        AGENT[Agent.cpp worker pool]
        STATES[C++ state verifiers + Edge]
    end

    subgraph External["External registries"]
        REG[SOS / Sunbiz / BizFile / Comptroller sites]
        DBPR[myfloridalicense.com]
    end

    UI --> API
    APP --> FBV
    API --> FBV
    FBV --> SC
    FBV --> QSV
    FBV --> DLV
    FBV --> STATE_PHP
    QSV --> QAPI
    QAPI --> FVQ
    QAPI --> AR
    FVQ --> STORE
    AR --> STORE

    SVC -->|claim / complete / heartbeat| QAPI
    SVC --> CTRL
    GUI --> CTRL
    SVC --> AGENT
    AGENT --> STATES
    STATES --> REG
    DLV --> DBPR
```

---

## End-to-end flow: verify document (queue mode)

```mermaid
sequenceDiagram
    participant App as PHP app / api.php
    participant QSV as QueuedSunbizVerifier
    participant QAPI as sunbiz_queue_api.php
    participant Queue as FileVerificationQueue
    participant Agent as businessverifier_agent.exe
    participant Registry as State registry site

    App->>QSV: verifyDocumentNumber(doc, state)
    QSV->>QAPI: POST enqueue (app_token, state)
    QAPI->>Queue: write pending/job.json
    QAPI-->>QSV: job_id

    loop Poll up to sunbiz_queue_timeout
        QSV->>QAPI: GET status (app_token)
        QAPI-->>QSV: pending / processing / completed
    end

    Agent->>QAPI: POST claim (agent_token, agent_id, states, long poll)
    QAPI->>Queue: claim job for matching state
    QAPI-->>Agent: job payload

    loop While processing
        Agent->>QAPI: POST heartbeat (extend lease)
    end

    alt Edge-backed state (MS, LA, NC, CA, WV, TN, VA)
        Agent->>Agent: EdgePoolManager.acquire(state)
        Agent->>Registry: CDP invoke on pooled slot
    else HTTP state (FL, GA, AL, SC, TX, KY)
        Agent->>Registry: HttpClient lookup
    end
    Registry-->>Agent: HTML or JSON
    Agent->>Agent: parse → structured JSON

    Agent->>QAPI: POST complete (agent_token, result)
    QAPI->>Queue: move processing → completed

    QSV->>QAPI: GET status → completed
    QAPI-->>QSV: result JSON
    QSV-->>App: entity record
```

**Typical elapsed time:** 3–15 seconds (state, agent load, Edge setup, poll timing).

---

## Multi-agent queue model

Multiple Windows PCs can share one queue:

| Concept | Implementation |
|---------|----------------|
| Shared secret | Same `agent_token` on all PCs (`queue_config.php` + `config.json`) |
| Machine identity | Unique `agent_id` per PC (`config.json`) |
| State routing | Jobs carry a `state` field; agents claim only jobs matching `enabled_states` |
| Concurrency | `worker_count` / `max_concurrent_jobs` per PC (max 25) |
| Lease | `job_lease_seconds` in `queue_config.php`; extended via `heartbeat` while processing |
| Registry | `AgentRegistry` writes `agent_registry.json`; health reports `active_agents_by_state` |
| Client timeout | `client_pending_timeout_seconds` — stale pending jobs failed so agents do not replay abandoned work |

---

## Authentication model

Two static bearer tokens. No user sessions.

| Token | Config location | HTTP header | Can do |
|-------|-----------------|-------------|--------|
| `app_token` | `queue_config.php`, `hosting_config.php` | `X-Verification-Token` or `Authorization: Bearer` | `enqueue`, `status`, `health` |
| `agent_token` | `queue_config.php`, agent `config.json` | same | `claim`, `complete`, `fail`, `heartbeat`, `agent_startup` |

The browser test UI talks only to `api.php` (which uses `app_token` server-side). Agents never need `app_token`.

---

## Job lifecycle (queue)

```
pending/     → job created by enqueue (includes state + type + payload)
processing/  → job claimed by agent (atomic rename + lease)
completed/   → result written by agent
failed/      → error written by agent, TTL expiry, or client timeout
```

`FileVerificationQueue` also:

- Deletes expired jobs (TTL, default 3600s)
- On `agent_startup`: fails orphaned `processing/` jobs and expires stale `pending/` jobs
- Reclaims stale `processing/` jobs if an agent crashed (lease expiry)
- Skips expired pending jobs on `claim` so agents do not re-run requests the PHP client already timed out on

### Queue API actions (`sunbiz_queue_api.php`)

| Action | Token | Purpose |
|--------|-------|---------|
| `enqueue` | app | Create job |
| `status` | app | Poll job by id |
| `health` | none* | Queue counts, agents by state |
| `claim` | agent | Long-poll claim next job |
| `complete` | agent | Post result |
| `fail` | agent | Post error |
| `heartbeat` | agent | Extend leases + register agent |
| `agent_startup` | agent | Cleanup orphans on worker start |

### Supported job types

| `type` | PHP entry point | Agent handler |
|--------|-----------------|---------------|
| `verify_document` | `FloridaBusinessVerifier::verifyDocumentNumber` | Per-state C++ verifier |
| `search_name` | `FloridaBusinessVerifier::searchBusinessByName` | Per-state C++ verifier |
| `verify_name` | `FloridaBusinessVerifier::verifyBusinessByName` | Per-state C++ verifier |
| `entity_detail` | via Sunbiz interface | Detail fetch |

---

## PHP library structure

Namespace: `VerifyBusiness\`

### Entry point

| Class | Role |
|-------|------|
| `FloridaBusinessVerifier` | Unified API — registry backends, DBPR, queue dispatch |
| `StateCodes` | Supported states, labels, agent-required flags, catalog for UI |

### Registry backends (strategy pattern)

`FloridaBusinessVerifier::create()` selects the Sunbiz/registry transport:

| Class | When used | Behavior |
|-------|-----------|----------|
| `QueuedSunbizVerifier` | `sunbiz_queue_url` set | Enqueue + poll (production) |
| `RemoteSunbizVerifier` | `sunbiz_remote_url` set | HTTP delegate to another worker host |
| `SunbizVerifier` + per-state classes | neither set | Direct PHP scrape on current machine |

Per-state PHP verifiers in `api/`:

| Path | State |
|------|-------|
| `api/fl/SunbizVerifier.php` | Florida |
| `api/ga/GeorgiaVerifier.php` | Georgia |
| `api/al/AlabamaVerifier.php` | Alabama |
| `api/sc/SouthCarolinaVerifier.php` | South Carolina |
| `api/ms/MississippiVerifier.php` | Mississippi |
| `api/la/LouisianaVerifier.php` | Louisiana |
| `api/nc/NorthCarolinaVerifier.php` | North Carolina |
| `api/ca/CaliforniaVerifier.php` | California |
| `api/tx/TexasVerifier.php` | Texas |
| `api/wv/WestVirginiaVerifier.php` | West Virginia (queue → Windows agent + Edge CDP) |
| `api/tn/TennesseeVerifier.php` | Tennessee |
| `api/ky/KentuckyVerifier.php` | Kentucky (HTTP ASP.NET UpdatePanel) |
| `api/va/VirginiaVerifier.php` | Virginia (queue → Windows agent + Edge CDP) |

`FloridaBusinessVerifier::registryVerifierForState()` routes direct (non-queue) calls to the correct class.

### Queue infrastructure

| Class | Role |
|-------|------|
| `FileVerificationQueue` | File-based job store, leases, reclaim |
| `VerificationJob` | Job DTO (id, type, state, payload, status, timestamps) |
| `AgentRegistry` | Tracks active `agent_id` registrations per state |

### Licenses

| Class | Role |
|-------|------|
| `DbprLicenseVerifier` | Florida DBPR — always PHP on server |

Exposed via `verifyLicenseNumber()` and `verifyBusiness()` (combined registry + optional license). The test UI offers combined check only — no standalone DBPR tab.

### HTTP / diagnostics

| Class | Role |
|-------|------|
| `HttpClient` | cURL wrapper, optional system curl |
| `HtmlParser` | DOM helpers for PHP parsers |
| `HostingDiagnostics` | Server capability report (`api.php?action=diagnose`) |

---

## Web package files (this folder)

| File | Role |
|------|------|
| `autoload.php` | PSR-4 autoload for `lib/` and `api/` — no Composer on server |
| `api.php` | JSON API for `index.html` and integrations |
| `index.html` | Multi-state browser test console |
| `sunbiz_queue_api.php` | Queue REST surface for app + agents |
| `hosting_config.php` | App-level config (created from example) |
| `queue_config.php` | Queue tokens, storage path, lease/TTL settings |
| `DEPLOY.md` | Deployment guide |
| `ARCHITECTURE.md` | This document |

### Test UI (`index.html`) tabs

| Tab | Purpose |
|-----|---------|
| Document / Control # | Per-state ID lookup (labels/examples from state picker) |
| Search by Name | Registry name search |
| Verify by Name | Best match + details |
| Combined Check | Registry + optional Florida DBPR license |
| Queue Status | Pending/processing counts, active agents per state |
| Diagnostics | PHP/hosting/queue health |

State picker loads catalog from `api.php?action=status` when available.

---

## Windows home agent (`sunbiz-agent-cpp/`)

Separate repository folder; required for production queue mode and for Edge-protected states.

### Processes

| Mode | Command | Role |
|------|---------|------|
| Worker service | `businessverifier_agent.exe --service` | Background worker pool + control API |
| Monitor GUI | `businessverifier_agent.exe` | Desktop UI — does not stop workers when closed |
| Console | `businessverifier_agent.exe --console` | Headless debugging |

### Key components

| Component | Role |
|-----------|------|
| `AgentService.cpp` | Service window, control API server, in-memory log ring |
| `Agent.cpp` | Claim → verify → complete/fail loop, multi-state dispatch |
| `QueueClient.cpp` | HTTP client for `sunbiz_queue_api.php` |
| `AgentControlClient.cpp` | GUI ↔ local control API |
| `GuiApp.cpp` | Monitor / Server / Advanced tabs |
| `WorkerDeploy.cpp` | Start/stop/restart worker service from GUI |
| `EdgePoolManager.cpp` | Shared Edge slot pool — acquire, migrate, pre-warm, release |
| `states/*` | Per-state C++ verifiers (FL, GA, AL, SC, MS, LA, NC, CA, TX, WV, TN, KY, VA, …) |
| `config.json` | Queue URL, tokens, `agent_id`, `enabled_states`, `edge_pool`, worker pool, `edge_sessions`, debug |

### Monitor GUI tabs

| Tab | Purpose |
|-----|---------|
| **Monitor** (default) | Activity log, pause, hide — live job watching |
| **Server** | Start/stop/restart workers, status panel, auto-start on launch |
| **Advanced** | Debug mode, last error, Edge process counts, log tail, clear all logs |

**States ▾ menu:** Lists all active registries with checkmarks for `enabled_states`. With 13 states the menu uses **two columns** — **West Virginia (SOS)** and **Virginia (SCC)** appear in the right column. The summary line **Enabled registries** only shows states you have checked on, not every available state.

### Local control API (`127.0.0.1:17821`)

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/api/health` | GET | Reachability |
| `/api/status` | GET | Worker pool, pause state, poll time, enabled states |
| `/api/logs` | GET | Recent log lines |
| `/api/logs/clear` | POST | Clear agent log + in-memory buffer |
| `/api/pause` / `/api/resume` | POST | Pause claiming |
| `/api/stop` | POST | Graceful shutdown |
| `/api/states` | POST | Hot-reload `enabled_states` |
| `/api/workers` | POST | Hot-reload worker pool size |
| `/api/debug` | GET/POST | Debug settings |

### Helper scripts (`Helper_Scripts/`)

Deployed beside the exe on build. PowerShell in `service/`, launchers as `.bat`. See `Helper_Scripts/README.md` for Setup, Start/Stop Workers, Windows Service (NSSM), Apply Update, debug toggles, and auto-reload watcher.

### Edge pool data layout (worker PC)

```
build/Release/data/
├── edge_pool/
│   └── slot_{0..N-1}/     # profile, temp, meta.json, edge.pid, edge.port
├── cookies/               # Exported jars (FL, CA, VA, WV, …)
├── logs/
│   ├── agent.log
│   ├── *_session_record.jsonl   # Job lifecycle + invoke steps (always for MS/NC/SC)
│   ├── ms_setup_trace.jsonl     # MS Edge setup steps
│   ├── nc_setup_trace.jsonl     # NC Edge setup steps
│   └── *_debug/bundle_*/        # Failure snapshots (slot-aware when applicable)
└── temp/                  # Legacy + non-pool temp; invoke error sidecars
```

### Debug and logging

| Location | Contents |
|----------|----------|
| `data/logs/agent.log` | Worker service log, pool pre-warm, acquire/migrate |
| `data/logs/helper.log` | PowerShell helper log |
| `data/logs/*_session_record.jsonl` | Per-state job + invoke trace (MS, NC, SC always persist job events) |
| `data/logs/*_setup_trace.jsonl` | MS/NC Edge setup step trace |
| `data/edge_pool/slot_*/meta.json` | Parked state and slot status for monitor |
| `config.json` → `debug` | Verbose logging, control API logging, queue request logging |

`debug.log_control_api: false` prevents spam when the monitor polls an offline control API.

Session recorders write **job start / success / failure** and timing steps even when `debug_enabled` is false. Enable per-state `debug_enabled` or global `debug.enabled` for HTML artifacts and failure bundles.

---

## Verifier selection logic

```mermaid
flowchart TD
    START[FloridaBusinessVerifier::create]
    Q{sunbiz_queue_url set?}
    R{sunbiz_remote_url set?}
    QS[QueuedSunbizVerifier]
    RS[RemoteSunbizVerifier]
    DS[Direct per-state PHP verifiers]

    START --> Q
    Q -->|yes| QS
    Q -->|no| R
    R -->|yes| RS
    R -->|no| DS
```

**Production x10 setup:** always use `QueuedSunbizVerifier`.

---

## Entity result shape (registry)

Fields vary by state. Common keys after successful `verify_document`:

```json
{
  "found": true,
  "state": "FL",
  "document_number": "M22000004323",
  "entity_name": "DISNEY AD SERVICES CO., LLC",
  "entity_type": "Foreign Limited Liability Company",
  "status": "ACTIVE",
  "is_active": true,
  "principal_address": "...",
  "mailing_address": "...",
  "registered_agent": { "name": "...", "address": "..." },
  "detail_url": "https://...",
  "verified_at": "2026-06-08T12:00:00+00:00",
  "source": "sunbiz"
}
```

PHP and C++ parsers are maintained in parallel; **rebuild the agent** after parser changes in `sunbiz-agent-cpp/`.

---

## Repository layout (full project)

```
untitled/
├── FloridaBusinessVerifier/          ← DEPLOY THIS to web root
│   ├── lib/                          PHP core (queue, StateCodes, HttpClient, …)
│   ├── api/                          Per-state PHP verifiers
│   ├── api.php, index.html
│   ├── sunbiz_queue_api.php
│   ├── storage/verification_queue/
│   ├── DEPLOY.md, ARCHITECTURE.md
│   └── hosting_config.php, queue_config.php
│
├── sunbiz-agent-cpp/                 ← Build on Windows worker PC(s)
│   ├── src/                          Agent, GUI, state verifiers, control API
│   ├── scripts/launchers/            → copied to Helper_Scripts/ on build
│   └── build/Release/
│       ├── businessverifier_agent.exe
│       ├── config/config.json
│       ├── Helper_Scripts/
│       └── data/logs/
│
└── composer.json                     Dev autoload (optional locally)
```

---

## AI assistant quick context

When helping with this project, assume:

1. **This is a multi-state system** — always pass `state` to registry methods; check `StateCodes::agentRequired()` for Edge dependencies.
2. **Queue mode is the supported production path** — at least one worker PC must be running with the target state in `enabled_states`.
3. **`app_token` / `agent_token` must match** across `queue_config.php`, `hosting_config.php`, and every agent `config.json`.
4. **`queue_api_url` and `sunbiz_queue_url` must point to the same PHP file.**
5. **Each worker PC needs a unique `agent_id`.**
6. **DBPR is server-side PHP only** — `verifyLicenseNumber()` / combined check; not queued to the agent.
7. **Parser changes require an agent rebuild** — PHP (`api/`) and C++ (`sunbiz-agent-cpp/src/states/`) are separate implementations.
8. **Control API errors in `helper.log`** (`Could not connect to server` on port 17821) mean **local workers are down**, not a remote queue server failure.
9. **Rebuild after C++ or GUI changes** — close `businessverifier_agent.exe` before building; if link fails you may only see `businessverifier_agent.exe.previous` in Release.
10. **McAfee / unsigned exe** — add Release and `build` folders to exclusions; use `Helper_Scripts\Antivirus Help.bat`.
11. **Test via** `index.html` or `api.php?action=status` before debugging application integration.

### Common tasks

| Task | Where to look |
|------|---------------|
| Add a new state | `StateCodes.php`, `api/{st}/`, `sunbiz-agent-cpp/src/states/`, agent `enabled_states` |
| Change queue timeout | `hosting_config.php` → `sunbiz_queue_timeout` |
| Agent connection errors | `config.json` tokens/URL, `sunbiz_queue_api.php?action=health` |
| Stuck jobs | `FileVerificationQueue`, restart workers (`agent_startup`) |
| HTTP / transport issues (KY, VA) | `HttpClient.cpp` host routing, `data/cookies/`, session debug logs |
| Virginia Edge / reCAPTCHA | `docs/VIRGINIA_SCC_EDGE.md`; no 2captcha in agent |
| GUI States menu / VA missing | `GuiApp.cpp` two-column menu; state must be in catalog + checked in config |
| Edge pool / slot issues | `docs/EDGE_POOL.md`, `data/edge_pool/slot_*/meta.json`, `agent.log` |
| Edge / reCAPTCHA failures | `data/logs/{st}_session_record.jsonl`, `edge_sessions` in config |
| MS/SC verify slower than search | Check for `verify_detail_reused` in session log; rebuild agent if missing |
| GUI worker control | `GuiApp.cpp`, `WorkerDeploy.cpp`, `Helper_Scripts/` |
| Deploy new server version | Upload `FloridaBusinessVerifier/`, preserve `storage/` and configs |
| Deploy new agent version | Build, `Helper_Scripts/Apply Update.bat` on worker PC |

---

## Design constraints

- **Shared hosting friendly** — no Redis, no database, no long-running PHP on server
- **Synchronous app API** — PHP waits for agent result (poll loop in `QueuedSunbizVerifier`)
- **Idempotent job files** — JSON on disk, atomic rename for claim, lease for multi-agent safety
- **Residential / Edge for protected registries** — Windows worker pool with configurable concurrency
- **Multi-agent horizontal scale** — multiple PCs, unique `agent_id`, per-state enable lists
- **Fail visible** — agent logs, queue `failed/`, API JSON errors, GUI Advanced diagnostics
