﻿# Changelog

This file is the explicit mutation log for `SpaceHorizonLibrary`.

## 2026-04-22

- Converted compose ownership to framework-owned by setting `compose_owner=framework` across platforms (Ollama, Frappe, ATC, Flux.1[schnell], GitLab, MeshCentral, Nextcloud, OpenProject).
- Added contract-driven framework compose rendering inputs:
  - Ollama: `contracts/framework_compose_contract.json` plus static compose templates under `contracts/compose/` (stack-mode variants + GPU overlays).
  - Frappe: `contracts/framework_compose_contract.json` using `base_candidates` (first-existing upstream `src/frappe_docker/*` compose file) plus a deterministic LGF overlay template under `contracts/compose/`.
  - ATC: `contracts/framework_compose_contract.json` plus a build-from-source compose template (web build context under `src/lgf-atc/web` + mariadb).
  - Flux.1[schnell]: `contracts/framework_compose_contract.json` plus a base compose template and a GPU overlay template.
  - GitLab: `contracts/framework_compose_contract.json` plus base/SSH overlay templates (SSH port enabled only when configured).
  - MeshCentral / Nextcloud / OpenProject: `contracts/framework_compose_contract.json` plus static compose templates matching the prior platform render output.
- OpenProject now persists the required proxy `Caddyfile` into bench state during env render so framework-owned compose can bind-mount it deterministically.
- OpenProject proxy now bind-mounts only `${PROXY_DATA_ROOT}/Caddyfile` (not the entire `/etc/caddy` dir), and bootstrap ensures the file exists before `docker compose up` so the proxy cannot restart-loop due to a missing config.
- Frappe bootstrap DB gate (1.5/4) now avoids `bash -lc`, passes the root password via `env MYSQL_PWD=...`, forces a short TCP connect to `127.0.0.1`, adds a timeout wrapper around the probe, and logs periodic progress to prevent "hang" confusion on slow first boots.
- Frappe bootstrap DB gate (1.5/4) now normalizes quoted env values from rendered `.env`, falls back to `-h localhost` (socket-style) after TCP, and emits an occasional one-line client hint to make failures diagnosable.
- Frappe env rendering now persists the DB root password under `state/db_root_password` so rerenders cannot silently rotate the root password while the persistent `db-data` docker volume remains.
- Frappe bootstrap now fails fast on `Access denied` when a bench-scoped `db-data` volume exists, with explicit remediation steps (remove the volume for test benches or reinstall with the matching `--db-pass`).
- Frappe bootstrap now attempts a one-time, first-boot-only automatic MariaDB root recovery on `ERROR 1045` by using a temporary `--skip-grant-tables` recovery container to reset the volume’s root password and ensure `root@'%'` exists with full privileges, so failed partial installs can self-heal without deleting `db-data`.
- Added a contract-driven Frappe DB manager manifest (`platform/frappe/contracts/db_manager_manifest.json`) and wired bootstrap to enforce it before `create-site` runs, using the framework-owned DB manager engine. This centralizes stateful MariaDB glue (password/host grants/recovery) behind a contract instead of spreading it across bootstrap gates.
- Frappe bootstrap now brings up dependency services first (db/redis/configurator), performs DB root recovery + host grant enforcement, and only then starts the `create-site` one-shot job. This prevents `create-site` from failing early before DB grants can be repaired on stale volumes.
- Downgraded expected bootstrap self-heal behavior (DB root recovery + first-boot asset rebuild) from WARN-level logs to explicit INFO "step:" logs so normal operations don’t read like failures.
- Frappe bootstrap gate 2/4 (create-site) now retries once on `MySQLdb.OperationalError (2013)` / "Lost connection" failures after restarting DB, and emits DB OOM/restart/log context on failure to reduce blind debugging.
- Frappe compose override generator now also forces `queue-short`, `configurator`, and `create-site` to use `CFG_ERP_IMAGE_TAG` (so a v16 bench cannot accidentally pull v15 ERP images for those services).
- Frappe compose override generator now also forces an idempotent `create-site` command so partial/previous site directories don’t brick bootstrap with “Site frontend already exists” failures.
- Frappe now sets `MYSQL_ROOT_HOST=%` and `MARIADB_ROOT_HOST=%` on the `db` service (via the contract compose overlay and the platform compose generator) so the `create-site` container can connect as root over the bench docker network (avoids `Access denied for user 'root'@'172.18.x.x'` during first boot).
- Updated git-mirror `sources_manifest.json` contracts to use `ref=origin/HEAD` instead of assuming `main`, preventing ref-resolution failures when mirrors use `master` (or other defaults).

## 2026-04-21

