Skip to content

v3.2.0 — Architecture Release

Latest

Choose a tag to compare

@botAGI botAGI released this 20 May 14:50

[3.2.0] — 2026-05-18

Architecture release: state store + service registry + golden tests + Go scaffolding.

Closes the v3.2.0 milestone (58 REQ-IDs across 7 phases, 35/35 plans complete).
v3.2.0 is infrastructure code only — zero new container images, zero new
daemons, zero new product features. Net diff ~+3500 / −500 LOC. Driven by
AGmind-Autofix-Architecture-Spec-v1.0.2 §9.2 (deferred from v3.1.2 hotfix).

The release lands four substrates that future milestones (v3.3+, v4.0 Go port)
build on: versioned state store at /var/lib/agmind/state/, declarative service
registry at templates/services/registry.yaml with build-time codegen, byte-exact
golden tests under tests/golden/, and namespace-reserving Go scaffolding placeholders.

Three High findings deferred from v3.1.2 close in this milestone: HEALTH-02B
(resolver consolidation), ENV-PARSE-01 (legacy grep|cut env parser migration),
DUPLICATION-01 (lib/X.shscripts/X.sh reconcile).

Target platform is unchanged: DGX Spark (GB10, aarch64), LAN profile only.

Added — Architecture

State store substrate (Phases 11 + 14):

  • STATE-01/var/lib/agmind/state/ directory created on install with 0700 root:root perms.
  • STATE-02lib/state.sh API: state_get / state_set / state_get_secret / state_set_secret with flock per-file locking.
  • STATE-03 — Schema versioning via ${STATE_DIR}/schema_version text file (integer, monotonic).
  • STATE-04 — Migration framework: lib/migrations.sh runner + discrete lib/migrations/NNN-<name>.sh scripts.
  • STATE-05 — First migration 001-initial.sh copies legacy *.preserved files into versioned state.
  • STATE-06agmind upgrade --check reports current schema, pending migrations, and config diff vs versions.env.
  • STATE-07agmind upgrade --apply runs pending migrations atomically (flock + temp-then-rename + tar-backup).
  • STATE-08agmind upgrade --rollback <schema_version> restores from the auto-backup tarball.
  • STATE-09 — ADR-0011 documents state store architecture decisions.
  • STATE-10 — Integration test test_upgrade_v3_1_2_to_v3_2_0.sh against a real v3.1.2 baseline.
  • STATE-11 — Consumer migration: lib/config.sh, compose renderers, CLI commands now read secrets via state_get_secret (not direct .env parsing). Closes BACKUP-01.

Service registry (Phase 12):

  • REG-01templates/services/registry.yaml is the single source of truth for the service catalog.
  • REG-02lib/registry.sh dual-backend API (yq + python3+PyYAML fallback for airgapped hosts).
  • REG-03 — Build-time codegen lib/_registry.indexed.sh (fast bash assoc-arrays, generated artifact).
  • REG-04lib/service-map.sh::SERVICE_GROUPS derives from registry, not hand-curated.
  • REG-05lib/service-map.sh::ALL_COMPOSE_PROFILES derives from registry.
  • REG-06lib/service-map.sh::NAMED_PROFILE_EXPANSION derives from registry.
  • REG-07tests/compose/test_registry_compose_parity.sh enforces 1:1 registry ↔ compose match.
  • REG-08tests/compose/test_no_hardcoded_service_lists.sh forbids new hand-edited lists.
  • REG-09 — ADR-0012 documents the registry schema + codegen pipeline + drift-prevention strategy.

Golden tests + lint + mock infra (Phase 13):

  • TEST-01tests/golden/ directory structure: inputs/, expected/, scenarios.list.
  • TEST-02 — 5 baseline scenarios: minimal_lan, full_lan, rag_milvus, ragflow, cluster_peer.
  • TEST-03 — Per-scenario byte-exact diff: .env, compose, nginx.conf, monitoring configs.
  • TEST-04generate_random_named deterministic mode under AGMIND_TEST_SEED (name-based, not counter-based).
  • TEST-05tests/lint/LANDMINES.md codifies project "learned the hard way" invariants as machine-readable patterns.
  • TEST-06tests/unit/test_golden_no_known_landmines.sh enforces LANDMINES against rendered configs.
  • TEST-07make golden-update documented; commit-msg golden-accept-reason: <text> trailer required.
  • TEST-08tests/mocks/README.md documents PATH-override mock pattern + 28-mock inventory.
  • TEST-09 — Pre-commit hooks added: golden-update guard + ASCII-only-bash (manual stage).
  • TEST-10 — CI lane golden-tests matrix (5 scenarios parallel) runs on every push.

