263 lines
14 KiB
Markdown
263 lines
14 KiB
Markdown
# Changelog
|
|
|
|
Operator- and user-facing changes. Internal refactoring, test additions and documentation-only
|
|
commits are not listed unless they change what an operator sees or does.
|
|
|
|
## Unreleased
|
|
|
|
### Security
|
|
|
|
- Runtime Worker packaging now upgrades the digest-pinned Ubuntu base before installation and pins
|
|
the inference stack plus inherited Python security dependencies to reviewed fixed versions. The
|
|
public-candidate gate scans the resulting fourth image instead of treating the private worker as
|
|
an unexamined exception.
|
|
- The Runtime Worker removes unneeded kernel-development headers after installation, eliminating
|
|
their upstream-unfixed vulnerability surface without removing required runtime libraries.
|
|
- Public candidate scans distinguish fixable or newly observed HIGH/CRITICAL findings from an
|
|
exact reviewed upstream-unfixed baseline. A changed CVE, package, installed version, severity or
|
|
newly available fix fails closed.
|
|
- Node enrollment and publisher credentials now require their exact fixed scopes at both service
|
|
and database boundaries. Schema `20260830_0023` validates every existing row before adding the
|
|
constraints and refuses the upgrade when malformed legacy scope data exists.
|
|
- Request-body streaming now has finite ASGI event/progress budgets in addition to byte limits;
|
|
progressless frame floods receive the typed `request_body_progress_exhausted` response.
|
|
- PostgreSQL role provisioning now removes the database's default public temporary-table grant;
|
|
production startup continues to attest that the runtime role cannot create or use it.
|
|
|
|
### Fixed
|
|
|
|
- Fresh schema `20260830_0024` installs no longer let Psycopg misread PostgreSQL `%rowtype` and
|
|
`%I` syntax as client placeholders.
|
|
- Public-candidate acceptance now works across the Gitea sibling Docker daemon while retaining
|
|
isolated volumes, private workers, exact HTTP contract probes and deterministic cleanup.
|
|
|
|
## v1.2.1 — 2026-08-30
|
|
|
|
A packaging and provenance patch. No feature, API, schema or runtime-behaviour change; schema stays
|
|
`20260828_0022` and no migration runs. It exists because v1.2.0's production acceptance found two
|
|
defects that every existing gate was blind to — both in the artifacts rather than the source.
|
|
|
|
### Fixed
|
|
|
|
- **The published console could not reach its own API.** Vite inlines `VITE_API_BASE_URL` at build
|
|
time, but the release build never passed it, so every release image since v1.1.0 compiled the
|
|
Dockerfile's development default `http://localhost:8000` into an immutable bundle — and the nginx
|
|
CSP, derived from the same argument, hardcoded the same wrong origin. A release build now requires
|
|
an explicit `--public-api-origin` (or `MODELFORGE_PUBLIC_API_ORIGIN`) and refuses to package
|
|
without one.
|
|
- **The Node Agent's identity could drift from its tag.** `docker-compose.node-agent.yml` declared a
|
|
build with no arguments, so a Compose-built agent carried version `0.0.0` and empty
|
|
revision/created labels while still being tagged from `MODELFORGE_VERSION`. Production ran an
|
|
image tagged `1.1.1` whose contents were `1.2.0`. The projection now passes the release identity,
|
|
as the API and console projections already did.
|
|
|
|
### Added
|
|
|
|
- `scripts/release_image_acceptance.py`: a gate that inspects the **built** console image — its
|
|
compiled bundle, its rendered CSP and its OCI labels — rather than the source that produced it.
|
|
The release build runs it before packaging and refuses to publish an image that cannot reach the
|
|
API it was built for. Verified against the exact image that broke production.
|
|
- Regression coverage for both defects: the release build fails closed without an origin, the origin
|
|
reaches the console build, the CSP names the same origin and is never widened to a wildcard, every
|
|
release image declares complete OCI labels, and every Compose projection that builds a published
|
|
image passes the release identity.
|
|
|
|
### Operations
|
|
|
|
- The release manifest now records the console's compiled-in API origin, so an operator can see it
|
|
without unpacking the image.
|
|
- Local development is unchanged: `docker compose up` still defaults to `http://localhost:8000`.
|
|
Fail-closed applies to the release path only.
|
|
|
|
## v1.2.0 — 2026-08-29
|
|
|
|
The Premium Operator Console release. No API contract, domain model, runtime behavior or database
|
|
schema changed; schema stays `20260828_0022` and no migration runs.
|
|
|
|
### Added
|
|
|
|
- A production command center built only from backend-authoritative evidence, stating unknowns as
|
|
unknown rather than as zero.
|
|
- Quick jump (Ctrl+K): a modal command palette over all 13 workspaces, matching name, domain and
|
|
keywords.
|
|
- An evidence timeline of recent control-plane activity, each entry linking to the workspace where
|
|
it can be verified.
|
|
- A split-pane Registry detail view covering upstream facts, local governance, revisions, artifacts
|
|
and provenance.
|
|
- One console-wide guarded destructive-action dialog showing identity, dependency posture and
|
|
permanent impact before an explicit acknowledgement unlocks the confirm control.
|
|
|
|
### Changed
|
|
|
|
- Workspaces are grouped by operator mental model (Command, Model supply, Serving, Infrastructure,
|
|
Assurance, Projects) while every existing route hash is preserved.
|
|
- One refined design token layer for light and dark, with semantic status roles that always include
|
|
text and explicit focus rings.
|
|
- Every route is usable from 1440 px down to a 390 px mobile viewport through a modal navigation
|
|
drawer, with no horizontal overflow at any tested width.
|
|
|
|
### Fixed
|
|
|
|
- The ARIA tabs pattern is complete across all six tabbed workspaces: every tab carries a stable
|
|
`id` and `aria-controls`, and every panel is a real `role="tabpanel"` naming its tab back.
|
|
- Lifecycle, Migrations and Recovery tablists gained roving `tabindex`, an accessible tablist name
|
|
and Left/Right/Home/End keyboard movement, which they previously lacked entirely.
|
|
- Capability residency unload no longer uses a native `window.confirm`; it uses the console safety
|
|
dialog and shows the VRAM released and the cold-load cost the next request will pay.
|
|
- Operator token fields in Operations, Recovery, Lifecycle and Migrations now sit in a real form
|
|
with a stable `id`, a `name` and an explicit `<label for>`.
|
|
|
|
### Accessibility
|
|
|
|
- Skip link to a programmatically focusable main landmark.
|
|
- Quick jump and the mobile drawer contain focus, dismiss on Escape and restore focus to the control
|
|
that opened them.
|
|
- Status is never encoded by colour alone.
|
|
- `prefers-reduced-motion` collapses animation and transition durations; `forced-colors: active`
|
|
re-expresses focus and active navigation in system colours.
|
|
- Essential mobile controls and navigation rows meet a 44 px target.
|
|
|
|
### UX
|
|
|
|
- Warnings state the observed condition and name the workspace where an operator can resolve it.
|
|
- Destructive registry and residency actions present impact before they present a confirm control.
|
|
- Surfaces use compact rows, quiet borders and a restrained status palette rather than decorative
|
|
effect.
|
|
|
|
### Security / Operations
|
|
|
|
- The operator credential stays request-scoped: no `localStorage`, no `sessionStorage`, no cookie,
|
|
no URL. Every token form prevents its own default submission so nothing is serialized into a query
|
|
string.
|
|
- `autocomplete="off"` is retained deliberately on operator-token fields rather than moving to
|
|
`current-password`, which would invite a password manager to persist and sync a high-privilege
|
|
control-plane credential.
|
|
- The Node Agent's functional behavior is unchanged from the NVIDIA-certified v1.1.1
|
|
implementation; it is rebuilt only because `VERSION` is the single source of truth for packaged
|
|
manifests. No re-enrollment is required.
|
|
|
|
### Known limitations
|
|
|
|
- The console has no committed visual-regression baseline; visual acceptance is a human-reviewed
|
|
browser pass.
|
|
- Point-in-time database recovery remains `NOT_SUPPORTED`.
|
|
|
|
## v1.1.1 — 2026-08-29
|
|
|
|
### Fixed
|
|
|
|
- Replaced the Node Agent's Alpine/musl runtime with a digest-pinned Debian/glibc runtime so the
|
|
NVIDIA Container Toolkit can inject and load GPU Node's glibc-linked NVML driver library.
|
|
- NVIDIA-configured agents now validate real NVML inventory and matching telemetry before
|
|
enrollment or publication. Missing NVML, an empty device list, or missing GPU telemetry exits
|
|
with a typed diagnostic instead of publishing an apparently healthy zero-GPU node.
|
|
|
|
### Security / Operations
|
|
|
|
- The Node Agent remains UID 100/GID 101, read-only, capability-free and
|
|
`no-new-privileges`; its multi-stage image contains no compiler or package installer.
|
|
- CPU-only nodes remain supported through the explicit `cpu` accelerator mode. Canonical GPU
|
|
Compose projections set `nvidia` and fail closed.
|
|
|
|
### Known limitations
|
|
|
|
- External workloads can legitimately trigger `EXTERNAL_GPU_PRESSURE`; ModelForge observes but
|
|
does not terminate those workloads.
|
|
|
|
## v1.1.0 — 2026-08-28
|
|
|
|
### Added
|
|
|
|
- Operator-only compute-node decommission preview and execute APIs, with exhaustive fail-closed
|
|
blockers, generation/digest concurrency checks, idempotent exactly-once audit and retained
|
|
provenance.
|
|
- A Console danger-zone flow that explains blockers, cleanup and preserved history before requiring
|
|
a reason, operator and exact typed node identity.
|
|
- A terminal node invariant and runbook. Decommissioned identities cannot ordinarily re-enroll,
|
|
rotate credentials, publish agent state, refresh inventory or return to scheduler placement.
|
|
|
|
### Changed
|
|
|
|
- The runtime schema target is `20260828_0022`. Schema `20260827_0021` remains a supported
|
|
upgrade source, not a runtime-compatible schema; rollback requires the verified pre-upgrade
|
|
backup because downgrade migrations are intentionally unsupported.
|
|
- The Console now uses shared design tokens, persistent light/dark themes, grouped responsive
|
|
navigation, page-specific headers and keyboard-visible focus.
|
|
|
|
### Fixed
|
|
|
|
- API clients preserve typed error envelopes and correlation IDs, and accept successful empty HTTP
|
|
responses without attempting to decode JSON.
|
|
- Failure and recovery states retain meaningful visual styling in both themes.
|
|
- The Node Agent Compose projection accepts an exact release image tag or digest while retaining an
|
|
explicitly local source-build workflow; it never falls back to `latest`.
|
|
|
|
### Security / Operations
|
|
|
|
- Decommission revokes active node credentials, prevents old identities from resurrecting, removes
|
|
disposable current state and preserves historical provenance and an exactly-once audit event.
|
|
- Release tooling binds versioned images, CycloneDX SBOM, provenance and checksums to an exact source
|
|
commit without mutating floating `latest` tags.
|
|
- Published image bases are digest-pinned and security-updated; Python runtime images remove pip and
|
|
setuptools after dependency verification, and all three components retain dedicated non-root
|
|
runtime users.
|
|
|
|
### Known limitations
|
|
|
|
- Point-in-time recovery remains `NOT_SUPPORTED`; verified snapshot restore is the recovery model.
|
|
- SQLite remains an isolated unit-test backend and is not supported for production.
|
|
- One historical M13/M15 LAB cutover remains explicitly unreconciled because external Qdrant truth
|
|
is unavailable; it has no production deployment, gateway or scheduler dependency.
|
|
|
|
## v1.0.0 — 2026-08-27
|
|
|
|
The first stable release. See
|
|
[docs/RELEASE_NOTES_v1.0.0.md](docs/RELEASE_NOTES_v1.0.0.md) for the full description.
|
|
|
|
### Added
|
|
|
|
- One authoritative product version, `1.0.0`, with every packaged manifest checked against it.
|
|
- `GET /api/v1/version` — build identity and compatibility, unauthenticated.
|
|
- Declared compatibility ranges for the database schema and the agent protocol, answered as
|
|
`COMPATIBLE`, `TOO_OLD`, `TOO_NEW` or `UNKNOWN` — never a silent pass.
|
|
- Fail-closed startup validation in production: missing or weak operator key, development database
|
|
password, remote code execution, missing backup encryption key, wildcard CORS origin, invalid URL,
|
|
unwritable storage root, incompatible schema or PostgreSQL major, and impossible policy
|
|
combinations.
|
|
- A production deployment overlay that refuses to render without its secrets.
|
|
- `scripts/preflight.py`, `scripts/bootstrap.py`, `scripts/upgrade.py` and
|
|
`scripts/release_build.py`.
|
|
- A Content-Security-Policy on the operator console.
|
|
- OCI image labels and build identity arguments on all three images.
|
|
- Configurable host ports for every published service.
|
|
- Operator documentation: installation, first run, upgrade, configuration, compatibility, node
|
|
agent, Unraid deployment, capabilities, project integration, operations and troubleshooting.
|
|
|
|
### Changed
|
|
|
|
- `GET /api/v1/system` reports `release_channel` instead of `milestone`.
|
|
- The console no longer displays development milestone labels.
|
|
- `.env.example` and the configuration reference are generated from the typed settings.
|
|
- The Runtime Worker's inference stack moved to an optional `inference` extra, so lint, typecheck
|
|
and its tests no longer require the full PyTorch stack.
|
|
|
|
### Fixed
|
|
|
|
- **A clean clone could not start.** A `models/` ignore rule intended for model weights also matched
|
|
`config/models/`, so the candidate registry manifest was never in the repository.
|
|
- **Migrations ran against the wrong database.** The Alembic environment discarded an explicitly
|
|
supplied URL and used the configured one, so an upgrade rehearsal aimed at an isolated copy would
|
|
have migrated the deployment's own database.
|
|
- **The disaster-recovery projection published its PostgreSQL to the LAN**, reachable as a superuser
|
|
with development credentials.
|
|
- **The readiness probe re-read every manifest on every call** — 77 file reads and 528 ms per probe.
|
|
- **The Node Agent pinned an old control-plane version**, making its image unbuildable at release.
|
|
- **The console rendered a "not implemented" panel over the delivered Recovery workspace**, because
|
|
the placeholder list had drifted from the navigation.
|
|
- **Managed validation reported success without running any test suite.**
|
|
|
|
### Known limitations
|
|
|
|
Point-in-time recovery is `NOT_SUPPORTED`. Upgrades require downtime. Model Lab and Benchmarks have
|
|
no console workspace. See the release notes for the full list.
|