# UAT Plan: Policy Source Tracking in Persistent Mode

**Goal:** Verify that persistent mode now tracks and displays policy source attribution (pack name, version, issuer) in conflict reports — matching ephemeral mode behavior.

**Hypothesis:** Teams adopting Aphoria's persistent mode need full provenance in conflict reports. Without knowing *which* Trust Pack flagged a violation, developers can't escalate to the right team or understand why a policy exists.

## 1. Test Environment

**Aphoria Version:** 0.1.0 + PackSourceStore
**Configuration:**
```toml
# Project A: Policy Publisher
[scan]
mode = "persistent"

# Project B: Policy Consumer
[scan]
mode = "persistent"
policies = ["../project_a/security-standard.pack"]
```

## 2. Success Criteria

| Test Case | Expected Result | Status |
|-----------|-----------------|--------|
| Import stores pack source | `PackSourceStore` contains entry for each assertion subject | |
| Conflict shows policy_source | `ConflictingSource.policy_source` is `Some(...)` not `None` | |
| Pack name correct | `policy_source.pack_name` matches exported pack name | |
| Pack version correct | `policy_source.pack_version` matches exported version | |
| Issuer hex correct | `policy_source.issuer_hex` is 8 chars (4 bytes of public key) | |
| Multiple packs isolated | Assertions from different packs show their respective sources | |
| Persistence survives restart | Reopen `LocalEpisteme`, pack sources still queryable | |

## 3. Execution Plan

### Step 1: Create Policy Publisher (Project A)

```bash
mkdir -p /tmp/uat-policy-source/project_a
cd /tmp/uat-policy-source/project_a

# Initialize Aphoria
mkdir -p .aphoria
cat > aphoria.toml << 'EOF'
[episteme]
data_dir = ".aphoria/db"
EOF

# Create a TLS policy assertion
aphoria bless "code://rust/acme/tls/cert_verification" enabled true \
  --reason "All Acme services MUST verify TLS certificates"

# Export as Trust Pack
aphoria export --name "Acme Security Standard" --output security-standard.pack
```

**Checkpoint:** Verify `security-standard.pack` exists and is valid:
```bash
ls -la security-standard.pack
# Should be non-empty binary file
```

### Step 2: Create Policy Consumer (Project B)

```bash
mkdir -p /tmp/uat-policy-source/project_b/src
cd /tmp/uat-policy-source/project_b

# Create Cargo.toml
cat > Cargo.toml << 'EOF'
[package]
name = "project_b"
version = "0.1.0"
EOF

# Create violating code
cat > src/client.rs << 'EOF'
fn create_client() -> Client {
    reqwest::Client::builder()
        .danger_accept_invalid_certs(true)  // Violates policy!
        .build()
        .unwrap()
}
EOF

# Configure Aphoria with imported policy
cat > aphoria.toml << 'EOF'
[episteme]
data_dir = ".aphoria/db"

[policies]
security = "../project_a/security-standard.pack"
EOF
```

### Step 3: Import Policy and Scan

```bash
cd /tmp/uat-policy-source/project_b

# Import the policy (stores pack sources)
aphoria import ../project_a/security-standard.pack

# Run persistent mode scan
aphoria scan . --mode persistent --format json > scan_result.json
```

### Step 4: Verify Policy Source Attribution

```bash
# Check JSON output for policy_source field
cat scan_result.json | jq '.findings[].conflicting_sources[].policy_source'
```

**Expected Output:**
```json
{
  "pack_name": "Acme Security Standard",
  "pack_version": "0.1.0",
  "issuer_hex": "a1b2c3d4"
}
```

### Step 5: Verify Persistence

```bash
# Restart and scan again (should still have policy source)
aphoria scan . --mode persistent --format table
```

**Expected:** Table output shows "Source: Acme Security Standard (a1b2c3d4)" in conflict details.

## 4. Edge Cases

| Scenario | Expected Behavior |
|----------|-------------------|
| Hardcoded corpus assertion (no pack) | `policy_source: null` |
| Same subject from multiple packs | Last imported pack wins |
| Empty pack (no assertions) | No pack sources stored |
| Corrupted pack file | Import fails with signature error |

## 5. Artifacts

Upon completion, create:
- `2026-02-04-uat-policy-source-results.md` with pass/fail for each criterion
- Screenshot of table output showing policy source attribution

## 6. Risk Assessment

- **False Negative:** If pack source lookup fails silently, conflicts show `policy_source: None` and we lose provenance. Mitigated by `warn!` logging on lookup errors.
- **Performance:** JSON serialization for every subject adds latency. Acceptable for policy import (one-time cost), not in hot path.

---

**Next Step:** Execute Steps 1-5 and record results.
