Adopter Release & Upgrade Contract¶
Fgentic is consumed by pointing Flux at this repository. Without a release contract that means tracking main with no tested boundary. This document defines the distribution semantics an operator needs: a tag is a tested pin-set, described by a machine-readable Bill of Materials, shipped with upgrade notes, and tracked through a Flux GitRepository that follows tags rather than a moving branch.
What a release is¶
A release is a git tag (vMAJOR.MINOR.PATCH) that marks a specific, reviewed revision of infra/ and apps/ as a coherent pin-set. Three artifacts define it:
- The tag — the immutable git revision an adopter reconciles.
- The BOM (
release/bom.yaml) — every pinned chart source, HelmRelease chart version, and digest-pinned container image reconciled by the reference release profile at that revision. - The upgrade note (
docs/upgrades/<version>.md) — the config/values migrations, SOPS/secret changes, and manual steps to move to that version. Empty-but-present is acceptable when a release needs no manual action.
The tag is the unit an adopter pins; the BOM makes the pin-set auditable for supply-chain and air-gap review; the upgrade note makes the move between two tags followable.
The Bill of Materials¶
release/bom.yaml is generated by scripts/gen-bom.sh and verified by mise run check:bom (scripts/check-bom.sh); do not edit it by hand. It is deterministic — every list is sorted and no generation timestamp is embedded — so the verify gate can regenerate it and diff.
Scope¶
The BOM enumerates the reference release profile: the reconciled clusters/local + clusters/gcp Flux DAG under infra/ plus the apps/matrix-a2a-bridge/deploy unit, with the tracked default platform-settings (llm_provider=vertex; the admin, synthetic-canary, alert-delivery, knowledge-ingestion, and embeddings profiles disabled; no external mautrix bridge composed). It records:
chartSources— pinnedOCIRepository/GitRepositorychart artifacts (OCI tag or digest, immutable git commit).helmReleases— each HelmRelease with its chart, resolved version, and source.helmRepositories— the chart hosts (a classic Helm repo carries no in-file version pin; the version lives on the HelmRelease).images— every container image, keyed by itssha256:digest (the globally-unique, registry-independent supply-chain identifier). When the repository can be reconstructed from the HelmRelease manifests,refis a complete, mirrorable[registry/]repository:tag@sha256:…reference andresolved: true; when the repository is a chart default absent from the repo,refkeeps the baretag@sha256:token,resolved: false, and anote:records that ahelm templaterender is needed to qualify it (see air-gap install).taggedImages— every image pinned by an explicitimage:tag override in a reconciled HelmRelease's values (for example the OpenTelemetry, Jaeger, and Keycloak images), captured as registry/repository/tag plus the sibling digest when present, and the sameresolved:/note:markers asimages. These would otherwise be invisible to an air-gap adopter mirroring strictly from the BOM; the verify gate re-derives and enforces them fail-closed exactly like the digest images.
What the BOM deliberately excludes¶
Optional and disabled-by-default surfaces are not silently dropped — every excluded path is in the committed allowlist in scripts/lib/bom-scope.sh with a one-line reason. The excluded classes are: test fixtures (*_test.go, integration Dockerfiles, app test scripts), disposable labs (clusters/demo/*, infra/federation/*), disabled-by-default profiles (admin, canary, alert-delivery, knowledge, embeddings, external bridges, self-hosted models), the opt-in matrix-group-sync and activitypub-agent-gateway units, and governance metadata such as the MCP catalog and surface pin. A deployment that enables one of those profiles must extend the BOM scope before it can claim the same pin-set guarantee.
Completeness is enforced, fail-closed¶
check:bom re-derives the pin census from the repository and fails when:
- The committed BOM differs from
gen-bom.sh's current output (drift from reality). - Any in-scope image digest is missing from the BOM.
- Any pin-bearing file is neither in-scope nor covered by the exclusion allowlist — so a new chart or image added later that nobody classified fails the gate.
This is the point of the artifact: an incomplete BOM that silently under-covers would give false air-gap and supply-chain confidence. Regenerate and re-verify after any pin change:
Recommended Flux flow: track tags, never main¶
Adopters reconcile a tag, not main. main receives fast-forward digest-pin commits from CD and unreleased work; tracking it means reconciling untested pin-sets. Point the Flux GitRepository at a tag (or a semver range) so an upgrade is a reviewed, deliberate bump:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: fgentic
namespace: flux-system
spec:
interval: 30m
url: https://github.com/fmind-ai/fgentic.git
ref:
tag: v0.2.0 # pin the tested pin-set; bump deliberately after reading the upgrade note
# Or a bounded range to auto-adopt patches within a minor line:
# semver: ">=0.2.0 <0.3.0"
Upgrading is then: read docs/upgrades/<next>.md, apply any listed migrations, update the ref.tag, and let Flux reconcile. See the Day-2 Operations Handbook for the reconciliation and rollback procedure.
Support statement¶
The tested upgrade paths and the single-maintainer reality are stated honestly in the Public Surface Stability Contract. Do not assume an untested tag-to-tag jump is supported.
Contract status¶
v0.1.1 is the first release shipped under this contract. Its tag includes the generated BOM, and its v0.1.1 upgrade note records every operator action found by the live v0.1.0 → v0.1.1 local-cluster drill. The drill preserved the PostgreSQL PVC while advancing the exact Flux source revision, Gateway API bundle, Helm releases, Matrix stack, and bridge.
The repository gates prove the pin-set and documentation remain internally consistent. A release is not runtime-qualified until its N-1 → N drill has also completed; record any discovered compatibility action in that release's upgrade note before calling the path supported.