Skip to content

feat(core): operator read tools and the agent-chat grant for the back-office assistant - #401

Open
mp-blurify wants to merge 6 commits into
devfrom
feat/agent-read-tools
Open

mp-blurify wants to merge 6 commits into
devfrom
feat/agent-read-tools

Conversation

@mp-blurify

Copy link
Copy Markdown
Collaborator

Summary

  • Add the agent-chat:use grant that a back-office AI assistant is gated on; the static and seeded admin roles hold it, and only the read-write level grants it.
  • Add the payments.flow_daily and financial.summary analytics read tools (analytics:view).
  • Add the withdrawals.queue (withdrawal:view) and players.deposit_compare (transaction:view) wallet read tools.
  • IdentityReader gains an optional batched getUserIdsByPlayerIds; the comparison fails closed without it.
  • Cover every new tool end to end through the MCP kernel, and record the tools and the player-id key rule in ADR-0042 and the wallet module doc.

Why

An assistant that answers an operator's questions reads platform tools through the MCP kernel on the asking admin's own grants. The tools so far are per player or narrow reports: the questions an operator asks first - how payments flowed this week, what waits in the withdrawal queue, which segment deposits less than last month, the financial summary of a period - had no tool. Core also had no grant to let an admin use such an assistant apart from running agents.

Every new tool is bounded (windows of at most 92 or 366 days, capped lists with a truncated flag or a hard limit), returns only allow-listed keys, and names a player only by player id under a playerId-style key, because consumers pseudonymise by key name. None returns a review note, address, transaction hash, username, email or user id.

Diagram

flowchart LR
  A[Admin's question] --> H[Assistant turn]
  H -->|tool call| K[MCP kernel]
  K -->|grant check on the admin's roles| G{granted?}
  G -->|no| F[forbidden, audited]
  G -->|yes| V[input contract: bounded windows and limits]
  V --> T[read tool: analytics or wallet]
  T --> R[allow-listed keys, playerId keys only]
  R --> H
Loading

Alternatives considered

  • A generic query tool over the database: no grant per question, no redaction, unbounded reads.
  • Serving the admin report routes as tools unchanged: they carry free text (review notes, addresses) and unbounded lists; the tools pick allow-listed keys and cap every list.
  • Declaring the grant from the consumer's plugin: the IAM resource list is fixed in core, so the grant lives here.

Risks

  • agent-chat:use is new: roles other than the static and seeded admin roles do not hold it until an operator grants it, and nothing checks it until a consumer gates on it.
  • players.deposit_compare refuses a segment above 20 000 players (segment_too_large).
  • A custom IdentityReader without getUserIdsByPlayerIds makes the deposit comparison fail closed.
  • financial.summary keeps bonus cost as bonus money converted to cash, so NGR does not deduct cashback credits such as rakeback; the tool description says so. Whether NGR should deduct them is a separate decision.

Mateusz Paś and others added 6 commits November 5, 2026 11:45
…tant

The agent hub gates its back-office assistant on `agent-chat:use`. Core
only declares the grant: the assistant reads platform tools through the
MCP kernel on the asking admin's own grants. The static admin role and
the seeded admin role hold it, like `mcp-access`, and only the
read-write level grants it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Mateusz Paś <mateusz.pas@studiosoftware.com>
Two operator-level read tools for the back-office assistant, both gated
on `analytics:view`:

- `payments.flow_daily` counts and sums deposits and withdrawals per
  UTC day or ISO week, type, status (every wallet transaction status)
  and currency over at most 92 days, 14 by default. One grouped query,
  cached like the other financial reports, capped at 1000 rows with a
  `truncated` flag. It names no player.
- `financial.summary` wraps the existing summary and product split:
  deposits, withdrawals, net deposits, GGR, bonus cost and NGR per
  currency, rails folded together, plus stakes, payouts and GGR per
  product, over at most 366 days. Every list is capped.

The day-range defaults and bounds of `ggr.summary` move into one helper
the three tools share. Bonus cost keeps its meaning (bonus money
converted to cash); the description says that cashback credits such as
rakeback are not in it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Mateusz Paś <mateusz.pas@studiosoftware.com>
…ools

Two operator-level read tools for the back-office assistant:

- `withdrawals.queue` (`withdrawal:view`) gives the queue's pending and
  on-hold counts, totals per currency and average pending wait, plus
  the oldest 1 to 20 queued withdrawals with their withdrawal id,
  player id, amount, status, wait, KYC status and the queue's risk
  tags. It reads no review note, address, hash, username or email. The
  risk tags the admin queue shows move into one helper both use.
- `players.deposit_compare` (`transaction:view`) compares the completed
  deposits of a tagged segment between two windows of at most 92 days,
  each player priced into the fx pivot currency, and ranks the largest
  drops or rises (at most 50). It pages the segment through
  `PLAYER_SEGMENT_READER` and refuses a segment above 20 000 players as
  `segment_too_large`. Each page costs one query for its user ids and
  one array-parameter query for its deposits; a quote is fetched once
  per currency pair. A player with an unpriceable deposit is counted,
  never guessed.

`IdentityReader` gains an optional batched `getUserIdsByPlayerIds`
(with `userIdsOfPlayers`, which fails closed when it is missing), and
the pivot pricing the wallet reader used moves into a module helper the
comparison shares.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Mateusz Paś <mateusz.pas@studiosoftware.com>
…cp kernel

The kernel suite now expects the eight read tools and calls each new one
against seeded ledger rows: exactly the allow-listed keys, realistic
totals (every status of a payment day, cashback outside bonus cost, the
oldest held withdrawal, a vip segment's drop in the pivot currency), no
review note, address, email or user id in what is served, and
`invalid_input` for an out-of-bounds range, window or limit. An admin
whose seeded role lacks the tool's grant gets `forbidden`, audited once.
The transport suite lists the new tools under their model names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Mateusz Paś <mateusz.pas@studiosoftware.com>
ADR-0042 gains a dated update: the four operator-level read tools and
their grants, the bounds and caps every one of them keeps, the free text
and identifiers none of them returns, the rule that a player is named
only by player id under a `playerId`-style key because consumers
pseudonymise by key name, and the `agent-chat:use` grant. The wallet
module doc lists its two new tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Mateusz Paś <mateusz.pas@studiosoftware.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant