# Repository Engine `Potable.Repository` is a pure-functional repo engine built on top of Potable primitives. Every operation is parameterized by: - current head CID (or `nil`) - repo DID - signing material / verifier spec as needed - blockstore process reference No internal mutable state is hidden in the module. ## Data Model - Record path key: `collection <> "/" <> rkey` - Record value: CID of DAG-CBOR encoded record map - MST maps path -> record CID - Commit points to MST root via `"data"` field ## API Summary Create and mutate: - `create_repo(did, signing_material, store) -> {:ok, head_cid} | {:error, reason}` - `apply_writes(head, did, writes, signing_material, store) -> {:ok, new_head_cid} | {:error, reason}` Read: - `get_record(head, collection, rkey, store) -> {:ok, map} | :not_found` - `list_records(head, collection, opts, store) -> {:ok, [{rkey, map}]}` Portability: - `export_car(head, store) -> {:ok, binary} | {:error, reason}` - `import_car(car_bytes, store) -> {:ok, head_cid} | {:error, reason}` Integrity: - `verify_repo(head, verifier_spec, store) -> :ok | {:error, reason}` - `verify_repo_with_resolver(head, resolver_module, store, opts) -> :ok | {:error, reason}` ## Write Semantics Each `apply_writes/5` call: 1. resolves current MST root from current head (if any) 2. applies ordered write set to MST 3. ensures non-`nil` MST root block exists (empty root when needed) 4. creates signed commit with `prev = old_head` 5. stores commit block and returns new commit CID ### Write Tuple Types - `{:create, collection, rkey, record_map}` - `{:update, collection, rkey, record_map}` - `{:delete, collection, rkey}` ### Enforcement `apply_writes/5` enforces: - collection validation (`.` required, `/` forbidden) - rkey character constraints (allows composite keys used by Roster, rejects invalid chars) - create vs update vs delete semantics: - create fails with `{:error, :already_exists}` if key exists - update/delete fail with `{:error, :not_found}` if key is missing - record value validation: - map keys must be strings after atom-key normalization - floats are rejected with `{:error, {:unsupported_value_type, :float}}` ### Record Key Conversion - Atom-keyed maps are accepted on input. - All persisted/read maps use string keys. ## Read Semantics `get_record/4`: - returns `:not_found` for `nil` head - traverses commit -> MST root -> key lookup -> record block decode `list_records/4`: - prefixes MST scan by `collection <> "/"` to isolate collection - supports `limit` and `after` options ## Export/Import Semantics `export_car/2` walks commit chain and collects: - commit blocks - all referenced MST node blocks - all referenced record blocks `import_car/2`: - imports and validates all blocks via `Potable.CAR` - requires exactly one root - returns `{:error, :invalid_root_count}` for zero/multi-root archives ## Verification Semantics `verify_repo/3` checks: 1. commit signature validity 2. commit block CID-content consistency 3. MST block CID-content consistency 4. record block CID-content consistency Useful for: - tamper detection - migration validation - import verification after transfer `verify_repo_with_resolver/4` additionally enforces: 1. commit DID continuity across the full chain 2. DID/revision-aware verifier lookup via resolver callback 3. key rotation/revocation policy at verification time