Migrating from v1.x to v2.0.0¶
Scope status (post-Scope-Freeze 2026-05-10) — See ARCHITECTURE.md for the canonical 37 MÓDULOs + 7 Test Kinds + DOM/CPOS/PIE-PA safety architecture. ADRs 0014, 0019-0025 cover post-Freeze additions.
TL;DR — If you're on the all-in-one flow (
docker compose up -dagainst the rootdocker-compose.yml), there's nothing to do other thangit pull && docker compose up -d --build. If you're on the split topology introduced in v1.6.x, you need to rewire the Docker networks once. Everything below is for the split users.
What changed in v2.0.0¶
This is a major architectural release. The headline changes that motivate the 2.x version bump:
- Three-stack split topology — the previous control + fleet split (v1.6.x) is now joined by a third Compose project,
ai_forse_webserver, hosting up to 20 Caddy 2.8 webservers serving HTTP/2 (TCP) + HTTP/3 (QUIC over UDP). - Two segmented Docker networks —
ai_forse_oobi(--internal, no NAT, no internet) for control-plane traffic,ai_forse_prod(regular bridge with NAT) for the data plane. Replaces the singleai_forse_bridgefrom v1.6.x. - Dashboard cockpit — KPI strip with traffic-light tones, global time-range picker, percentile latency, site × time heatmap, top-N rankings, payload/object size stats, per-target composition with Quantidade/Bytes toggle.
- Per-target pause/resume as a primary action with a unified Status badge (Active / Paused / Auto-paused).
- Operational autoscaler — slider-driven 1..20 webserver scale alongside the existing 1..300 agent slider; both backed by template snapshot + self-heal.
- Three GHCR images —
web-agent-{agent,dashboard,webserver}all signed with Cosign keyless OIDC, SBOM-attested, multi-arch (amd64 + arm64).
Who needs to migrate¶
| You ran v1.x like this | Migration required? |
|---|---|
docker compose up -d (root docker-compose.yml, all-in-one) |
No. Just git pull && docker compose up -d --build. |
Split: docker-compose.control.yml + docker-compose.fleet.yml (v1.6.x) |
Yes — Docker networks need a one-time rewire. See below. |
| Kubernetes (k8s/) | No — the K8s manifests already used the same segmented network model via NetworkPolicy. |
Migration recipe (split topology only)¶
The legacy ai_forse_bridge is replaced with two networks: ai_forse_oobi (internal-only) and ai_forse_prod (NAT). Postgres and dashboard now attach only to OOBI; agents and webservers attach to both with explicit Compose priority so the data plane is the default route.
Option A — Use the helper script (recommended)¶
cd ~/AI_forSE
git pull origin main
# 1) Tear down the v1.x stacks (preserves the postgres volume)
scripts/stack-up.sh down
# 2) Drop the legacy v1.6.x network
# Safe to do iff no other containers on this host depend on
# ai_forse_bridge — the helper warns if it sees the legacy one.
docker network rm ai_forse_bridge 2>/dev/null || true
# 3) Bring everything back up — the helper creates ai_forse_oobi
# (--internal) and ai_forse_prod automatically and starts all
# three projects (control + fleet + webserver) in the right order.
scripts/stack-up.sh up
The helper now also accepts scale-webserver N (1..20) so you can scale the new pool from the CLI:
scripts/stack-up.sh scale-webserver 5
Option B — By hand¶
cd ~/AI_forSE
git pull origin main
# 1) Stop the v1.x stacks (preserves volumes)
docker compose -p ai_forse_fleet -f docker-compose.fleet.yml down --remove-orphans
docker compose -p ai_forse_control -f docker-compose.control.yml down --remove-orphans
# 2) Drop the legacy network
docker network rm ai_forse_bridge 2>/dev/null || true
# 3) Create the two segmented networks
docker network create --driver bridge --internal ai_forse_oobi
docker network create --driver bridge ai_forse_prod
# 4) Bring everything back up (control first so the dashboard has
# a chance to apply migration 0011 before the fleet/webserver
# register themselves)
docker compose -p ai_forse_control -f docker-compose.control.yml up -d
docker compose -p ai_forse_fleet -f docker-compose.fleet.yml up -d
docker compose -p ai_forse_webserver -f docker-compose.webserver.yml up -d
Option C — Add the webserver stack only (skip the network rewire)¶
Not recommended (you keep the old single-bridge security posture), but supported for the impatient:
git pull origin main
docker compose -p ai_forse_webserver -f docker-compose.webserver.yml \
up -d --no-deps webserver
The webserver containers will attach to the EXISTING ai_forse_oobi and ai_forse_prod if they exist; otherwise they fail with a clear "network not found" message and you fall back to Option A.
Database migration (automatic, idempotent)¶
Migration 0011_webserver_fleet.sql adds:
cluster_config.desired_webserver_count(default 1, CHECK 1..20)cluster_config.webserver_template_snapshotjsonb + timestamptz- New table
webservers(peer ofagents) - New table
webserver_metrics(time-series scrape buffer)
It runs automatically when the dashboard container starts up via instrumentation.ts. Safe to re-run (uses IF NOT EXISTS everywhere).
Sanity checks after migration¶
# 1) Three stacks present
scripts/stack-up.sh ps
# 2) Two networks present, OOBI is --internal
docker network inspect ai_forse_oobi | jq '.[0].Internal' # → true
docker network inspect ai_forse_prod | jq '.[0].Internal' # → false (or absent)
# 3) Postgres + dashboard literally cannot reach the internet
docker compose -p ai_forse_control exec dashboard sh -c \
'wget -qO- --timeout=5 https://example.com 2>&1 | head -3'
# expected: timeout / no route to host
# 4) Agent CAN reach internet (default route via PROD)
docker compose -p ai_forse_fleet exec agent sh -c \
'wget -qO- --timeout=5 https://example.com 2>&1 | head -1'
# expected: <!doctype html>
# 5) Webserver fleet endpoints reachable
docker run --rm --network ai_forse_oobi curlimages/curl:latest \
curl -sIk https://ai_forse_webserver-webserver-1/healthz | head -1
# expected: HTTP/2 200
# 6) New /webservers UI tab loads
open http://localhost:3000/webservers
Rollback¶
If something breaks and you need to roll back to v1.6.1 quickly:
git checkout v1.6.1
docker compose -p ai_forse_webserver -f docker-compose.webserver.yml down -v
docker network rm ai_forse_oobi ai_forse_prod 2>/dev/null || true
docker network create ai_forse_bridge
scripts/stack-up.sh up
The new cluster_config.desired_webserver_count and the webservers / webserver_metrics tables stay in the DB — they're harmless when v1.x dashboard runs (it ignores them). When you upgrade back to v2.x they're picked up where they left off.
See also¶
docs/SPLIT_STACKS.md— full split-topology guide with diagramsCHANGELOG.md— every change since v1.6.1, with rationaledocker-compose.{control,fleet,webserver}.yml— the three Compose filesscripts/stack-up.sh— three-stack convenience wrapper