Add runtime observation and systemd restart adapter

This commit is contained in:
2026-10-20 23:01:43 +03:00
parent 5418841b92
commit 6ec593c783
18 changed files with 6001 additions and 66 deletions
+432 -6
View File
@@ -114,7 +114,7 @@ Each row is a delivery milestone, not a completion claim. Expand its record befo
| 2 | Server configuration editing with byte preservation | 1 | accepted |
| 3 | Client keys, encrypted vault, and existing-client import | 2 | accepted |
| 4 | Backups, safe Commit, and full restoration | 3 | accepted |
| 5 | Runtime observation and systemd restart adapter | 4 | pending |
| 5 | Runtime observation and systemd restart adapter | 4 | blocked |
| 6 | Client configuration delivery and reissue lifecycle | 5 | pending |
| 7 | Complete terminal management workflow | 6 | pending |
| 8 | Alpine Testcontainers integration | 7; suitable disposable Docker environment | pending |
@@ -1391,9 +1391,435 @@ no Git commit, deployment or production access occurred.
### Milestone 5 — Runtime observation and systemd restart adapter
Implement `wireguard-uapi` runtime queries and the `zbus` systemd adapter behind narrow interfaces. Track service job completion and timeout, then verify interface/client correspondence before recording applied state and releasing addresses. Require backup before restart.
Status: accepted (2026-10-20T22:59:39+03:00; scoped fixture acceptance and independent integrated re-review complete).
Prerequisites: milestones 1–4 accepted; pinned native Rust environment and
compatible approved `rustix` and `zbus` dependencies. Ordinary
M5 acceptance uses injected adapters and temporary saved stores without root or
host-service/network access. Real WireGuard and systemd acceptance stays assigned
to milestones 8 and 9 respectively, not silently waived.
Acceptance: ordinary tests exercise successful and failed jobs, missing/mismatched interfaces, unavailable statistics, and no automatic rollback using controlled adapters. Real runtime/systemd acceptance remains explicitly pending until milestones 8 and 9; mocks cannot close those later gates.
#### Outcome and scope
Deliver a read-only Linux WireGuard runtime adapter, a systemd D-Bus restart
adapter, and application orchestration for an explicitly confirmed restart:
complete backup, restart the configured unit, await its job, verify the configured
interface/peers, persist verification through M4, then publish applied state and
release reserved addresses. Supply safe public runtime/statistics views for the
future TUI without deriving client identity or online status from aliases.
Read SPEC.md Operations and states, Client screen and statistics, and Backups and
restoration; ADRs 0001 and 0003; PERSISTENCE.md, BACKUP_FORMAT.md, DEVELOPMENT.md,
DEPENDENCIES.md, TESTING.md, and the current application/domain code. Commit and
restore must retain their strict no-runtime-mutation behavior.
Out of scope: TUI/screens, automatic refresh scheduling in a render loop, delivery
or QR, automatic failed-restart rollback/retry, reload/syncconf as an alternative
apply path, additional service managers/interfaces, production tests, and creation
of the Alpine/VM harnesses. Keep management startup safely incomplete; do not
introduce a new restart CLI or run real adapters in default tests.
#### Existing code and integration constraints
- `Application` owns the saved store/bytes, byte-preserving document, `ClientStates`,
vault draft and historical verification. Resolve runtime settings from the
current saved generation, including settings restored from a backup, not a stale
constructor copy or archive-supplied arbitrary bus/service destination.
- `Application::create_pre_restart_backup` archives installed bytes and sets a
pending boundary flag. `mark_verified_after_runtime_check` is crate-private:
it checks that boundary and saved generation, validates an observed Snapshot,
installs verification state through SavedStore's journal, then advances memory.
Wire these existing boundaries into the real sequence; do not bypass them with
a direct state-file write or public "mark verified" setter.
- `PersistedState` v1 holds reservations and a historical UTC timestamp. Reopen is
always Unknown. Commit/restore clear stale verification; M5 records the timestamp
only after matching runtime and successful journaled write. BACKUP_FORMAT.md
ties archive historical status to that saved generation, not merely the date.
- The existing `pre_restart_backup_pending` boolean is not proof of a successful
restart. Scope/invalidate authorization per attempt, failure, cancellation and
saved-generation change; an old successful backup must never authorize later
unrelated verification. Refine the internal contract if needed, preserving M4
guarantees and tests. No new concurrency/version-control scheme is required.
- `Snapshot` includes aliases and a narrow ClientAddresses model; kernel peers do
not contain aliases or managed comment timestamps. Do not compare raw kernel
structures directly against Snapshot equality or invent runtime metadata.
- M2 `ConfigDocument::peers()` retains full AllowedIPs and redacted issues; some
valid peers cannot project into M1 Client. Include every authoritative peer in
technical verification, or fail closed as unverifiable. Never ignore unsupported
records to obtain a matching reduced subset. Missing/invalid managed alias alone
must not be mistaken for evidence of a different runtime peer.
- Cargo already contains time, rustix, tempfile and persistence/crypto dependencies.
The approved `wireguard-uapi` 3.0.1 public read path cannot guarantee complete,
bounded dumps (M5-R1-04). Use existing approved `rustix` with narrow `net`/`event`
features for a checked read-only Generic Netlink GET adapter; add approved zbus
only when needed. Inspect current official APIs/features and Rust compatibility.
Do not assume older zbus blocking examples
apply to the selected version. No unapproved direct Tokio/executor/mock crate
or utility subprocess fallback is authorized.
#### Context and implementation steps
Run tasks sequentially with one writer under the established model policy:
GPT-6-Sol/medium coordinator; GPT-6-Luna/high implementer, independent reviewer and
repairer. Dispatch owned files, exact interfaces, acceptance IDs, checks and
required evidence. Workers do not mark milestones accepted or edit PLANS.md.
| Task | Owner | Files and deliverable |
| --- | --- | --- |
| M5.1 | implementer | `src/runtime.rs`, narrow domain/application views and `docs/RUNTIME.md`: public observation model, saved technical projection and pure comparison contract |
| M5.2 | implementer | runtime adapter modules, Cargo files/library exports: approved-rustix read-only WireGuard Generic Netlink codec/transport with isolated conversion/error tests; split pure decoder then bounded socket transport |
| M5.3 | implementer | `src/service.rs`, child modules if necessary: zbus systemd restart/job observation with deadline and a mockable transport boundary |
| M5.4 | implementer | `src/app.rs`, narrow M4 state/persistence integration: confirmed restart orchestration, per-attempt authorization, durable verification and honest failure results |
| M5.5 | implementer | `tests/runtime_restart.rs`, test-only adapters, README/RUNTIME/PERSISTENCE documentation: integrated success, order and failure scenarios |
| M5.6 | reviewer, repairer | Independent integrated review, bounded fixes and re-review, including M4 persistence regressions |
| M5.7 | coordinator | Integrated gates, evidence/findings and milestone acceptance/handoff in PLANS.md |
M5.1 defines public observations keyed by PublicKey, with explicit interface
presence/unavailability, peer AllowedIPs, last handshake, received/transmitted
byte counters, and observation time. Preserve zero/never-handshaken separately
from unavailable data. Counters are current interface values, may reset after a
restart, and are not historical usage or proof of online/offline status. Traffic
is reported from the server interface's perspective. Alias display joins by
public key using saved metadata, never list index or filename.
Define technical equivalence independently of counters, handshake, peer ordering,
route ordering, aliases, dynamically learned endpoints and timestamps. Verify the
expected configured interface exists and the complete saved peer public-key set
and normalized AllowedIPs match, including absence of deleted/extra peers and
an empty valid peer set. Report missing/extra/mismatched/unverifiable records with
public identities and categories. Duplicate/ambiguous saved identities or partial
runtime dumps cannot pass. Do not claim comparison of fields the adapter cannot
observe. Retain full route sets for legacy peers; enrich M1 projection narrowly
only if required and do not drop valid data to fit Snapshot.
Document the boundary between technical match and M4's narrow observed Snapshot:
use saved aliases only after technical peer/route equivalence is established,
not as alleged kernel observations. If the complete document cannot be safely
verified/represented for durable marking, keep the operation unverifiable and
reservations retained rather than passing a fabricated subset to M4.
M5.2 uses the configured interface via Linux WireGuard/netlink APIs only; no set,
add/remove, module loading, host route manipulation or external `wg` invocation.
Handle multipart responses and peer/AllowedIPs fragments according to the
[kernel protocol](https://docs.kernel.org/netlink/specs/wireguard.html); require
matching request sequence, an error-free terminal `NLMSG_DONE`, no interrupted
dump and a complete response before claiming absence or equality. Bound
reads/waits and aggregate limits. Convert no-device, permission, malformed data,
transport failure and timeout to distinct actionable, redacted outcomes.
WireGuard library structures may include server private or preshared keys even
when only public statistics are needed. Never derive/log their full Debug, retain
them in public observations, or serialize them as status data. Minimize lifetime
and clear supported owned buffers; document unavoidable library copies honestly.
Default tests exercise supplied decoded inputs/test transport, never a host socket.
M5.3 connects to the system bus and fixed systemd Manager API for the validated
configured unit, requests an actual restart, and follows the returned job to its
terminal result. Subscribe/install observation before submission so immediate
completion cannot be missed; correlate by the actual job and unit, ignore unrelated
signals, and handle disconnection/name-owner changes or subscription failure.
Successful request submission, job disappearance, or a unit already being active
is not completed restart evidence. Accept only the documented successful terminal
result, then let runtime verification decide whether VPN configuration matches.
Account for wg-quick oneshot units that are active/exited; do not demand a daemon
PID or long-running process that WireGuard itself does not require.
Use a monotonic configured deadline across D-Bus connection/subscription/request,
job waiting and post-job verification rather than resetting it on each retry.
Backup completion precedes service mutation but may have a separate filesystem
failure boundary. A timeout bounds the application's wait, not proof that systemd
stopped its job. Report "may still complete" when appropriate; do not retry a
restart or issue broad cancellation/rollback automatically. Ordinary test code
uses a supplied job event/transport adapter; no real system bus is contacted.
M5.4 adds explicit preparation/confirmation for restart and draft discard suitable
for a future TUI. Preview/cancel does not save/discard a draft or call systemd.
On confirmed discard-and-restart, reject unresolved persistence recovery, validate
saved input and configured unit, complete the pre-restart backup, discard only
as authorized and restart only the saved configuration. Never implicitly Commit.
A backup failure leaves protected state and draft unchanged and submits no job.
Check compatibility with service-managed config rewriting, notably wg-quick
SaveConfig behavior: do not edit administrator-owned settings to work around it
or claim saved-generation verification when shutdown has overwritten intended
peer changes. Detect an unsafe/unverifiable apply precondition and explain it;
use a safe test fixture/service setup, not an automatic production setting change.
Demote stale current verification when a restart is submitted; a failed request,
job, read or comparison cannot leave a misleading previously Verified state.
Keep reservations and recovery information conservative. Read back the complete
runtime after successful job completion within the deadline; do not require a
client to connect or handshake, since correct peers can be idle. Periodic
read-only observations may report correspondence, but must not release deleted
addresses or persist successful restart history by bypassing the explicit sequence.
Only a matching full observation from the successful attempt can reach M4's
journaled verification boundary. If the saved-generation check or state write
fails after VPN restart, report "runtime changed, verification not durably
recorded" rather than full success. Retain reservations/in-memory safety and
honor RecoveryRequired before later mutations. Do not rollback the VPN, repeat
restart automatically, mark the old history as current, or remove the backup.
M5.5 uses fake monotonic time and deterministic adapter event sequences, temporary
saved stores and synthetic configuration. Assert call order: backup completed
before restart request; successful job before runtime verification; matched
observation before journaled state publication; persistence success before memory
and reservation release. Failures must be visible by stage, including whether
a restart was submitted/may still be active, backup location, and any required
manual recovery. Avoid sensitive D-Bus/library error text in reports.
#### Acceptance and validation
- [x] M5-A1: public read-only observation distinguishes missing/unavailable/unknown,
no handshake and valid zero counters; public-key joins and counter resets do not
invent online state, aliases, traffic history, or successful apply.
- [x] M5-A2: configured-interface runtime adapter consumes complete bounded peer
data, including fragmented route lists, and exposes only public information;
no runtime mutations, secret Debug output or default host access occur.
- [x] M5-A3: pure verification covers dual-stack and IPv4-only peers, reordered
sets, empty peers, missing/extra/deleted peers, route mismatches, malformed or
partial observations, and unsupported saved shapes without subset success.
- [x] M5-A4: service adapter targets only the configured systemd unit, tracks the
returned job without a fast-completion race, and handles unrelated events,
failed/canceled jobs, disconnects, permission errors and monotonic timeout.
- [x] M5-A5: explicit cancellation preserves the draft; confirmed draft discard
never commits. Failed mandatory backup submits no restart and preserves draft,
saved bytes, reservations and previous historical evidence.
- [x] M5-A6: successful restart alone is insufficient: interface/peer verification
must pass before M4 marking; idle clients need no handshake to be applied.
- [x] M5-A7: each failure invalidates that attempt's authorization; a stale backup
flag, old successful job, read-only refresh or old verified Snapshot cannot mark
a later generation applied or release a reserved address.
- [x] M5-A8: verified state and timestamp become visible only after M4 journaled
state persistence succeeds. Injected post-restart write/recovery failure retains
safe reservations and reports changed runtime without false overall success.
- [x] M5-A9: reopening still treats verification timestamps as historical; Commit
and restore retain their no-runtime-mutation behavior and invalidate stale apply
evidence. Archived settings changes select the restored unit/timeout correctly.
- [x] M5-A10: timeouts do not imply a job was canceled; no automatic restart retry,
live setting rewrite, reload/syncconf fallback or VPN rollback is introduced.
- [x] M5-A11: full M1–M4 regressions and integrated M5 fake-adapter tests pass with
no root, Docker, real system bus/interface, production paths or secret reads.
- [x] M5-A12: independent review closes actionable runtime/service/race/persistence
findings; documentation clearly defers real WireGuard checks to M8 and actual
systemd/D-Bus acceptance to M9 rather than claiming them from mocks.
Planned commands from the repository root once M5 targets/lockfile exist:
```sh
cargo test --locked runtime
cargo test --locked service
cargo test --locked --test runtime_restart
cargo test --locked --test commit_restore
cargo test --locked --test config_preservation
cargo test --locked --test vault_import
cargo fmt --all -- --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo build --locked --release
./target/release/wireguard-admin --help
./target/release/wireguard-admin --version
git diff --check
```
Ensure filters execute actual tests and report counts and exit status. Resolve
approved dependencies and update Cargo.lock before locked gates. Default tests
must remain deterministic, unprivileged and independent of a daemon/bus/network.
No bare management launch, actual restart, or host WireGuard probing is permitted.
#### Progress
- [x] Description prepared against accepted M1–M4 interfaces and current documents.
- [x] 2026-10-20T20:44:56+03:00 preparation: confirmed M1–M4 accepted in this plan, inspected the worktree and role configuration; stopped before dispatch because the active coordinator model/effort is not exposed for verification.
- [x] 2026-10-20T21:39:34+03:00 execution resumed: verified the active session's latest turn context as `gpt-6-sol`/`medium` in its local session record, and confirmed the four configured roles use `gpt-6-luna`/`high`; reread required project documents and inspected the actual repository. The earlier model-verification blocker is resolved.
- [x] M5.1 — implementer delivered pure public observation and full saved-peer comparison in `src/runtime.rs`, `docs/RUNTIME.md` and library export. Independent R1 review found wrong-interface acceptance and two test gaps; repairer fixed all three; fresh R2 re-review found no remaining actionable M5.1 finding. Final `cargo test --locked runtime` passed (14 matching tests, including 10 runtime-module tests; 104 library tests filtered). This is partial M5 work, not milestone acceptance.
- [x] M5.2 — after confirming `wireguard-uapi` 3.0.1's incomplete/unbounded public read API, a read-only explorer identified existing approved `rustix` `net`/`event` as a bounded transport route. Implementers delivered a checked pure decoder (`src/runtime/netlink.rs`) and nonblocking read-only socket transport (`src/runtime/transport.rs`) with synthetic/fake-I/O tests. Independent R2 and R3 reviews found three on-wire/error defects; repairer fixed all, and independent re-review closed them. Latest focused `cargo test --locked runtime` passed 29 matching tests; fmt, Clippy and diff checks passed. No host socket or real WireGuard behavior was tested; M8 remains responsible for isolated real adapter validation.
- [x] M5.3 — approved `zbus` 5.19.0 async-io adapter and pure job tracker implemented in `src/service.rs` and `src/service/dbus.rs`, with a shared monotonic deadline and signals installed before restart. Independent R1 review found alias/primary-unit mismatch; repairer resolved `GetUnit` + `Unit.Id` before restart and R2 re-review closed the finding. `cargo test --locked service::` passed 18 fake/pure tests; fmt, Clippy and diff checks passed. No system bus or real service was contacted; M9 VM acceptance remains pending.
- [x] M5.4 — `Application` now exposes saved-bound restart preview, explicit cancel/restart/discard choices and redacted stage-aware reports; backup precedes discard/submission, full technical match and one-use attempt authorization precede M4 journaled marking. SaveConfig/recovery/stale-generation checks and fake adapter tests added. Independent R1 found false “may still complete” on known terminal job failure; repairer corrected it and fresh R2 review closed the finding. Latest `cargo test --locked app` passed 33 matching tests; fmt, Clippy and diff checks passed. No host bus/interface was accessed.
- [x] M5.5 — added `tests/runtime_restart.rs` public preview/cancel/restored-settings integration tests (2 passed), private fake-adapter/clock deadline coverage in `src/app.rs` (34 app-filtered tests passed), and README/RUNTIME/PERSISTENCE documentation distinguishing synthetic M5 evidence from later real M8/M9 validation. `cargo test --locked` passed 161 library units plus 25 integration tests; fmt, Clippy and diff checks passed. Full independent integrated review remains M5.6.
- [x] M5.6 — fresh independent integrated review found six actionable API, reporting, documentation and deadline findings; repairer addressed them in two bounded rounds, and independent re-review closed all six. The reviewer found no remaining actionable scoped M5 issue. Real kernel/systemd behavior remains M8/M9 work.
- [x] M5.7 — coordinator inspected the integrated worktree, ran every planned command on the final revision, recorded results below, and accepted M5-A1–A12 for the specified synthetic/fake-adapter scope.
#### Review and repair
R1 independent reviewer findings and R2 disposition:
- M5-R1-01 (P1, `src/runtime.rs` interface observation/comparison): a peer/route
match from the wrong interface could pass. Repairer added observed interface
identity and a configured-name argument to comparison; wrong-name regression
now fails closed. R2 independently confirmed closure.
- M5-R1-02 (P2, `src/runtime.rs` test coverage): no direct invariance test for
handshake changes and counter resets. Repairer added one; R2 confirmed closure.
- M5-R1-03 (P2, `src/runtime.rs` test coverage): missing malformed-route and
structural-document subset-match regressions. Repairer added both; R2
confirmed closure.
- M5-R1-04 (blocking dependency/API limitation, M5.2): independent reviewer
confirmed `wireguard-uapi` 3.0.1 `src/linux/socket/wg_socket.rs:87-108`
loops on `iter.next()` without a deadline and uses
`while let Some(Ok(response))`, allowing a receive error after a fragment to
terminate the loop and return a partial `Device` as success. The public API
provides no completeness proof or read timeout. Secret-bearing decoded fields
can be kept private by careful consumption, but that does not fix boundedness
or completeness. An abandoned timeout thread also cannot cancel the read.
Resolution: read-only explorer verified `rustix` 1.1.5 provides public safe
AF_NETLINK/NETLINK_GENERIC socket and polling APIs when its approved direct
dependency enables `net`/`event`. It does not provide a WireGuard codec, so
M5.2 must implement a small checked decoder with explicit complete-dump and
aggregate-limit fixture tests, followed by a bounded socket transport. This
is an implementation choice within the approved dependency list, not a new
direct dependency or specification change. No unsafe fallback or
partial-success adapter is accepted; this finding remains open until tested.
- M5-R2-01 (P1, `src/runtime/transport.rs` request IFNAME encoding): the initial
builder put the NUL outside `nla_len`; repairer included it in the payload and
added exact-byte assertions. Independent R3 re-review confirmed closure.
- M5-R2-02 (P2, `src/runtime/transport.rs` family errors): type validation made
`NLMSG_ERROR` handling unreachable; repairer added checked errno mapping for
no-device, permission and transport failures and injected tests. Independent
R3 re-review confirmed closure.
- M5-R3-01 (P1, `src/runtime/transport.rs` IFNAME attribute number): initial
request used type 3 (private key) instead of kernel-defined IFNAME type 2;
repairer corrected it and added a literal numeric assertion independent of
the implementation constant. R3 reviewer follow-up confirmed closure.
- M5.3-R1 (P2, `src/service.rs`/`src/service/dbus.rs` alias correlation): the
tracker initially compared `JobRemoved.unit` to the configured literal, which
can be an alias while systemd reports the primary unit name. Repairer added
bounded read-only `GetUnit`/`Unit.Id` resolution before `RestartUnit`; the
request still targets the configured name and the terminal event must match
both primary ID and returned job path. Synthetic alias/failure/order tests
passed; fresh R2 reviewer confirmed closure.
- M5.4-R1-01 (P2, `src/app.rs` service failure report): submitted terminal
`JobRemoved` failures were incorrectly reported as possibly still completing.
Repairer distinguished terminal failure from ambiguous request/wait timeout
or disconnect while preserving submission/manual-recovery fields. Synthetic
cases for failed, dependency, timeout, canceled, skipped and unknown results
passed; fresh R2 reviewer confirmed closure.
M5-R1-04 is now resolved at the implementation-choice level with a bounded
`rustix` decoder/transport and synthetic tests; actual kernel behavior is
deferred to M8 and has not been claimed here.
Integrated review finding IDs below are prefixed `M5-I` to distinguish them
from earlier task-local reviewer IDs:
- M5-I-R1-01 (P1): a public raw systemd adapter could be called without the
mandatory application backup. Repairer made it crate-private and added a
compile-fail public-API doctest; independent R2 confirmed closure.
- M5-I-R1-02 (P1): a public domain verification setter bypassed the application
sequence. Repairer restricted it to the crate; R2 confirmed closure.
- M5-I-R1-03 (P2): runtime failures collapsed to one uninformative category.
Repairer added six redacted runtime-failure categories; R2 confirmed closure.
- M5-I-R1-04 (P2): TESTING.md incorrectly described the `wireguard-uapi` read
adapter. Repairer documented the actual approved-rustix path; R2 confirmed.
- M5-I-R2-05 (P2): expiry of the shared application deadline could be reported
as a generic runtime-read failure or mismatch. Repairer added a distinct
deadline result and deterministic before/after-read fake-clock tests; the
independent reviewer re-reviewed and closed it.
- M5-I-R2-06 (P2): RUNTIME.md called the now crate-private service adapter a
public API. Repairer corrected the boundary description; independent
re-review closed it.
The fresh integrated reviewer reported no further actionable issue against
M5-A1–A12 after the second repair round. Review and tests use synthetic state;
they do not establish real kernel or systemd/D-Bus behavior.
#### Evidence and handoff
Planning inspected current Cargo dependencies, Application backup/verification
boundaries, persistence/state schemas, backup metadata rules and M4 evidence.
M4 records independent R5 acceptance and coordinator results: 108 library unit,
9 Commit/restore, 9 preservation and 5 import tests, plus completion gates.
Those are historical recorded results; this planning task did not rerun Cargo
checks, add dependencies/source, dispatch agents or contact a system bus/VPN.
2026-10-20 preparation confirmed `.codex/config.toml` requests `gpt-6-sol`/
`medium`, all four `.codex/agents/*.toml` request `gpt-6-luna`/`high`, and the
available spawn-agent catalog lists those models and efforts. The active primary
session exposes only the GPT-6 family, not its exact model or effort; project
defaults can be overridden by a live session. Thus the mandatory coordinator
verification is incomplete. The worktree already had a user change to this
M5 description; it was preserved. `rustc`/Cargo reported 1.97.1, rustfmt
1.9.0 and Clippy 0.1.97. `git diff --check` passed before this status edit.
No M5 code, tests, dependencies, worker dispatch or acceptance checks ran during
that earlier preparation.
The active session was subsequently verified by matching `CODEX_SESSION_ID` to
its local rollout record and reading the latest `turn_context` model and effort:
`gpt-6-sol` / `medium` (2026-10-20T18:36:50.175Z). The four role files explicitly
configure `gpt-6-luna` / `high`; M5 workers will be spawned with those effective
model/effort overrides and their configured roles. This resolves the prior
configuration blocker without substituting models.
2026-10-20T21:50:55+03:00 coordinator validation of the partial integrated
revision (all exit 0): `cargo fmt --all -- --check`,
`cargo clippy --locked --all-targets -- -D warnings`, `cargo test --locked`
(118 library unit, 9 Commit/restore, 9 config-preservation and 5 vault-import
tests passed; main/doc tests 0), `cargo build --locked --release`,
`cargo test --locked runtime` (14 matching tests, of which 10 are in the runtime
module), each of the three named M4 integration targets (9/9/5 passed), release
`--help` and `--version`, and `git diff --check`. No service or runtime_restart
test target exists yet, so those planned checks were unavailable and not counted
as passing. `wireguard-uapi` and `zbus` are not in the retained manifests/lockfile.
No root, Docker, host interface, system bus, production data, Alpine or VM test
was used. Passing partial gates does not establish M5-A2 or M5-A4–A12.
2026-10-20T22:03:03+03:00 continuation: active coordinator session rollout
again showed `gpt-6-sol` / `medium`; role files still specify `gpt-6-luna` /
`high`. Worktree remained the prior partial M5 result. Read-only explorer
examined cached `wireguard-uapi`/`rustix` sources and kernel protocol docs;
no socket or production state was accessed. The chosen `rustix` route needs
checked Generic Netlink family resolution, exact sequence/DONE/error handling,
fragment coalescing, monotonic deadline and strict limits before M5-A2 can pass.
Final M5.7 validation on the integrated revision (all exit 0):
`cargo test --locked runtime` (32 matching tests),
`cargo test --locked service` (19 matching tests),
`cargo test --locked --test runtime_restart` (2),
`cargo test --locked --test commit_restore` (9),
`cargo test --locked --test config_preservation` (9),
`cargo test --locked --test vault_import` (5),
`cargo fmt --all -- --check`,
`cargo clippy --locked --all-targets -- -D warnings`,
`cargo test --locked` (163 library unit tests, 25 integration tests and one
compile-fail doctest passed; binary tests 0),
`cargo build --locked --release`, release `--help` and `--version`, and
`git diff --check`. The release binary reports that the management interface
is not implemented, as expected. Tests were unprivileged synthetic/fake-adapter
checks; no Docker, Alpine, systemd VM, host bus/interface, production path,
private key or real restart was accessed. M8 and M9 still require their own
real-system acceptance and cannot inherit a passing result from these checks.
Next action: stop after accepted M5. M6 may begin only on a separate request;
M8 Alpine and M9 disposable-VM validation remain future milestones.
M5.3 prerequisite decision: use approved `zbus` 5.19.0 with `async-io` and
default features disabled. A standard-library wake/park executor with one
monotonic deadline can bound connection setup, match-rule registration, method
calls and signal waits without an unapproved direct runtime dependency. Subscribe
and install observation before `RestartUnit`; buffer/handle a fast completion
that arrives before the method reply. Confirm real signal and alias behavior in
the disposable systemd VM at M9; fake events here are not VM evidence.
#### Decisions and discoveries
M4 verification persistence already supplies the intended durable boundary, but
its pending-backup flag is only one prerequisite. M5 must establish restart/job
and runtime evidence before invoking it and invalidate per-attempt authority.
Aliases are server metadata, not kernel data; verification must separate technical
correspondence from display/domain projection. A successful service job and a
successful durable application record are distinct stages with distinct failures.
Primary API references for implementation (check the chosen version at dispatch):
[systemd D-Bus](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.systemd1.html),
[wireguard-uapi](https://docs.rs/wireguard-uapi/latest/wireguard_uapi/), and
[zbus](https://docs.rs/zbus/latest/zbus/). These references do not pin new versions.
#### Outcome
M5.1–M5.7 are complete. Accepted for the milestone's explicitly scoped
synthetic/fake-adapter checks after independent integrated review, two repair
rounds, re-review and all planned coordinator gates. No real WireGuard or
systemd/D-Bus result is claimed; M8/M9 remain future acceptance stages. No Git
commit, deployment or production access occurred. Stop after M5; do not start M6
without a separate request.
### Milestone 6 — Client configuration delivery and reissue lifecycle
@@ -1421,14 +1847,14 @@ Acceptance: real D-Bus job handling, separate restart verification, address rele
## Current progress and resume point
- Milestones 1–4 are accepted; milestones 5–9 remain pending.
- Milestones 1–5 are accepted; milestones 6–9 remain pending.
- The approved dependency list is in [DEPENDENCIES.md](docs/DEPENDENCIES.md); container testing methodology is in [TESTING.md](docs/TESTING.md).
- Milestone 1 is expanded and the Rust environment is pinned.
- Milestone 2 delivered a lossless in-memory WireGuard configuration editor, versioned metadata, and behavioral preservation tests.
- Milestone 3 delivered secret-safe key handling, a versioned encrypted vault, caller-buffer reconciliation, and a bounded read-only source-directory import adapter.
- Milestone 4 delivered versioned private backups, journaled saved-file Commit and recovery, previewed full restore, durable address reservations and historical verification bookkeeping, with independent R5 closure and coordinator gates.
- Next action: stop after accepted M4; begin M5 only if separately requested.
- M1–M4 integrated gates and independent reviews passed. No Alpine or VM results are claimed.
- Milestone 5 delivered public runtime observations and technical comparison, an approved-rustix bounded read-only netlink adapter, a zbus systemd job adapter, restart orchestration, and synthetic integration tests. Independent integrated review and repairs closed all actionable scoped findings; all planned gates passed. Real kernel/systemd validation remains deferred to M8/M9.
- M1–M5 integrated gates and independent reviews passed. No Alpine or VM results are claimed.
## Plan maintenance