# Architectural Decision Records - LastID Rust SDK

Track architectural decisions with context, alternatives, and consequences.

---

## Template

```markdown
# ADR-[000]: Descriptive Title

**Status:** `PROPOSED | ACCEPTED | SUPERSEDED | REJECTED`
**Date:** YYYY-MM-DD
**Deciders:** @username1, @username2

---

## 1. Context and Problem Statement
*Describe the technical challenge. Why is this decision needed?*

## 2. Decision Drivers
* [e.g., Cross-platform compatibility]
* [e.g., Zero-cost abstractions]
* [e.g., 95% test coverage requirement]

## 3. Considered Options
1. **Option A:** [Short description]
2. **Option B:** [Short description]

## 4. Decision Outcome
Chosen Option: **[Option Name]**

### Justification
*Why is this the best path? Reference constitution principles if applicable.*

## 5. Consequences
* **Positive:** [e.g., Compile-time guarantees]
* **Negative:** [e.g., Increased complexity]
* **Risks:** [e.g., Dependency concerns]

## 6. Validation Plan
* [ ] Tests verify the decision holds under all conditions.
* [ ] Cross-platform verification completed.
```

---

## Accepted Decisions

### ADR-001: TOML-Only Configuration (No YAML)

**Status:** `ACCEPTED`
**Date:** 2026-01-16

#### 1. Context and Problem Statement
The SDK needs configuration file support. YAML was considered but `serde_yaml` has been abandoned (RUSTSEC-2025-0068).

#### 2. Decision Drivers
* Security advisory compliance (48hr response requirement per constitution)
* Cross-platform compatibility
* Rust ecosystem alignment (Cargo.toml precedent)

#### 3. Considered Options
1. **YAML:** Familiar to many developers
2. **TOML:** Native Rust ecosystem, actively maintained
3. **JSON:** Universal but verbose

#### 4. Decision Outcome
Chosen Option: **TOML**

#### Justification
TOML is the standard in Rust ecosystem, has active maintenance, and aligns with the SDK's security-first principles. JSON remains supported for API responses.

#### 5. Consequences
* **Positive:** No security advisory, consistent with Cargo.toml
* **Negative:** Some developers less familiar with TOML
* **Risks:** None identified

---

### ADR-002: Type-State Pattern for Policy Builders

**Status:** `ACCEPTED`
**Date:** 2026-01-16

#### 1. Context and Problem Statement
Policy builders need compile-time validation to prevent invalid configurations.

#### 2. Decision Drivers
* Customer-facing quality (constitution principle I)
* Code cleanliness (constitution principle III)
* Prevent runtime errors in production

#### 3. Considered Options
1. **Runtime validation:** Check at build() time
2. **Type-state pattern:** Compile-time enforcement via phantom types

#### 4. Decision Outcome
Chosen Option: **Type-state pattern**

#### Justification
Compile-time enforcement catches errors before code ships. Aligns with Rust's zero-cost abstractions philosophy.

#### 5. Consequences
* **Positive:** Invalid states unrepresentable
* **Negative:** More complex type signatures
* **Risks:** Learning curve for contributors

---

### ADR-003: parking_lot for Thread-Safe Locks (No Lock Poisoning)

**Status:** `ACCEPTED`
**Date:** 2026-01-18

#### 1. Context and Problem Statement
The SDK uses `SharedLock<T>` for thread-safe caching of tokens and DPoP nonces. With `std::sync::RwLock`, if a thread panics while holding a lock, the lock becomes "poisoned" and subsequent access returns `PoisonError`. The original code handled this by:
- Calling `.expect("lock poisoned")` which would panic
- Or using `.ok()` which silently ignores failures

Both approaches are problematic for a library: panicking is unacceptable, and silently ignoring errors can lead to stale data.

#### 2. Decision Drivers
* Reliability for identity/auth operations (constitution principle I)
* Libraries should not panic (Rust best practice)
* Data protected by locks (tokens, nonces) can be re-acquired from server if corrupted
* Cross-platform compatibility (WASM uses RefCell, native uses RwLock)

#### 3. Considered Options
1. **Return `Result<Guard, PoisonError>`:** Propagate errors to callers
2. **Use `unwrap_or_else` with poison recovery:** Clear poison and continue
3. **Use `parking_lot::RwLock`:** Locks without poisoning semantics

#### 4. Decision Outcome
Chosen Option: **`parking_lot::RwLock`**

#### Justification
`parking_lot` is a well-established crate used by Firefox and Tokio ecosystem. It provides:
- **No lock poisoning:** When a thread panics, the lock is automatically released and remains usable
- **Better performance:** Faster than `std::sync` primitives
- **Simpler API:** `read()`/`write()` return guards directly, not `Result`
- **Same semantics as RefCell on WASM:** Unified mental model across platforms

For an identity SDK where reliability is critical, automatic recovery from panics is preferred over propagating failures. The cached data (tokens, nonces) can always be re-acquired from the server if corrupted.

#### 5. Consequences
* **Positive:** Simpler code, no panic paths, automatic recovery from thread panics
* **Negative:** Additional dependency (parking_lot)
* **Risks:** None identified - parking_lot is mature and widely used

#### 6. Validation Plan
* [x] Test verifies lock remains usable after thread panic (`test_lock_survives_panic_in_another_thread`)
* [x] All 230 existing tests pass
* [x] Clippy lints pass

---

## Proposed Decisions

*No pending proposals.*

---

## Superseded Decisions

*No superseded decisions.*
