feat(auto-update): add guarded remediation worker #134

Merged
nimmo merged 3 commits from issue-130-guarded-remediation-worker into main 2026-08-01 09:32:44 +01:00
Owner

Refs #130 (kept open pending genuine normal-rollout and no-op evidence)

Outcome

Implements the isolated OpenCode/Qwen remediation worker and deterministic Forgejo controller for structured rejected-update incidents from #129, using the single qwen3.6:35b-a3b-q8_0 policy selected by #128.

  • Reconstructs the exact validated base plus retained rejected candidate lock in a disposable detached worktree.
  • Runs one bounded advisory attempt in Bubblewrap with a clean environment, private home, hidden .git, no credentials, no shell/web/MCP/plugins, a read-only candidate tree, and only two writable proposal outputs.
  • Treats incident evidence as untrusted and prompt-injection-capable; raw model events and logs are deleted.
  • Restricts remediation to high-confidence single leaf applications or isolated services; core, kernel, driver, toolchain, language-set, schema/evaluation, infrastructure, ambiguous, and unsafe patch cases become diagnosis-only.
  • Requires exact structured output and controller-owned baseline/reproduction/patched host builds, flake checks, closure comparison, and package source/revision proof.
  • Publishes only fingerprint-deduplicated issues and issue-linked PRs from deterministic code. The model cannot receive Forgejo authority, change main, merge, deploy, or publish flake.lock.
  • Applies time, token, disk, output, patch, build, retry, and cleanup bounds. Interrupted and orphaned runner worktrees are pruned from persistent state.
  • Accepts publication on the exact base or its one proven producer-created lock-only successor, so remediation PRs inherit the accepted partial lock without changing or reverting it.

Regression coverage

Hermetic integration uses temporary Git/Forgejo state and fake OpenCode, Bubblewrap, Nix, and Tea; it creates no real incident issue or PR. It covers:

  • eligible leaf remediation to a validated issue-linked PR;
  • core and module-schema diagnosis-only outcomes;
  • patched build failure and non-reproduced candidate refusal;
  • blocked security-policy patch refusal;
  • simulated model write outside its output mount;
  • one-attempt fingerprint state, terminal-state scan filtering, lock-only main advancement, credential-free model environment, and stale/orphan cleanup.

Validation

  • ./tests/nixos-update-remediation-regressions.sh — passed
  • ./tests/auto-update-regressions.sh — passed
  • ./tests/nova-remediation-benchmark.sh — passed
  • ShellCheck at warning severity — passed
  • actionlint with repository exclusions — passed
  • forgejo-runner validate --directory . — passed for both workflows
  • Ruff lint and format check — passed
  • nix fmt — 124 files checked, no changes required
  • nix flake check — passed; evaluated electra, lena, vega, lyra, and cosmos and built the formatting check
  • git diff --check — passed

Rollout note

No manual updater run or deployment was performed. This does not interfere with #129 passive rollout observation. After merge, the new Nova workflow should be observed on a normal even-hour run; any required genuine deployment/no-op evidence will be recorded before the issue is finally closed.

