CRUMB a card from devarno-cloud

REST API — Sprite CRUD & Verification

iris intermediate 5 min read

ELI5

The sprite API is like a library’s card catalog system. You can add new books (create), look up details (get), update information (update), remove books (delete), and verify that a book hasn’t been secretly swapped for a fake (fingerprint check).

Technical Deep Dive

Endpoint Summary

MethodPathOperationStatus Codes
POST/v1/spritescreateSprite201, 400, 409
GET/v1/sprites/{id}getSprite200, 404
PUT/v1/sprites/{id}updateSprite200, 400, 404, 409
DELETE/v1/sprites/{id}deleteSprite204, 404, 409
GET/v1/sprites/{id}/fingerprintverifySpriteFingerprint200, 404

Create Sprite (POST /v1/sprites)

sequenceDiagram
participant Client
participant Router as sprites.py
participant Registry as SpriteRegistry
participant Engine as FingerprintEngine
Client->>Router: POST /v1/sprites
Note over Client,Router: Content-Type: application/json OR application/x-yaml
Router->>Router: Parse body → SpriteCreate
Router->>Router: validate_sprite_name()
Router->>Registry: Check (name, version) duplicate
alt Duplicate exists
Registry-->>Router: Conflict
Router-->>Client: 409 Name+Version conflict
else Unique
Router->>Engine: compute_fingerprint(sprite_data)
Engine-->>Router: blake3:64hex
Router->>Registry: create(sprite_data, fingerprint)
Registry->>Registry: Generate UUID + timestamp
Registry-->>Router: Sprite (with id, fingerprint, created)
Router-->>Client: 201 Sprite
end

Accepts: application/json or application/x-yaml Returns: 201 Created with full Sprite object (server-generated id, fingerprint, metadata.created)

Update Sprite (PUT /v1/sprites/{id})

sequenceDiagram
participant Client
participant Router as sprites.py
participant Registry as SpriteRegistry
Client->>Router: PUT /v1/sprites/{id}
Router->>Registry: get_by_id(id)
alt Not found
Registry-->>Router: None
Router-->>Client: 404
else Found
Router->>Router: Validate version > current (packaging.version)
alt Version not greater
Router-->>Client: 409 Version conflict
else Valid update
Router->>Router: Recompute fingerprint
Router->>Registry: update(id, data, fingerprint)
Registry-->>Router: Updated Sprite
Router-->>Client: 200 Sprite
end
end

Rules:

  • id and name are immutable
  • version must be strictly greater than current (uses packaging.version comparison)
  • Fingerprint is always recomputed
  • Previous version is recorded in registry history

Delete Sprite (DELETE /v1/sprites/{id})

flowchart TD
A["DELETE /v1/sprites/{id}"] --> B{"Sprite in active council?"}
B -->|Yes| C["409 Conflict"]
B -->|No| D{"Protected?"}
D -->|Yes| E{"force=true?"}
E -->|No| F["409 Protected sprite"]
E -->|Yes| G["Delete ✓"]
D -->|No| G
G --> H["204 No Content"]

Rules:

  • Rejected (409) if sprite is referenced by any active council
  • Protected sprites require ?force=true query parameter
  • Returns 204 No Content on success

Verify Fingerprint (GET /v1/sprites/{id}/fingerprint)

sequenceDiagram
participant Client
participant Router as sprites.py
participant Registry as SpriteRegistry
participant Engine as FingerprintEngine
Client->>Router: GET /v1/sprites/{id}/fingerprint
Router->>Registry: get_by_id(id)
alt Not found
Registry-->>Router: None
Router-->>Client: 404
else Found
Router->>Engine: verify_fingerprint(sprite, stored_hash)
Engine->>Engine: Strip id/created/fingerprint → canonical → Blake3
Engine-->>Router: verified: true/false
Router-->>Client: 200 Fingerprint {verified, stored, computed, verified_at}
end

Returns:

{
"sprite_id": "uuid",
"algorithm": "blake3",
"stored_hash": "a1b2c3...",
"computed_hash": "a1b2c3...",
"verified": true,
"verified_at": "2026-04-27T12:00:00Z"
}

Registry Index Structure

erDiagram
SPRITE_REGISTRY {
UUID id PK
string name
string version
string role
json capabilities
text system_prompt
boolean protected
boolean gate_authority
json metadata
string fingerprint_algorithm
string fingerprint_hash
datetime created
}
NAME_VERSION_INDEX {
string name
string version
UUID sprite_id FK
}
SPRITE_REGISTRY ||--o{ NAME_VERSION_INDEX : "indexed by"

The SpriteRegistry maintains two data structures:

  1. dict[UUID, Sprite] — primary storage keyed by UUID
  2. dict[(name, version), UUID] — uniqueness index for duplicate detection

Key Terms

  • SpriteCreate → The request model for creating a sprite (no id or fingerprint; server generates these)
  • SpriteUpdate → Partial update model; name and id are immutable; version must monotonically increase
  • Name+version conflict → Attempting to create a sprite with an existing (name, version) pair returns 409
  • Protected sprite → A sprite that cannot be deleted without ?force=true and cannot be bypassed in chains
  • Fingerprint verification → Recomputing the Blake3 hash from canonical data and comparing with stored hash

Q&A

Q: Can I create a sprite with the same name but different version? A: Yes. The uniqueness constraint is on (name, version), not just name. SOL-FORGE v1.0.0 and SOL-FORGE v2.0.0 can coexist.

Q: What content types does the create endpoint accept? A: application/json and application/x-yaml. The endpoint inspects the Content-Type header to determine the parser.

Q: Can I change a sprite’s name via PUT? A: No. name is immutable. If you need a differently named sprite, create a new one.

Q: How does version comparison work? A: The service uses packaging.version to compare versions. 2.0.0 > 1.10.0 > 1.9.9 > 1.0.0-alpha.

Q: Is fingerprint verification case-sensitive? A: No. The engine performs case-insensitive hex comparison: A1B2 == a1b2.

Examples

The sprite API is like a government ID system:

  • POST = Applying for a new passport (you provide info, government assigns ID number and issues the document)
  • GET = Showing your passport at border control (lookup by ID number)
  • PUT = Renewing your passport (new version number, new photo, same ID number)
  • DELETE = Surrendering your passport (only allowed if you have no active visas — i.e., not in any active council)
  • Fingerprint verify = The hologram check — border control shines a UV light to verify the passport hasn’t been forged

neighbors on the map