Go migration scaffolding — zero Go code (Phase 15):

  • GO-01cmd/agmind/.gitkeep reserves the binary namespace.
  • GO-02internal/.gitkeep reserves the internal-packages namespace.
  • GO-03docs/ROADMAP-GO.md documents Stage 0.5/0.7 (already shipped) plus Stage 1-6 plan.
  • GO-04 — ADR-0010 captures Go migration intent + equivalence-proof requirements + arm64-only enforcement.
  • GO-05 — ADR-0013 captures the single Go binary cmd/agmind/ decision with internal/ packages (Q-07).
  • GO-06 — README mentions Go scaffolding + "no Go code in v3.2.0" disclaimer (EN + RU).

Added — CLI surface

  • agmind upgrade --check — read-only schema + pending-migrations report (STATE-06).
  • agmind upgrade --apply — atomic migration with auto-backup tarball (STATE-07).
  • agmind upgrade --rollback <schema_version> — restore from auto-backup (STATE-08).

Changed — Refactors

HEALTH-02B resolver consolidation (Phase 14):

  • RESOLVER-01lib/health.sh::resolve_active_services replaces get_service_list plus ad-hoc compose detection.
  • RESOLVER-02 — Resolver reads from the service registry (REG-02 path); no compose round-trip in the hot path.
  • RESOLVER-03 — Existing 65+ health tests pass against the new resolver via a thin backward-compat alias.
  • RESOLVER-04tests/unit/test_resolve_active_services.sh adds 14 test cases / 43 assertions.

ENV-PARSE-01 migration (Phase 14, 73 callsites across 7 files):

  • ENV-03b — Canary migration: 3 callsites in lib/health.sh::_resolve_active_services_uncached (VECTOR_STORE/LLM_PROVIDER/EMBED_PROVIDER).
  • ENV-03c — Bulk sweep: 41 (boolean/enum) + 3 (numeric) + 29 (secrets) callsites = 73 total across lib/{health,compose,authelia,openwebui,config,restore}.sh + install.sh + scripts/agmind.sh.