Refs #130 (kept open pending genuine normal-rollout and no-op evidence) ## Outcome Implements the isolated OpenCode/Qwen remediation worker and deterministic Forgejo controller for structured rejected-update incidents from #129, using the single `qwen3.6:35b-a3b-q8_0` policy selected by #128. - Reconstructs the exact validated base plus retained rejected candidate lock in a disposable detached worktree. - Runs one bounded advisory attempt in Bubblewrap with a clean environment, private home, hidden `.git`, no credentials, no shell/web/MCP/plugins, a read-only candidate tree, and only two writable proposal outputs. - Treats incident evidence as untrusted and prompt-injection-capable; raw model events and logs are deleted. - Restricts remediation to high-confidence single leaf applications or isolated services; core, kernel, driver, toolchain, language-set, schema/evaluation, infrastructure, ambiguous, and unsafe patch cases become diagnosis-only. - Requires exact structured output and controller-owned baseline/reproduction/patched host builds, flake checks, closure comparison, and package source/revision proof. - Publishes only fingerprint-deduplicated issues and issue-linked PRs from deterministic code. The model cannot receive Forgejo authority, change `main`, merge, deploy, or publish `flake.lock`. - Applies time, token, disk, output, patch, build, retry, and cleanup bounds. Interrupted and orphaned runner worktrees are pruned from persistent state. - Accepts publication on the exact base or its one proven producer-created lock-only successor, so remediation PRs inherit the accepted partial lock without changing or reverting it. ## Regression coverage Hermetic integration uses temporary Git/Forgejo state and fake OpenCode, Bubblewrap, Nix, and Tea; it creates no real incident issue or PR. It covers: - eligible leaf remediation to a validated issue-linked PR; - core and module-schema diagnosis-only outcomes; - patched build failure and non-reproduced candidate refusal; - blocked security-policy patch refusal; - simulated model write outside its output mount; - one-attempt fingerprint state, terminal-state scan filtering, lock-only `main` advancement, credential-free model environment, and stale/orphan cleanup. ## Validation - `./tests/nixos-update-remediation-regressions.sh` — passed - `./tests/auto-update-regressions.sh` — passed - `./tests/nova-remediation-benchmark.sh` — passed - ShellCheck at warning severity — passed - actionlint with repository exclusions — passed - `forgejo-runner validate --directory .` — passed for both workflows - Ruff lint and format check — passed - `nix fmt` — 124 files checked, no changes required - `nix flake check` — passed; evaluated electra, lena, vega, lyra, and cosmos and built the formatting check - `git diff --check` — passed ## Rollout note No manual updater run or deployment was performed. This does not interfere with #129 passive rollout observation. After merge, the new Nova workflow should be observed on a normal even-hour run; any required genuine deployment/no-op evidence will be recorded before the issue is finally closed.
feat(auto-update): add guarded remediation worker
Some checks failed
Build and Push Attic Cache / test (pull_request) Failing after 22s
Build and Push Attic Cache / build (pull_request) Has been skipped
Build and Push Attic Cache / remediate (pull_request) Has been skipped
AI pull-request review / review (pull_request) Failing after 2m40s
c25788f9e6
Refs #130
fix(auto-update): make remediation task limit runner-safe
All checks were successful
Build and Push Attic Cache / test (pull_request) Successful in 55s
Build and Push Attic Cache / build (pull_request) Has been skipped
Build and Push Attic Cache / remediate (pull_request) Has been skipped
AI pull-request review / review (pull_request) Successful in 8m59s
ddcc54255c
Refs #130
Author
Owner

CI failure follow-up (ddcc542)

Root cause: Linux RLIMIT_NPROC counts all tasks/threads for the real UID. The controller set an absolute ceiling of 128, while the shared Nova runner UID had 434 tasks during reproduction. The fake Bubblewrap and a real Bubblewrap smoke both failed before OpenCode could start with EAGAIN / Resource temporarily unavailable; the eligible case therefore correctly fell back to diagnosis-only, but violated the integration expectation.

Fix: reserve the reviewed model allowance above the measured ambient UID task baseline for the immediate kernel limit, while independently measuring the launched subprocess tree and terminating it above the policy ceiling of 128 tasks. This removes the host-load assumption without weakening the worker-specific cap.

Regression/evidence:

  • the hermetic eligible fixture now pressures the shared UID to at least 128 tasks before the fake Bubblewrap forks OpenCode and still requires published-pr;
  • controller status assertions now include stdout, stderr, and durable remediation state;
  • exact Nova runner reproduction passed under the CI PATH and clean environment;
  • real Nova Bubblewrap smoke passed at ambient 437 / computed ceiling 565;
  • remediation, updater, benchmark, ShellCheck, actionlint, Forgejo workflow validation, Ruff, formatting, nix flake check, and git diff --check all passed locally.

No manual updater run or deployment was performed.

CI failure follow-up (`ddcc542`) Root cause: Linux `RLIMIT_NPROC` counts all tasks/threads for the real UID. The controller set an absolute ceiling of 128, while the shared Nova runner UID had 434 tasks during reproduction. The fake Bubblewrap and a real Bubblewrap smoke both failed before OpenCode could start with `EAGAIN` / `Resource temporarily unavailable`; the eligible case therefore correctly fell back to diagnosis-only, but violated the integration expectation. Fix: reserve the reviewed model allowance above the measured ambient UID task baseline for the immediate kernel limit, while independently measuring the launched subprocess tree and terminating it above the policy ceiling of 128 tasks. This removes the host-load assumption without weakening the worker-specific cap. Regression/evidence: - the hermetic eligible fixture now pressures the shared UID to at least 128 tasks before the fake Bubblewrap forks OpenCode and still requires `published-pr`; - controller status assertions now include stdout, stderr, and durable remediation state; - exact Nova runner reproduction passed under the CI PATH and clean environment; - real Nova Bubblewrap smoke passed at ambient 437 / computed ceiling 565; - remediation, updater, benchmark, ShellCheck, actionlint, Forgejo workflow validation, Ruff, formatting, `nix flake check`, and `git diff --check` all passed locally. No manual updater run or deployment was performed.
Author
Owner

