Background
Surfaced by PR review of #5 — type-design analyst suggested adding `#[non_exhaustive]` to `pub enum MitreTactic` in `src/mitre.rs`. Validated against external best-practice (Perplexity): "appropriate for closed-today, possibly-extended-later enums bound to external versioned standards" — MITRE ATT&CK is exactly this case (e.g., v14 added new tactics; v18 is current as of this writing).
What `#[non_exhaustive]` does
```rust
#[non_exhaustive]
pub enum MitreTactic {
Reconnaissance,
// ...
}
```
Forces every `match` on `MitreTactic` outside this crate to include a wildcard arm (`_ => ...`). When MITRE adds a new tactic in a future version and we add the variant, downstream code does NOT break — the wildcard arm catches it.
Trade-offs
| With |
Without (current) |
| Adding a new variant is non-breaking. |
Adding a new variant is a breaking change for any external matcher. |
| Callers must include `_ => ...` in every match. |
Compiler enforces full exhaustiveness — typo-safe. |
| Aligns with `std::io::ErrorKind` precedent for evolving external standards. |
Aligns with `clap::ArgKind` precedent for fixed CLI semantics. |
Why deferred
The crate has no external consumers today, so the API-stability benefit of `#[non_exhaustive]` is theoretical. The minor cost — wildcard arms in our own matches — is real. But the cost is low and the benefit kicks in the moment anyone outside this crate matches on the enum.
Acceptance criteria
- `#[non_exhaustive]` added to `pub enum MitreTactic`.
- Internal `match` statements (`Display` impl, `technique_tactic` lookup) updated only if needed (in-crate matches don't require the wildcard arm).
- A short comment near the attribute explaining the rationale ("MITRE adds tactics in new ATT&CK versions; downstream callers should be insulated").
Background
Surfaced by PR review of #5 — type-design analyst suggested adding `#[non_exhaustive]` to `pub enum MitreTactic` in `src/mitre.rs`. Validated against external best-practice (Perplexity): "appropriate for closed-today, possibly-extended-later enums bound to external versioned standards" — MITRE ATT&CK is exactly this case (e.g., v14 added new tactics; v18 is current as of this writing).
What `#[non_exhaustive]` does
```rust
#[non_exhaustive]
pub enum MitreTactic {
Reconnaissance,
// ...
}
```
Forces every `match` on `MitreTactic` outside this crate to include a wildcard arm (`_ => ...`). When MITRE adds a new tactic in a future version and we add the variant, downstream code does NOT break — the wildcard arm catches it.
Trade-offs
Why deferred
The crate has no external consumers today, so the API-stability benefit of `#[non_exhaustive]` is theoretical. The minor cost — wildcard arms in our own matches — is real. But the cost is low and the benefit kicks in the moment anyone outside this crate matches on the enum.
Acceptance criteria