UUniCAS DOCS
Console GitHub
UNICAS / DOCUMENTATIONEdit source

#Scenarios and sequences

Status: published integration scenarios

These sequences use placeholders such as APP_ID, SPACE_ID, ROOT_HASH, and CAPABILITY. They contain no production identity or bearer material.

#Acquire a least-privileged capability

The App authenticates its own user and authorizes the business action before choosing any capability claims. UniCAS does not authenticate the App user and does not provide Space enumeration for that user.

sequenceDiagram
    actor User as App user
    participant UI as App frontend
    participant App as App backend / issuer
    participant CAS as UniCAS Space data plane

    User->>UI: Sign in to the App
    UI->>App: Request access for a business action
    App->>App: Authenticate user and resolve Principal
    App->>App: Authorize Principal -> App / Space / refDomain
    App->>App: Select minimum permission and short expiry
    App-->>UI: Signed Space capability
    UI->>CAS: Space request with Bearer capability
    CAS->>CAS: Resolve issuer and active App
    CAS->>CAS: Verify signature, audience, time, App, Space, permission
    CAS-->>UI: Operation response

If the capability is expired or otherwise invalid, the App frontend returns to its backend for a newly authorized capability. It must not retry with broader permissions or an administrator credential.

#Read metadata and streamed content

Read metadata first when the App needs size, media type, child refs, or retention state. Content is streamed and may be read in a byte range.

sequenceDiagram
    participant UI as App frontend
    participant CAS as UniCAS Space data plane

    UI->>CAS: GET .../nodes/ROOT_HASH/metadata<br/>cas:nodes:read capability
    alt Node is ready in the same Space
        CAS-->>UI: 200 metadata + retention state
        UI->>CAS: GET .../nodes/ROOT_HASH/content<br/>optional Range
        alt Full read
            CAS-->>UI: 200 streamed canonical bytes
        else Satisfiable range
            CAS-->>UI: 206 selected bytes
        else Invalid or unsatisfiable range
            CAS-->>UI: 416 + Content-Range: bytes */size
        end
    else Node absent or not readable
        CAS-->>UI: 404
    end

GET operations are safe to repeat, but callers should still use cancellation and bounded retry policy. Retry transient transport or server failures; do not retry 401, 403, or an unsatisfiable range unchanged. The public client does not implement a general automatic retry loop.

#Upload an immutable node and acquire a lease

The hash is the lowercase SHA-256 digest of canonical node bytes. A lease protects the preparation window; it is not a durable business reference and does not imply that content is ready.

sequenceDiagram
    participant App as App workflow
    participant CAS as UniCAS Space data plane
    participant Upload as Authorized upload target

    App->>CAS: POST .../nodes/HASH/lease<br/>leaseDurationMs + cas:nodes:lease
    alt Node already ready
        CAS-->>App: 200 ready lease
    else Direct upload required
        CAS-->>App: 200 awaiting_upload + PUT instructions
        App->>Upload: PUT canonical bytes with returned headers
        alt Upload accepted or already present
            Upload-->>App: Success or tolerated 412
            App->>CAS: Repeat the same POST lease(HASH)
            CAS-->>App: 200 ready lease
        else Upload or finalization fails
            Upload-->>App: Error
            App->>App: Keep same hash and bounded retry while session/lease is valid
        end
    end

The lease request never carries canonical bytes, upload length, or upload ID. Hash mismatch and malformed content return awaiting_replacement_upload with a fresh write-once target. A valid parent waiting for dependencies returns validated_awaiting_children with every distinct unready child hash.

The low-level client performs one lease request. The blob client performs the direct PUT, tolerates 412 as an already-satisfied upload step, and repeats the same lease request.

#Atomically commit or release Root Refs

A business state transition is one atomic changes map. Moving authority from one root to another must be { oldHash: -1, newHash: +1 } in one request, not two requests.