Gate status after rerun monitoring

  • Required Attic/test workflow run 926 is green for exact head ddcc54255cbcb56515367f8b992126c62defc9bb.
  • Automated review run 925 and bounded manual retries 927, 928, and 929 all failed before publishing a review. Their only terminal errors were malformed/empty Ollama JSON (Expecting value, Expecting property name enclosed in double quotes, and Extra data). No automated-review comment or actionable finding was produced.
  • The established reviewer sends the full 183,327-byte PR diff plus up to 60,000 bytes of guidance into a 65,536-token context and has no internal model-response retry. Repairing or rebudgeting that separate reviewer path is outside this PR fix.

PR #134 remains open and unmerged. The review gate must become genuinely green before merge.

Gate status after rerun monitoring - Required Attic/test workflow run 926 is green for exact head `ddcc54255cbcb56515367f8b992126c62defc9bb`. - Automated review run 925 and bounded manual retries 927, 928, and 929 all failed before publishing a review. Their only terminal errors were malformed/empty Ollama JSON (`Expecting value`, `Expecting property name enclosed in double quotes`, and `Extra data`). No automated-review comment or actionable finding was produced. - The established reviewer sends the full 183,327-byte PR diff plus up to 60,000 bytes of guidance into a 65,536-token context and has no internal model-response retry. Repairing or rebudgeting that separate reviewer path is outside this PR fix. PR #134 remains open and unmerged. The review gate must become genuinely green before merge.
Author
Owner

Automated code review

Reviewed commit: 2717aadeada26979b04c7c82f0812b2bf67c12a6

Verdict: Ready to merge

No blocking or important findings were retained, and deterministic checks passed. Suggestions remain advisory.

Overall assessment

The pull request implements a guarded remediation worker and deterministic Forgejo controller to handle rejected NixOS flake-input updates. It enforces strict security boundaries via Bubblewrap, fail-closed resource limits, narrow eligibility policies, and deterministic validation (baseline reproduction, patch application, host builds, closure comparison, and package/source proofs). Hermetic integration tests cover eligible, unsafe, blocked-safety, boundary-write, and infrastructure-failure scenarios. The implementation aligns with the stated objectives and passes all provided validation gates.

Blocking findings

None.

Important findings

None.

Suggestions

  • Single-file controller complexity (scripts/nixos-update-remediation.py:1; medium confidence)
    The file spans 3075 lines and consolidates policy validation, incident state management, Bubblewrap/OpenCode execution, deterministic Nix validation, Git worktree operations, and Forgejo publication via the Tea client into one module.
    Impact: High cognitive load for future reviewers and maintainers; increases risk of regression when modifying isolated subsystems like the publisher or sandbox launcher.
    Suggested fix: Extract distinct responsibilities (e.g., TeaPublisher, ValidationRunner, process_tree_task_count, deterministic_validation) into separate modules or a small package structure to improve test isolation and long-term maintainability.

Tests and validation

  • No configured deterministic checks.

Questions

  • Does the repository policy require splitting large controller scripts into modular packages, or is the single-file executable pattern acceptable for this automation layer?

Review limitations

  • Review is based solely on supplied diff and text; runtime behavior on the actual Fedora Nova runner host cannot be verified.
  • Static analysis of the Python script does not cover dynamic execution paths, external API rate limits from Forgejo/Tea, or real-world prompt-injection edge cases beyond the provided fixtures.
  • Nix evaluation and closure comparison logic was assessed structurally; actual build times and store pressure on Nova were not observed.

