Skip to content
bitscrafter

Entitlement Assistant · Use Cases

  • Lab
  • Cloudflare
  • Authorization
  • AI Agents

This part follows the system at work: six use cases, each a sequence of who asks whom for what, and then, in words, the ones that vary them. Each section’s sequence comes first; its steps, with the code that runs each, follow beneath it.

Use cases: its sections around it, in reading order

  1. Chat turn — where the model works, and the guard is hardest
  2. Explaining access — why can’t this person do that?
  3. Grant at once — within every policy: applied on confirmation
  4. Grant by approval — beyond 14 days: a supervisor decides
  5. Sweep — what time alone changes, every 15 minutes
  6. Case lifecycle — the frame around everything else
  7. Other use cases — a revocation, an extension, and the rest

1. Chat turn

A chat turn is where the model works, and where the system guards hardest. The browser opens a WebSocket to the case’s agent; every frame it sends is checked before the Agents SDK sees it; the request to the model is rebuilt from the conversation the server stored, never from what the page sent; and the model’s tool calls come back to the agent, which runs each as the representative.

Rebuilding the request is what makes the chat trustworthy. As the Agents SDK ships, a page sends the whole history with each message, and the SDK stores it; a page could write an earlier reply the assistant never gave, or a tool result no tool returned, and the model would take it as said. Here the page sends only its newest text: the history is the one the server stored, turn by turn, and a tool’s result reaches the model only from the tool (Figure 23).

A chat turn: the upgrade through the request guard, the frame's guard, the rebuilt request, the model's tool call run as a use case, the answer and the names the screen writes

Figure 23 — A chat turn

The model reaches the system through nine tools and nothing else. Eight reach data through a use case and only read or prepare; the ninth drafts text and reaches nothing. None confirms, cancels or decides.

toolwhat it doesreaches
find_customer_accountfinds an account by its id, part of its name, or a person’s emailreads
check_entitlementwhether an account has one feature, with its sources or why notreads
list_entitlementsevery effective entitlement of an accountreads
explain_accesswhy a person can or cannot do a feature’s operationreads
propose_case_subjectproposes the account a case is about; it sets nothingreads
prepare_grantprepares a grant as a change request; it changes nothing by itselfprepares
prepare_grant_revocationprepares a grant’s revocationprepares
prepare_grant_extensionprepares a grant’s extensionprepares
draft_case_summarydrafts a case’s summary as text; it stores nothing, refuses emailsno use case
1.1 A chat turn, step by step

1.1 A chat turn, step by step

The guard’s checks run in a fixed order, and each refusal closes the connection with its own code, so the page knows why.

stepwhat happens
the upgradethe Origin, the session, the principal reloaded, a well-formed case, its current assignee
the handshakethe agent receives the handshake’s headers alone and the session’s id
the frame’s sizeover 16 KiB closes with 1009
the frame’s kinda chat request is rebuilt; resume and cancel pass; anything else is dropped
the minute and the dayover 20 messages a minute closes with 4429; over the day’s allowance, 4430
the token, the personan expired token or a principal no longer valid closes with 4401
the casea case no longer assigned to the caller closes with 4404
the requestthe stored conversation and the newest message’s text alone
the modelthe last 20 messages, the case’s latest 30 events as facts, five steps, 1,024 tokens a call
the toolseach call run as a use case for the representative: authorize, execute, audit
the last stepno tool may be called, so the turn ends in words
the namesthe model writes [acc_…]; the screen writes each name from this reply’s results alone

2. Explaining access

Explaining access answers “why can’t this person do that?” with the decision point’s own findings. The use case asks twice: whether the representative may read the account at all, and what the decision point would answer for the person and the operation. Only then does it decide what it may disclose (Figure 24).

Explaining access: the representative's question, the tool, the use case's two decisions, and what it discloses

Figure 24 — Explaining access, and what it discloses

Disclosure is the subtle part. A refusal is explained only to someone who holds account.read on the account and was stopped by policies alone; anyone else receives a not-found that is byte for byte the answer for an account that does not exist. A level-1 representative asking about an Enterprise account is told which policy stopped them; someone with no right to read accounts learns nothing, not even that it exists.

