Operations
Tool / Contract Summary
This page documents how the repository is deployed, verified, restarted, and observed. It is the runtime companion to the contract and API documentation.
Business Value
- gives operators a deterministic run path for local, CI, and live-host verification
- keeps runtime evidence aligned with Fabric contract truth
- prevents host or container mutation from happening without an auditable verify path
Current Verified State
- reference live host:
<internal-runtime-redacted> - host verification posture: read-first over SSH before assuming runtime failure
- main stack and platform-plane compose files live in
deploy/compose/ - runtime evidence can be cross-checked through
/api/v1/tools/host-snapshot,/api/v1/tools/runtime-status,/api/v1/tools/runtime-evidence,/api/v1/tools/runtime-contracts, and/api/v1/tools/runtime-observations
Workspace Git/Scan Guardrails (Mandatory)
- Gitea is Source of Truth; local Windows workspaces are disposable working copies.
- Never run Codex sessions from an unscoped workspace root; always use a concrete repo path.
- Limit active repo sessions to 2-3 in parallel.
- Before each run in a repo:
git fetch --prune,git checkout <branch>,git pull --ff-only. - No background git discovery loops (
git status,git ls-files, worktree scans) without explicit scoped need. - Automation scripts must run repo-scoped only, never global over a workspace root.
- CI Actions job logs are lost on rerun: rerunning a job (manual or Gitea's own automatic reassignment of a stuck task) replaces the entire log content of the prior task attempt server-side, under the same job ID, with no warning and no versioning --
GET /repos/{owner}/{repo}/actions/jobs/{id}/logsonly ever returns the latest attempt. Before triggering or allowing a rerun on a job whose failure you may need to root-cause later, download and archive its log first (fabric#1893: an unmocked-live-network test failure during a Gitea outage was only recoverable because the reviewing session had downloaded the job log before the automatic rerun overwrote it).
scan_and_fix Standard
scripts/scan_and_fix.shmust enforce runner timeout + single-run lock + operator credential resolution from environment or secret-managed inputs.scripts/scan_open_issues_repo_only.shmust exist and query only current repo open issues via Gitea API.
Workspace Hygiene
- Daily cleanup: stale
_worktrees/*,_tmp/*,test-results/*, large temporary artifacts. - Weekly cleanup: stale local branches/worktrees.
- Never leave valuable artifacts as untracked files in workspace root.
Dirty-State Policy
- Dirty state is allowed while actively implementing.
- Before new scan/automation runs: commit/stash, or use a dedicated worktree.
- Never propagate
dirty_unknownstates.
Incident Playbook (git.exe storm)
- Identify parent of
git.exe(usually oneCodex.exe). - Stop only the offending process tree.
- Restart session on concrete repo path.
- Reduce parallel sessions.
- Verify
git.execount drops within 30-60s.
Available Now
Runtime paths
- main stack:
deploy/compose/jhf-fabric.stack.yml - low-CPU main stack:
deploy/compose/jhf-fabric.stack.low-cpu.yml - platform plane:
deploy/compose/jhf-fabric.platform-plane.yml - low-CPU platform plane:
deploy/compose/jhf-fabric.platform-plane.low-cpu.yml - ephemeral suite:
deploy/compose/docker-compose.test.yml - low-CPU ephemeral suite:
deploy/compose/docker-compose.test.low-cpu.yml
Operational scripts
scripts/resolve-runtime-env.shscripts/build-runtime-tool-env.shscripts/ensure-fabric-docker-resources.shscripts/redeploy-host-stack.shscripts/redeploy-platform-plane.shscripts/reconcile-platform-api-contract-runtime.shscripts/prepare-platform-plane-assets.shscripts/test-up.shscripts/test-run.shscripts/test-down.shscripts/bootstrap_wikijs_docs.pyscripts/safe_docker_logs.shscripts/post-deploy-guardrails.shscripts/verify-runtime-guardrails.shscripts/verify_runtime_materialization.pyscripts/verify_fabric_control_plane_production_readiness.pyscripts/materialize_stalwart_admission_host172.sh
Platform API contract reconcile
scripts/reconcile-platform-api-contract-runtime.sh [standard|low-cpu] is the bounded Host172 reconcile path for Fabric contract changes served by jhf-fabric-platform-api. It requires exact origin/main, no tracked changes, and no unclassified untracked files; existing runtime/evidence/ artifacts are the sole allowed untracked class. It rebuilds and recreates only the api service with --no-deps, then proves the live planning-contract surface publishes the required rubric-v2 and migration references. Use scripts/redeploy-platform-plane.sh only when an intentionally broader platform-plane change requires its other services to be recreated.
Wiki.js and platform-plane assets
deploy/compose/platform-plane/wiki/HELPIFYR_WIKI_HOME.mddeploy/compose/platform-plane/wiki/favicon.svgdeploy/compose/platform-plane/wiki/jadda_helpifyr_logo.svgdeploy/compose/platform-plane/wiki/helpifyr-wiki-theme.cssdocs/operations/WIKIJS_PLATFORM_PLANE.md
Optional / Extended
- low-CPU deployment variants
- platform-plane services such as Wiki.js, Prometheus, Grafana, and OpenTelemetry Collector
- optional consumers such as internal docs portals and downstream runtime dashboards
Planned / Not In Current Scope
- any host mutation path that is not represented by a real script or guarded preview surface
- undocumented write flows against providers or downstream tools
Public Surfaces
Operator runtime and evidence routes:
GET /healthGET /api/v1/platform/servicesGET /api/v1/tools/host-snapshotGET /api/v1/tools/runtime-statusGET /api/v1/tools/runtime-evidenceGET /api/v1/tools/runtime-contractsGET /api/v1/tools/runtime-observationsGET /api/v1/production-readiness/fabric/control-planeGET /api/v1/production-readiness/universal-work-security-opsGET /api/v1/observability/readinessGET /api/v1/security/readinessGET /api/v1/recovery/readinessGET /api/v1/signoff/readiness
Contract Families
Operations interact directly with:
- runtime port contracts
- provider instance registry
- drift reports
- docs and wiki governance contracts
- shared topology and shared service baseline contracts
Producer / Consumer Zuordnung
- producer: Fabric publishes runtime observations and contract-shaped operational evidence
- consumer: operators, CI, Wiki.js, and downstream repos
- boundary rule: host observations are consumed into Fabric, but they do not override contract truth
Compatibility Window
- live-host posture is Linux and POSIX/bash first
- compose and redeploy scripts are the canonical operational interface
- direct ad-hoc mutation is not considered a compatible operator path
Lifecycle Status
- active deployment and verification posture
- host and platform-plane scripts are maintained alongside the API and contract layers
Readiness / Drift / Monitoring
Recommended health and readiness order:
GET /healthGET /api/v1/platform/servicesGET /api/v1/observability/readinessGET /api/v1/security/readinessGET /api/v1/recovery/readinessGET /api/v1/signoff/readiness- subsystem-specific readiness for persistence, Dapr, events, tooling, identity, or providers as needed
Monitoring stack:
- Prometheus for metrics collection
- Grafana for dashboards
- OpenTelemetry Collector for telemetry export
/api/v1/monitoring/metricsfor tool and policy metrics
Deployment / Verify
Validate compose
bash ./scripts/resolve-runtime-env.sh /tmp/jhf-fabric-resolved.envdocker compose --env-file /tmp/jhf-fabric-resolved.env -f deploy/compose/jhf-fabric.stack.yml configdocker compose -f deploy/compose/jhf-fabric.platform-plane.yml configdocker compose --env-file deploy/compose/platform-plane/wiki/.env -f deploy/compose/jhf-fabric.platform-plane.yml configdocker compose -f deploy/compose/docker-compose.test.yml config
Deploy or redeploy
bash ./scripts/redeploy-host-stack.shbash ./scripts/redeploy-platform-plane.shbash ./scripts/prepare-platform-plane-assets.shbash ./scripts/ensure-fabric-docker-resources.shbash ./scripts/verify-runtime-guardrails.shpython ./scripts/verify_runtime_materialization.py --checkpython ./scripts/verify_runtime_materialization.py --check --live-via-ssh <internal-runtime-redacted><internal-runtime-redacted>python ./scripts/verify_fabric_control_plane_production_readiness.py --checkpython ./scripts/verify_fabric_control_plane_production_readiness.py --check --live-via-ssh <internal-runtime-redacted><internal-runtime-redacted> --output runtime/evidence/issue967.fabric_control_plane_live.latest.json
Signed Stalwart admission post-merge materialization
scripts/materialize_stalwart_admission_host172.sh is the only repo-owned Host172 materializer for the signed Fabric Stalwart admission surface. It is preview-only by default and does not open SSH or mutate the host unless --apply is explicit. This tool is not a Heddle, AdGuard, Caddy, or Stalwart materializer and never manages those services.
Before an operator uses --apply, the merged target must be the exact 40-character origin/main commit and the operator must supply a host configuration reference, not secret values:
bash scripts/materialize_stalwart_admission_host172.sh \
--target-commit <merged-origin-main-sha> \
--config-ref /home/administrator/.config/helpifyr/runtime-secrets/jhf-fabric-auth.env
The apply path fetches origin, rejects any target that is not fetched origin/main, snapshots git/container/compose evidence under /home/administrator/.local/state/jhf-fabric-materialization/, and archives tracked patches plus untracked work. It writes and verifies snapshot-manifest.sha256 over the recovery artifacts before any checkout or compose action; a missing or changed artifact is a hard stop. It refuses a tracked-dirty checkout rather than resetting, cleaning, stashing, or deleting it. A clean checkout is fast-forwarded to the exact target only after the snapshot. Preflight checks only the canonical auth-overlay contract in /home/administrator/.config/helpifyr/runtime-secrets/jhf-fabric-auth.env: FABRIC_STALWART_ADMISSION_PRIVATE_KEY_FILE must be a readable absolute file reference, while FABRIC_HEDDLE_STALWART_MANAGEMENT_READ_TOKEN must be a direct non-file value. The materializer never prints either secret and fails closed on duplicate, missing, empty, or ambiguous entries. See docs/contracts/HELPIFYR_STALWART_HOST172_AUTH_OVERLAY.md.
After compose configuration succeeds, only Fabric api and daprd are recreated with --no-deps. Verification requires /health and the public JWKS endpoint to return 200, while unauthenticated admission and revocation reads must return 401. An authenticated admission readback is optional and requires --authorized-check plus explicit exact scope values; it is permitted only through the supplied token-reference file and must return 200.
Rollback and break-glass
- Normal rollback: stop immediately on any non-zero result. The snapshot path is printed only after success or dirty-state refusal and contains the pre-change commit, patches, untracked archive when present, Fabric container inspect readback, and
snapshot-manifest.sha256. Verify the manifest before using recovery artifacts. Compose configuration is validated quietly and never written out because rendered configuration can expose environment values. Restore or reconcile only through a separately reviewed, exact-commit operator procedure; this materializer intentionally has no automatic rollback or destructive restore mode. - Dirty checkout break-glass: do not use
git reset,git clean, or this script to force through it. Preserve the emitted snapshot, have the checkout owner classify the work, then rerun only after the owner has made the checkout clean through an approved recovery path. - Secret/config break-glass: do not place values on the command line or in issue comments. Repair the secret-managed env-file reference and readable signing-key file, then rerun preflight. A missing/ambiguous reference is a hard stop.
- Runtime break-glass: if Fabric health or endpoint status checks fail after the scoped recreate, stop. Do not restart Heddle, AdGuard, Caddy, or Stalwart. Use the snapshot and bounded Fabric-only diagnostics to hand off to the Fabric runtime owner.
Local API start
uvicorn helpifyr_fabric.api.app:app --reload
Ephemeral verification
bash ./scripts/test-up.shbash ./scripts/test-run.shbash ./scripts/test-down.sh
Docs bootstrap
python scripts/bootstrap_wikijs_docs.py --wiki-url http://<internal-runtime-redacted>:33001 --site-host https://docs.helpifyr.com/- add
--dry-runto preview output without writing pages python scripts/docs/materialize_public_docs_site.pypython scripts/docs/export_public_docs_bundle.pynpm run build --prefix docs-sitenpm run deploy:cloudflare --prefix docs-site
Wiki.js bootstrap remains internal/operator-only. The live canonical public docs entrypoint is https://docs.helpifyr.com/; https://docs.helpifyr.com/ remains only the admitted alias or handoff surface.
The tracked bundle contracts/docs/public_docs_site_bundle.json remains the canonical Fabric-generated handoff artifact and must not reintroduce jhf-web or https://docs.helpifyr.com/ as the current public publisher truth.
Scan&Fix automation
Quickstart:
bash scripts/scan_and_fix.sh --dry-runbash scripts/scan_and_fix.shbash scripts/scan_and_fix.sh --issue 344 --dry-runbash scripts/scan_and_fix.sh --max-issues 1bash scripts/scan_and_fix.sh --executor-cmd 'python -c "import sys; print(sys.stdin.read())"' --issue 344
Dry-run:
- prints the reconciled open issue set in ranked order
- classifies the queue into
really-open-repo-owned,already-covered-by-pr,blocked_external, andnon_actionable_open - excludes open pull requests from the executable issue queue even when the backing Gitea issues API returns them in the same feed
- falls back to the visible repo-scoped Gitea
/pullspage plus per-PR detail reads when the open-pulls list API returns an empty set but open PRs still exist - prints the generated execution prompt with repo, issue, branch, worktree, and live-verify host/user context
- does not invoke the runner
- when no
--issueor--max-issuesis provided, the dry-run shows the full currently open ranked queue plus the actionable executable subset
Live-run:
- prefer
--executor-cmdwhen you want an explicit runner path, for example a local Codex wrapper - if
--executor-cmdis omitted, the script falls back toSCAN_AND_FIX_RUNNER_CMD, then to the first verified local Codex CLI candidate it can execute, including a verified per-user installation before any inaccessible WindowsApps alias - the auto-discovered local Codex fallback uses the local danger-full-access execution mode by default because nested Windows
--full-autoruns can fail before repo work starts with sandbox spawn errors; use--executor-cmdwhen you need a different runner posture explicitly - example:
bash scripts/scan_and_fix.sh --executor-cmd 'python -c "import sys; print(sys.stdin.read())"' --issue 344
- default behavior:
bash scripts/scan_and_fix.shprocesses the full currently open ranked issue set, then dispatches only thereally-open-repo-ownedsubsetbash scripts/scan_and_fix.sh --max-issues 1limits the run to the highest-ranked issue- open pull requests are skipped so the queue stays issue-driven instead of PR-driven, and issues already covered by an open PR, explicitly marked
blocked_external, or already declaredplanned_only/planned_program_work/future_featureare reported but not dispatched by default - shared-host CI executes only the
scanfix_fastpathpytest subset by default; the heavierscanfix_extendedharness/fallback coverage is reserved for explicit local verification orworkflow_dispatchso the shared runner lane stays low-pressure
Supported parameters:
--issue <id>--dry-run--max-issues <n>--since <duration>--labels <csv>--severity-order "critical,high,medium,low"--host <host>--user <user>--executor-cmd <cmd>
Typical failure modes:
- missing required API credentials in the operator environment or secret-managed inputs
- no matching open issue after filters are applied
--executor-cmdomitted,SCAN_AND_FIX_RUNNER_CMDunset, and no usable local Codex CLI candidate available- runner command returns non-zero
- long all-open runs started without a confirming dry-run after issue churn, causing an unintended queue shape
- operator expects mutation on
main; the wrapper only prepares issue-driven branch/PR work
Known Limits
- direct host/port verification remains canonical when a service has not yet published its own hostname contract
- platform-plane components are optional and may not be present on every installation
- runtime observations can be delayed or degraded when provider dependencies are unavailable
Exceptions / Waivers
- legacy
*.<internal-runtime-redacted>hostnames are redirect surfaces only and must not be treated as primary Fabric-owned truth - some runtime probes are intentionally lightweight and policy-limited to avoid pressure on host services
Logs
For live-host log inspection, use the bounded snapshot policy in operations/HOST_DOCKER_LOG_GUARDRAILS.md (docs/operations/HOST_DOCKER_LOG_GUARDRAILS.md).
Main stack
timeout 15s docker compose -f deploy/compose/jhf-fabric.stack.yml logs --since 10m --tail 80 apitimeout 15s docker compose -f deploy/compose/jhf-fabric.stack.yml logs --since 10m --tail 80 daprdtimeout 15s docker compose -f deploy/compose/jhf-fabric.stack.yml logs --since 10m --tail 80 postgrestimeout 15s docker compose -f deploy/compose/jhf-fabric.stack.yml logs --since 10m --tail 80 natsbash ./scripts/post-deploy-guardrails.sh jhf-fabric
Platform plane
timeout 15s docker compose -f deploy/compose/jhf-fabric.platform-plane.yml logs --since 10m --tail 80 apitimeout 15s docker compose -f deploy/compose/jhf-fabric.platform-plane.yml logs --since 10m --tail 80 prometheustimeout 15s docker compose -f deploy/compose/jhf-fabric.platform-plane.yml logs --since 10m --tail 80 grafanatimeout 15s docker compose --env-file deploy/compose/platform-plane/wiki/.env -f deploy/compose/jhf-fabric.platform-plane.yml logs --since 10m --tail 80 wikijstimeout 15s docker compose -f deploy/compose/jhf-fabric.platform-plane.yml logs --since 10m --tail 80 otel-collectorbash ./scripts/post-deploy-guardrails.sh jhf-fabric
CPU-Safe Runtime Guardrails
- Standard verify and redeploy paths must stay bounded and low-pressure.
- Use
bash ./scripts/verify-runtime-guardrails.shbefore release-oriented changes to confirm repo-owned stack truth, bounded diagnostics, and low-pressure defaults. - Use
python ./scripts/verify_runtime_materialization.py --check --live-via-ssh <internal-runtime-redacted><internal-runtime-redacted>when runtime/config changes are involved to prove repo truth, active compose labels, container env/mounts/networks, and app readback stayed aligned. - Post-deploy cleanup is mandatory through
bash ./scripts/post-deploy-guardrails.sh jhf-fabric; the script fails closed if stale repo-owneddocker logs,docker compose ... logs, ordocker execdiagnostics remain beyond the configured minimum age.
Typical Failure Modes
- Dapr sidecar unavailable
- PostgreSQL bootstrap or migration incomplete
- NATS or event publication readiness drift
- stale repository manifests or tool profiles
- Grafana active-dashboard provisioning drift
- provider runtime evidence delay or DNS/network mismatch on the host
Diagnosis Order
- validate compose config
- inspect
docker compose ... ps - inspect bounded Fabric API log snapshots
- inspect bounded dependency service log snapshots
- run readiness endpoints in the order above
- use subsystem runbooks before mutating state
Restart And Recovery
- restart only the affected Fabric-owned service when possible
- prefer additive rebuild or restart over manual state edits
- use STACK_RECOVERY_RUNBOOK (
docs/operations/STACK_RECOVERY_RUNBOOK.md) before direct persistence mutation - use recovery and signoff readiness surfaces to confirm post-restart state
Runtime Dependencies
- PostgreSQL
- NATS JetStream
- Dapr sidecar
- Gitea for repository contract intake
- optional platform-plane observability services
- optional internal docs consumer through Wiki.js
Related Issues
- operational history and remaining backlog items live under
docs/issues/anddocs/AUTONOMOUS_BACKLOG.md
License
- License: AGPLv3
- Project: https://helpifyr.com