Run the plan-execute loop inside the daemon #11

Closed
opened 2026-10-11 14:58:51 +08:00 by Breadway · 1 comment
Owner

Gap found while delivering RAM-10 (the standalone CLI).

The action coordinator (RAM-7) can execute a plan with confirmations, a bounded journal, and recovery, and the CLI can now report every recorded action with its reason, target, timestamp, result, requested effect, and observed effect. Nothing yet connects the two: the daemon's monitor loop collects an observation, runs the state machine, and produces a dry-run plan, but it never hands that plan to the coordinator. So the journal is always empty and the end-to-end path "pressure in, memory released, pressure down" is still not demonstrable.

Scope

  • A plan-execute step in the daemon, on the monitor tick or just after it, that runs only when the mode is automatic and only the actions the configuration allows.
  • Adapter and control executor wiring: pass the real executors from the control layer (RAM-9) and the adapter registry (RAM-8) to the coordinator instead of the test fake.
  • Capability and generation revalidation against the live inventory immediately before each write, as the coordinator already requires.
  • Record each attempt in the shared journal so breadram actions shows real history, and publish the resulting state so a restart recovers owned values safely.
  • Failure handling: a failed or panicking execution must not stop the monitor, and a refused action must be journaled rather than silently dropped.

Acceptance criteria

  • With mode automatic and an allowed action configured, a pressured host is measurably relieved and the journal shows the reason, the target, the timestamp, the result, and the measured effect.
  • With mode monitor nothing is written, whatever the pressure, and the CLI's explanation still describes what automatic mode would do.
  • A restart restores only values breadram still owns and leaves a newer external configuration alone.
  • Tests cover an execution that succeeds, one the executor refuses, one whose target is superseded between planning and writing, and one that fails mid-apply.

Related: RAM-20 (managed scopes) and RAM-21/RAM-22 (priorities and budgets) depend on this step existing, since policy depth is not observable until actions actually run.

Gap found while delivering RAM-10 (the standalone CLI). The action coordinator (RAM-7) can execute a plan with confirmations, a bounded journal, and recovery, and the CLI can now report every recorded action with its reason, target, timestamp, result, requested effect, and observed effect. Nothing yet connects the two: the daemon's monitor loop collects an observation, runs the state machine, and produces a dry-run plan, but it never hands that plan to the coordinator. So the journal is always empty and the end-to-end path "pressure in, memory released, pressure down" is still not demonstrable. ### Scope - A plan-execute step in the daemon, on the monitor tick or just after it, that runs only when the mode is `automatic` and only the actions the configuration allows. - Adapter and control executor wiring: pass the real executors from the control layer (RAM-9) and the adapter registry (RAM-8) to the coordinator instead of the test fake. - Capability and generation revalidation against the live inventory immediately before each write, as the coordinator already requires. - Record each attempt in the shared journal so `breadram actions` shows real history, and publish the resulting state so a restart recovers owned values safely. - Failure handling: a failed or panicking execution must not stop the monitor, and a refused action must be journaled rather than silently dropped. ### Acceptance criteria - With mode `automatic` and an allowed action configured, a pressured host is measurably relieved and the journal shows the reason, the target, the timestamp, the result, and the measured effect. - With mode `monitor` nothing is written, whatever the pressure, and the CLI's explanation still describes what automatic mode would do. - A restart restores only values breadram still owns and leaves a newer external configuration alone. - Tests cover an execution that succeeds, one the executor refuses, one whose target is superseded between planning and writing, and one that fails mid-apply. Related: RAM-20 (managed scopes) and RAM-21/RAM-22 (priorities and budgets) depend on this step existing, since policy depth is not observable until actions actually run.
Author
Owner

Implemented and merged in PR #15, main at 639f630.

What landed: breadram-core/src/execution.rs (the plan-execute step), breadram-core/src/coordinator/persist.rs (the versioned state file), journal additions (from_owned_values, history), the adapter registry built from configured providers, and the daemon wiring in breadramd/src/daemon.rs. docs/ARCHITECTURE.md gained AD-11 and docs/AGENT-HANDOFF.md now describes the real current state.