- Added the GitLab platform library (`platform/gitlab`) with contract-driven install options and a bootstrap readiness probe that treats the UI as ready even when `/-/health` returns 404 in some configurations.
- Implemented `Seed Internal LGF Repo` for GitLab by creating the `platform-mirrors` group and seeding `lgf-atc` and `lgf-libraries` into that group.
- Reworked GitLab seeding to create empty projects first and then mirror-push (`git clone --mirror` + `git push --mirror`) from the internal mirrors into the new GitLab projects instead of relying on GitLab `import_url` behavior.
- Removed the separate “seed MSP key” input to avoid duplicate MSP key switches; GitLab seeding now uses the primary MSP key path (`--MSP-key` / stored MSP key) for internal mirror auth.
- Refactored `platform/flux-schnell` to be deterministic and bench-local: pin the ComfyUI Flux image by digest, persist only `state/flux/models` and `state/flux/output` (do not bind-mount `/app`), and align bootstrap/env/compose so ComfyUI no longer gets stuck in a `git pull` loop on a non-git directory after partial installs.

## 2026-04-11

- Added install-time `default_admin_username` metadata for applicable platforms: Nextcloud, OpenProject, and Frappe.
- Corrected MeshCentral metadata to remove default-admin username guidance and record first-login account creation instructions instead.
- Added placeholder `contracts/status_manifest.json` files for Frappe, MeshCentral, Nextcloud, and OpenProject declaring status as framework-owned generic Docker Compose state.
- Removed legacy platform-owned `platform_status.sh` scripts now that status execution is framework-owned under JSON manifest.
- Added `contracts/support_manifest.json` files for Frappe, MeshCentral, Nextcloud, and OpenProject declaring framework-owned support bundle generation with optional platform enrichment.
- Preserved Frappe support enrichment under contract and removed legacy unused support bundle scripts for MeshCentral, Nextcloud, and OpenProject.
- Added `contracts/systemd_manifest.json` files for Frappe, MeshCentral, Nextcloud, and OpenProject declaring framework-owned systemd integration.
- Removed legacy platform-owned `platform_systemd.sh` scripts, platform apply dependencies, and library-owned nuke cleanup snippets now that systemd unit generation and cleanup are framework-owned.

## 2026-04-12

- Removed platform install_switches.sh scripts now that framework-install consumes contracts/install_contract.json directly for parsing, validation, logging, and help output.
- install_contract.json now declares cfg_var for each option/flag so framework install parsing/validation is contract-driven without platform-specific switch glue.
- Frappe install_contract.json: moved ERP assets version to Advanced options and defaulted it to v16.
- Frappe ui_data.json: moved ERP Assets Version to Advanced options and defaulted it to v16 in the Operator Console New Bench form.
- Updated platform_apply.sh for Frappe, MeshCentral, Nextcloud, and OpenProject to stop sourcing platform_install_dependencies.sh now that dependency installation is framework-owned and contract-extended via install_dependencies_manifest.json.
- Added per-platform contracts/install_dependencies_manifest.json files so framework-owned install_dependencies can install platform-specific extra dnf packages (e.g. nextcloud nfs-utils/cifs-utils).
- Removed legacy platform-owned platform_install_dependencies.sh scripts now that host dependency installation is framework-owned and fully driven by contracts/install_dependencies_manifest.json.
- Removed legacy `platform_validate_install_config` hook declarations from per-platform `contracts/library_manifest.json` files now that install config validation is framework-owned via install_contract.json parsing/validation.
- MeshCentral now sets `TLSOffload: true` in rendered `state/meshcentral-data/config.json` when `--reverse-proxy` is specified, so reverse-proxy benches correctly treat TLS as terminated upstream.
- Added per-platform `contracts/ingress_manifest.json` files declaring which rendered env port keys must be reverse-proxy restricted (default `LISTEN_PORT`), enabling framework-owned multi-port reverse-proxy ingress enforcement without library-owned firewall logic.
- MeshCentral reverse-proxy ingress policy now protects both `LISTEN_PORT` and `MPS_PORT`, making MeshCentral RP-only ingress for all published ports when `--reverse-proxy` is specified.
- Added per-platform `contracts/proxy_manifest.json` files (MeshCentral, OpenProject, Nextcloud, Frappe) so the Operator Console can generate reverse proxy configurations from contracts and platform metadata without hardcoding per-platform behavior in the UI.
- MeshCentral platform metadata now records the resolved `mps_port` (and listen_port) from persisted state/rendered env when not explicitly provided, so the Operator Console reverse proxy generator can auto-fill the Upstream MPS port.
- MeshCentral bootstrap now logs `docker compose up` failure output to make stack bring-up failures actionable (port binds, image pull errors, etc.) instead of emitting only a generic error.
- MeshCentral bootstrap now detects the Docker "content digest ... not found" failure mode and performs a one-time bounded self-heal (remove + re-pull the MeshCentral image, then retry compose up once).
- MeshCentral self-heal no longer pulls from registry: it strictly reloads the local tarball after verifying the tarball SHA256 against `digests.md`, preserving mandatory digest matching.
- MeshCentral acquire_sources now enforces tarball SHA256 digest matching (artifact SHA256 in `digests.md`) and probes the loaded image with `docker create` to catch broken Docker content-store state early. RepoDigest enforcement remains optional until MeshCentral digests lock includes an image digest reference.
- Frappe verify-operational HTTP probe now respects LISTEN_PROTO (http|https) and uses TLS-insecure curl probing (-k) only when https is configured; removed hardcoded http://127.0.0.1:LISTEN_PORT probes that could fail on HTTPS benches.
- Frappe helpdesk route contract check now probes the internal bench network path (`http://frontend:8080`) from inside the bench, matching the established assets live probe and preventing false failures when host-mapped LISTEN_PORT/LISTEN_PROTO differ from internal transport.
- Added `contracts/compose_manifest.json` for Frappe, MeshCentral, Nextcloud, and OpenProject declaring compose rendering as platform-owned with an explicit framework escape hatch (compose-from-JSON framework rendering reserved for a later pass).
- Converted `contracts/verify_manifest.json` for Frappe, MeshCentral, Nextcloud, and OpenProject to declare framework-owned verify with per-platform contract-driven variation, and removed platform-owned `platform_verify.sh` scripts.

