<!-- SOLIDIVISM · part 28 -->
action: 'code.deploy', target: 'foundation.js:v16')
```

### What the Ledger Shows After Rollback

```
v14 deployed     → event recorded
v15 deployed     → event recorded
v15 failed       → event recorded (test failure, user report, etc.)
rollback to v14  → event recorded (initiated + completed)
v14 running      → event recorded (verification)
```

All five events persist. The ledger tells the full story: what was tried, what failed, what was restored.

### What Rollback Does NOT Do

- Does NOT delete v15 deployment event
- Does NOT delete failure event
- Does NOT modify any existing ledger entries
- Does NOT clear localStorage cache (pending events still sync)

### Emergency Rollback (3D broken, Epistemology unreachable)

If the 3D world is broken and Epistemology cannot record:
1. Restore code via file operation (no database needed)
2. When system recovers, backfill: INSERT `rollback.completed` event with `source: 'backfill'` and `event_time` set to actual rollback time
3. Mark as backfilled (confidence may be lower for exact timestamps)

---

## SAFEGUARD 5: FAILURE MODE TESTS

### T-F1: Process Restart

**Test:** Kill Node server mid-session. Restart. Verify:
- Ledger entries before restart are intact (in PostgreSQL, not memory)
- In-memory Maps rebuild correctly from database
- Unsynced localStorage events are retried
- No duplicate events (idempotency keys prevent re-insertion)

```javascript
// Simulate: insert event, kill before sync confirmed
// Restart, attempt sync again with same idempotency key
// Assert: single row in database (UNIQUE constraint on idempotency_key)
```

### T-F2: Duplicate Events

**Test:** Send same event twice (same idempotency key). Verify:
- Second INSERT is rejected (UNIQUE violation)
- Server returns already-accepted status
- Browser removes from cache (not stuck in retry loop)

```sql
-- First insert succeeds
-- Second insert with same idempotency_key → UNIQUE violation
-- Application catches, returns { status: 'duplicate', event_id: <existing> }
```

### T-F3: Concurrent Writes

**Test:** Two browser tabs write events simultaneously. Verify:
- Both events recorded (no lost updates)
- Timestamps reflect actual insertion order (clock_timestamp, not transaction start)
- No deadlocks (INSERT-only workload, no lock contention)

```javascript
// Tab A and Tab B each POST 100 events concurrently
// Assert: 200 rows in database, all with unique event_ids
// Assert: no errors, no retries needed
```

### T-F4: Corrupted Records

**Test:** Manually corrupt a record's checksum (via admin role). Verify:
- Read path detects mismatch
- Corrupted event is flagged, not trusted
- System continues operating (does not crash)
- Corruption event is recorded in ledger (via separate uncorrupted insert)

```javascript
const event = await Ledger.read(eventId);
assert(event === null);  // Rejected due to checksum mismatch
assert(CorruptionLog.has(eventId));  // Flagged
```

### T-F5: Unauthorized Modifications

**Test:** Attempt UPDATE and DELETE as application role. Verify:
- Both are rejected (trigger raises exception)
- Application handles rejection gracefully
- No data modified

```sql
-- As solidivism_app role:
UPDATE solidivism_events SET action = 'hacked' WHERE event_id = '...';
-- Expected: ERROR: solidivism_events is append-only.

DELETE FROM solidivism_events WHERE event_id = '...';
-- Expected: ERROR: solidivism_events is append-only.
```

### T-F6: Incomplete Transactions

**Test:** Begin transaction, INSERT event, kill connection before COMMIT. Verify:
- No partial event in database (transaction rolled back)
- Browser retries on reconnect (event still in localStorage cache)
- No orphaned data

```javascript
// Simulate: POST events, server begins transaction, connection drops
// Assert: 0 rows committed for that batch
// Assert: browser retains events in cache, retries successfully
```

---

## SAFEGUARD 6: PERSONA INTEGRITY

### Evidence-Aware Contemplation

The Persona's `contemplate()` and `reflect()` functions must:

1. **Read from PostgreSQL, not memory.** When generating wonder or assessing confidence, query the authoritative ledger.

2. **Never fabricate significance.** If significance cannot be grounded in actual entities/decisions:
```javascript
{
  significance: {
    type: "unknown",
    acknowledgment: "Cannot determine why this matters. Not inventing significance."
  }
}
```

3. **Never inflate confidence.** Confidence levels derived from evidence count and type:
```javascript
function assessConfidence(evidence) {
  const verified = evidence.filter(e => e.causalType === 'verified').length;
  const inferred = evidence.filter(e => e.causalType === 'inferred').length;
  if (verified >= 2) return 'high';
  if (verified === 1) return 'medium';  // Single verified is not high
  if (inferred >= 2) return 'medium';
  if (inferred === 1) return 'low';
  return 'unknown';
  // No path to 'high' without multiple verified evidence
}
```

4. **Self-e