Refactor acceptance and architecture handoff

This commit is contained in:
2026-10-30 23:30:16 +02:00
parent 7123197ec4
commit 4c86472740
11 changed files with 314 additions and 164 deletions
+2 -1
View File
@@ -36,7 +36,8 @@ unavailable; they do not imply zero traffic or successful application.
**Reserved address**: **Reserved address**:
An address retained so that it cannot be assigned to another client while a An address retained so that it cannot be assigned to another client while a
deleted peer may still exist on the running interface. It is released only deleted peer may still exist on the running interface. It is released only
after the saved peer set is successfully verified as applied. after a confirmed restart has verified the complete saved peer set and the
verification state has been durably saved.
**First delivery**: **First delivery**:
The one-time, password-free delivery of a newly created client's connection The one-time, password-free delivery of a newly created client's connection
+12 -12
View File
@@ -136,7 +136,7 @@ Each row is a delivery milestone, not a completion claim. Expand its record befo
| 24 | Session-owned first delivery and password reissue scenarios | 23 | accepted | | 24 | Session-owned first delivery and password reissue scenarios | 23 | accepted |
| 25 | Explicit restart verification scenario | 24 | accepted | | 25 | Explicit restart verification scenario | 24 | accepted |
| 26 | Application read models and thin TUI command adapter | 25 | accepted | | 26 | Application read models and thin TUI command adapter | 25 | accepted |
| 27 | Integrated refactoring acceptance and architecture handoff | 26 | pending | | 27 | Integrated refactoring acceptance and architecture handoff | 26 | accepted |
### Milestone 1 — Rust foundation, settings, and domain states ### Milestone 1 — Rust foundation, settings, and domain states
@@ -4130,7 +4130,7 @@ Focused commands `cargo test --locked tui::` (88), `--test tui_workflow` (9), `-
### Milestone 27 — Integrated refactoring acceptance and architecture handoff ### Milestone 27 — Integrated refactoring acceptance and architecture handoff
Status: pending. Prerequisite: M26 accepted. Status: accepted (2026-10-30T23:21:10+02:00; independent R1–R4 re-review, A4 evidence check and final integrated Rust gates passed). Prerequisite: M26 accepted. Initial tree clean at `7123197`; pinned Rust/Cargo 1.97.1, rustfmt 1.9.0 and Clippy 0.1.97 verified. This session's coordinator GPT-6-Sol/medium was user-confirmed; project configuration and explicit M27 worker dispatch selected GPT-6-Luna/high. M1–8 and M10–26 are accepted; M9 remains retired/unaccepted by user direction and is not a prerequisite.
#### Outcome and scope #### Outcome and scope
@@ -4138,9 +4138,9 @@ Verify the integrated refactoring against the original behavior map and demonstr
| Task | Owner | State | Bounded deliverable | | Task | Owner | State | Bounded deliverable |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| M27.1 | implementer | pending | Remove proven-obsolete compatibility paths and reconcile architecture map | | M27.1 | implementer `/root/m27_implement` | complete | Reconciled architecture map, reading guide, glossary and layout; caller audit retained active fixture APIs; DOC checks passed; no Rust edits |
| M27.2 | independent reviewer | pending | Integrated behavior/authority/security/readability audit | | M27.2 | fresh reviewer `/root/m27_review` | complete | A2 passed on source inspection; M27-R1/R3 actionable documentation/comment findings and R2 plan consistency finding recorded |
| M27.3 | repairer; reviewer; coordinator | pending | Bounded repairs, final integrated gates and handoff | | M27.3 | repairer `/root/m27_repair`; reviewer; coordinator | complete | R1–R4 closed; six focused suites, final RUST gates and independent A4 evidence/plan check passed |
1. Compare every M19 source/test mapping with actual final owners. Remove obsolete forwarding APIs only after checking all binary, library, integration and container-driver callers. Remove stale milestone comments that incorrectly describe implemented paths as future work. Do not delete historical evidence or turn old verification limitations into new success claims. 1. Compare every M19 source/test mapping with actual final owners. Remove obsolete forwarding APIs only after checking all binary, library, integration and container-driver callers. Remove stale milestone comments that incorrectly describe implemented paths as future work. Do not delete historical evidence or turn old verification limitations into new success claims.
2. Record a concise reading guide for create -> Commit -> first delivery -> explicit restart, delete -> Commit -> verified address release, and preview -> confirm restore. For each, name the entry point, rule owner, side-effect boundary and failure tests. A reviewer must be able to follow the scenario without discovering hidden UI authorization or independent metadata authority. Record justified exceptions instead of hiding them behind a size metric. 2. Record a concise reading guide for create -> Commit -> first delivery -> explicit restart, delete -> Commit -> verified address release, and preview -> confirm restore. For each, name the entry point, rule owner, side-effect boundary and failure tests. A reviewer must be able to follow the scenario without discovering hidden UI authorization or independent metadata authority. Record justified exceptions instead of hiding them behind a size metric.
@@ -4150,16 +4150,16 @@ Verify the integrated refactoring against the original behavior map and demonstr
#### Acceptance and validation #### Acceptance and validation
- [ ] M27-A1: all M19 mappings resolved to actual owners/tests; glossary/layout/reading guide agree with code; obsolete bypasses removed or explicitly justified. - [x] M27-A1: all M19 mappings resolved to actual owners/tests; glossary/layout/reading guide agree with code; obsolete bypasses removed or explicitly justified.
- [ ] M27-A2: integrated independent audit finds no unresolved behavior, authority, authorization or secret-handling regression. - [x] M27-A2: integrated independent audit finds no unresolved behavior, authority, authorization or secret-handling regression.
- [ ] M27-A3: preserved-format synthetic fixtures and all required host RUST gates pass on final source; exact outcomes and separate Alpine/VM limitations recorded. - [x] M27-A3: preserved-format synthetic fixtures and all required host RUST gates pass on final source; exact outcomes and separate Alpine/VM limitations recorded.
- [ ] M27-A4: milestone register, outcomes and current resume point agree; evidence contains reproducible source identity and final review disposition. - [x] M27-A4: milestone register, outcomes and current resume point agree; evidence contains reproducible source identity and final review disposition.
Evidence: docs/evidence/milestone-27.md. Outcome: not accepted. Handoff: stop after scoped acceptance; no subsequent milestone is authorized by this plan. Review and repair: independent M27-R1 (missing `display_projection` caller audit), R2 (stale resume point), R3 (implemented paths described as future) and R4 (fixture-only public backup API) were repaired and re-reviewed. R4's first repair exposed a Clippy dead-code child helper; the bounded follow-up made both levels test-only, and final Clippy/full gates passed. Independent reviewer confirmed A4 after verifying evidence hashes, artifact, gates and plan consistency. [M27 evidence](docs/evidence/milestone-27.md) records source identity, exact host results and Alpine/VM limits. Outcome: accepted for host/synthetic refactoring scope. Handoff: stop after M27; no subsequent milestone is authorized by this plan.
## Current progress and resume point ## Current progress and resume point
- M26 is accepted for host/synthetic scope: app-owned secret-free facts and per-action eligibility drive TUI presentation, while the command adapter owns prepared contexts and the worker keeps generation/lifecycle control. Independent R1–R4 closure and required Rust gates passed. [M26 evidence](docs/evidence/milestone-26.md) records final inputs and limits. M27 remains pending; M9 remains retired/unaccepted and its real-system limitations remain unchanged. - M27 is accepted for host/synthetic refactoring scope after independent R1–R4 closure, six focused suites, final Rust gates and A4 evidence/plan verification. [M27 evidence](docs/evidence/milestone-27.md) identifies tested source and limitations. Stop here; no next milestone or deployment is authorized. Current Alpine revalidation and disposable-VM systemd checks remain incomplete; M9 remains retired/unaccepted.
- M18 was accepted on 2026-10-29: structured, accurate in-app Help, responsive wrapping and bounded scrolling passed independent R1/R2 closure, synthetic/PTY checks and pinned Rust completion gates. [M18 evidence](docs/evidence/milestone-18.md) records final inputs and limits. At that handoff, M19 had not started. - M18 was accepted on 2026-10-29: structured, accurate in-app Help, responsive wrapping and bounded scrolling passed independent R1/R2 closure, synthetic/PTY checks and pinned Rust completion gates. [M18 evidence](docs/evidence/milestone-18.md) records final inputs and limits. At that handoff, M19 had not started.
@@ -4188,7 +4188,7 @@ Evidence: docs/evidence/milestone-27.md. Outcome: not accepted. Handoff: stop af
- Milestone 8 delivered reviewed opt-in Alpine Testcontainers coverage for real IPv4 WireGuard peers, application lifecycle, saved/runtime separation, restoration, import/reissue, backup failures and the real Rustix reader. Host gates and three fresh real-container runs passed on one stable source fingerprint; M8-A1–A10 accepted. Real IPv6 behavior is unverified by user-authorized scope. - Milestone 8 delivered reviewed opt-in Alpine Testcontainers coverage for real IPv4 WireGuard peers, application lifecycle, saved/runtime separation, restoration, import/reissue, backup failures and the real Rustix reader. Host gates and three fresh real-container runs passed on one stable source fingerprint; M8-A1–A10 accepted. Real IPv6 behavior is unverified by user-authorized scope.
- Milestone 9 is retired and unaccepted: the reviewed disposable VM preparation and guarded first start did not establish Debian/systemd acceptance. The exact VM was powered off after the user stopped work. M9.2–M9.3 were not started; M9-A1–A9 are unchecked. - Milestone 9 is retired and unaccepted: the reviewed disposable VM preparation and guarded first start did not establish Debian/systemd acceptance. The exact VM was powered off after the user stopped work. M9.2–M9.3 were not started; M9-A1–A9 are unchecked.
- M18–M26 handoffs remain complete. Stop after M26; begin M27.1 only on a separate request. Keep M16 validation limitations separate from TUI evidence. Do not access production, commit, deploy or resume VM work. - M18–M27 handoffs are complete. Stop after M27 acceptance; no next milestone is authorized. Keep M16 validation limitations separate from TUI evidence. Do not access production, commit, deploy or resume VM work.
## Plan maintenance ## Plan maintenance
+85 -57
View File
@@ -1,19 +1,13 @@
# Project Layout # Project Layout
Read this document when creating or reorganizing modules. The layout below This is the integrated package layout after M26. Paths below exist in the
reflects the current package; sections marked planned describe later test and repository; scenario descriptions name current owners. Add modules when a
integration work only. cohesive responsibility needs them, not as placeholders.
## Target project layout The repository has one Cargo package with a binary (`src/main.rs`) and a library
(`src/lib.rs`). Startup and process exit remain in `main.rs`; testable
The repository has one Cargo package with a binary (`src/main.rs`) and a application logic and the TUI are library modules. The library target is not a
library (`src/lib.rs`). Startup and process exit remain in `main.rs`; testable separately published package.
application logic and the management TUI are library modules. A library target
does not require publishing a separate library package. Introduce a workspace
only when independently reusable or separately built components justify it.
Implemented modules include the following. Add modules as implementation
requires them; do not generate empty scaffolding for future integration work.
```text ```text
Cargo.toml Cargo.toml
@@ -23,64 +17,98 @@ AGENTS.md
CONTEXT.md CONTEXT.md
PLANS.md PLANS.md
README.md README.md
.gitignore
src/ src/
main.rs # Startup, arguments, process exit main.rs # Startup, arguments, process exit
lib.rs # Module declarations and application API lib.rs # Library modules; test-only container driver gate
config.rs # Application settings and path resolution startup.rs # Root boundary, settings/store loading, session entry
domain.rs # Clients, identities, address allocation/reservations, change states config.rs # Settings validation and executable-relative paths
app.rs # Application operations and orchestration domain.rs # Client projection, address allocation/reservations, apply knowledge
app.rs # Application facade, session, and public operation types
app/ app/
draft.rs # Coordinated in-memory document, client-state, and vault drafts draft.rs # Coordinated document/client/vault draft replacements
first_delivery.rs # Session-local first-issue authorization and retry state first_delivery.rs # Session-local one-use capability and retry state
first_file.rs # Password-free first-file and optional QR scenario first_file.rs # First-delivery file and optional QR scenario
reissue.rs # Password-per-action saved-client reissue
read_model.rs # Secret-free application facts and per-action eligibility read_model.rs # Secret-free application facts and per-action eligibility
reissue.rs # Per-action vault authentication and saved-client delivery commit.rs # Backup, saved install, and Commit publication
commit.rs # Prepare, backup, install, and publish saved-state Commit restore.rs # Preview, reservation rebuild, and confirmed saved replacement
restore.rs # Bound preview and confirmed saved-state replacement backups.rs # Manual/pre-operation backup and archive listing
backups.rs # Manual/pre-operation backup and archive-list scenarios restart.rs # Restart preview, backup/job/verify/publication sequence
restart.rs # Bound restart preview, backup, job, verification, and publication scenario
wireguard.rs # Server configuration module boundary wireguard.rs # Server configuration module boundary
wireguard/ wireguard/
document.rs # Parsing and edits preserving original text document.rs # Lossless parse, peer inspection and document authority
metadata.rs # Managed client comment blocks edit.rs # Byte-preserving peer and metadata edits
vault.rs # Encryption, import, secret retrieval metadata.rs # Managed comment grammar and metadata validation
backup.rs # Backup archives and restoration vault.rs # Vault format, encryption, key matching and retrieval
runtime.rs # Running WireGuard interface and statistics vault/
service.rs # Systemd operations and restart verification source.rs # Read-only configured client-source access
delivery.rs # Client configuration files and QR generation import.rs # Client-file reconciliation and encrypted import
tui.rs # Terminal UI entry point persistence.rs # Saved-file installation, recovery and state codec
backup.rs # Versioned archive encoding, parsing and preview
runtime.rs # Runtime observations, peer projections and comparison
runtime/
netlink.rs # Bounded Generic Netlink WireGuard reader
transport.rs # Read-only runtime transport
service.rs # Systemd request and job completion adapter
service/
dbus.rs # D-Bus systemd implementation
delivery.rs # Client configuration rendering and adapter boundary
delivery/
files.rs # Secure client file publication
qr.rs # Terminal QR generation
tui.rs # TUI entry and session lifecycle
tui/ tui/
state.rs # Screen state and navigation state.rs # Screens, selection, UI generations and navigation
events.rs # Commands, worker lifecycle, and background events events.rs # Typed commands, worker queue and lifecycle
events/ events/
executor.rs # Application command adaptation and prepared contexts executor.rs # Application command adaptation and prepared contexts
forms.rs # Short-lived forms and secret owners forms.rs # Short-lived form inputs and sensitive commands
render.rs # Rendering render.rs # Visual strings, styles, wrapping and layout
terminal.rs # Terminal setup and cleanup terminal.rs # Terminal setup, event loop and cleanup
container_driver.rs # Test-only Alpine scenario driver (`cfg(test)`)
tests/ tests/
config_preservation.rs # Untouched server configuration remains identical config_preservation.rs # Synthetic byte-preservation behavior
commit_restore.rs # Persistence, backups, restore, runtime isolation commit_restore.rs # Persistence, backups, restore and runtime isolation
client_delivery.rs # Client file delivery and lifecycle workflows client_delivery.rs # First delivery, retry, reissue and lifecycle behavior
vault_import.rs # Existing-client import and reconciliation workflows runtime_restart.rs # Restart scenario behavior using controlled adapters
tui_workflow.rs # Synthetic worker-level TUI workflows vault_import.rs # Import and reconciliation behavior
fixtures/ # Synthetic configuration and archive inputs tui_workflow.rs # Worker-level TUI workflows and synthetic PTY checks
support/ testcontainers_wireguard.rs # Explicitly selected, ignored Alpine integration suite
mod.rs # Shared test adapters and helpers support/ # Shared fixtures, adapters and container harness
fixtures/wireguard/ # Synthetic server configuration
containers/alpine/ # Pinned Alpine runtime image and readiness support
vm/ # Guarded disposable-VM preparation/test scripts
config/ config/
wireguard-admin.example.toml # Safe example; settings format chosen at implementation wireguard-admin.example.toml # Safe distributable example settings
docs/ docs/
SPEC.md SPEC.md
IMPLEMENTATION.md PROJECT_LAYOUT.md
architecture/domain-refactoring.md
adr/ adr/
target/ # Cargo output; never commit target/ # Cargo output; never commit
``` ```
- Use modules named for their responsibility. Avoid catch-all `utils`, `helpers`, or `common` modules; place supporting code with its owner. ## Ownership rules
- Begin with a single module file and split into child modules when needed. Prefer `name.rs` with `name/child.rs` for production modules; `tests/support/mod.rs` keeps test helpers from becoming a separate integration test target.
- Declare application modules once in the library, rather than duplicating them in both `main.rs` and `lib.rs`. Keep internals private or `pub(crate)`; expose only the library API needed by the binary and behavioral integration tests. - `Application` is the public facade. Scenario ordering belongs in `src/app/`
- Keep focused unit tests beside their modules under `#[cfg(test)]`; put cross-module behavioral tests in `tests/`. Use `tests/support/` for test-only adapters rather than exporting test infrastructure from the production library. owners; the facade delegates without transferring authority to the TUI.
- The `config/` directory contains distributable examples, not live settings. The example filename above is illustrative and does not settle the settings format. Actual settings remain alongside the deployed executable as specified. - The server `ConfigDocument` is authoritative for peers and metadata.
- Keep live server configurations, private keys, delivered client files, and runtime `Backup/` data out of the source tree and version control. Ignore generated build output and local deployment data without hiding synthetic fixtures. `ClientStates` is only the manageable-client projection. Editing preserves
- Add `examples/` only for runnable Rust examples and `benches/` only when benchmarks are needed. Do not add empty directories or scripts that duplicate Cargo commands. unowned bytes and comments.
- Keep the layout aligned with actual module responsibilities as the code grows. Update this section when files move; do not preserve obsolete paths merely to match the initial tree. - Domain logic does not perform file, crypto, runtime, service, or rendering
work. Persistence owns installed state; backup owns archive encoding;
runtime owns observations/comparison; service owns systemd calls.
- `app/read_model.rs` supplies secret-free facts and action eligibility.
TUI state owns selection/navigation/generation; the executor binds prepared
continuations and calls application operations; renderers own presentation.
- Keep module internals private or `pub(crate)` where possible. Public facade
APIs retained for integration fixture setup are documented with their caller
audit in [the architecture map](architecture/domain-refactoring.md).
- Keep focused unit tests beside their modules and cross-module behavior in
`tests/`. `src/container_driver.rs` is included only in the library test
harness. Its opt-in Alpine application fixture is not systemd acceptance.
- `config/` holds safe examples, not live settings. Runtime data and archives
remain outside the source tree. Do not commit live configuration, keys,
delivered client files, or generated `Backup/` data.
- Keep this map aligned with actual files and responsibility. Do not add empty
directories or speculative traits/modules.
+149 -84
View File
@@ -1,9 +1,10 @@
# Domain and application refactoring contract # Domain and application refactoring contract
Status: migration contract for M20–M27. This document describes the current Status: integrated architecture map and handoff after M26. M20–M26 moved the
implementation and the agreed destination boundaries; it does not authorize responsibilities below to their current owners. This document records verified
behavior, file-format, dependency, or product changes. M19 completes only after source ownership and behavioral proof; it does not authorize behavior,
independent review and DOC checks. file-format, dependency, or product changes. M27 review and acceptance remain
pending.
## Authority and boundaries ## Authority and boundaries
@@ -32,74 +33,144 @@ these owners. The TUI submits typed requests and displays secret-free facts; it
does not authorize business operations or parse saved configuration. The does not authorize business operations or parse saved configuration. The
document editor never rebuilds the server file from a client snapshot. document editor never rebuilds the server file from a client snapshot.
## Reading guide: common workflows
These paths identify the application entry, the rule owner, the side-effect
boundary, and tests that exercise failures as well as success.
### Create, Commit, first delivery, explicit restart
- **Entry:** TUI `UiCommand::CreateClient`, `Commit`, `DeliverFirstIssue`, and
`PreviewRestart` followed by the explicit restart choice; the adapter is
`src/tui/events/executor.rs`. The facade methods are
`Application::prepare_new_client`, `commit`, `deliver_first_issue_file`,
`preview_restart`, and `restart`.
- **Rule owners:** `app/draft.rs` coordinates the draft; `app/commit.rs` owns
Commit; `app/first_delivery.rs` owns the one-use session capability and
retries; `app/first_file.rs` owns first-file output; `app/restart.rs` owns
backup, job completion, comparison and durable apply publication. The app
read model reports eligibility; the TUI does not grant it.
- **Effect boundary:** creation changes memory only. Commit backs up and installs
saved files/vault, without a runtime call. First delivery writes the selected
client file and may display its QR. Only the later explicit restart may call
the service/runtime adapters; addresses and current applied knowledge change
only after complete verification and durable bookkeeping.
- **Failure proof:** `app::new_client_preparation_is_transactional_and_uncommitted_keys_cannot_issue`,
`app::commit_failure_keeps_pending_issue_and_successful_retry_authorizes_it`,
`app::failed_file_publication_can_retry_in_a_different_directory`,
`app::restart_backup_failure_preserves_draft_and_submits_no_job`,
`app::restart_mismatch_and_post_restart_write_failure_never_release_addresses`.
### Delete, Commit, verified address release
- **Entry:** `UiCommand::DeleteClient`, then `Commit`, then `PreviewRestart`
and a confirmed restart choice through the executor; facade methods are
`Application::delete_client`, `commit`, and `restart`.
- **Rule owners:** `app/draft.rs` stages peer removal; `ConfigDocument` in
`wireguard/document.rs` and `wireguard/edit.rs` owns peer identity and
byte-preserving edits; `domain.rs` owns pending/committed reservations and
allocation; `app/commit.rs` persists the deletion; `app/restart.rs` publishes
release only after `runtime.rs` verifies the full saved peer set and durable
state install succeeds.
- **Effect boundary:** delete is draft-only. Commit backs up and changes saved
files/vault but leaves the running interface unchanged. The address remains
reserved through any restart failure or mismatch and is released only after
verified publication.
- **Failure proof:** `app::deletion_of_unprojectable_peer_persists_its_exact_host_route_reservation`,
`app::deletion_of_unprojectable_peer_with_broad_route_fails_without_draft_change`,
`commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes`,
`app::restart_mismatch_and_post_restart_write_failure_never_release_addresses`.
### Preview and confirm restore
- **Entry:** TUI `UiCommand::PreviewRestore`, then `ConfirmRestore` or cancel;
`src/tui/events/executor.rs` binds the preview to its worker generation.
Facade methods are `Application::preview_restore` and `confirm_restore`.
- **Rule owners:** `app/restore.rs` validates the archive, rebuilds internal
reservations and coordinates confirmed replacement; `backup.rs` owns archive
validation/encoding; `persistence.rs` owns safe installation and recovery.
The selected archive's settings, configuration and vault remain authoritative
for restored saved state.
- **Effect boundary:** preview and cancel are read-only. Confirmation requires a
fresh precautionary backup, then replaces saved files/vault as a whole. It
resets current apply knowledge to Unknown and does not call the running VPN or
request a vault password.
- **Failure proof:** `app::preview_is_read_only_and_confirm_restores_without_unlocking_vault`,
`app::restore_accepts_changed_non_path_settings_and_rejects_changed_paths`,
`app::restore_does_not_reserve_unprojectable_exact_hosts_owned_by_restored_document`,
`commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes`,
`events::prepared_delivery_and_restore_confirmations_are_bound_to_the_reviewed_generation`.
## Current concepts and migration map ## Current concepts and migration map
References use repository-relative paths and line numbers from the M19.1 source References use current repository-relative module paths. The M19.1 map is
inspection. Test names identify existing synthetic behavioral coverage; no test resolved below against the integrated M20–M26 implementation. Test names point
is claimed to have been rerun for this document. to existing behavioral coverage; this documentation update does not claim those
tests were rerun.
### Application session fields and workflows ### Application session fields and workflows
| Current type / field / function | Business meaning | Authority | Proposed owner | Readers / writers | Existing proof | Migration | | Current type / field / function | Business meaning | Authority | Current owner | Readers / writers | Existing proof | Resolution |
| --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- |
| `Application::store` (`src/app.rs:81-94`) | Saved-file boundary, configured paths, validation and install capability | `SavedStore` paths and installed files | Application facade/session, then `app/commit.rs`, `app/restore.rs`, `app/backups.rs` workflow owners | All app operations read; commit/restore update installed files | `commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes`; persistence `complete_install_publishes_components_with_private_modes` | M23 | | `Application::store` (`src/app.rs`) | Saved-file boundary, configured paths, validation and install capability | `SavedStore` paths and installed files | Application facade; scenario owners in `app/commit.rs`, `app/restore.rs`, `app/backups.rs`, `app/restart.rs` | Read by application scenarios; saved files change only through saved-operation owners | `commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes`; persistence `complete_install_publishes_components_with_private_modes` | Resolved M23/M25 |
| `Application::saved` | Exact installed generation held by this session | `SavedBytes` read from `SavedStore` | Application session; saved-operation contexts in M23/M25 | Open/read, commit, restore, verified bookkeeping, restart preview | `app::commit_advances_saved_state_without_applying_and_backup_contains_old_bytes`; `app::successful_restore_clears_verified_current_history_but_backup_retains_it` | M23, M25 | | `Application::saved` (`src/app.rs`) | Exact installed generation held by this session | `SavedBytes` read from `SavedStore` | Application session; bound contexts in `app/restore.rs` and `app/restart.rs` | Open/read, Commit, restore, verified bookkeeping, restart preview | `app::commit_advances_saved_state_without_applying_and_backup_contains_old_bytes`; `app::successful_restore_clears_verified_current_history_but_backup_retains_it` | Resolved M23/M25 |
| `Application::document` | Lossless current server-configuration draft and peer authority | Original/current saved server bytes parsed as `ConfigDocument` | `app/draft.rs` draft owner (M22), with editing rules in `wireguard/edit.rs` | Application reads; create/rename/delete/restore replace it; Commit serializes it | `app::new_client_preparation_is_transactional_and_uncommitted_keys_cannot_issue`; `config_preservation::edits_keep_interface_and_unowned_bytes_exact_and_can_be_reparsed` | M22 | | `Application::draft` (`src/app.rs`, `src/app/draft.rs`) and its document | Coordinated in-memory document, client projection, vault, and draft-only reservations | Authoritative server document plus encrypted vault; `ClientStates` is a restricted projection | `app/draft.rs` stages and publishes coordinated replacements; `wireguard/edit.rs` owns byte-preserving edits | Draft operations prepare replacements; Commit serializes the staged values | `app::new_client_preparation_is_transactional_and_uncommitted_keys_cannot_issue`; `config_preservation::edits_keep_interface_and_unowned_bytes_exact_and_can_be_reparsed` | Resolved M22 |
| `Application::states` | Narrow draft/saved management snapshots, apply knowledge, reservations | Document projection for manageable clients plus persisted internal state | Domain `ClientStates`, optionally `domain/apply.rs` and `domain/reservations.rs` | App edits/Commit/restart/reopen; app and TUI currently read | Domain tests `discard_restores_draft_and_commit_keeps_applied_snapshot_separate`, `successful_verified_apply_releases_deleted_addresses_and_mismatch_does_not`; `persistence::persisted_history_never_marks_the_runtime_verified` | M20, M21, M22 | | `Application::states` (`src/domain.rs`) | Narrow draft/saved management snapshots, current apply knowledge, and address reservations | Document projection for manageable clients plus persisted internal state | Domain `ClientStates` and `AddressReservations`; persistence only encodes/decodes durable fields | App draft/Commit/restart/reopen; read model exposes secret-free facts | `domain::discard_restores_draft_and_commit_keeps_applied_snapshot_separate`; `domain::successful_verified_apply_releases_deleted_addresses_and_mismatch_does_not`; `persistence::persisted_history_never_marks_the_runtime_verified` | Resolved M20–M22 |
| `Application::vault` | Encrypted vault draft used for secret encryption, import and reissue | Installed vault bytes at open, then current app draft | `app/draft.rs` coordinates; cryptographic/value operations stay in `vault.rs` | App setup/import/create/delete/Commit/reissue read or update it | `app::selected_file_import_uses_the_existing_vault_draft_without_saving`; `app::deletion_only_removes_selected_current_record_and_retains_other_records`; `vault::encrypted_bundle_round_trips_without_unlocking_and_retrieves_with_password` | M22, M24 | | `Application::draft.vault` (`src/app/draft.rs`) | Encrypted vault draft used for secret encryption, import, deletion, and reissue | Installed vault bytes at open, then current app draft | `app/draft.rs` coordinates; cryptographic/value operations stay in `vault.rs` and `vault/import.rs` | App setup/import/create/delete/Commit/reissue | `app::selected_file_import_uses_the_existing_vault_draft_without_saving`; `app::deletion_only_removes_selected_current_record_and_retains_other_records`; `vault::encrypted_bundle_round_trips_without_unlocking_and_retrieves_with_password` | Resolved M22/M24 |
| `draft_unsupported_reservations` | Draft-only exact host addresses retained when a saved peer cannot project to `Client` | Saved document peer routes and pending deletion | Domain reservation policy, staged by application draft owner | Delete adds; Commit persists/promotes; discard clears | `app::deletion_of_unprojectable_peer_persists_its_exact_host_route_reservation`; `app::deletion_of_unprojectable_peer_with_broad_route_fails_without_draft_change` | M21, M22 | | Pending exact-host reservations (`ClientStates::address_reservations`, `src/domain.rs`) | Draft-only exact host addresses retained when a saved peer cannot project to `Client` | Saved document peer routes and pending deletion | Domain `AddressReservations`, coordinated by `app/draft.rs` | Delete adds; Commit persists/promotes; discard clears | `app::deletion_of_unprojectable_peer_persists_its_exact_host_route_reservation`; `app::deletion_of_unprojectable_peer_with_broad_route_fails_without_draft_change` | Resolved M21/M22 |
| `historical_apply` | Last successfully persisted verification timestamp/status, for archive/history display | `PersistedState.last_verified_at_utc` and archive manifest | Persistence codec owns representation; application read model presents it | Open/backup/restore/restart bookkeeping | `persistence::persisted_history_never_marks_the_runtime_verified`; `app::verified_history_persists_across_reopen_without_marking_runtime_applied`; `app::historical_verified_timestamp_does_not_suppress_reissue_warning_after_reopen` | M21, M23, M26 | | `historical_apply` | Last successfully persisted verification timestamp/status, for archive/history display | `PersistedState.last_verified_at_utc` and archive manifest | Persistence codec owns representation; application read model presents it | Open/backup/restore/restart bookkeeping | `persistence::persisted_history_never_marks_the_runtime_verified`; `app::verified_history_persists_across_reopen_without_marking_runtime_applied`; `app::historical_verified_timestamp_does_not_suppress_reissue_warning_after_reopen` | Resolved M21/M23/M26 |
| `verified_saved_projection` | Saved generation verified by the current session, used for delivery activation warning | Successful full runtime comparison bound to saved bytes | Application session/restart scenario; read-only view exposes only safe status | Restart publication writes; delivery warning reads; edits/restore invalidate as appropriate | `app::first_issue_warning_tracks_verified_saved_generation_for_file_and_qr`; `app::historical_verified_timestamp_does_not_suppress_reissue_warning_after_reopen` | M21, M24, M25, M26 | | `verified_saved_projection` | Saved generation verified by the current session, used for delivery activation warning | Successful full runtime comparison bound to saved bytes | Application session/restart scenario; read-only view exposes only safe status | Restart publication writes; delivery warning reads; edits/restore invalidate as appropriate | `app::first_issue_warning_tracks_verified_saved_generation_for_file_and_qr`; `app::historical_verified_timestamp_does_not_suppress_reissue_warning_after_reopen` | Resolved M21/M24–M26 |
| `active_restart_attempt`, `next_restart_attempt` | One-use authorization that binds verification publication to the confirmed attempt and saved generation | Application-created attempt ID plus saved-byte equality | Private `app/restart.rs` scenario context | Preview/confirm/restart lifecycle; verified persistence consumes it | `app::restart_confirmation_rejects_a_generation_changed_after_preview`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses` | M20, M25 | | `active_restart_attempt`, `next_restart_attempt` | One-use authorization that binds verification publication to the confirmed attempt and saved generation | Application-created attempt ID plus saved-byte equality | Private `app/restart.rs` scenario context | Preview/confirm/restart lifecycle; verified persistence consumes it | `app::restart_confirmation_rejects_a_generation_changed_after_preview`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses` | Resolved M20/M25 |
| `initial_issues`, `next_issue_authorization` | Creation-session-only first-delivery eligibility, one-use authorization and retry state | Generated key held in memory, committed peer directives and encrypted record binding | `app/delivery.rs` session owner; `vault.rs` remains cryptographic authority | Create registers after coordinated draft staging; Commit promotes; delivery consumes or updates; delete/discard/invalidation removes | `app::first_issue_authorization_is_single_flight_and_success_consumes_it`; `app::deletion_and_discard_revoke_only_session_bound_initial_material`; `app::uncertain_first_file_publication_retains_warning_and_skips_qr` | M20, M22, M24 | | `FirstDeliverySession` (`src/app/first_delivery.rs`) | Creation-session-only first-delivery eligibility, one-use authorization and retry state | Generated key held in memory, committed peer directives and encrypted record binding | `app/first_delivery.rs` owns session capability state; `app/first_file.rs` runs first-file output; vault owns ciphertext/crypto and delivery adapters own publication | Coordinated creation registers; Commit promotes; file delivery consumes or updates; delete/discard/invalidation removes | `app::first_issue_authorization_is_single_flight_and_success_consumes_it`; `app::deletion_and_discard_revoke_only_session_bound_initial_material`; `app::uncertain_first_file_publication_retains_warning_and_skips_qr` | Resolved M20/M22/M24 |
| `open`, `open_from_saved_store`, `open_saved` (`src/app.rs:493-545`) | Construct a session from supplied state or derive supported state from saved document; reopen is Unknown now, regardless of history | Installed files/document; persisted reservations/history | Application session constructor | Production startup uses `open_from_saved_store`; `open` is used by tests | `startup::management_session_loads_supported_state_and_keeps_unsupported_peers_visible`; `app::verified_history_persists_across_reopen_without_marking_runtime_applied` | M22/M27 compatibility review | | `open_from_saved_store`, `open` (`src/app.rs`) | Construct a session from installed saved bytes; injected-state `open` exists for fixture/state-seeding callers. Reopen is Unknown regardless of history. | Installed files/document; persisted reservations/history | Application session constructors | Production startup uses `open_from_saved_store`; `open` is still called by library unit and integration fixtures | `startup::management_session_loads_supported_state_and_keeps_unsupported_peers_visible`; `app::verified_history_persists_across_reopen_without_marking_runtime_applied` | Resolved M22; retained fixture API, see caller audit |
| `prepare_new_client`, `add_client`, `rename_client`, `delete_client`, `discard_draft` (`src/app.rs:603-705,1253-1385`) | Stage all client/document/vault changes without saved-file or runtime effects | Document plus restricted client projection and vault | `app/draft.rs` and cohesive `app/clients.rs` operations, calling domain/editor/vault owners | UI uses prepare/rename/delete/discard commands; container test driver uses prepared flow; `add_client` has test callers only | `app::new_client_preparation_is_transactional_and_uncommitted_keys_cannot_issue`; `client_delivery::committed_creation_retries_after_overwrite_decline_and_duplicate_aliases_are_independent`; `client_delivery::deletion_and_restore_remove_password_free_authority_and_reopen_requires_vault_password` | M22 | | `prepare_new_client`, `add_client`, `rename_client`, `delete_client`, `discard_draft` (`src/app.rs`) | Stage client/document/vault changes without saved-file or runtime effects; `add_client` is a legacy fixture helper and does not issue a key/vault secret | Document plus restricted client projection and vault | `app/draft.rs`, application facade and domain/editor/vault owners; no separate `app/clients.rs` was needed | TUI uses prepared create/rename/delete/discard; test fixtures still call `add_client` | `app::new_client_preparation_is_transactional_and_uncommitted_keys_cannot_issue`; `client_delivery::committed_creation_retries_after_overwrite_decline_and_duplicate_aliases_are_independent`; `client_delivery::deletion_and_restore_remove_password_free_authority_and_reopen_requires_vault_password` | Resolved M22; retained fixture helper, see caller audit |
| `commit`, `preview_restore`, `confirm_restore` (`src/app.rs:1853-1965,2041-2147`) | Commit atomically installs staged saved bytes after backup; restore is a preview-bound full saved-state replacement after backup | App draft for Commit; validated archive payload for restore | `app/commit.rs`, `app/restore.rs`; low-level formats/install remain in `backup.rs`/`persistence.rs` | TUI executor calls facade; store installs only with `BackupComplete` | `app::commit_advances_saved_state_without_applying_and_backup_contains_old_bytes`; `app::preview_is_read_only_and_confirm_restores_without_unlocking_vault`; `commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes` | M23 | | `commit`, `preview_restore`, `confirm_restore` (`src/app.rs`) | Commit atomically installs staged saved bytes after backup; restore is a preview-bound full saved-state replacement after backup | App draft for Commit; validated archive payload for restore | `app/commit.rs`, `app/restore.rs`; low-level formats/install remain in `backup.rs`/`persistence.rs` | TUI executor calls facade; store installs only with `BackupComplete` | `app::commit_advances_saved_state_without_applying_and_backup_contains_old_bytes`; `app::preview_is_read_only_and_confirm_restores_without_unlocking_vault`; `commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes` | Resolved M23 |
| `preview_restart`, `restart`, `mark_verified_with_attempt` (`src/app.rs:1422-1530,1967-2038`) | Confirmed restart scenario: preconditions, backup, service job completion, runtime comparison, durable status then publish applied knowledge | Saved generation + complete `SavedPeerProjection` + runtime observation | `app/restart.rs`; service submission stays `service.rs`; comparison stays `runtime.rs`; durable fields stay persistence | TUI previews/confirms; fixture callback is test-only; success updates state only after durable write | `app::confirmed_restart_orders_backup_job_read_and_durable_publication`; `app::service_timeout_reports_submission_and_may_still_complete`; `app::failed_verified_history_write_does_not_advance_memory_or_reopen_as_verified` | M20, M21, M25 | | `preview_restart`, `restart`, verified-result publication (`src/app.rs`, `src/app/restart.rs`) | Confirmed restart scenario: preconditions, backup, service job completion, runtime comparison, durable status then publish applied knowledge | Saved generation + complete `SavedPeerProjection` + runtime observation | `app/restart.rs`; service submission in `service.rs`; comparison in `runtime.rs`; durable fields in persistence | TUI previews/confirms; fixture apply callback is `#[cfg(test)]`; success updates state only after durable write | `app::confirmed_restart_orders_backup_job_read_and_durable_publication`; `app::service_timeout_reports_submission_and_may_still_complete`; `app::failed_verified_history_write_does_not_advance_memory_or_reopen_as_verified` | Resolved M20/M21/M25 |
### Domain state and transitions ### Domain state and transitions
| Current type / field / operation | Business meaning | Authority | Proposed owner | Readers / writers | Existing proof | Migration | | Current type / field / operation | Business meaning | Authority | Current owner | Readers / writers | Existing proof | Resolution |
| --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- |
| `Client` / `ClientAddresses` / `Snapshot` (`src/domain.rs:60-147`) | Public, manageable projection keyed by public key; aliases may repeat, IPv6 may be absent for legacy clients | Public key and supported host-address projection from document | Domain client/value modules | App operations and read model; draft/saved snapshot transitions | `domain::aliases_may_repeat_but_control_characters_are_rejected`; `domain::existing_ipv4_only_clients_remain_ipv4_only`; `wireguard::wireguard_projection_supports_ipv4_only_and_rejects_ipv6_only_or_default_routes` | M20/M21 mechanical module move only if useful | | `Client` / `ClientAddresses` / `Snapshot` (`src/domain.rs`) | Public, manageable projection keyed by public key; aliases may repeat, IPv6 may be absent for legacy clients | Public key and supported host-address projection from document | Domain value types in `domain.rs`; no child module split was needed | App operations and read model; draft/saved snapshot transitions | `domain::aliases_may_repeat_but_control_characters_are_rejected`; `domain::existing_ipv4_only_clients_remain_ipv4_only`; `wireguard::wireguard_projection_supports_ipv4_only_and_rejects_ipv6_only_or_default_routes` | Resolved M20/M21 |
| `ClientStates::draft` / `saved` (`src/domain.rs:159-165`) | Manageable-client snapshots for staged and committed state, not all server peers | Document is source; snapshots are derived | Domain client states, mutated only through narrow transitions | Application edits draft, Commit advances saved; TUI currently reads both | `domain::discard_restores_draft_and_commit_keeps_applied_snapshot_separate`; `app::commit_advances_saved_state_without_applying_and_backup_contains_old_bytes` | M21/M22 | | `ClientStates::draft` / `saved` (`src/domain.rs`) | Manageable-client snapshots for staged and committed state, not all server peers | Document is source; snapshots are derived | Domain client states, mutated only through narrow transitions | Application edits draft and Commit advances saved; TUI consumes read-model facts | `domain::discard_restores_draft_and_commit_keeps_applied_snapshot_separate`; `app::commit_advances_saved_state_without_applying_and_backup_contains_old_bytes` | Resolved M21/M22 |
| `applied_snapshot` / domain `RuntimeObservation` | Optional management snapshot last verified plus current knowledge enum; may be `None` while full technical verification is Verified for valid unmanageable peers | Current verified runtime comparison; historical timestamp is separate | Domain apply knowledge; technical evidence remains runtime-owned | Restart publication changes; reopen resets current knowledge; read model maps current knowledge | `app::restart_verifies_metadata_free_legacy_routes_without_partial_applied_snapshot`; `app::verified_history_persists_across_reopen_without_marking_runtime_applied` | M20 naming; M21 transitions | | `applied_snapshot` / `ApplyStatus` | Optional management snapshot last verified plus current knowledge; may be `None` while full technical verification is Verified for valid unmanageable peers | Current verified runtime comparison; historical timestamp is separate | Domain apply knowledge; technical evidence remains runtime-owned | Restart publication changes; reopen resets current knowledge; read model maps current knowledge | `app::restart_verifies_metadata_free_legacy_routes_without_partial_applied_snapshot`; `app::verified_history_persists_across_reopen_without_marking_runtime_applied` | Resolved M20/M21 |
| `reserved_addresses` and `restore_persisted_reservations` (`src/domain.rs:164,210-231`) | Persisted conservative addresses that cannot be allocated | Prior saved peer routes and internal state | `domain/reservations.rs` value/rules; `persistence.rs` only encodes/decodes | Allocator reads; Commit/reopen/restart update; restart success may release | `domain::a_draft_only_deletion_does_not_create_a_committed_reservation`; `domain::successful_verified_apply_releases_deleted_addresses_and_mismatch_does_not`; `persistence::state_codec_is_canonical_and_rejects_bad_or_unsupported_state` | M21 | | `reserved_addresses` and `restore_persisted_reservations` (`src/domain.rs`) | Persisted conservative addresses that cannot be allocated | Prior saved peer routes and internal state | `domain.rs` owns reservation value/rules; `persistence.rs` only encodes/decodes | Allocator reads; Commit/reopen/restart update; restart success may release | `domain::a_draft_only_deletion_does_not_create_a_committed_reservation`; `domain::successful_verified_apply_releases_deleted_addresses_and_mismatch_does_not`; `persistence::state_codec_is_canonical_and_rejects_bad_or_unsupported_state` | Resolved M21 |
| `draft_mut` / `commit_draft` / `discard_draft` (`src/domain.rs:233-256`) | Current unrestricted draft mutation and snapshot transitions | `ClientStates` snapshots, ultimately document-derived | Replace with narrow domain operations in M21/M22; no public unrestricted mutator | Production `draft_mut` callers are only inside `Application`; direct outside-app callers are colocated domain tests | Domain tests above; app tests `discard_restores_draft_without_writing_installed_bytes`, `commit_failure_keeps_pending_issue_and_successful_retry_authorizes_it` | M21/M22; visibility removal after caller migration | | Narrow `stage_client`, `remove_draft_client`, `commit_draft`, `discard_draft` (`src/domain.rs`) | Mutate the manageable draft projection through scoped operations and preserve saved/applied separation | `ClientStates` snapshots, ultimately document-derived | Application draft coordinator calls crate-private stage/remove and public commit/discard transitions | No unrestricted `draft_mut` accessor remains; direct mutation in domain tests is limited to transitions | `domain::discard_restores_draft_and_commit_keeps_applied_snapshot_separate`; `app::discard_restores_draft_without_writing_installed_bytes`; `app::commit_failure_keeps_pending_issue_and_successful_retry_authorizes_it` | Resolved M21/M22; escape hatch removed |
| `mark_applied_after_verification`, `mark_technically_applied_after_verification`, runtime unknown/unavailable (`src/domain.rs:258-296`) | Change present apply knowledge only after verified result publication; preserve current uncertainty and optional management projection | Runtime comparison result plus successful persisted bookkeeping | Domain apply transitions called only by application restart scenario | App restart success/failure/reopen; periodic TUI statistics must not call them | `domain::successful_verified_apply_releases_deleted_addresses_and_mismatch_does_not`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses`; `tui::statistics_refresh_is_generation_bound_and_never_changes_applied_state` | M20/M21 | | Verified apply, technically verified apply, runtime unknown/unavailable transitions (`src/domain.rs`) | Change present apply knowledge only after verified result publication; preserve current uncertainty and optional management projection | Complete runtime comparison plus successful persisted bookkeeping | Domain transitions are crate-private and called by the application restart scenario | App restart success/failure/reopen; statistics reads cannot call transitions | `domain::successful_verified_apply_releases_deleted_addresses_and_mismatch_does_not`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses`; `tui::statistics_refresh_is_generation_bound_and_never_changes_applied_state` | Resolved M20/M21 |
| `allocate_ipv4`, `allocate_ipv6`, `AddressAvailability` (`src/domain.rs:341-464`) | Pure address allocation against server, occupied and reserved sets | Validated settings and document-derived address sets | Domain address allocator/reservations | App create reads | `domain::ipv4_allocation_skips_server_occupied_reserved_network_and_broadcast`; `domain::ipv6_allocates_first_free_address_from_a_very_large_range`; `tui_workflow::create_form_submits_automatic_dual_stack_client_without_changing_saved_state` | M21 | | `allocate_ipv4`, `allocate_ipv6`, `AddressAvailability` (`src/domain.rs`) | Pure address allocation against server, occupied and reserved sets | Validated settings and document-derived address sets | Domain address allocator and reservations | App create reads | `domain::ipv4_allocation_skips_server_occupied_reserved_network_and_broadcast`; `domain::ipv6_allocates_first_free_address_from_a_very_large_range`; `tui_workflow::create_form_submits_automatic_dual_stack_client_without_changing_saved_state` | Resolved M21 |
### Peer and runtime projections ### Peer and runtime projections
| Current projection | Business meaning / authority | Proposed owner and consumers | Existing proof | Migration | | Current projection | Business meaning / authority | Current owner and consumers | Existing proof | Resolution |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| `PeerInspection`, `PeerIssue`, `DocumentIssue`, `ConfigDocument` (`src/wireguard/document.rs:104-176`) | Every authoritative server peer section, byte spans, parsed routes and anomalies. Identity can be absent or duplicated. Malformed/no-key peers remain inspectable by document position. | `wireguard/document.rs`; app editing/deletion/restart and application read model consume it | `wireguard::wireguard_peer_issues_report_missing_malformed_and_duplicate_identity_fields`; `tui::malformed_peer_can_be_inspected_by_document_location_without_mutation_identity`; `tui::duplicate_public_keys_remain_inspectable_by_peer_position_but_not_mutable` | M22/M25/M26 | | `PeerInspection`, `PeerIssue`, `DocumentIssue`, `ConfigDocument` (`src/wireguard/document.rs`) | Every authoritative server peer section, byte spans, parsed routes and anomalies. Identity can be absent or duplicated. Malformed/no-key peers remain inspectable by document position. | `wireguard/document.rs`; app editing/deletion/restart and application read model consume it | `wireguard::wireguard_peer_issues_report_missing_malformed_and_duplicate_identity_fields`; `tui::malformed_peer_can_be_inspected_by_document_location_without_mutation_identity`; `tui::duplicate_public_keys_remain_inspectable_by_peer_position_but_not_mutable` | Resolved M22/M25/M26 |
| `ClientDisplay` / `SessionDisplay` (`src/app.rs:39-77,559-600`) | Secret-free current draft-document rows; `mutable_identity` only for one supported and unique projected client; metadata alias is descriptive, not independent authority | Move fact construction into app-owned `app/read_model.rs`; renderer consumes it | `tui::enter_opens_an_unsupported_peer_for_inspection_without_mutation_identity`; `tui::issues_screen_hides_valid_address_shape_limits_but_keeps_genuine_errors` | M26 | | `ClientDisplay`, `SessionDisplay`, `ApplicationView` (`src/app/read_model.rs`) | Secret-free current draft-document rows and authoritative per-action eligibility; mutable identity only for an unambiguous manageable peer | App-owned read model; `Application` facade exposes it | `tui::enter_opens_an_unsupported_peer_for_inspection_without_mutation_identity`; `tui::issues_screen_hides_valid_address_shape_limits_but_keeps_genuine_errors` | Resolved M26 |
| `SessionView::from_application`, `ClientStateRow`, `VisibleRecord` (`src/tui/state.rs:44-165`) | Current duplicate app projection plus UI generation, saved peer count, state map, reservation facts and visible removed rows | Split: application owns public secret-free view and action eligibility; TUI retains selection, screen, scroll and rendering state | `tui_workflow::saved_peer_projection_counts_legacy_peers_without_inventing_managed_state`; `tui::keyboard_navigation_reaches_draft_removed_rows_without_authorizing_them`; `tui::refresh_preserves_selection_by_public_key_not_alias_or_row_position` | M26 | | `SessionView`, `ClientStateRow`, `VisibleRecord` (`src/tui/state.rs`) | Maps `ApplicationView` into UI navigation state; keeps generation, selection, screens and rows, without reparsing saved bytes or constructing authority | TUI state consumes app facts and owns UI selection/navigation | `tui_workflow::saved_peer_projection_counts_legacy_peers_without_inventing_managed_state`; `tui::keyboard_navigation_reaches_draft_removed_rows_without_authorizing_them`; `tui::refresh_preserves_selection_by_public_key_not_alias_or_row_position` | Resolved M26 |
| Renderer-derived state and issue text (`src/tui/render.rs:1198-1265,1759-1835`) | Display labels/counts assembled from projection facts; currently some business categories are inferred in UI | Move counts/classification to read model only where authoritative facts permit; keep styling, wrapping, geometry and final strings/rendering TUI-owned | `tui::persistent_details_follow_the_highlight_and_keep_geometry_fixed`; `tui::client_rows_show_draft_state_and_escape_anomalous_unsupported_peers`; `tui::issues_screen_hides_valid_address_shape_limits_but_keeps_genuine_errors` | M26 | | Renderer-derived labels and issue text (`src/tui/render.rs`) | Styles and renders app facts; no operation eligibility or peer authority is inferred from labels | Renderer owns visual strings, styling, wrapping, geometry and layout | `tui::persistent_details_follow_the_highlight_and_keep_geometry_fixed`; `tui::client_rows_show_draft_state_and_escape_anomalous_unsupported_peers`; `tui::issues_screen_hides_valid_address_shape_limits_but_keeps_genuine_errors` | Resolved M26 |
| `SavedPeerProjection`, `RuntimeObservation`, `TechnicalMatch` (`src/runtime.rs:19-218`) | Complete technical route set independent of manageable `Client`; valid subnet-route peers can be restart-verified without UI mutability. Handshakes/counters are not apply evidence. | Runtime owns projection/comparison and read-only transport; app restart scenario coordinates; read model may expose only status/findings needed for UI | `runtime::projection_keeps_valid_unsupported_routes_and_ipv4_only_peers`; `runtime::counters_and_handshake_changes_do_not_change_technical_match`; `app::restart_verifies_metadata_free_legacy_routes_without_partial_applied_snapshot` | M20 name clarification; M25/M26 | | `SavedPeerProjection`, `RuntimeObservation`, `TechnicalMatch` (`src/runtime.rs`) | Complete technical route set independent of manageable `Client`; valid subnet-route peers can be restart-verified without UI mutability. Handshakes/counters are not apply evidence. | Runtime owns projection/comparison and read-only transport; app restart scenario coordinates; read model exposes only safe status/findings | `runtime::projection_keeps_valid_unsupported_routes_and_ipv4_only_peers`; `runtime::counters_and_handshake_changes_do_not_change_technical_match`; `app::restart_verifies_metadata_free_legacy_routes_without_partial_applied_snapshot` | Resolved M20/M25/M26 |
### Authorization, prepared contexts and worker generations ### Authorization, prepared contexts and worker generations
| Current context | Meaning and authority | Proposed owner | Readers / writers | Existing proof | Migration | | Current context | Meaning and authority | Current owner | Readers / writers | Existing proof | Resolution |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| UI selection guard `UiState::selected_client_mutable` (`src/tui/state.rs:473-491`) | Presentation-level guard requires one matching row, matching document position if selected, and a mutable identity; cannot grant operation authority | TUI selection state only; application owns typed per-action eligibility and execution revalidation | Terminal key handlers and footer hints read it; app methods/editors independently reject invalid actions | `tui::selection_uses_peer_position_for_duplicate_keys_and_disables_mutation`; `tui::removed_saved_client_is_visible_and_never_mutable` | M26 | | UI selection guard `UiState::selected_client_mutable` (`src/tui/state.rs`) | Presentation-level guard requires one matching row, matching document position if selected, and a mutable identity; cannot grant operation authority | TUI selection state only; application owns typed per-action eligibility and execution revalidation | Terminal key handlers and footer hints read it; app methods/editors independently reject invalid actions | `tui::selection_uses_peer_position_for_duplicate_keys_and_disables_mutation`; `tui::removed_saved_client_is_visible_and_never_mutable` | Resolved M26 |
| Current rename/delete/delivery UI prerequisites (`src/tui/terminal.rs:771-823`) | Current TUI rename/delete guards both require a supported unique mutable identity; delivery/reissue additionally require saved membership. Separately, `Application::delete_client` supports deletion by public key for some exact-host-route peers outside `ClientStates`. M26 must audit this mismatch against the planned per-action eligibility contract; do not infer that current keyboard UI exposes that app-level capability or silently prohibit the documented supported path. | Application reports typed per-action eligibility, then each application operation revalidates its own preconditions; terminal maps eligibility to enabled actions | Terminal selects target; `ConfigDocument`/app authoritatively validate at execution | `tui::detail_hints_only_offer_saved_delivery_for_mutable_saved_selection`; `app::deletion_of_unprojectable_peer_persists_its_exact_host_route_reservation`; `app::deletion_of_unprojectable_peer_with_broad_route_fails_without_draft_change` | M26 | | Per-action UI prerequisites (`src/tui/terminal.rs`, `src/app/read_model.rs`) | Selection is presentation-only; rename/delete/delivery/reissue availability comes from typed app eligibility, and each operation revalidates on execution | App read model owns availability facts; terminal maps them to actions and hints | `tui::state` binds selected row; app methods and config editor validate mutation | `tui::detail_hints_only_offer_saved_delivery_for_mutable_saved_selection`; `app::deletion_of_unprojectable_peer_persists_its_exact_host_route_reservation`; `app::deletion_of_unprojectable_peer_with_broad_route_fails_without_draft_change` | Resolved M26 |
| `InitialIssue`, `IssueContext`, `FirstIssueAuthorization`, `IssueStage` (`src/app.rs:96-126,976-1219`) | Session-local secret and one-use authorization bound to identity, peer directives and encrypted record; retries reflect publication/cleanup uncertainty | `app/delivery.rs` owns session lifecycle; vault owns ciphertext/crypto; file adapter owns publication mechanics | Create registers; Commit enables; each delivery validates/consumes; edits/delete/discard invalidate as appropriate | `app::committed_first_issue_publishes_selected_file_and_consumes_eligibility`; `app::published_file_is_reported_when_saved_store_bookkeeping_fails`; `app::failed_first_delivery_requires_consuming_capability_before_retry`; `app::temporary_cleanup_failure_requires_manual_cleanup_before_first_issue_retry` | M20/M24 | | First-issue session context (`src/app/first_delivery.rs`, `src/app/first_file.rs`) | Session-local secret and one-use authorization bound to identity, peer directives and encrypted record; retry state reflects publication/cleanup uncertainty | `app/first_delivery.rs` owns session lifecycle; `app/first_file.rs` owns first-file scenario; adapters own crypto and publication | Create registers; Commit enables; delivery validates/consumes; edits/delete/discard invalidate | `app::committed_first_issue_publishes_selected_file_and_consumes_eligibility`; `app::published_file_is_reported_when_saved_store_bookkeeping_fails`; `app::failed_first_delivery_requires_consuming_capability_before_retry`; `app::temporary_cleanup_failure_requires_manual_cleanup_before_first_issue_retry` | Resolved M20/M24 |
| `Application::vault_draft_mut` (`src/app.rs:1310-1314`) | Public unrestricted mutable vault escape hatch | Remove or narrow after callers migrate; vault logic stays in vault/app draft owners | Only current caller: colocated app test `replacing_the_encrypted_record_invalidates_committed_first_issue` (~3525); no production, startup, integration or container-driver caller | Same test plus `app::deletion_and_discard_revoke_only_session_bound_initial_material` | M24/M27; replace test setup intentionally before visibility removal | | `ApplicationExecutor` prepared destination and restore preview (`src/tui/events/executor.rs`) | Worker-owned continuation state bound to target, delivery mode/QR choice, attempt, preview and request generation | Private named contexts in the executor child | Executor command handling; clears on unrelated actions, consumes on confirmation/cancel | `events::prepared_delivery_and_restore_confirmations_are_bound_to_the_reviewed_generation`; `client_delivery::overwrite_confirmation_is_bound_to_the_selected_destination`; TUI workflow restore cancellation/confirmation | Resolved M20; both contexts use named structs |
| `ApplicationExecutor::prepared_destination`, `restore_preview` (`src/tui/events.rs:290-301`) | Worker-owned continuation state bound to target, delivery mode/QR choice, attempt, preview and request generation; prepared-destination tuple currently has six elements and restore-preview tuple three | Private named contexts in `tui/events.rs` or a cohesive private executor child | `ApplicationExecutor::execute_at` and `execute_sensitive_at`; clears on unrelated actions, consumes on confirmation/cancel | `events::prepared_delivery_and_restore_confirmations_are_bound_to_the_reviewed_generation`; `client_delivery::overwrite_confirmation_is_bound_to_the_selected_destination`; TUI workflow restore cancellation/confirmation | M20 | | `PendingOperation`, `SessionView.generation`, worker generation (`src/tui/events.rs`, `src/tui/state.rs`) | Monotonic identity for submitted work and returned view; stale view/statistics cannot overwrite current UI state | TUI worker/execution adapter only; not domain state | Mutating submit increments; worker tags result; UI accepts matching generations; periodic statistics rechecks generation across read | `events::delayed_statistics_are_bounded_and_do_not_advance_generation`; `events::statistics_started_before_a_mutation_are_discarded_as_stale`; `tui::stale_view_is_rejected_and_unsupported_selected_peer_is_not_mutable` | Resolved M20/M26 |
| `PendingOperation`, `SessionView.generation`, worker generation (`src/tui/events.rs:168-189,755-888`; `src/tui/state.rs:52-66,226-235`) | Monotonic identity for submitted work and returned view; stale view/statistics cannot overwrite current UI state | TUI worker/execution adapter only; not domain state | Mutating submit increments; worker tags result; UI accepts matching generations; periodic statistics rechecks generation across read | `events::delayed_statistics_are_bounded_and_do_not_advance_generation`; `events::statistics_started_before_a_mutation_are_discarded_as_stale`; `tui::stale_view_is_rejected_and_unsupported_selected_peer_is_not_mutable` | M20/M26 | | `FormController`, `SecretInput`, `SecretText`, `SensitiveCommand` (`src/tui/forms.rs`, `src/tui/events.rs`) | Short-lived form state and zeroizing password command; secrets excluded from view/debug/clone | Forms own input; worker carries secret command; application consumes only during vault operation | Form submits sensitive command; worker invokes setup/reissue; form clears on cancel/consumption | `tui::compact_form_hints_follow_the_active_form_without_leaking_input`; `vault::every_retrieval_requires_the_correct_password`; `client_delivery::reissue_unlocks_installed_saved_record_each_time_and_warns_after_reopen` | Resolved M24/M26; lifetimes preserved |
| `FormController`, `SecretInput`, `SecretText`, `SensitiveCommand` (`src/tui/forms.rs:50-145`; `src/tui/events.rs:78-100`) | Short-lived form state and zeroizing password command; secrets excluded from view/debug/clone | Forms own input; worker carries secret command; application consumes only during vault operation | Form submits sensitive command; worker invokes setup/reissue; form clears on cancel/consumption | `tui::compact_form_hints_follow_the_active_form_without_leaking_input`; `vault::every_retrieval_requires_the_correct_password`; `client_delivery::reissue_unlocks_installed_saved_record_each_time_and_warns_after_reopen` | M24/M26; preserve lifetimes |
### Public API escape-hatch callers and removal conditions ### Public API escape-hatch callers and removal conditions
| API | Actual callers | Safe path and timing | | API | Actual callers | Safe path and timing |
| --- | --- | --- | | --- | --- | --- |
| `ClientStates::draft_mut` (`src/domain.rs:233`) | Production: `Application` methods only (`app.rs:611,680,1259,1301`). Other direct callers: `domain.rs` unit tests. No `lib.rs`, startup, TUI, integration-test or container-driver consumer. | Replace application uses with narrow stage/rename/remove operations as M21/M22 move transitions. Update colocated tests to exercise those operations. Reduce visibility only after the complete source and test search finds no external caller. | | `ClientStates::draft_mut` | No current declaration or callers. Former unrestricted accessor was replaced by crate-private `stage_client`/`remove_draft_client` and narrow transitions in `src/domain.rs`; full `rg` audit finds no production, test, startup, binary, integration or container-driver reference. | Removed in M22 after caller audit; no replacement is needed by callers. [M22 evidence](../evidence/milestone-22.md) records the review. |
| `Application::vault_draft_mut` (`src/app.rs:1312`) | Only app unit test `replacing_the_encrypted_record_invalidates_committed_first_issue`; no production or integration caller. | Replace test mutation with a purpose-built test fixture or behavior through a legitimate application operation; do not retain a production mutation bypass for tests. Remove/narrow in M24 or M27 after verification. | | `Application::vault_draft_mut` | No current declaration or callers. The public mutation bypass was removed and no test-only API replaced it. | Removed in M22; vault state is mutated through coordinated application operations. [M22 evidence](../evidence/milestone-22.md) records the review. |
| `Application::add_client` (`src/app.rs:605`) | No production caller. Integration: `tests/commit_restore.rs` at archive-cycle, reservation and backup-failure setup; `tests/runtime_restart.rs` fixture helper; app unit restart setup. Distinct `ConfigDocument::add_client` remains used by application/editor and preservation tests. | Preserve app facade operations through M22, migrate fixture uses to deliberate setup or create workflow while keeping assertions, then remove only if full caller audit confirms no external library consumer. M27 owns final pruning. | | `Application::add_client` (`src/app.rs`) | Unit-test setup in `src/app.rs`; integration-fixture setup in `tests/commit_restore.rs` and `tests/runtime_restart.rs`. No binary, startup, production module, `tests/support`, or `src/container_driver.rs` caller. `ConfigDocument::add_client` remains the actual byte-preserving editor used by `prepare_new_client` and preservation tests. | Retained as a public compatibility/test-seeding operation because current integration fixtures still use it. It does not generate/encrypt a private key and must not be mistaken for the normal create workflow. Removal requires deliberate fixture migration. |
| `Application::open(store, states)` (`src/app.rs:493`) | App unit tests and integration fixture constructors in `client_delivery.rs`, `commit_restore.rs`, `runtime_restart.rs`, `tui_workflow.rs`. No production startup caller. | Keep compatibility while tests depend on seeded state. Migrate tests that need no injected state to `open_from_saved_store`; tests that specifically validate state seeding may retain a justified constructor. Remove only after binary, library, integration and test-only container callers are checked in M27. | | `Application::open(store, states)` (`src/app.rs`) | Unit tests and fixture helpers in `tests/client_delivery.rs`, `tests/commit_restore.rs`, `tests/runtime_restart.rs`, and `tests/tui_workflow.rs`. No binary/startup or production caller; no container-driver caller. | Retained for tests that seed `ClientStates` and apply knowledge. Production startup uses `open_from_saved_store`; fixture construction is the only current consumer class. |
| `Application::open_from_saved_store` (`src/app.rs:501`) | Production: `startup::open_management_session` (`src/startup.rs:65-92`). Also application/event/TUI tests and `container_driver::open_fixture_application`. `container_driver` itself is library `#[cfg(test)]` only (`src/lib.rs:14-17`). | Required production entry point; retain or provide an equivalent public facade. Fixture driver has no production fixture-apply capability. | | `Application::open_from_saved_store` (`src/app.rs`) | Binary startup through `startup::open_management_session`; application/TUI/integration tests; `container_driver::open_fixture_application` in `src/container_driver.rs`, which is included only under `#[cfg(test)]` in `src/lib.rs`. | Required production and fixture entry point; retain. Container driver normal tests are synthetic; its ignored Alpine scenario is opt-in and is not a systemd acceptance test. |
| `Application::display_projection` (`src/app.rs`) | No production-module, binary, or actual startup-path call. `startup::tests::management_session_loads_supported_state_and_keeps_unsupported_peers_visible` calls it after exercising session startup. There are no `tests/` integration-test calls. The only other direct callers are in `src/container_driver.rs`'s `#[cfg(test)]` synthetic lifecycle test `phase_protocol_keeps_creation_commit_and_first_delivery_in_one_app_session`; the ignored Alpine scenario does not call it. Current TUI presentation uses `Application::read_model`. | Retain for now as a public compatibility projection: the startup unit and synthetic fixture tests still exercise its inclusion of unsupported peers. Its compatibility value and test coverage do not make it a production authorization/read path. Removal requires deliberate migration of those callers and an API compatibility decision; do not infer it is obsolete solely because M26 moved TUI reads to `read_model`. |
| Former public `Application::create_pre_restart_backup` (`src/app.rs`) | Direct callers are confined to colocated app unit tests: helper `test_mark_verified`, `manual_and_pre_restart_backups_are_listed_without_runtime_calls`, and `failed_verified_history_write_does_not_advance_memory_or_reopen_as_verified`. No binary, integration-test, or container-driver caller. | Restricted to a private `#[cfg(test)]` method because only fixtures use it. Production restart performs its mandatory backup within `app/restart.rs`; no production API exception remains. |
## Transition tables ## Transition tables
@@ -124,7 +195,7 @@ saved-file or runtime mutation; drafts may remain in memory where specified.
| Delete saved manageable client in draft | Target's addresses known | No committed reservation yet; addresses remain occupied by saved snapshot | Draft deletion only | Discard restores client and no pending reservation is published | `domain::a_draft_only_deletion_does_not_create_a_committed_reservation` | | Delete saved manageable client in draft | Target's addresses known | No committed reservation yet; addresses remain occupied by saved snapshot | Draft deletion only | Discard restores client and no pending reservation is published | `domain::a_draft_only_deletion_does_not_create_a_committed_reservation` |
| Delete saved unprojectable peer in draft | Every route to be retained is an exact IPv4 `/32` or IPv6 `/128` host route | Exact routes enter draft-only reservation set | Prevent allocation while deletion is staged | Broad/subnet route or missing address evidence rejects deletion without draft mutation | `app::deletion_of_unprojectable_peer_persists_its_exact_host_route_reservation`; `app::deletion_of_unprojectable_peer_with_broad_route_fails_without_draft_change` | | Delete saved unprojectable peer in draft | Every route to be retained is an exact IPv4 `/32` or IPv6 `/128` host route | Exact routes enter draft-only reservation set | Prevent allocation while deletion is staged | Broad/subnet route or missing address evidence rejects deletion without draft mutation | `app::deletion_of_unprojectable_peer_persists_its_exact_host_route_reservation`; `app::deletion_of_unprojectable_peer_with_broad_route_fails_without_draft_change` |
| Commit deletion | Mandatory backup and saved install succeed | Deleted saved addresses enter persisted reservation set; committed client snapshot advances | Allocator excludes current draft/saved and reserved addresses | Backup/install failure does not publish release or new saved state | `domain::discard_restores_draft_and_commit_keeps_applied_snapshot_separate`; `app::state_file_round_trip_keeps_pending_addresses` | | Commit deletion | Mandatory backup and saved install succeed | Deleted saved addresses enter persisted reservation set; committed client snapshot advances | Allocator excludes current draft/saved and reserved addresses | Backup/install failure does not publish release or new saved state | `domain::discard_restores_draft_and_commit_keeps_applied_snapshot_separate`; `app::state_file_round_trip_keeps_pending_addresses` |
| Restore archive removing current peers | Preview is valid and confirmation accepted; pre-restore backup succeeds | Rebuilt internal state carries existing persisted reservations and addresses from `ClientStates::saved()`, except addresses assigned by restored manageable clients. `preview_restore` does not collect exact host routes from unprojectable peers in the installed saved server configuration or `draft_unsupported_reservations`; their preservation is not established. | Full saved replacement only; runtime is untouched | Cancel leaves saved state unchanged; backup/install failure leaves recoverable prior state and drafts | `commit_restore::restore_reserves_addresses_of_current_saved_clients_that_the_archive_removes`; `app::partial_restore_failure_preserves_session_and_pre_restore_backup_then_reopens_to_old_set` | | Restore archive removing current peers | Preview is valid and confirmation accepted; pre-restore backup succeeds | Rebuilt internal state carries archived/current persisted reservations, addresses from current manageable clients, and exact host routes from unsupported current peers; reservations are excluded for addresses still assigned by restored peers | Full saved replacement only; runtime is untouched | Cancel leaves saved state unchanged; backup/install failure leaves recoverable prior state and drafts | `commit_restore::restore_reserves_addresses_of_current_saved_clients_that_the_archive_removes`; `app::restore_does_not_reserve_unprojectable_exact_hosts_owned_by_restored_document`; `app::partial_restore_failure_preserves_session_and_pre_restore_backup_then_reopens_to_old_set` |
| Verified restart publication | Confirmed attempt still matches installed generation; completed service job; complete interface/peer match; internal-state install succeeds | Reservations for removed clients clear | Persist verified timestamp/state, then publish current applied knowledge | Mismatch/read/service/timeout/persistence failure retains reservations and conservative apply knowledge | `domain::successful_verified_apply_releases_deleted_addresses_and_mismatch_does_not`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses` | | Verified restart publication | Confirmed attempt still matches installed generation; completed service job; complete interface/peer match; internal-state install succeeds | Reservations for removed clients clear | Persist verified timestamp/state, then publish current applied knowledge | Mismatch/read/service/timeout/persistence failure retains reservations and conservative apply knowledge | `domain::successful_verified_apply_releases_deleted_addresses_and_mismatch_does_not`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses` |
### Current and historical verification ### Current and historical verification
@@ -153,7 +224,7 @@ saved-file or runtime mutation; drafts may remain in memory where specified.
| Trigger | Preconditions | Next state | Side effects | Failure or cancellation | Existing proof | | Trigger | Preconditions | Next state | Side effects | Failure or cancellation | Existing proof |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| Select archive for preview | Safe archive name and valid archive format | Opaque preview holds validated bytes plus metadata; UI receives redacted summary/change list and generation | Read-only archive validation; no password and no runtime call | Invalid/traversal archive rejected; cancel drops preview | `app::preview_is_read_only_and_confirm_restores_without_unlocking_vault`; `commit_restore::archive_parser_rejects_traversal_links_duplicates_and_oversized_members` | | Select archive for preview | Safe archive name and valid archive format | Opaque preview holds validated bytes plus metadata; UI receives redacted summary/change list and generation | Read-only archive validation; no password and no runtime call | Invalid/traversal archive rejected; cancel drops preview | `app::preview_is_read_only_and_confirm_restores_without_unlocking_vault`; `commit_restore::archive_parser_rejects_traversal_links_duplicates_and_oversized_members` |
| Confirm matching preview | Preview token still belongs to the operation generation; installation paths remain compatible | Selected archive replaces saved settings, server configuration and vault as a whole after mandatory pre-restore backup; running VPN remains unchanged | Preview rebuilds internal state instead of preserving its archive bytes: retain archived reservations and current reservations, add addresses of currently saved clients removed by the archive, then exclude addresses assigned by restored clients. The rebuilt state has no historical verification timestamp; current apply knowledge becomes Unknown. No restart occurs. The pre-restore backup retains the prior saved bytes and history. | Stale/cancelled preview cannot write; backup/install failure preserves prior saved state or requires journal recovery | `events::prepared_delivery_and_restore_confirmations_are_bound_to_the_reviewed_generation`; `app::restore_accepts_changed_non_path_settings_and_rejects_changed_paths`; `commit_restore::restore_reserves_addresses_of_current_saved_clients_that_the_archive_removes`; `app::successful_restore_clears_verified_current_history_but_backup_retains_it`; `commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes` | | Confirm matching preview | Preview token still belongs to the operation generation; installation paths remain compatible | Selected archive replaces saved settings, server configuration and vault as a whole after mandatory pre-restore backup; running VPN remains unchanged | Rebuilt internal state carries archived and current persisted reservations, addresses of current manageable clients and unsupported peers' exact host routes that the restore removes; addresses still assigned by the restored configuration are excluded. Draft-only exact routes are included. The rebuilt state has no historical verification timestamp; current apply knowledge becomes Unknown. No restart occurs. The pre-restore backup retains the prior saved bytes and history. | Stale/cancelled preview cannot write; backup/install failure preserves prior saved state or requires journal recovery | `events::prepared_delivery_and_restore_confirmations_are_bound_to_the_reviewed_generation`; `app::restore_accepts_changed_non_path_settings_and_rejects_changed_paths`; `commit_restore::restore_reserves_addresses_of_current_saved_clients_that_the_archive_removes`; app `restore_does_not_reserve_unprojectable_exact_hosts_owned_by_restored_document`; `app::successful_restore_clears_verified_current_history_but_backup_retains_it`; `commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes` |
| Cancel preview/confirmation | No restore install has begun | Existing saved state and draft remain | Clear app-executor preview context | No backup/install/runtime side effect | `tui_workflow::worker_backup_restore_preview_cancel_and_confirm_are_separate_saved_operations`; app preview read-only test above | | Cancel preview/confirmation | No restore install has begun | Existing saved state and draft remain | Clear app-executor preview context | No backup/install/runtime side effect | `tui_workflow::worker_backup_restore_preview_cancel_and_confirm_are_separate_saved_operations`; app preview read-only test above |
### Restart attempt identity and uncertainty ### Restart attempt identity and uncertainty
@@ -167,49 +238,43 @@ saved-file or runtime mutation; drafts may remain in memory where specified.
| Job complete, observe and compare | Job successful; remaining shared deadline; expected configured interface and complete runtime peer set | Matching result becomes candidate for durable verification | Bounded observation and pure comparison; no direct state publish yet | Read error/timeout/missing interface/incomplete dump/mismatch stops publication and retains reservations | `app::shared_deadline_expired_after_successful_job_stops_before_runtime_read`; `app::shared_deadline_expired_after_runtime_read_reports_timeout_before_comparison`; `runtime::partial_duplicate_and_unavailable_records_never_pass` | | Job complete, observe and compare | Job successful; remaining shared deadline; expected configured interface and complete runtime peer set | Matching result becomes candidate for durable verification | Bounded observation and pure comparison; no direct state publish yet | Read error/timeout/missing interface/incomplete dump/mismatch stops publication and retains reservations | `app::shared_deadline_expired_after_successful_job_stops_before_runtime_read`; `app::shared_deadline_expired_after_runtime_read_reports_timeout_before_comparison`; `runtime::partial_duplicate_and_unavailable_records_never_pass` |
| Durable verification succeeds | Attempt token and both current/attempt saved bytes still equal; full technical match; internal state install succeeds | Publish current verified knowledge and clear retained addresses | Persist timestamp/reservations first; update in-memory session after successful install | Failed persistence leaves conservative state; no second restart or automatic rollback | `app::failed_verified_history_write_does_not_advance_memory_or_reopen_as_verified`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses` | | Durable verification succeeds | Attempt token and both current/attempt saved bytes still equal; full technical match; internal state install succeeds | Publish current verified knowledge and clear retained addresses | Persist timestamp/reservations first; update in-memory session after successful install | Failed persistence leaves conservative state; no second restart or automatic rollback | `app::failed_verified_history_write_does_not_advance_memory_or_reopen_as_verified`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses` |
## Destination modules and staged migration ## M20–M26 migration disposition
These destinations are bounded homes for current responsibilities, not a request This register resolves the destinations proposed by M19 against the integrated
to create empty files. Keep established public facade calls until callers have source. The milestone labels are historical; the owner column names the current
migrated. Existing low-level adapters and persisted formats remain in place. code. Public facade calls remain where the caller audit below documents an
active integration-fixture dependency. Existing low-level adapters and
persisted formats remain in place.
| Milestone | Production surface and destination | Compatibility / preserved boundary | Existing baseline and exact focused commands | | Milestone | Production surface and destination | Compatibility / preserved boundary | Existing baseline and exact focused commands |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| M20 — vocabulary and named contexts | `domain.rs` apply-knowledge naming; `runtime.rs` measured observations; `tui/state.rs` presentation mapping; `tui/events.rs` private named prepared-delivery and restore contexts. Split coherent domain children only if useful. | No business-rule movement, new type semantics, schema change, secret Clone/Debug, or command redesign. Replace the six-element prepared-destination tuple with named fields for identity, QR choice, delivery mode, retry attempt, generation and destination. Keep public imports via re-export only when actual callers need them. | `cargo test --locked domain::`; `cargo test --locked runtime::`; `cargo test --locked tui::events::`; `cargo test --locked tui::state::`. Proof names: `verified_state_requires_a_matching_applied_snapshot`, `counters_and_handshake_changes_do_not_change_technical_match`, `prepared_delivery_and_restore_confirmations_are_bound_to_the_reviewed_generation`. | | M20 — vocabulary and named contexts | Domain/apply vocabulary is in `src/domain.rs`; observations/comparison in `src/runtime.rs`; presentation mapping in `src/tui/state.rs`; `PreparedDestinationContext` and `RestorePreviewContext` are private named structs in `src/tui/events/executor.rs`. | Semantics remain unchanged; no domain child split was justified. | Historical focused checks recorded in M20 evidence; current generation-bound proof is `events::prepared_delivery_and_restore_confirmations_are_bound_to_the_reviewed_generation`. |
| M21 — reservations and apply knowledge | `domain/reservations.rs` and `domain/apply.rs` as justified; allocator remains domain; `persistence.rs` retains TOML serialization; `runtime.rs` retains technical matching; app restart caller migrates to transitions. | Preserve PersistedState version/field names and semantics, exact host-route retention, Unknown on reopen, optional incomplete management snapshot, and no public unrestricted mark-applied API. | `cargo test --locked domain::`; `cargo test --locked persistence::`; `cargo test --locked app::`. Proof names: reservation and verified-release domain tests; `persisted_history_never_marks_the_runtime_verified`; `restart_mismatch_and_post_restart_write_failure_never_release_addresses`. | | M21 — reservations and apply knowledge | `src/domain.rs` owns `AddressReservations`, allocation and narrow apply transitions; `src/persistence.rs` encodes durable state; `src/runtime.rs` compares technical peer state; `src/app/restart.rs` coordinates verified publication. | No `domain/reservations.rs` or `domain/apply.rs` split was warranted; unrestricted draft mutation was removed. Persisted schema and semantics remain in persistence. | `domain::exact_host_routes_stay_pending_until_commit_and_discard_drops_them`; `persistence::persisted_history_never_marks_the_runtime_verified`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses`. |
| M22 — coordinated draft and create/edit/import | `app/draft.rs` coordinates document, client projection, encrypted vault and draft-only reservations; cohesive `app/clients.rs` and `app/import.rs` only if responsibility warrants. Keep `Application` facade methods. Domain mutators become narrow; `vault/source.rs` still reads sources and `vault/import.rs` reconciles/encrypts. | Prepare fallible replacements before publication; document remains authoritative; no file/runtime writes; no partially staged issue capability. Preserve original files, anomaly reports, metadata and unsupported peers. Retain app facade entry points while startup/tests migrate. | `cargo test --locked app::`; `cargo test --locked --test config_preservation`; `cargo test --locked --test client_delivery`; `cargo test --locked --test vault_import`; `cargo test --locked --test tui_workflow`. Existing coverage: app create/import/deletion tests and `initial_setup_encrypts_valid_files_and_leaves_sources_and_server_unchanged`. | | M22 — coordinated draft and create/edit/import | `src/app/draft.rs` coordinates document/client/vault/reservation drafts; `src/app.rs` remains the facade; `src/vault/source.rs` reads sources and `src/vault/import.rs` reconciles/encrypts. | No separate `app/clients.rs` or `app/import.rs` was justified. `Application::open`/`add_client` remain for injected-state and fixture setup, documented in the caller audit. | `app::new_client_preparation_is_transactional_and_uncommitted_keys_cannot_issue`; config preservation, delivery, import and workflow integration suites. |
| M23 — saved Commit, backups and restore | `app/commit.rs`, `app/restore.rs`, `app/backups.rs` own ordered scenarios; `persistence.rs` keeps journaling/path safety and `backup.rs` keeps archive encoding/parsing. | No persisted format, archive member/version, settings-path policy, rollback, runtime or service behavior changes. Keep preview byte-bound and saved-only. | `cargo test --locked app::`; `cargo test --locked persistence::`; `cargo test --locked backup::`; `cargo test --locked --test commit_restore`; `cargo test --locked --test client_delivery`. Proof includes commit/install failure and restore preview/cancel/backup tests. | | M23 — saved Commit, backups and restore | `src/app/commit.rs`, `src/app/restore.rs`, and `src/app/backups.rs` own scenarios; `src/persistence.rs` owns journaling/path safety and `src/backup.rs` owns archive encoding/parsing. | Preview is byte-bound and saved-only. M23 added restoration of exact routes from unsupported current peers; this closed the earlier noted reservation gap. | `app::commit_advances_saved_state_without_applying_and_backup_contains_old_bytes`; `app::preview_is_read_only_and_confirm_restores_without_unlocking_vault`; `restore_does_not_reserve_unprojectable_exact_hosts_owned_by_restored_document`; `commit_restore::backup_failure_blocks_commit_and_restore_without_losing_drafts_or_saved_bytes`. |
| M24 — delivery scenarios | `app/delivery.rs` owns first-issue session eligibility, retry and password reissue orchestration; `delivery.rs`, `delivery/files.rs`, `delivery/qr.rs`, vault crypto stay focused adapters. | Preserve one-use/session-only secret capability, prepared destination ownership, same payload for file/QR, per-client password and publication uncertainty/manual cleanup. | `cargo test --locked app::`; `cargo test --locked delivery::`; `cargo test --locked vault::`; `cargo test --locked --test client_delivery`; `cargo test --locked --test tui_workflow`. | | M24 — delivery scenarios | `src/app/first_delivery.rs` owns first-issue capability/retry state; `src/app/first_file.rs` runs first-file delivery; `src/app/reissue.rs` runs password reissue. `src/delivery.rs`, `src/delivery/files.rs`, `src/delivery/qr.rs`, and `src/vault.rs` are focused adapters/value owners. | No `app/delivery.rs` was created because session capability, file delivery and saved-record reissue have separate cohesive ownership. | `app::failed_file_publication_can_retry_in_a_different_directory`; `app::temporary_cleanup_failure_requires_manual_cleanup_before_first_issue_retry`; `client_delivery::reissue_unlocks_installed_saved_record_each_time_and_warns_after_reopen`. |
| M25 — restart scenario | `app/restart.rs` owns preview, attempt token, backup/job/read/compare/durable-publication order. `runtime.rs` owns complete peer projection/comparison; `service.rs` owns systemd adapter; persistence owns durable state. Keep test-only fixture apply behind `#[cfg(test)]`. | Preserve shared deadline, generation/attempt checks, job-submission uncertainty, unsupported-but-verifiable peers, and reservations until durable success. No real host service calls during tests. | `cargo test --locked app::`; `cargo test --locked runtime::`; `cargo test --locked service::`; `cargo test --locked --test commit_restore`; `cargo test --locked --test runtime_restart`. | | M25 — restart scenario | `src/app/restart.rs` owns preview, attempt token, backup/job/read/compare/durable-publication order; `src/runtime.rs` owns complete peer projection/comparison; `src/service.rs` owns systemd adapter; persistence owns durable state. | Fixture apply is compiled only under `#[cfg(test)]`. No host service calls occur in ordinary fixture tests. | `app::confirmed_restart_orders_backup_job_read_and_durable_publication`; `app::service_timeout_reports_submission_and_may_still_complete`; `app::restart_mismatch_and_post_restart_write_failure_never_release_addresses`. |
| M26 — read model and thin TUI command adapter | `app/read_model.rs` owns secret-free peer/state/issue/reservation/apply facts and per-action eligibility. `tui/state.rs` retains UI navigation/generation; events/executor owns worker lifecycle and command adaptation; forms own transient inputs; renderers own visual strings/styles/layout. | No TUI parsing of saved bytes or duplicated authorization policy. Preserve malformed-row inspection by document position, draft removals, action-specific eligibility, QR disclosure, keyboard behavior, worker serialization/generations/cancellation/shutdown and layout. | `cargo test --locked tui::`; `cargo test --locked --test tui_workflow`; `cargo test --locked --test client_delivery`. Exact worker, view-generation, selection and PTY tests are listed above. | | M26 — read model and TUI command adapter | `src/app/read_model.rs` owns secret-free peer/state/issue/reservation/apply facts and per-action eligibility. `src/tui/state.rs` owns UI navigation/generation; `src/tui/events.rs` and `src/tui/events/executor.rs` own worker lifecycle and command adaptation; forms own transient inputs; renderers own visual output. | TUI does not parse saved bytes or duplicate business authorization. Split of broader terminal/render modules was deferred; their shared lifecycle/layout helpers did not justify a larger move. | `tui::`; `tui_workflow`; `client_delivery`; M26 evidence records focused/full host results and limits. |
| M27 — integrated cleanup and handoff | Reconcile actual final owners in source, `docs/PROJECT_LAYOUT.md`, glossary and a reading guide; remove obsolete forwarding APIs only after all callers have migrated. | No feature addition, format/dependency changes, assertion weakening, or real-system claim. Review library/binary/integration/test-only container callers and M8 evidence invalidation. | `cargo test --locked --test config_preservation`; `cargo test --locked --test commit_restore`; `cargo test --locked --test client_delivery`; `cargo test --locked --test runtime_restart`; `cargo test --locked --test vault_import`; `cargo test --locked --test tui_workflow`; plus required RUST gates. |
### Test inventory gaps and verification notes ### Test inventory and verification notes
- There is no `tests/client_lifecycle.rs` target. Lifecycle coverage is - There is no `tests/client_lifecycle.rs` target. Lifecycle coverage is
distributed across `app::`, `client_delivery`, `commit_restore`, distributed across `app::`, `client_delivery`, `commit_restore`,
`vault_import`, and `tui_workflow`; the planned M22–M26 commands use existing `vault_import`, and `tui_workflow`; the M22–M26 work used existing
targets, and a new target is needed only if acceptance finds a real behavioral targets, and a new target is needed only if acceptance finds a real behavioral
gap. gap.
- There is no dedicated current integration test named for application - Application projection and eligibility are covered by colocated `app::`
projection/action eligibility. Existing checks are spread across `app::` tests plus `tui::` and `tui_workflow::` tests; no separate integration target
display logic, `tui::state`, `tui::render`, and `tui_workflow::saved_peer_projection_counts_legacy_peers_without_inventing_managed_state`. was needed.
- Restore reservation coverage currently proves only that addresses from - Restore reservation coverage includes manageable saved clients, exact routes
manageable clients in `ClientStates::saved()` survive replacement from unprojectable current peers, persisted reservations, and exact routes
(`commit_restore::restore_reserves_addresses_of_current_saved_clients_that_the_archive_removes`). retained by the restored document. `app/restore.rs` excludes routes still
`Application::preview_restore` unions persisted reservations with those owned by restored peers. The previous M19/M23 gap note is superseded by
manageable saved-client addresses; it does not read exact host routes from `restore_does_not_reserve_unprojectable_exact_hosts_owned_by_restored_document`.
unprojectable peers in the installed saved server configuration or include - `ClientStates::draft_mut` and `Application::vault_draft_mut` no longer exist.
`draft_unsupported_reservations`. The existing policy keeps deleted-client `Application::add_client` and injected-state `Application::open` remain
addresses reserved until verified restart, so this is a potential correctness public because integration fixtures use them; the caller audit above records
gap, not an agreed exception. M23 should add focused restore coverage for those exceptions. They are not the production create/startup path.
these sources and repair any uncovered preservation under the existing
requirement before claiming they are reserved.
- `ClientStates::draft_mut` and `Application::vault_draft_mut` have no external
production consumers. The latter currently exists in the public API solely
to support one colocated app test. App `add_client` and `open` have public
integration-test fixture consumers, so their removals need an explicit
fixture/API migration, not just a `pub` reduction.
- Existing test-only container driver is `src/container_driver.rs` included only - Existing test-only container driver is `src/container_driver.rs` included only
by `src/lib.rs` under `#[cfg(test)]`. Its normal fixture tests are synthetic; by `src/lib.rs` under `#[cfg(test)]`. Its normal fixture tests are synthetic;
ignored `container_driver::alpine_scenario_driver` is opt-in and is not an ignored `container_driver::alpine_scenario_driver` is opt-in and is not an
+54
View File
@@ -0,0 +1,54 @@
# Milestone 27 evidence — integrated refactoring handoff
Recorded 2026-10-30T23:18:12+02:00. Baseline HEAD: `7123197ec4a3fad74b71f5c7b598f1d6fd74d3a1`, initially clean. Final working tree is uncommitted and changes `CONTEXT.md`, `PLANS.md`, `docs/PROJECT_LAYOUT.md`, `docs/architecture/domain-refactoring.md`, `src/app.rs`, `src/app/backups.rs`, `src/app/first_file.rs`, `src/app/restart.rs`, `src/runtime/netlink.rs`, and `src/service.rs`. No Cargo manifest, lockfile, dependency, feature, persisted codec, archive, vault, settings-default, WireGuard editor, or fixture file changed in M27. Rust/Cargo 1.97.1, rustfmt 1.9.0, Clippy 0.1.97, native host target. All tests below used synthetic fixtures/PTY only; no production configuration, keys, VPN, host service, Docker daemon, or VM was accessed.
## Final inputs
| Input | SHA-256 |
| --- | --- |
| `CONTEXT.md` | `7dcfa4d86f70fb850f3416d6659275ee28237b5075c5beed82d2a33ad44150a4` |
| `docs/PROJECT_LAYOUT.md` | `f973207e71f20c6c912105c16546a51150acf63551a7f196ecd38d2101e9a44b` |
| `docs/architecture/domain-refactoring.md` | `45ad18a43b224f318b0a7e55548d47f7ccea8e2e719e3378ef35f419e3ec8391` |
| `src/app.rs` | `e235ff788c1b5f1ac0ac9951a9c4bb578205dfc65903d3ae80ed9f3142fb38da` |
| `src/app/backups.rs` | `b3b01289b20e262c24cfce79c507fe4d3761102df4863a11b3a90b2398b0692f` |
| `src/app/first_file.rs` | `d41fa3e2d2150c401ceee9caaeb7268b741a970105e5266123334cd78d977073` |
| `src/app/restart.rs` | `5d26cb877fd8a8211549e15868ccd450729ce3ecb54ea954efd15b379f5a2ce0` |
| `src/runtime/netlink.rs` | `396f4726880c7cf54764d6ff0c67aa1ab2d6c66cd36af7b1be4ca0e04862bab3` |
| `src/service.rs` | `e7c7a4367e2a0dc8a87113e3083d8998e7aebb56f6d4c32d5c763b9f239fa8eb` |
| `target/release/wireguard-admin` | `cb6e995d64a7cb7537c5fb17e86d609ca62fff150f519a970febd0800b0d4177` |
Source-input fingerprint from `rg --files src tests/support tests/containers tests/testcontainers_wireguard.rs Cargo.toml Cargo.lock | sort | xargs sha256sum | sha256sum`: `1b746e31e2e8c96f511c34b51e417b486d65fa0cc17983fa15e12882dd9c6a02`. This includes the final test-only backup visibility repair and identifies the host-tested source independently of the dirty plan/evidence files.
## Architecture and preservation audit
M19's baseline source was recorded against `23d6180f2478f636c185d67b8bb3788d21656ce3`. The coordinator inspected `git diff --stat` from that commit through M26 HEAD and the changed production/format-sensitive file list; that diff spans the M20–26 application/domain/TUI moves and changes only persistence test references, not its codec. `Cargo.toml`, `Cargo.lock`, settings defaults, backup/vault/byte-preserving editor implementation, and synthetic fixture files did not change in that baseline-to-M26 diff. The independent reviewer inspected the integrated refactor against the M19 map, current source and shared preservation matrix, including authority, public identity, unsupported/ambiguous peers, original imports, retained plaintext discipline, short-lived delivery secrets, saved/runtime separation, restart uncertainty, address release, TUI eligibility/generation and public visibility. No unresolved behavior, authorization, or secret-handling regression was found. Historical M19 restore-reservation gap was closed by M23 and is now mapped to actual tests and owner.
The architecture document now gives the three requested end-to-end reading paths with entry point, rule owner, side-effect boundary and failure tests, and resolves each M19 owner/transition to actual M20–26 modules/tests. The glossary remains domain-only and the layout lists present files. `ClientStates::draft_mut` and `Application::vault_draft_mut` were already removed. `Application::open`, `add_client`, and `display_projection` have active unit/integration or test-only container callers and remain with explicit caller/retention rationale; production startup/create uses the intended methods. A fixture-only pre-restart backup facade and its helper were restricted to private `#[cfg(test)]` code. Stale comments describing implemented confirmation, D-Bus and netlink flows as future work were corrected. No test assertion was weakened.
Existing preserved-format and behavior coverage includes the focused `config_preservation`, `commit_restore`, `client_delivery`, `runtime_restart`, `vault_import`, and `tui_workflow` suites below, plus persistence, archive, vault, domain, service and application tests in the full suite. Old fixture inputs still load with unchanged meaning under these host checks; this is synthetic compatibility evidence, not a new real-system run.
## Integrated checks
All commands ran in the repository root after the final source repair. Exit 0 unless specified.
| Command | Actual result |
| --- | --- |
| `cargo test --locked --test config_preservation` | 10 passed, 0 failed |
| `cargo test --locked --test commit_restore` | 9 passed, 0 failed |
| `cargo test --locked --test client_delivery` | 5 passed, 0 failed |
| `cargo test --locked --test runtime_restart` | 3 passed, 0 failed |
| `cargo test --locked --test vault_import` | 5 passed, 0 failed |
| `cargo test --locked --test tui_workflow` | 9 passed, 0 failed |
| `cargo fmt --all -- --check` | Exit 0 |
| `cargo clippy --locked --all-targets -- -D warnings` | Exit 0 |
| `cargo test --locked` | Exit 0; library 352 passed, 2 ignored; integration and 2 doc tests passed; opt-in Alpine tests stayed ignored |
| `cargo build --locked --release` | Exit 0; artifact hash above |
| `git diff --check` | Exit 0 |
The first final-gate attempt after making the fixture facade test-only found Clippy dead code in its child helper. The repair made the child helper test-only too; the entire table above was rerun on that final source. The initial failed attempt is diagnostic history, not a passing gate.
## Independent review and limits
Fresh reviewer `/root/m27_review` was separate from implementer `/root/m27_implement`; repairer `/root/m27_repair` made bounded fixes. R1 (missing `display_projection` caller audit), R2 (stale plan resume point), R3 (future-work source comments), and R4 (fixture-only public backup API) were repaired and re-reviewed. R4's first repair exposed the Clippy dead-code helper; the second repair and final gates closed it. The reviewer independently verified the final source, fingerprint and binary hashes, reran formatting, Clippy, full tests, release build and diff check, and confirmed M27-A4 plan/evidence consistency after the register correction. No scoped review finding remains.
M8's last Alpine result used fingerprint `b28dc6e4cb92aa6edf384d966ba5952a8d6d0efe4c22d6a804b67fb2c0297da2`; today's final source fingerprint differs. The M8 run is historical and **does not validate this source**. No explicitly selected current disposable daemon/driver was provided for M27, so Alpine revalidation is incomplete and no Alpine pass is claimed. The retired M9 disposable-VM/systemd checks remain unverified; Alpine would not prove actual systemd/D-Bus behavior. Real IPv6 capability/traffic and release readiness are also unverified. M27 acceptance is limited to host/synthetic scope.
+4 -3
View File
@@ -869,9 +869,10 @@ impl Application {
backups::list_backups(self) backups::list_backups(self)
} }
/// Reusable mandatory backup boundary for M5 before it invokes restart. /// Create a pre-restart archive for fixture verification bookkeeping.
/// This method only archives saved bytes; it never calls a runtime adapter. /// Production restart sequencing owns its mandatory backup operation.
pub fn create_pre_restart_backup(&mut self) -> Result<std::path::PathBuf, AppError> { #[cfg(test)]
fn create_pre_restart_backup(&mut self) -> Result<std::path::PathBuf, AppError> {
backups::create_pre_restart_backup(self) backups::create_pre_restart_backup(self)
} }
+1
View File
@@ -30,6 +30,7 @@ pub(super) fn list_backups(application: &Application) -> Result<Vec<ArchiveSumma
} }
} }
#[cfg(test)]
pub(super) fn create_pre_restart_backup( pub(super) fn create_pre_restart_backup(
application: &mut Application, application: &mut Application,
) -> Result<std::path::PathBuf, AppError> { ) -> Result<std::path::PathBuf, AppError> {
+1 -1
View File
@@ -14,7 +14,7 @@ impl Application {
/// record, and one-use token are valid. The mutable app borrow remains held /// record, and one-use token are valid. The mutable app borrow remains held
/// across `publish`, so no application mutation can interleave after the /// across `publish`, so no application mutation can interleave after the
/// final saved-state validation and before the file adapter runs. /// final saved-state validation and before the file adapter runs.
#[allow(dead_code)] // M6.3 invokes this for its initial-file action. #[allow(dead_code)] // Retained as a unit-test seam for generic publication closures.
pub(crate) fn deliver_first_issue<T, E>( pub(crate) fn deliver_first_issue<T, E>(
&mut self, &mut self,
identity: PublicKey, identity: PublicKey,
+1 -1
View File
@@ -20,7 +20,7 @@ use time::format_description::well_known::Rfc3339;
use super::{AppError, Application, clone_saved, historical_apply_from_saved, same_saved_bytes}; use super::{AppError, Application, clone_saved, historical_apply_from_saved, same_saved_bytes};
/// Read-only, saved-generation-bound restart preview for a future confirmation UI. /// Read-only, saved-generation-bound preview used by the explicit restart confirmation flow.
pub struct RestartPreview { pub struct RestartPreview {
saved: SavedBytes, saved: SavedBytes,
interface: String, interface: String,
+2 -2
View File
@@ -40,8 +40,8 @@ pub(crate) struct DecodeContext {
pub family_id: u16, pub family_id: u16,
} }
/// Hard aggregate limits for one dump. These are deliberately supplied by the /// Hard aggregate limits for one dump, supplied by the current netlink
/// future adapter so its policy is visible at construction time. /// transport so its policy is visible at construction time.
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct DecodeLimits { pub(crate) struct DecodeLimits {
pub max_datagrams: usize, pub max_datagrams: usize,
+1 -1
View File
@@ -66,7 +66,7 @@ pub enum JobResult {
Other, Other,
} }
/// An event delivered by the future D-Bus adapter. /// An event emitted by the D-Bus adapter and consumed by the job tracker.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum ServiceEvent { pub enum ServiceEvent {
JobRemoved { JobRemoved {