## 2026-04-10

- Activated the project-local LGF AI interaction contract in engineering mode for this workspace session.
- Added this changelog to record future explicit mutations in the platform library repository.
- Converted `platform/meshcentral` repair to the framework-owned repair contract model while preserving existing bounded repair behavior.
- Added `platform/meshcentral/contracts/repair_manifest.json` and refactored `platform/meshcentral/platform_repair.sh` into explicit repair phase functions.
- Updated `platform/meshcentral/platform_verify_operational.sh` to use bounded MeshCentral HTTP readiness logic instead of a one-shot HTTPS probe, matching the established bootstrap probe behavior.
- Extended `platform/meshcentral` repair to reconstruct rendered truth from `state/platform.json`, rebuild override/hash-lock state, restore `config.json` via bootstrap helpers, and reconcile runtime topology against rendered compose truth.
- Converted `platform/nextcloud` repair to the framework-owned repair contract model with `platform/nextcloud/contracts/repair_manifest.json`.
- Refactored `platform/nextcloud/platform_repair.sh` to rebuild rendered truth from `state/platform.json` plus explicit persisted state, reconcile runtime topology, and preserve Nextcloud-specific storage repair behavior.
- Updated `platform/nextcloud/platform_verify_operational.sh` to use bounded Nextcloud HTTP readiness logic and capture HTTP failure context via existing bootstrap helpers.
- Corrected `platform/nextcloud/platform_repair.sh` so structural validation no longer refuses on pre-repair compose invalidity; compose validation remains enforced after authoritative rerender where repair can actually restore rendered truth.
- Exported bootstrap runtime context from `platform/nextcloud/platform_repair.sh` so existing Nextcloud bootstrap helpers can be reused during repair without unbound-variable failures.
- Converted `platform/frappe` repair to the framework-owned repair contract model with `platform/frappe/contracts/repair_manifest.json`.
- Refactored `platform/frappe/platform_repair.sh` to rebuild rendered env/compose/override truth from explicit persisted state, preserve Frappe drift/source correction behavior, and refresh bench integrity lock artifacts through framework repair helpers.
- Updated `platform/frappe/platform_verify_operational.sh` to use bounded frontend readiness probing while preserving the existing Frappe HTTP and asset acceptance criteria.
- Corrected `platform/frappe/platform_repair.sh` so dependency-recovery rerender only occurs when that phase actually reacquires sources, rather than carrying earlier reacquisition state forward implicitly.
- Corrected `platform/frappe/platform_repair.sh` to export `BENCH_ROOT` and `STATE_DIR` before calling `platform_set_image_contract()`, preventing unbound-variable failure during repair rerender.
- Updated `platform/frappe` repair so convergence now reuses `platform_restore_converge_bench()`, bringing app materialization, migrate/doctype handling, asset reconstruction, cache clearing, and helpdesk contract enforcement into repair instead of relying on plain runtime recreate.
- Corrected Frappe source-acquisition helper path references so restore/repair convergence loads `platform_acquire_sources.sh` instead of the stale non-existent `acquire_sources.sh` path.
- Corrected Frappe required-app resolution so restore/repair convergence always includes the platform-required custom apps `hrms`, `telephony`, and `helpdesk`, even when a damaged runtime under-reports them.
- Added custom-app frontend dependency hydration to Frappe restore/repair convergence before `bench build`, matching the existing bootstrap sequence required for successful asset rebuilds.
- Updated `platform/frappe/platform.sh` so Frappe platform metadata now persists `url`, `listen_proto`, `listen_port`, and `reverse_proxy`, aligning its connection metadata with the other platform libraries.
- Removed active sourcing of library-owned reverse-proxy enforcement helpers from Frappe, OpenProject, and MeshCentral entry/bootstrap paths so reverse-proxy ingress restriction can be owned uniformly by the framework instead of the platform libraries.
