feat(error): land the fail-closed key-source error taxonomy

- KeySourceError with exactly five variants (Locked, Absent,
  Decryption, UnknownKeyVersion, Decode) — ADR-005 decision 4's
  failure matrix as distinct shapes, the vault taxonomy reshaped
  never collapsed; no catch-all, no Other/Unknown
- payload shapes pinned: Locked/Absent payload-free;
  Decryption/UnknownKeyVersion carry the vault's opaque messages;
  Decode carries a message so the RC-pinned ssh-key error type
  never enters the public API (flagged for the wave-1 gate)
- each variant doc-commented with ADR-005 semantics + fail-closed
  consequence; module stays engine-blind (no vault/russh types)
- no From<VaultServiceError>: non-mappable vault variants would
  force a collapse; w1-key-sources maps explicitly at its seam
- exhaustive-match + Display/Debug/Clone unit tests

Verified: cargo test (default + all-features), cargo clippy
--all-targets --all-features -- -D warnings, cargo fmt --check,
cargo doc --no-deps, taskgraph validate
This commit is contained in:
glm-5.3-flash committed 2026-10-28 06:22:52 +00:00
1 parent 78ae905b21
commit d85299df38
3 files changed
+220 -7

No files matched your search

+42 -7
View File
@@ -1,7 +1,7 @@
---
id: w1-error-model
name: Wave 1 — the error model (fail-closed taxonomy)
status: pending
status: completed
depends_on: [w1-manifest]
scope: narrow
risk: low
@@ -39,13 +39,13 @@ message is the honest content), flagged for the wave-1 gate.
## Acceptance Criteria
- [ ] `KeySourceError` has exactly the five pinned variants; no
- [x] `KeySourceError` has exactly the five pinned variants; no
catch-all, no `Other`/`Unknown`
- [ ] Doc comments state each variant's ADR-005 semantics and its
- [x] Doc comments state each variant's ADR-005 semantics and its
fail-closed consequence
- [ ] Unit tests construct every variant and assert `Display`/`Debug`
- [x] Unit tests construct every variant and assert `Display`/`Debug`
paths compile clean
- [ ] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
- [x] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
`cargo fmt --check` pass
## References
@@ -56,8 +56,43 @@ message is the honest content), flagged for the wave-1 gate.
## Notes
> To be filled by implementation agent
> Payload shapes pinned (flagged for the wave-1 gate): `Locked` and
> `Absent` are payload-free — no honest content beyond the variant
> itself (the caller knows which source it requested);
> `Decryption(String)` and `UnknownKeyVersion(String)` carry the
> vault's opaque messages (`VaultServiceError::Encryption` /
> `InvalidPath` arrive as strings per POC-2 §3 — string is the honest
> content). `Decode` carries `String` rather than the typed
> `ssh_key::Error` (`russh::keys::decode_secret_key`'s error type):
> the ssh-key RC type is deliberately kept out of the published
> public API — when the RC settles the payload can be re-typed, but
> freezing an RC error type now would be a worse one-way door. The
> module doc comment records the deliberately-not-error classes
> (auth declines = dispositions per ADR-004; wire decline reasons =
> wave-2; config validation = none unless w1-config finds a need —
> the OQ-08 fields decline at request time). No `From<VaultServiceError>`
> blanket impl on purpose: alkvault's taxonomy has variants
> (`Mnemonic`, `Derivation`, `AlreadyUnlocked`, `UnsupportedKeyType`)
> that do not map onto the five without collapsing, and the ADR's
> reshape-never-collapse rule kills the conversion; w1-key-sources
> maps explicitly at its seam. The module stays engine-blind — no
> alkvault or russh types referenced at the error layer. Tests: an
> exhaustive `match` (no wildcard — the closed-variant invariant is
> compile-time enforced) plus `Display` string assertions over all
> five variants, `Debug` output, and `Clone` payload carrying.
## Summary
> To be filled on completion
> `src/error.rs` landed: `KeySourceError` with exactly five variants
> (`Locked`, `Absent`, `Decryption(String)`, `UnknownKeyVersion(String)`,
> `Decode(String)`), each doc-commented with its ADR-005 semantics and
> fail-closed consequence (locked → no dial + no server; absent/decryption/
> unknown-version/decode → no dial; host-key path → no server
> construction throughout). Re-exported from the crate root
> (`mod error; pub use error::KeySourceError;` — the alktty pattern).
> No catch-all, no `Other/Unknown`, no blanket `From` from the vault's
> taxonomy. Four unit tests (exhaustive match over the enum,
> `Display`, `Debug`, `Clone`). Verified: `cargo test` (4/4 + doc
> tests), `cargo test --all-features`, `cargo clippy --all-targets
> -- -D warnings` (default + all-features), `cargo fmt --check`,
> `cargo doc --no-deps` (no warnings), `taskgraph validate` clean.