Diff coverage

  • .forgejo/workflows/attic-cache.yml: reviewed — included in a context-limited batch
  • README.md: reviewed — included in a context-limited batch
  • flake.nix: reviewed — included in a context-limited batch
  • justfiles/maintenance.just: reviewed — included in a context-limited batch
  • remediation/nova-policy.json: reviewed — included in a context-limited batch
  • remediation/worker-prompt.md: reviewed — included in a context-limited batch
  • scripts/nixos-update-incident-bundle.sh: reviewed — included in a context-limited batch
  • scripts/nixos-update-remediation.py: reviewed — included in a context-limited batch
  • tests/auto-update-regressions.sh: reviewed — included in a context-limited batch
  • tests/fixtures/nixos-update-remediation/blocked-safety/proposal.patch: reviewed — included in a context-limited batch
  • tests/fixtures/nixos-update-remediation/blocked-safety/result-template.json: reviewed — included in a context-limited batch
  • tests/fixtures/nixos-update-remediation/eligible-leaf/proposal.patch: reviewed — included in a context-limited batch
  • tests/fixtures/nixos-update-remediation/eligible-leaf/result-template.json: reviewed — included in a context-limited batch
  • tests/fixtures/nixos-update-remediation/module-schema/result-template.json: reviewed — included in a context-limited batch
  • tests/fixtures/nixos-update-remediation/unsafe-core/proposal.patch: reviewed — included in a context-limited batch
  • tests/fixtures/nixos-update-remediation/unsafe-core/result-template.json: reviewed — included in a context-limited batch
  • tests/nixos-update-remediation-integration.py: reviewed — included in a context-limited batch
  • tests/nixos-update-remediation-regressions.sh: reviewed — included in a context-limited batch
Review metadata
  • Reviewer: forgejo-ai-review v1
  • Model: qwen3.6:35b-a3b-q8_0
  • Guidance loaded: .forgejo/ai-review.md, .forgejo/ai-review.yml, AGENTS.md, README.md
  • Commits considered: 3
  • Previous automated review: updated
  • Findings: 1
<!-- forgejo-ai-review:v1 --> ## Automated code review Reviewed commit: `2717aadeada26979b04c7c82f0812b2bf67c12a6` ## Verdict: Ready to merge No blocking or important findings were retained, and deterministic checks passed. Suggestions remain advisory. ### Overall assessment The pull request implements a guarded remediation worker and deterministic Forgejo controller to handle rejected NixOS flake-input updates. It enforces strict security boundaries via Bubblewrap, fail-closed resource limits, narrow eligibility policies, and deterministic validation (baseline reproduction, patch application, host builds, closure comparison, and package/source proofs). Hermetic integration tests cover eligible, unsafe, blocked-safety, boundary-write, and infrastructure-failure scenarios. The implementation aligns with the stated objectives and passes all provided validation gates. ### Blocking findings None. ### Important findings None. ### Suggestions - **Single-file controller complexity** (scripts/nixos-update-remediation.py:1; medium confidence) The file spans 3075 lines and consolidates policy validation, incident state management, Bubblewrap/OpenCode execution, deterministic Nix validation, Git worktree operations, and Forgejo publication via the Tea client into one module. Impact: High cognitive load for future reviewers and maintainers; increases risk of regression when modifying isolated subsystems like the publisher or sandbox launcher. Suggested fix: Extract distinct responsibilities (e.g., `TeaPublisher`, `ValidationRunner`, `process_tree_task_count`, `deterministic_validation`) into separate modules or a small package structure to improve test isolation and long-term maintainability. ### Tests and validation - No configured deterministic checks. ### Questions - Does the repository policy require splitting large controller scripts into modular packages, or is the single-file executable pattern acceptable for this automation layer? ### Review limitations - Review is based solely on supplied diff and text; runtime behavior on the actual Fedora Nova runner host cannot be verified. - Static analysis of the Python script does not cover dynamic execution paths, external API rate limits from Forgejo/Tea, or real-world prompt-injection edge cases beyond the provided fixtures. - Nix evaluation and closure comparison logic was assessed structurally; actual build times and store pressure on Nova were not observed. ### Diff coverage - `.forgejo/workflows/attic-cache.yml`: **reviewed** — included in a context-limited batch - `README.md`: **reviewed** — included in a context-limited batch - `flake.nix`: **reviewed** — included in a context-limited batch - `justfiles/maintenance.just`: **reviewed** — included in a context-limited batch - `remediation/nova-policy.json`: **reviewed** — included in a context-limited batch - `remediation/worker-prompt.md`: **reviewed** — included in a context-limited batch - `scripts/nixos-update-incident-bundle.sh`: **reviewed** — included in a context-limited batch - `scripts/nixos-update-remediation.py`: **reviewed** — included in a context-limited batch - `tests/auto-update-regressions.sh`: **reviewed** — included in a context-limited batch - `tests/fixtures/nixos-update-remediation/blocked-safety/proposal.patch`: **reviewed** — included in a context-limited batch - `tests/fixtures/nixos-update-remediation/blocked-safety/result-template.json`: **reviewed** — included in a context-limited batch - `tests/fixtures/nixos-update-remediation/eligible-leaf/proposal.patch`: **reviewed** — included in a context-limited batch - `tests/fixtures/nixos-update-remediation/eligible-leaf/result-template.json`: **reviewed** — included in a context-limited batch - `tests/fixtures/nixos-update-remediation/module-schema/result-template.json`: **reviewed** — included in a context-limited batch - `tests/fixtures/nixos-update-remediation/unsafe-core/proposal.patch`: **reviewed** — included in a context-limited batch - `tests/fixtures/nixos-update-remediation/unsafe-core/result-template.json`: **reviewed** — included in a context-limited batch - `tests/nixos-update-remediation-integration.py`: **reviewed** — included in a context-limited batch - `tests/nixos-update-remediation-regressions.sh`: **reviewed** — included in a context-limited batch <details><summary>Review metadata</summary> - Reviewer: forgejo-ai-review v1 - Model: qwen3.6:35b-a3b-q8_0 - Guidance loaded: .forgejo/ai-review.md, .forgejo/ai-review.yml, AGENTS.md, README.md - Commits considered: 3 - Previous automated review: updated - Findings: 1 </details>
Author
Owner

