# BUILD NOTES — Sovereign Identity Fabric

## Design decisions

- **Crypto reuse.** The HMAC-SHA256 + base64url "JWS-with-HMAC" pattern is
  lifted directly from `../packet_layer/token_mint.py` and
  `../forensics_lab_unified/caller_id.py` (same `_b64u_encode/_decode`,
  `hmac.compare_digest` constant-time signature check, per-entity `os.urandom(32)`
  secret). Nothing cryptographic was reinvented.
- **Structural prefix encodes both axes.** Rather than only a type prefix
  (`PSN-`/`BIZ-`/`GOV-` as in the inbound caller-id), the fabric prefix encodes
  kind *and* jurisdiction (`GOV-DOM-`, `BIZ-INT-`, …). `verify()` distinguishes a
  wrong-**kind** reason from a wrong-**jurisdiction** reason for precise flags.
- **Rotation = epoch bump + secret re-derivation.** Bumping only an epoch would
  let an attacker with a leaked secret re-sign; re-deriving the secret as well
  means a stale token fails *both* the epoch check and the signature check. The
  verify test at check #5 asserts the signature failure path specifically.
- **Cloud IN/OUT are independent streams.** Each entity gets separate `in` and
  `out` secrets + epochs (`cloud_streams` table), so the inbound and outbound
  cloud tokens are structurally different *and* rotate independently. A `CLD-IN-`
  token is rejected when presented as outbound (check #8).
- **Egress (ADD-B)** has its *own* per-entity secret+epoch stream
  (`egress_streams`), separate from the identity secret, so egress can rotate on
  its own cadence. Sensitivity drives ttl + rotation cadence
  (`TOP`=60s, `SENSITIVE`=900s, `PUBLIC`=3600s). A forged/re-signed or replayed
  token triggers an instant egress rotation (breach response). `trace()` joins
  the `egress_items` row with every hash-chained ledger event carrying the
  tracking id.
- **Ledger hash-chain.** `row_hash = sha256(prev_hash + canonical_json(row))`.
  `verify_chain()` recomputes the whole chain; check #14 mutates a row and
  confirms detection.

## Storage
Three SQLite DBs (all local, git-ignorable): `fabric.db` (entities + cloud
streams), `fabric_ledger.db` (hash-chained audit), `egress.db` (egress streams +
tracked items). `reset_db()` on each clears WAL/SHM sidecars too.

## Verification
`verify_run.py` runs **20** checks (14 fabric + 6 egress), all PASS. It resets
all DBs first so the run is deterministic and self-contained.

## Constraints honored
- No `socket`, `requests`, or `urllib` outbound anywhere. `fabric_server.py`
  binds `127.0.0.1:5070` only. Flask is the sole third-party dependency.
- Honest labels throughout: boundary-only enforcement, synthetic data, not audited.

## Known caveats
- The dashboard fetches Google Fonts CSS for styling *if a browser is open and
  online*; this is a client-side, cosmetic request made by the browser, not by
  the server, and matches the existing `lab_server.py`. The Python process
  itself performs no network I/O. Remove the `<link>` tags for a fully offline
  look.
- Token TTLs use wall-clock `time.time()`; `verify(..., at_time=)` allows
  deterministic expiry testing.