Acceptance criteria, each with the evidence behind it

  • Automatic mode, allowed action, pressured host is measurably relieved, journal shows reason/target/timestamp/result/measured effect: run live in automatic mode against a transient user scope holding 200 MiB with a 4 MiB budget. breadram set MemoryHigh through systemd, MemoryCurrent went 66.8 MiB → 4.2 MiB, and breadram actions showed confirmed | at_ms | requested: -62599168 | observed: -9408512 with the reason "it is 62599168 bytes over its 4194304 byte budget…" and the owned value with its original. Later passes reported skipped_duplicate, so the action is not applied twice.
  • Monitor mode writes nothing whatever the pressure, and the explanation still describes what automatic would do: the same configuration in monitor mode reported the plan as dry_run with the monitor note, left the state file byte for byte unchanged, and wrote no journal entry.
  • A restart restores only what breadram still owns and leaves newer external configuration alone: on restart the setting returned to its recorded original with a rolled_back entry; a value that no longer matches what breadram last wrote is reported as left alone, and a state file this build cannot read is refused rather than reinterpreted.
  • Tests cover success, refusal, superseded target, and a failure mid-apply: execution.rs covers all four against a fake executor plus monitor-mode and duplicate-suppression cases; daemon.rs covers the daemon's own gating (automatic writes and journals, monitor writes nothing, disallowed action refused, second pass not repeated, state file round trip and unreadable file).

Verification on the merged head: cargo fmt --all -- --check clean, cargo clippy --workspace --all-targets -- -D warnings clean, cargo test --workspace 336 tests pass.

Two defects were caught by the live run rather than by reading: a recovered ownership record satisfied has_confirmed, which would have suppressed the action forever after a restart even though the restart had just undone it; and the startup restore note was cleared by the next tick.

Scope item not delivered, with the reason: "adapter and control executor wiring" is half done. The control executor is wired and real. The registry is built from config.providers (a provider now names the workload scope it owns, validated) and its activity evidence reaches the planner, so an idle-model release is plannable. What is missing is executing a provider action: there is still no HTTP Transport in breadram_core::adapter (only ScriptedTransport), so nothing can call a provider. That belongs with RAM-13/RAM-14 (which need it to talk to a real server) and RAM-45; I have not pretended otherwise in the docs or the PR.

Implemented and merged in PR [#15](https://git.breadway.dev/Breadway/breadram/pulls/15), `main` at `639f630`. **What landed**: `breadram-core/src/execution.rs` (the plan-execute step), `breadram-core/src/coordinator/persist.rs` (the versioned state file), journal additions (`from_owned_values`, `history`), the adapter registry built from configured providers, and the daemon wiring in `breadramd/src/daemon.rs`. `docs/ARCHITECTURE.md` gained AD-11 and `docs/AGENT-HANDOFF.md` now describes the real current state. **Acceptance criteria, each with the evidence behind it** - *Automatic mode, allowed action, pressured host is measurably relieved, journal shows reason/target/timestamp/result/measured effect*: run live in `automatic` mode against a transient user scope holding 200 MiB with a 4 MiB budget. breadram set `MemoryHigh` through systemd, `MemoryCurrent` went 66.8 MiB → 4.2 MiB, and `breadram actions` showed `confirmed | at_ms | requested: -62599168 | observed: -9408512` with the reason "it is 62599168 bytes over its 4194304 byte budget…" and the owned value with its original. Later passes reported `skipped_duplicate`, so the action is not applied twice. - *Monitor mode writes nothing whatever the pressure, and the explanation still describes what automatic would do*: the same configuration in monitor mode reported the plan as `dry_run` with the monitor note, left the state file byte for byte unchanged, and wrote no journal entry. - *A restart restores only what breadram still owns and leaves newer external configuration alone*: on restart the setting returned to its recorded original with a `rolled_back` entry; a value that no longer matches what breadram last wrote is reported as left alone, and a state file this build cannot read is refused rather than reinterpreted. - *Tests cover success, refusal, superseded target, and a failure mid-apply*: `execution.rs` covers all four against a fake executor plus monitor-mode and duplicate-suppression cases; `daemon.rs` covers the daemon's own gating (automatic writes and journals, monitor writes nothing, disallowed action refused, second pass not repeated, state file round trip and unreadable file). Verification on the merged head: `cargo fmt --all -- --check` clean, `cargo clippy --workspace --all-targets -- -D warnings` clean, `cargo test --workspace` 336 tests pass. Two defects were caught by the live run rather than by reading: a recovered ownership record satisfied `has_confirmed`, which would have suppressed the action forever after a restart even though the restart had just undone it; and the startup restore note was cleared by the next tick. **Scope item not delivered, with the reason**: "adapter and control executor wiring" is half done. The control executor is wired and real. The registry is built from `config.providers` (a provider now names the workload scope it owns, validated) and its activity evidence reaches the planner, so an idle-model release is plannable. What is missing is executing a provider action: there is still no HTTP `Transport` in `breadram_core::adapter` (only `ScriptedTransport`), so nothing can call a provider. That belongs with RAM-13/RAM-14 (which need it to talk to a real server) and RAM-45; I have not pretended otherwise in the docs or the PR.
Sign in to join this conversation.
No labels
No milestone
No project
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
Breadway/breadram#11
No description provided.