Automated review follow-up for ddcc542

The published review completed successfully at 128k, but its retained important finding is not valid:

  • git cat-file -e
Automated review follow-up for ddcc542 The published review completed successfully at 128k, but its retained important finding is not valid: - git cat-file -e <object>^{commit} uses Git revision type-peeling/type assertion syntax; it does not ask for a parent. The actual repository root commit 47b9c09846a52612727d51e0557a7edf1f790f35 passes both git cat-file -e <root>^{commit} and git rev-parse --verify <root>^{commit} on Git 2.55.0. - The integration repository creates validated base as its first and therefore root commit (tests/nixos-update-remediation-integration.py:151-180). Every incident fixture loads that root through the reviewed check, including the eligible published-pr case. Required CI is green. No root-commit code change is warranted. Suggestion assessment: - The exact status check is intentionally fail-closed. git status --porcelain without a version selects the stable porcelain-v1 machine format. The candidate worktree must contain exactly one unstaged flake.lock replacement; any staged, untracked, renamed, or additional modified path is a boundary violation. The boundary-write fixture verifies rejection when the model affects another path. Replacing this with a looser diff-index check would not improve the safety invariant. - Both build and remediate target the dedicated Nova host executor (registered label nova:host, capacity 2), not the separate Docker runner. They run as the same persistent host user, and state lives under /home/nimmo/.local/state/attic-cache-build outside GITHUB_WORKSPACE. The host state directory persists across jobs; the incident subdirectory is created only when a rejection occurs. A missing incident root is an explicit successful no-op at scripts/nixos-update-remediation.py:3026-3029. Artifacts are not required under the current reviewed runner topology; a future executor migration must preserve or deliberately replace this contract. - Nova runs Git 2.55.0, which supports the controller operations in use. 128k runtime evidence: - initial prompt: 65,880 tokens, completed untruncated - second-pass prompt: 51,497 tokens, completed untruncated - both Ollama requests reported truncated=0 - Forgejo review job succeeded in 8m59s and published the report No implementation change was made in response to these non-defects. No deployment or updater run was performed.
Author
Owner

Markdown clarification: the two verified commands used the literal revision 47b9c09846a52612727d51e0557a7edf1f790f35^{commit}; angle-bracket placeholders in the preceding comment were rendered as HTML and disappeared.

Markdown clarification: the two verified commands used the literal revision 47b9c09846a52612727d51e0557a7edf1f790f35^{commit}; angle-bracket placeholders in the preceding comment were rendered as HTML and disappeared.
fix(auto-update): pin remediation publication client
All checks were successful
Build and Push Attic Cache / test (pull_request) Successful in 1m27s
Build and Push Attic Cache / build (pull_request) Has been skipped
Build and Push Attic Cache / remediate (pull_request) Has been skipped
AI pull-request review / review (pull_request) Successful in 6m48s
2717aadead
Resolve Tea from the flake lock on Nova and bootstrap it with the repository-scoped automatic Forgejo token in a private temporary config. Keep both token variables out of the deterministic controller process and preserve the model's clean tmpfs boundary.