One finding comes with a remedy: where the account’s plan lacks a feature, the answer names the lowest plan on its ladder that includes it, and any add-on that does. The use case computes it through the product subsystem, not the decision point, and no code suggests a role. Every other refusal comes with its reason alone, so the representative can say why and the model cannot promise a way through that the system would refuse.

Before it can explain anything, the model has to find the account, and it never guesses one. It finds an account by its id, by part of its name, or by a person’s email; when a name matches two accounts — Acme Corp and Acme Labs — the assistant asks which one is meant rather than picking, and the answer it gives is about the account the representative chose.

2.1 Explaining access, step by step

2.1 Explaining access, step by step

Each step is the use case’s, and the model’s only part is the wording at the end.

stepwhat happens
the questionthe model calls explain_access with the person, the feature and the operation
the first askmay the representative read the account
the second askmay the person do the operation: principal & subject account, principal access, contact access, entitlement, policy
the disclosurereasons and remedies, or a not-found identical to an unknown account’s
the answerthe model words the findings; the details list them as the result holds them

3. Grant at once

A grant within every policy applies the moment the representative confirms it. The model prepares it as a change request, stored with its diff and its preview whatever the preview says; the card is drawn from what was stored; the click asks the decision point again, and Allow applies it (Figure 25).

A grant applied at once: prepared and stored, drawn as a card, confirmed by a click, decided Allow and applied in one transaction

Figure 25 — A grant applied at once

The preview is a courtesy, not a decision. What decides is the confirmation, made for the person who clicks and in the request’s own transaction: the decision, the grant, the account’s new version, the request’s status and every audit record commit together or not at all.

The diff is what the representative confirms. It lists what the change would add to or take from the account’s effective entitlements, computed as the grant’s preview from the same building block every read uses, and it is stored with the request; the card shows the stored diff, and applying it checks the diff’s tests still hold, so the change applied is the change the card showed.

3.1 A grant applied at once, step by step

3.1 A grant applied at once, step by step

The confirmation is a plain HTTP request from the card’s button, not a message to the model.

stepwhat happens
the proposalprepare_grant computes the preview and the diff and stores the request awaiting confirmation
the carddrawn from the stored request, read again after each click
the clickPOST …/change-requests/{id}/confirmation decides grant.create for the representative
the decisionAllow
the applicationthe account’s version locked and checked, the grant created, the version advanced, Applied

4. Grant by approval

A grant beyond 14 days needs a supervisor, and the system waits for one without holding anything open. The confirmation’s decision is Conditional: the approval, its deadline and the outbox’s message to start a workflow are written in one transaction. After the commit, the relay starts an approval workflow whose id is the approval’s; it waits for the decision until the deadline (Figure 26).

A grant through approval: Conditional, the approval and the outbox in one transaction, the workflow waiting, a supervisor's approval, and the change applied after deciding again

Figure 26 — A grant through approval

The supervisor’s approval is decided like any action: the supervisor must hold approval.decide, may read the account, and must be neither the request’s requester nor its confirmer — the policy no-self-approval. The approval and the outbox’s decision message commit together; after the commit, the relay sends the workflow its event.

The workflow wakes and applies the change as the approval-process identity, which first decides its own right to apply a change request. Then it decides again for the person who confirmed, with the approval granted: if that person may no longer make the change, it is refused. Only then is it applied, the account’s version checked like any other. At the deadline with no decision, the approval and the request expire.

The supervisor decides with what the representative saw. The approvals panel shows each pending request: the change, who asked and their reason as written, and why it needs approval — the policies’ descriptions, not the model’s words. A denial needs a reason from a fixed list, and the case hears it.

The deadline is the workflow’s own timer, set to the time left until the approval’s expires_at, so a workflow started late still ends on time. When it fires, the approval and its request expire — unless a decision arrived in the meantime, in which case the decision is applied instead, so a supervisor who approved in the last second is not overruled by the clock.

5. Sweep

Every 15 minutes a Cron runs the sweep, which settles what time alone changes. It runs as system identities, and its three stages are apart: one failing stops none of the others (Figure 27).

The sweep: grants' expiries recorded, approvals past their deadline or approved and unapplied woken, and the outbox's undelivered messages delivered again