sequenceDiagram
    participant App as App backend
    participant CAS as UniCAS Space data plane

    App->>CAS: POST .../root-refs<br/>requestId + changes + cas:root-refs:update + refDomain
    CAS->>CAS: Validate all hashes, readiness, balances, and domain revision
    alt First successful commit
        CAS-->>App: 200 success, idempotent=false, revision
    else Same requestId and same canonical payload
        CAS-->>App: 200 success, idempotent=true, original revision
    else Same requestId with different payload
        CAS-->>App: 409 IDEMPOTENCY_CONFLICT
    else Missing/unready node or negative aggregate
        CAS-->>App: 404 or 409, no partial commit
    else Internal revision race
        CAS->>CAS: Bounded retry with backoff
        CAS-->>App: One atomic outcome
    end

If the client loses the response, retry the exact same canonical request with the same requestId. Never reuse a requestId for different changes.

To inspect committed state, page through GET .../root-refs with a cas:root-refs:read capability carrying the same refDomain. Pages are revision-stable; the response returns the domain and revision alongside the next cursor.

#Inspect usage and run bounded garbage collection

Usage and collection have independent authorities. Grant either or both only when the operational workflow requires them.

sequenceDiagram
    participant Operator as App-owned maintenance workflow
    participant CAS as UniCAS Space data plane

    Operator->>CAS: GET .../cas/usage<br/>cas:usage:read
    CAS-->>Operator: Counts and byte accounting
    Operator->>CAS: POST .../cas/gc<br/>{ maxNodes } + cas:gc:execute
    loop Up to maxNodes candidates
        CAS->>CAS: Recheck refs and lease immediately before delete
        alt Still unreferenced and lease expired
            CAS->>CAS: Delete content, then metadata
        else Became protected
            CAS->>CAS: Skip candidate
        end
    end
    CAS-->>Operator: examined, deleted, reclaimedContentBytes

The default bound is 100 nodes when maxNodes is omitted. A pass is advisory: it may leave more eligible work, so schedule additional bounded passes rather than assuming one call empties the Space.

#Retention model

A ready node survives while at least one protection applies:

  • a positive Root Ref balance;
  • a child reference from a protected graph; or
  • an unexpired lease.

GC eligibility requires no child refs, no Root Refs, and an expired lease. The collector rechecks eligibility immediately before deletion to avoid racing a new reference. Root Ref commit is the durable state boundary; leases exist to protect uploads while that commit is prepared.

Lease duration defaults to 15 minutes and is clamped to 60 seconds through 24 hours. Renewing an active lease preserves its original start and never shortens its expiry.

See State protection and garbage collection for the full accepted model.

#Failure and retry rules

Outcome Caller action
401 missing_token, invalid_token, unknown_issuer Stop the Space call. Re-authenticate or obtain a newly authorized capability through the App.
401 registry_unavailable Treat as a temporary authorization dependency failure; retry with backoff without changing authority.
403 APP_SUSPENDED Stop. App administration must resolve suspension outside the user flow.
403 resource_scope_mismatch Treat as a caller bug or attempted cross-resource use. Do not rewrite route identifiers from token data.
403 insufficient_permission Stop. Request a new capability only after the App independently authorizes the broader action.
404 Do not assume a different Space. Resolve the App-owned catalog or upload state.
409 upload or Root Ref conflict Resolve the named conflict; replay only when the operation's idempotency rules allow it.
413 Reduce payload or follow the configured upload limit; retries with the same oversized body will fail.
416 Correct the range using the returned total size.
429 CAS_UPLOAD_LIMIT No upload generation was created. Back off until active upload work drains, then repeat the same lease request.
500 or transport failure Use bounded exponential backoff and preserve operation identity. For Root Refs, retain the same requestId.

Authorization caches issuer authority for a short interval. A registry outage may use known authority within a 60-second hard-stale window and emits stale telemetry; after that bound the service fails closed with registry_unavailable.