Skip to content

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 -d against the root docker-compose.yml), there's nothing to do other than git 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:

  1. 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).
  2. Two segmented Docker networksai_forse_oobi (--internal, no NAT, no internet) for control-plane traffic, ai_forse_prod (regular bridge with NAT) for the data plane. Replaces the single ai_forse_bridge from v1.6.x.
  3. 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.
  4. Per-target pause/resume as a primary action with a unified Status badge (Active / Paused / Auto-paused).
  5. Operational autoscaler — slider-driven 1..20 webserver scale alongside the existing 1..300 agent slider; both backed by template snapshot + self-heal.
  6. Three GHCR imagesweb-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.

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_snapshot jsonb + timestamptz
  • New table webservers (peer of agents)
  • 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 diagrams
  • CHANGELOG.md — every change since v1.6.1, with rationale
  • docker-compose.{control,fleet,webserver}.yml — the three Compose files
  • scripts/stack-up.sh — three-stack convenience wrapper