Dormant helpers shipped in Phase 10 — activated by ENV-03b / ENV-03c migration above:

  • ENV-01lib/common.sh::_env_get (source-based reader for boolean/enum toggles where bash expansion is desired).
  • ENV-02lib/common.sh::_env_get_raw (awk byte-exact reader for secrets and literal values).
  • ENV-03 — Lint gate tests/lint/test_no_legacy_env_parse.sh forbids new grep ^X= | cut -d= patterns.
  • ENV-04tests/unit/test_env_get.sh covers all edge cases (#-in-value, escaped quotes, missing trailing newline, multiline heredocs).
  • ENV-05docs/env-parsing.md documents the migration recipe + when to use _env_get vs _env_get_raw.

DUPLICATION-01 closure (Phase 14):

  • DUP-01scripts/health.sh + scripts/detect.sh are verified symlinks to ../lib/X.sh.
  • DUP-02docs/lib-scripts-pairs.md inventory documents 4 pairs across 3 types (symlink × 2, justified-divergence × 2).
  • DUP-03install.sh::_copy_runtime_files uses cp -P (preserves symlinks; previously converted them to regular files).
  • DUP-04tests/compose/test_lib_scripts_parity.sh CI gate enforces per-row contract (symlink target / byte-identity / justified-divergence).
  • DUP-05 — Gate fails on any byte-divergence or symlink-target move.

Breaking Changes

1. State store at /var/lib/agmind/state/

What changed: Fresh installs initialize a versioned state directory under
/var/lib/agmind/state/ with schema_version=1. Upgrades from v3.1.x trigger
the agmind upgrade --check flow that detects the missing directory and
migrates legacy .preserved files (n8n_encryption_key, surrealdb_password,
portainer_agent_secret) plus ${INSTALL_DIR}/docker/.env secrets into the
versioned namespace via migration 001-initial.sh.

Why: Closes BACKUP-01 — the v3.1.x regression where re-running install.sh
on an existing host regenerated secrets (DB password, JWT keys, etc.) without
preserving the existing Postgres volume's hashes, breaking auth on next boot.

Rollback: Restore the auto-backup tarball:

sudo tar -xzf /var/lib/agmind/state/state.bak.<timestamp>/state.tar.gz -C /
git checkout v3.1.2
sudo bash install.sh

The migration is non-destructive of the legacy .preserved files and legacy
${INSTALL_DIR}/docker/.env — both remain in place after the migration for one
full release cycle.

2. ENV-PARSE-01 semantics

What changed: All legacy grep ^X=... | cut -d= patterns in lib/*.sh
and install.sh are now migrated to _env_get (source-based, for default
cases) or _env_get_raw (awk byte-exact, for secrets and literal cases). The
migration spans 73 callsites across 7 source files (lib/{health,compose,authelia,openwebui,config,restore}.sh,
install.sh, scripts/agmind.sh) plus the new lint gate tests/lint/test_no_legacy_env_parse.sh
forbids new occurrences.

Why: The old grep|cut pattern matched KEY=value literally but silently
truncated values containing # outside quotes, escaped quotes, multiline
heredocs, and missing-trailing-newline edge cases. _env_get_raw (awk-based,
no shell interpretation) preserves byte-exact secret values; _env_get
(source-based) is appropriate for boolean/enum toggles where bash expansion
is desired.

Rollback: git revert <ENV-MIGRATION-COMMITS> (Phase 14 plans 14-03 through
14-06). Behavior is byte-identical for valid .env files; only error reporting
and edge-case handling differ. Golden tests (TEST-01..03) confirm byte-identical
rendered .env pre/post migration.

3. Service registry codegen artifact

What changed: lib/_registry.indexed.sh is now a generated file
regenerate via make registry-codegen whenever templates/services/registry.yaml
changes. The CI registry-verify gate fails on drift between registry.yaml
and the generated _registry.indexed.sh.

Why: Phase 12 promotes service definitions from 5 hand-edited bash
assoc-arrays in lib/service-map.sh to a single YAML source of truth. Hand-editing
_registry.indexed.sh directly is forbidden (file header declares
# DO NOT HAND-EDIT — generated from templates/services/registry.yaml). The
codegen step locks down the single source of truth and prevents
PROFILES-ALL-01-class regressions.

Rollback: git checkout v3.1.2 -- lib/service-map.sh (restore hand-edited
arrays) + remove templates/services/registry.yaml + revert
install.sh::_copy_runtime_files whitelist additions. Not recommended
v3.1.2 hand-maintained service lists are the regression Phase 12 closed.
Stay on v3.2.0 and edit registry.yaml instead.

Internal — Tooling

Documentation + release-cut substrate (Phase 16, this phase):

  • DOCS-01 — This CHANGELOG v3.2.0 entry: all 58 REQ-IDs enumerated with one-line descriptions, three Breaking Changes (state store / ENV parser / registry codegen) with What/Why/Rollback, footer REQ category → Phase mapping.
  • DOCS-02docs/adr/INDEX.md updated with ADR-0010..0013 rows; sentinel-marker bootstrap.
  • DOCS-03scripts/generate-adr-index.py + make adr-index / make adr-index-check auto-regenerate the INDEX table between sentinel markers; pre-commit hook + CI job enforce drift gate.
  • DOCS-04README.md / README.ru.md updated with v3.2.0 architecture overview, Go scaffolding disclaimer, link to docs/ROADMAP-GO.md.
  • DOCS-05release-manifest.json published (v3.2.0 version, REQ-ID list, commit SHA, release-date single source of truth).
  • DOCS-06 — Version bumps across install.sh / lib/common.sh::AGMIND_VERSION / templates/versions.env / README badges, all derived from release-manifest.json (D-18 single-source-of-truth rule).

Build + CI surface:

  • make adr-index / make adr-index-check — auto-regenerate docs/adr/INDEX.md
    table between sentinel markers (DOCS-03, this phase).
  • make golden-test / make golden-update / make golden-update-all /
    make landmines-check / make landmines-sync — golden-test surface (Phase 13).
  • make registry-codegen / make registry-verify — registry codegen + drift gate (Phase 12).
  • Pre-commit hooks: 16 total — 14 inherited (shellcheck, yamllint, gitleaks,
    markdownlint, standard hygiene) + 2 added in Phase 13 (golden-update-guard
    commit-msg hook, ascii-only-bash manual-stage hook) + 1 added in Phase 16
    (adr-index local hook).
  • CI workflow .github/workflows/test.yml jobs: syntax, shellcheck,
    unit-tests (amd64), unit-tests-arm64, image-tags, manifest-consistency,
    adr-index-check (new), trivy, golden-tests (matrix × 5),
    golden-accept-reason-check.