Exercise the real client contract in CI and cover the missing ambient Tea condition in remediation regressions.
Author
Owner

Final Nova publisher follow-up (2717aad)

The exact target-environment audit found that Nova intentionally has neither an ambient tea binary nor a persistent Tea login. Installing a mutable host package would have fixed only half of that contract.

The revised workflow now:

  • resolves Tea 0.14.0 from the repository flake lock (nixos-update-remediation-tea);
  • authenticates with Forgejo Actions automatic forgejo-actions identity, which is repository-scoped and destroyed after the run;
  • stores that credential only in a mode-0700 config below host /tmp, deletes it on step exit, and removes FORGEJO_TOKEN/GITHUB_TOKEN before starting the deterministic controller;
  • keeps host /tmp hidden behind the model Bubblewrap tmpfs, while the existing clean-environment assertions continue to prove no Forgejo or deployment token reaches Bubblewrap/OpenCode;
  • exercises real read-only issue and PR pagination/JSON calls in the PR test job, while publication integration continues to use fakes and creates no real incident issue or PR.

Exact-head validation:

  • Attic run 568 / test job 1504: passed in 1m27s on Nova; checked out 2717aadeada26979b04c7c82f0812b2bf67c12a6, built locked Tea, logged in as forgejo-actions, and passed both publisher contract probes plus all updater/remediation/benchmark/Nix gates.
  • Automated review run 567 / job 1503: Ready to merge, no blocking or important findings; both 128k passes completed untruncated (68,307 and 53,574 prompt tokens, truncated=0).
  • Local: remediation regression/integration, auto-update regression, Nova benchmark, ShellCheck, actionlint, Forgejo workflow validation, Ruff lint/format, pinned formatting, nix flake check, real read-only Tea queries, and git diff --check all passed.

No Tea package was installed on Nova. No updater run or deployment was forced. The PR now uses a non-closing reference to #130 so the issue remains open until genuine normal even-hour rollout and required no-op evidence are recorded.

Final Nova publisher follow-up (`2717aad`) The exact target-environment audit found that Nova intentionally has neither an ambient `tea` binary nor a persistent Tea login. Installing a mutable host package would have fixed only half of that contract. The revised workflow now: - resolves Tea 0.14.0 from the repository flake lock (`nixos-update-remediation-tea`); - authenticates with Forgejo Actions automatic `forgejo-actions` identity, which is repository-scoped and destroyed after the run; - stores that credential only in a mode-0700 config below host `/tmp`, deletes it on step exit, and removes `FORGEJO_TOKEN`/`GITHUB_TOKEN` before starting the deterministic controller; - keeps host `/tmp` hidden behind the model Bubblewrap tmpfs, while the existing clean-environment assertions continue to prove no Forgejo or deployment token reaches Bubblewrap/OpenCode; - exercises real read-only issue and PR pagination/JSON calls in the PR test job, while publication integration continues to use fakes and creates no real incident issue or PR. Exact-head validation: - Attic run 568 / test job 1504: passed in 1m27s on Nova; checked out `2717aadeada26979b04c7c82f0812b2bf67c12a6`, built locked Tea, logged in as `forgejo-actions`, and passed both publisher contract probes plus all updater/remediation/benchmark/Nix gates. - Automated review run 567 / job 1503: Ready to merge, no blocking or important findings; both 128k passes completed untruncated (68,307 and 53,574 prompt tokens, `truncated=0`). - Local: remediation regression/integration, auto-update regression, Nova benchmark, ShellCheck, actionlint, Forgejo workflow validation, Ruff lint/format, pinned formatting, `nix flake check`, real read-only Tea queries, and `git diff --check` all passed. No Tea package was installed on Nova. No updater run or deployment was forced. The PR now uses a non-closing reference to #130 so the issue remains open until genuine normal even-hour rollout and required no-op evidence are recorded.
nimmo merged commit 32bb4093c9 into main 2026-08-01 09:32:44 +01:00
Sign in to join this conversation.
No reviewers
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
nimmo/nixos-config!134
No description provided.