Implement client configuration delivery and reissue lifecycle

This commit is contained in:
2026-10-21 21:52:24 +03:00
parent 6ec593c783
commit f718f739b4
13 changed files with 4911 additions and 20 deletions
+397 -4
View File
@@ -1823,9 +1823,401 @@ without a separate request.
### Milestone 6 — Client configuration delivery and reissue lifecycle
Generate full-tunnel IPv4/IPv6 configurations using settings and preserved existing parameters where applicable. Save a root-only plaintext file and optionally render a matching QR code. Enforce post-Commit initial delivery and per-client password-based reissue with session-scoped retry after file errors.
Status: accepted (2026-10-21T21:50:26+03:00; independent integrated re-review closed findings and all scoped M6.7 gates passed).
Prerequisites: milestones 1–5 accepted; pinned native Rust environment and
compatible approved dependencies. Validation uses generated keys, synthetic
saved stores and temporary output directories without root, a terminal, Docker,
production inputs or any actual runtime/service call.
Acceptance: file/QR payloads agree; no delivery before Commit; output failure permits directory change/retry; successful initial delivery or session exit ends password-free eligibility; overwrite requires confirmation; unrelated plaintext imports cannot bypass authentication.
#### Outcome and scope
Deliver testable application/library operations to create a new client with a
session-held private key, Commit its encrypted record and server entry, save its
plaintext WireGuard configuration after Commit, and optionally produce a QR code
for the same delivery. Subsequent issuance requires a fresh password per selected
client. Output errors permit changing the destination and retrying initial
issuance during the current creation session without password entry.
Read SPEC.md New client parameters, Encrypted vault, Connection delivery,
Importing existing clients and Operations and states; ADRs 0001–0003;
VAULT_FORMAT.md, CONFIG_FORMAT.md, PERSISTENCE.md, RUNTIME.md, DEVELOPMENT.md,
DEPENDENCIES.md, TESTING.md and the current Application/VaultBundle code.
Out of scope: TUI/password entry widgets, rendering live terminal screens,
plaintext source-file fallback, automatic key rotation/reconciliation, adding
connection settings, runtime mutation, automatic restart, actual phone/client
import, Alpine harness and VM tests. Keep startup safely incomplete. Generation
and saving an output file do not apply configuration to WireGuard.
#### Existing code and integration constraints
- `Application::add_client` currently accepts a prepared public `Client` and edits
server/domain drafts. It does not generate or own a private key or authorize
first delivery. Add a coordinated creation operation rather than treating any
existing/imported public key as eligible for password-free output.
- `WireGuardPrivateKey::generate`, `public_key`, and explicit Base64 exposure
exist. `VaultBundle::encrypt_record` encrypts a new key using the recipient,
while `retrieve_client_record` returns short-lived retained connection fields
only after password-based decryption and authenticated conflict checks.
- New-key records currently have no retained client parameters. Build their
configuration from authoritative saved peer addresses and current saved
application settings, not empty record defaults. Imported records can contain
DNS/MTU/endpoint/routes/keepalive/PSK; preserve supported existing parameters
rather than silently converting every imported client to a new default template.
- `RetrievedClientRecord` exposes its key and optional preshared key explicitly
and redacts Debug; do not turn it into a globally cached unlocked vault or add a
password-free retrieval API to work around first-delivery state.
- `Application::commit` saves staged document/vault/state only after backup and
journaled installation succeeds. `delete_client`, `discard_draft`, restore,
saved settings and restart choices can affect delivery eligibility. Integrate
with these transitions without regressing M4/M5 or bypassing recovery-required
handling. `Application::document()` is a draft; output must use committed bytes.
- M5 observes public technical runtime fields and does not supply a trusted server
private key for generation. Derive the server public key from the authoritative
saved `[Interface] PrivateKey` through existing X25519 code, in a narrow secret
boundary, or use an already validated authoritative derivation if available.
Missing/ambiguous/invalid server identity blocks output rather than guessing or
reading another file/interface. Never print or serialize the server private key.
- Cargo already contains the key/crypto, file-safety and time dependencies.
Approved `qrcode` may be added with minimal features (no image/SVG output needed).
No decoder, image, CLI, TUI, random, hash or new helper crate is implicitly
approved. Check official APIs/version compatibility before adding the crate.
#### Context and implementation steps
Run bounded tasks sequentially, one writer at a time. GPT-6-Sol/medium coordinates;
GPT-6-Luna/high implements, independently reviews and repairs. Dispatch file
ownership, prerequisite interfaces, acceptance IDs and actual required checks.
Only the coordinator updates milestone acceptance and evidence in PLANS.md.
| Task | Owner | Files and deliverable |
| --- | --- | --- |
| M6.1 | implementer | `src/delivery.rs` and child modules as needed, library exports, `docs/DELIVERY.md`: secret-safe payload model and deterministic configuration generation |
| M6.2 | implementer | `src/app.rs`, narrow delivery/domain integration: coordinated new-client creation and session-scoped first-issue state |
| M6.3 | implementer | delivery/files module, existing safe filesystem helpers: file preparation, explicit overwrite confirmation, secure output and retry results |
| M6.4 | implementer | delivery/QR module, Cargo files, app integration: optional matrix/text output bound to the same authorized payload/file action |
| M6.5 | implementer | `tests/client_delivery.rs`, focused unit tests and README/DELIVERY guidance: full first-issue/reissue and failure lifecycle |
| M6.6 | reviewer, repairer | Independent integrated review, bounded findings repair and re-review |
| M6.7 | coordinator | Integrated validation, evidence ledger and scoped acceptance/handoff in PLANS.md |
M6.1 renders a deterministic standard WireGuard client file: `[Interface]` with
client private key, saved addresses and DNS; `[Peer]` with server public key,
endpoint and routes. New clients have IPv4/IPv6 and routes `0.0.0.0/0, ::/0`,
using the configured template and authoritative saved host addresses. Define the
client Address prefix policy explicitly, keeping host identity separate from
server-side AllowedIPs; do not infer client addresses from the public endpoint.
No new MTU, keepalive or PSK defaults are introduced.
For imported reissue, retain validated existing optional fields and IPv4-only
shape where applicable. Never execute or copy hooks/unknown arbitrary directives
from source configs. Validate decrypted fields again at rendering boundaries so
newlines/control text cannot inject sections/directives. Compare retained identity
and addresses/server binding with fresh saved authoritative values; a stale or
mismatched record fails closed instead of silently regenerating a different
connection. Respect authenticated reissue_blocked, missing server/file-only cases,
and M2 unsupported projection without truncating routes to get a valid output.
Document precedence between saved server state, application defaults for new
clients, and retained imported fields; do not invent a conflict-resolution UI.
Keep plaintext payloads in explicitly exposed, short-lived zeroizing owners,
redacted Debug/errors and no generic Serialize/Display. Raw source/client output
is never an ordinary status object. Bound payload size. Passwords, encoded private
keys and rendered files must not appear in logs, panic output, snapshots or test
failure diagnostics. Document unavoidable encoding/QR-library copies honestly.
M6.2 coordinates address selection, key generation, server/client draft insertion,
vault encryption and temporary first-issue tracking as one preparation. Use M1
allocation/reservations and optional manual selection; reuse M2 edits and M3 key
matching. Failure at any preparation step leaves prior draft and eligibility
unchanged. Existing vault setup may require its initial password separately;
creating additional clients in an existing vault does not request that password.
Define an internal lifecycle such as pending-draft, committed-awaiting-first-file,
and issued/invalidated, keyed by PublicKey and actual creation/committed record
context rather than alias, UI row, or historical public-key presence. Store no
first-issue private key, password, or eligibility in settings, internal state,
backup, vault plaintext fields or recovery journal. Session state is not recreated
by reopen/restore/import. A failed/incomplete Commit cannot promote eligibility.
Unrelated valid commits/renames must not accidentally authorize another key or
consume an unused first issue; compare the relevant saved client/record context.
Discard/delete/restore/reopen/session end and any relevant key/record replacement
invalidate stale pending material. Define transition timing so cancellation and
failed backup/pre-install validation preserve unchanged work, while a successful
replacement or unresolved partial persistence cannot retain unsafe output authority.
A confirmed restart applying an unchanged saved client must not require a password
merely because runtime state changes. Do not conflate access activation with the
first-output permission. Successful saved deletion revokes output authorization
immediately, even if the old runtime peer remains active until restart.
M6.3 prepares destination selection without writing, then requires explicit
confirmation if a file exists. Never derive a path directly from an alias that
may repeat or contain separators; use a safe suggested filename and explicit
selected destination. Reject symlink/special-file destinations and unsafe ancestor
traversal; do not overwrite internal application files, server config, vault,
settings, journal or backups as a client output. Output goes only to the chosen
location; no directory-wide chmod/deletion or source-file cleanup.
Use secure temporary/staged writes, mode 0600 from creation, complete flush/sync,
atomic publication and parent sync as appropriate. New-file publication must not
silently replace a file; overwrite requires a confirmed bounded action for that
destination. Document behavior if failure follows publication (for example parent
sync failure): the file may already exist and must be reported honestly, with
explicit confirmation on retry, not claimed absent or automatically removed.
Output failure before confirmed success preserves retry eligibility for the same
initial client in the current session, allowing a different directory. A normal
plaintext file must be saved for every delivery action; QR-only success is not
allowed. Success consumes initial eligibility and drops the cached private key.
Later file/QR issuance for that client requires a fresh password. Password reissue
is per action/client, not session-wide vault unlocking; wrong password, conflict
or missing key has no source-file bypass. Retries may keep only bounded
operation-local material, never a reusable unlocked identity across unrelated actions.
M6.4 generates an optional QR from the exact bytes saved in that delivery action,
using qrcode's matrix/public rendering API without PNG/image features or external
qrencode. Support a future terminal renderer through a matrix/controlled text
representation with quiet zone and documented dimensions. Keep secret-bearing
matrix/text out of Debug, snapshots and ordinary progress messages. Do not expose
an unguarded second QR path that reconstructs private material from cached state.
One authorized action may include both file and QR; showing that same prepared
QR does not require a second password. If QR encoding exceeds capacity or fails,
the file can still be successfully delivered: report file success and QR failure
separately, consume first-issue eligibility, and do not report a total failure
that misleadingly permits another first file. A later new QR/delivery action then
requires password authorization. A future TUI displays/clears the operation-local
QR; terminal lifecycle implementation remains M7.
M6.5 covers complete library flows with private temporary stores and generated
synthetic keys. Use fault-injected file writes and unit-tested authorization
transitions, not privileged filesystem behavior. Assert file content through
redacted comparisons/parsed public values and explicit key correspondence without
printing secrets. Reuse M3 parsing for compatible generated files to demonstrate
identity/server/routes semantics. File/QR equality should be guaranteed by a
single payload source and tested at the encoding boundary; do not claim external
QR decoding/real-device compatibility unless actually checked or add a decoder
crate without approval.
#### Acceptance and validation
- [x] M6-A1: new clients yield valid full-tunnel dual-stack configurations using
committed addresses/settings and a correctly derived server key; missing or
ambiguous authoritative identity fails without guessing or exposing secrets.
- [x] M6-A2: imported reissue preserves supported existing optional parameters
and IPv4-only shape; stale identity/address/server bindings, authenticated
conflict flags and unsupported data block unsafe delivery without truncation.
- [x] M6-A3: coordinated creation stages a matching public client and encrypted
key; failed preparation leaves prior drafts intact. No output is authorized
before successful Commit or from an imported/existing key without a password.
- [x] M6-A4: failed/incomplete Commit does not promote first issue; a successful
Commit permits first output for the newly created client in that session.
Draft discard/delete/restore/reopen and record replacement cannot restore or
transfer stale eligibility; duplicate aliases remain independent by public key.
- [x] M6-A5: failed file save supports same-session retry/new directory without
password for initial issuance; success consumes eligibility. Reissue requires
fresh per-client authorization with no cached identity/plaintext-file fallback.
- [x] M6-A6: mandatory plaintext file creation uses 0600 from first write, safe
paths, bounded payloads, explicit overwrite confirmation and honest partial-
publication failure reporting; protected application/source files stay untouched.
- [x] M6-A7: optional QR uses the exact same payload as the saved file; QR failure
does not erase file success or grant another first issue. No independent QR-only
bypass or retained cross-action secret cache exists.
- [x] M6-A8: outputs warn when saved changes are not verified applied. Unavailable
runtime is not silently treated as active; delivery never invokes service or
WireGuard operations, releases reservations or changes apply history.
- [x] M6-A9: rendering/input injection, wrong password, missing vault/record,
duplicate/conflicting metadata, occupied/manual address failures, overwrite
decline, symlink/special paths, and write/flush/publication/sync failures are tested.
- [x] M6-A10: secret-bearing types, errors/Debug and tests do not disclose keys,
passwords, configuration payloads or QR matrices; ephemeral material is never
persisted in backup/journal/state and supported owned buffers clear on drop.
- [x] M6-A11: M1–M5 regressions and integrated gates pass unprivileged with no real
network, system bus, runtime, production paths or terminal required. Independent
review closes actionable auth-lifecycle/rendering/output-safety findings.
Planned commands from the repository root after M6 targets and lockfile exist:
```sh
cargo test --locked delivery
cargo test --locked --test client_delivery
cargo test --locked --test runtime_restart
cargo test --locked --test commit_restore
cargo test --locked --test vault_import
cargo test --locked --test config_preservation
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 focused filters run actual tests. Resolve approved qrcode and update
Cargo.lock before locked checks; do not add Ratatui/Crossterm prematurely. Record
commands, counts and exit results. All commands should exit zero; negative cases
are passing assertions. No phone QR scan, real tunnel, terminal screenshot, Alpine
or systemd result is required or claimed for this library/file-output milestone.
#### Progress
- [x] Description prepared against accepted M1–M5 code and current documents.
- [x] 2026-10-20T23:12:02+03:00 execution preparation: verified active coordinator `gpt-6-sol`/`medium` in this session's latest turn context and project worker roles `gpt-6-luna`/`high`; confirmed M1–M5 accepted, read required specification, ADRs and supporting documents, and inspected the clean source baseline. The pre-existing expanded M6 plan edit in this worktree is preserved.
- [x] M6.1 — implementer delivered bounded, zeroizing payload rendering in `src/delivery.rs`, library export and `docs/DELIVERY.md`, with new-client and authenticated-import paths. Independent R1 found an unchecked caller-supplied server identity; repairer moved derivation to the saved `[Interface] PrivateKey` boundary and added malformed/missing/ambiguous cases. Independent re-review closed M6.1-R1. Final focused `cargo test --locked delivery::tests` passed 7 tests; fmt, Clippy and diff checks passed. Fixture evidence only; no file/QR or host behavior claimed.
- [x] M6.2 — implementer added transactional dual-stack creation and encrypted vault staging, plus session-only first-file state in `src/app.rs` and a narrow encrypted-record context accessor in `src/vault.rs`. Independent R1 identified duplicate live authorizations; repairer made issuance single-flight with explicit retry states, and re-review closed it. The same reviewer identified stale standalone plaintext after app mutation; second repair moved output behind an app-owned `deliver_first_issue` closure holding the mutable session borrow, and re-review closed it. Final `cargo test --locked app::tests::` passed 41 synthetic tests; fmt, Clippy and diff checks passed. M6.3 still must connect actual file results to these states.
- [x] M6.3 — implementer added secure file-output adapter in `src/delivery/files.rs`, app first-issue bridge, narrow SavedStore protected-path accessor and documentation. Initial focused `cargo test --locked delivery` passed 16 and `cargo test --locked app` passed 47; fmt, Clippy and diff checks passed. Fresh independent review found two actionable findings (M6.3-R1/R2 below). Three targeted repair rounds and independent re-review closed both under the documented single-administrator threat model; final focused `cargo test --locked delivery` passed 20 and file-module tests passed 12; fmt, Clippy and diff checks passed. No production filesystem behavior is claimed.
- [x] M6.4 — implementer added approved `qrcode` 0.14.1 with default features disabled, bounded/zeroizing operation-local matrix representation, file-first optional QR integration and focused tests. Initial `cargo test --locked delivery` passed 22 and `cargo test --locked app` passed 51; fmt, Clippy and diff checks passed. Independent R1 found a public QR-only encoder path; repairer made it crate-private with a compile-fail doctest, and independent re-review closed the finding. Final focused delivery (22) and doctests (2) passed. No phone scan or terminal rendering is claimed.
- [x] M6.5 — implementer added fresh password-per-action reissue from installed vault bytes, validated authenticated key-only/imported provenance, a live-generation activation warning, five public synthetic lifecycle tests in `tests/client_delivery.rs`, and README/DELIVERY guidance. Initial focused integration (5), delivery (22), app (51) and partial-provenance regression (1) passed with fmt, Clippy and diff checks. Fresh independent review found first-issue outputs omitted the activation warning. Repairer added it to file-only, file+QR and definite-publication/bookkeeping-uncertain results; re-review found uncertain file publication still omitted it, so a second repair added warning to failed outcomes and injected file-only/QR uncertainty tests. Independent re-review closed the finding. At M6.5 closure, `cargo test --locked app::` passed 50 and `--test client_delivery` passed 5; fmt, Clippy and diff checks passed. Integrated gates ran later in M6.7.
- [x] M6.6 — a fresh independent integrated reviewer inspected M6-A1–A11 and found three actionable issues: secret-bearing assertion diagnostics, optional imported server-key binding in the public renderer, and unreported temporary-file cleanup failure. Repairer fixed all three; independent re-review closed them with no new actionable issue. The reviewer found M6-A1–A10 supported by scoped synthetic evidence and left M6-A11 pending coordinator integrated gates.
- [x] M6.7 — coordinator ran every planned command against the integrated revision, verified all exit zero and nonempty focused test filters, checked changed files and reviewer evidence, and accepted M6-A1–A11 for the explicitly scoped fixture/file-output milestone. No real WireGuard, systemd, terminal or phone scan is claimed.
#### Review and repair
M6.1-R1 (P2, `src/delivery.rs`): the initial renderers accepted a caller-supplied
server public key without proving it came from the saved server configuration;
the initial valid-looking test even used a different key. Repairer made both
renderers derive it from exactly one valid saved `[Interface] PrivateKey`, reject
missing/duplicate/malformed sources with a redacted error, and compare imported
retained identity to that key. Synthetic regression tests passed (7 focused);
the independent reviewer re-reviewed and closed the finding.
M6.2-R1 (P2, `src/app.rs`): two outstanding first-issue capabilities could
both expose plaintext before either was consumed. Repairer made authorization
single-flight/token-bound and added explicit pre-publication versus uncertain-
publication retry handling. The independent reviewer closed this part after
focused tests.
M6.2-R2 (P2, `src/app.rs`): invalidating a standalone token after deletion or
replacement did not revoke a caller-held plaintext payload. Repairer removed
that accessor and introduced an app-owned publication closure that validates
saved peer/record context immediately before the file writer runs while holding
`&mut Application`; stale deletion/replacement tests show the closure is not
invoked. Independent re-review closed the finding. The real file adapter is
still M6.3 work, not evidence from these synthetic closures.
M6.3-R1 (P2, `src/delivery/files.rs`): a confirmed overwrite rechecked the
destination inode before `renameat`, but another entry could replace it between
the check and publication and then be overwritten without confirmation. The
independent reviewer supplied a deterministic `Checkpoint::Publish` substitution
reproducer. Repairer changed confirmed replacement to atomic `RENAME_EXCHANGE`,
checks the displaced inode and rolls back without deleting unexpected entries;
rollback identity and parent sync failures report uncertainty. A later re-review
found the normal-success temp-name unlink still vulnerable to a different local
writer. Final repair requires a selected parent owned by root/current effective
user without group/world write, checks existing ancestors, and uses an exclusive
0600 temporary name with 128 bits of OS randomness. Independent re-review closed
R1 under the single-administrator threat model. Same-privilege concurrent name
changes remain explicitly outside scope; temporary 0600 output retained after a
rollback is documented for manual cleanup rather than risking deletion of an
unconfirmed entry.
M6.3-R2 (P2, `src/app.rs`): after a definite file publication, a fallible
post-publication saved-state read/mark could return an undifferentiated app error,
concealing that a plaintext file was already created. The independent reviewer
requested an explicit published-but-bookkeeping-uncertain result and fault test.
Repairer added `PublishedButBookkeepingUncertain` with definite file-success
evidence and invalidated the session-held first-issue key on bookkeeping failure.
The independent reviewer closed R2 after a synthetic post-publication saved-store
failure test. No password-free retry is authorized by that result.
M6.4-R1 (P2, `src/delivery/qr.rs`): a public QR encoder allowed a library caller
to render a payload and generate a QR without the mandatory file action.
Repairer restricted the encoder and module to crate visibility, kept public
output/error value types for the guarded app result, and added a compile-fail
doctest. Independent re-review closed the finding after file-first and
QR-failure tests. QR scanning and terminal rendering remain unverified/future.
M6.5-R1 (P2, `src/app.rs`): initial file-only and file-plus-QR delivery did
not report whether the saved client had been verified active. Repairer bound an
activation warning to the exact installed generation and the live verified
saved/applied snapshot, never the historical timestamp. Re-review found the
possibly-published parent-sync failure still lost the warning; second repair
carried it in the failed outcome and tested uncertain publication for both
variants with QR skipped. Independent re-review closed R1. All evidence is
synthetic/fault-injected, not live VPN or device compatibility.
M6.6-R1 (P2, `src/app.rs` tests): `assert_eq!` on saved and rendered client
configuration bytes could print a private key if a test failed. Repairer changed
those to boolean assertions and audited related tests. Independent integrated
re-review closed this secret-diagnostic finding.
M6.6-R2 (P2, `src/delivery.rs`/`src/vault.rs`): the public imported renderer
accepted a missing saved-server binding from a mutable retrieved record.
Repairer made retained fields private/read-only, required imported provenance and
an exact present saved-server binding, and added missing/stale binding tests.
Independent integrated re-review closed it.
M6.6-R3 (P2, `src/delivery/files.rs`/`src/app.rs`): ignored temp-file cleanup
errors could leave a plaintext 0600 staging file while reporting an ordinary
pre-publication failure. Repairer added a distinct `ManualCleanupRequired`
result, retry gating until explicit cleanup acknowledgement, documentation and
an injected cleanup-failure test confirming no selected-file publication.
Independent integrated re-review closed it. The user may still need to inspect
and remove a retained staging file; the application does not silently erase an
uncertain entry.
All actionable M6 task-local and integrated review findings are closed after
repair and independent re-review. The integrated reviewer found M6-A1–A10
supported by synthetic/fault-injected evidence; M6-A11 then passed the
coordinator's final integrated gates. No password check was weakened and no
preservation test was disabled.
#### Evidence and handoff
Initial planning inspected current Application creation/Commit/discard/restart interfaces,
VaultBundle key-only encryption and password-authorized retained fields, current
Cargo dependencies, M5 acceptance record and runtime documentation, plus product
specification/secret-storage ADR. M5 records scoped fixture acceptance and passing
integrated gates with independent re-review; real kernel/systemd checks remain
M8/M9. That planning-only turn did not rerun application tests, add crates/source, generate
private keys/output/QR, dispatch agents or contact host runtime/services.
Final M6.7 validation on the integrated revision (all exit 0):
`cargo test --locked delivery` (23 matching tests),
`cargo test --locked --test client_delivery` (5),
`cargo test --locked --test runtime_restart` (2),
`cargo test --locked --test commit_restore` (9),
`cargo test --locked --test vault_import` (5),
`cargo test --locked --test config_preservation` (9),
`cargo fmt --all -- --check`,
`cargo clippy --locked --all-targets -- -D warnings`,
`cargo test --locked` (205 library unit, 30 integration and two doctests passed;
binary tests 0), `cargo build --locked --release`, release `--help` and
`--version`, and `git diff --check`. Release `--help` correctly states the
management interface is not implemented. Checks used synthetic keys,
temporary stores/output directories and fake adapters without root, Docker,
host WireGuard/system bus, production paths or a terminal. The approved
`qrcode` 0.14.1 was added with default features disabled; no other direct
dependency was introduced. No phone QR scan, live tunnel, Alpine test or
disposable systemd VM result is claimed. Those validations remain future
M7–M9 work, not passing M6 evidence.
Next action: stop after accepted M6. M7 may begin only on a separate request;
do not create a Git commit or deploy.
#### Decisions and discoveries
New vault records contain a key but no template parameters, while imported
records retain supported connection fields. Delivery needs an explicit provenance
and precedence rule rather than assuming both are interchangeable. Creation must
retain ephemeral private material separately from password-only vault retrieval;
otherwise first delivery without a password is impossible. That ephemeral
material cannot be persisted or reconstructed after session loss.
M5 applies saved state and M6 exports saved state; neither should call the other
implicitly. File and QR are two representations of one authorized delivery action,
with file success as the first-issue completion boundary. M7 supplies the terminal
interaction around these library contracts.
#### Outcome
M6.1–M6.7 are complete. Accepted for the milestone's explicitly scoped
synthetic/file-output checks after independent integrated review, repair,
re-review and all planned coordinator gates. The TUI, phone compatibility,
real WireGuard and actual systemd/D-Bus behavior are not claimed; M7–M9 own
their later acceptance. No Git commit, deployment or production access occurred.
Stop after M6; do not start M7 without a separate request.
### Milestone 7 — Complete terminal management workflow
@@ -1847,14 +2239,15 @@ Acceptance: real D-Bus job handling, separate restart verification, address rele
## Current progress and resume point
- Milestones 1–5 are accepted; milestones 6–9 remain pending.
- Milestones 1–6 are accepted; milestones 7–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.
- 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.
- Milestone 6 delivered session-bound creation/first-file authorization, saved-state rendering and password-per-action reissue, secure plaintext file output, optional same-payload QR, and synthetic lifecycle tests. Independent integrated review and repair closed all actionable findings; all planned gates passed. TUI and real-system validation remain M7–M9.
- M1–M6 integrated gates and independent reviews passed. No Alpine or VM results are claimed.
## Plan maintenance