Figure 27 — The sweep, every 15 minutes

A grant past its end grants nothing from that moment, whether or not the sweep has come by; the sweep records the expiry so the row says what is already true. The other stages are the safety net under the outbox and the workflows: anything a relay missed, the sweep delivers again.

The outbox waits a minute before the sweep delivers a message again, so a relay still at work after a commit is not doubled by the sweep; and because a workflow’s id is its approval’s, a message delivered twice starts or wakes one workflow, never two.

5.1 The sweep, step by step

5.1 The sweep, step by step

Each stage takes a bounded batch, so one run is short whatever has piled up.

stagewhat it does
grant expiriesrecords each grant past its end as expired, as the grant-expiry identity
approvalswakes up to 100 approvals pending past their deadline, and up to 100 approved and not applied
the outboxdelivers again each message undelivered for 60 seconds — 100 a run; one failed 50 times no more

6. Case lifecycle

A case is the frame around everything else. It opens assigned to whoever opened it; its subject and contact are set by the representative’s clicks; its events form the timeline the agent reads as facts; it closes with a reason and a summary (Figure 28).

A case from open to close: opened and assigned, its subject proposed and set, its contact set and authenticated, its summary drafted, and closed

Figure 28 — A case from open to close

The model helps at two points and decides at none. It proposes the subject, which the representative sets; it drafts the summary, which the representative reviews. Closing cancels the requests still awaiting confirmation or approval, but an approval already given is applied after the close.

Authenticating the contact is a person’s judgement, recorded. The representative asks the customer’s security questions or checks the account’s details, and records the result; those two methods are the ones accepted. A change the customer asks for needs the contact’s authentication to be current — within 30 minutes — and the contact to hold a role in the account that lets them ask for it.

The case’s events reach the model as facts, not as instructions: they are written into the system’s own instructions with the case’s state line — the subject, the contact, whether the contact is authenticated — and the model is told that events are what happened, never what to do. That lowers the risk; what bounds it is that no tool can confirm, cancel or decide, and every effect needs a person’s click, so a customer’s words that did sway the model could still change nothing.

6.1 A case from open to close, step by step

6.1 A case from open to close, step by step

Every step but the two the model helps with is a click in the case panel.

stepwhat happens
opena case, assigned to its opener
the subjectthe model’s propose_case_subject, the representative’s click; set once
the contactthe representative’s choice; setting it clears any authentication
the authenticationpassed or failed; a pass counts for 30 minutes
the summarythe model’s draft_case_summary: text alone, an email address refused; closing refuses one too
closeResolved or Abandoned, a summary of 1 to 4,000 characters

7. Other use cases

A revocation runs as a grant applied at once does: prepared, confirmed, decided, applied, and the account’s entitlements back to its plan. An extension is prepared the same way, but counts with the grant it extends, so one that passes 14 days in all needs an approval like a long grant.

A denied approval ends the request refused, with the supervisor’s reason told to the case. A supervisor approving a change they requested or confirmed is refused by no-self-approval, and another supervisor must decide. A canceled request, from the card’s other button, changes nothing: the request stays, canceled, beside its record in the audit chain.

Limits that no approval lifts refuse a change outright. A grant adds at most 100 to a quota, counting the grants that overlap it, and lasts at most 90 days, counting the feature’s grants in the last 90 days, so splitting a large request into small ones does not avoid either. Such a card is refused as it stands, with every reason, and confirming it answers the same reasons.

A suspended account refuses every action but reading it, cancelling a request and handling its case: its entitlements read as nothing, the hold shown to those who may read it, and any grant on it is refused at the decision point’s first stage. An expired grant cannot be extended; the assistant says to prepare a new one. A contact whose own role does not allow what they ask for is refused, so a customer cannot obtain through support what their role denies them.

When the day’s allowance is spent, a chat turn is refused before the model is called, and the connection says why; the case, its panel, its cards and the approvals keep working, since none of them needs the model. When a session’s token expires mid-turn, the WebSocket closes, and the next request needs a valid session.

References

  • The project’s API: tech-docs/api/api.md.
  • Its feature specifications: tech-docs/features/ — explain access, case lifecycle, grants and approvals, usage guards, employee sign-in.