KDCube
← Engineering
KDCube Engineering · Concept

One Economics Boundary for Paid Surfaces

May this run, and who pays? Paid paths that join KDCube's accounting boundary use one lifecycle: verify, reserve, run, and settle.

13 July 2026Engineering9 minConceptVerdigris & Brass
economicspaid surfacesEconomicsGuardfunding splitquotaswallets

Your application already knows how to spend money on a user's behalf: an LLM call, an embedding, a web search. The question is not whether it costs — it is whether the platform gets to decide, before the call runs, that this user can afford it, and to charge the real cost afterward. Paid paths that join KDCube's accounting boundary use the same decision, without each application reimplementing plans, wallets, or budgets.

A paid surface is any place an application reaches a paid service: a chat turn, a standalone search box, a REST operation, a background job, a cron routine. The chat entrypoint already runs turns under the economics model. Other accountable work — search, REST operations, jobs, cron, or custom calls — joins the same model by using the enforcement engine. A direct, uninstrumented paid call remains outside this boundary.

THE MODEL

Verify, reserve, run, settle. Deny before anything runs — and no money hold is left behind.

Verify that the user's quota and funding can cover an estimate; reserve that estimate so concurrent requests cannot oversubscribe it; run the work; settle the actual cost across the funding sources.

ECONOMICS · THE LIFECYCLE OF A PAID CALLverifyquota + funding cover the estimatereservehold the estimate — no oversubscriberunyour paid work executessettleactual cost — commit or releasedenied — nothing ran, no hold left behindON DENYplan quota · primary funds · walletSETTLES ACROSS, IN ORDERVERIFY · RESERVE · RUN · SETTLE — THE SAME ON EVERY INTEGRATED SURFACE
Fig. 1 — one lifecycle for every integrated paid surface; denial leaves no trace on the ledger.

01 One request is one funding split

Before it can reserve anything, the engine resolves who pays. Every request is a single split. A primary funding source — an external subscription's period budget, or the project budget for everyone else — covers the part bounded by both the remaining plan quota and the primary funds. The user's wallet covers the remainder.

funding.splitMODEL
R = estimated cost
plan_part   = min(R, Q, P)      # Q = remaining plan quota, P = primary funds
wallet_part = R − plan_part     # the over-quota / over-funds remainder

When the plan quota or funds run out, plan_part simply shrinks toward zero and the wallet covers the rest in the same pass. The request only denies when there is no wallet, or the wallet cannot cover the remainder. At settlement the same order holds — plan quota and primary funds first, wallet for the over-quota remainder — and if the actual spend still overshoots, the project budget absorbs the residual as a last resort. Subscriptions and wallets never go negative.

ECONOMICS · ONE REQUEST, ONE FUNDING SPLITyour requestR = estimated costplan_partwallet_partprimary sourcesubscription period budget,or the project budget for everyone elseuser walletcovers the remainderplan_part = min(R, Q, P) · wallet_part = R − plan_partPROJECT BUDGET · ABSORBS RESIDUAL SHORTFALL AT SETTLEMENT · LAST RESORTSUBSCRIPTIONS AND WALLETS NEVER GO NEGATIVE
Fig. 2 — one split per request; the project budget is the last resort, never the first.

This is the part your application does not want to rewrite, and does not have to. It resolves once, in the engine, from the request's economics subject.

02 Two entry points, chosen by who settles

The engine offers exactly two ways in, and the choice is about who settles the cost.

EconomicsGuard is an async context manager around one accountable flow. On enter it resolves plan and funding, admits against quota, reserves the estimate, and binds accounting to the flow. On exit it reads back the flow's usage and settles the actual cost — committing or releasing the reservation.

entrypoint.pyPYTHON
async with EconomicsGuard(
    self, subject=subject,
    scope_id="report_render_42", flow="reports.render",
    estimate=EconomicsEstimate(reservation_usd=0.05),
) as decision:
    result = await do_the_paid_work()      # accounted calls run here

economic_preflight is the same admit and funding resolution with no reservation and no settlement — a feasibility gate for when the cost is metered elsewhere, or the caller degrades gracefully on denial.

entrypoint.pyPYTHON
try:
    await economic_preflight(self, subject=subject,
                             estimate=EconomicsEstimate(reservation_usd=0.01),
                             flow="reports.preview")
except EconomicsLimitException:
    use_cheaper_path()

Both raise EconomicsLimitException before any work runs. The code says why — rate_limited, no_funding_source, quota_lock_timeout — and the surface picks its reaction.

03 Search degrades instead of failing

The most common paid surface is semantic search, and it has a purpose-built facade so components never touch the guard. An economics-enabled entrypoint hands a searchable component one dependency:

entrypoint.pyPYTHON
model_service = self.search_model_service(flow="reports.search", subject=subject)

Two methods, deliberately different in how they fail. embed_texts([...]) embeds document/index material and lets exceptions propagate — a write must not silently skip content. embed_search_query(query, flow=...) wraps the query embed in a guard and returns None on economics denial, so the query layer falls back to lexical ranking (BM25, keyword) instead of failing the request. Memory search, canvas pin search, and task search all degrade this way.

THE CONTRACT

Search under economics does not break — it gets cheaper.

ECONOMICS · MANY SURFACES, ONE ENGINEchat turnalready runs under the modela guard nested inside → verify-onlybackground job / cronaccountable work, no turnyour standalone surfacesearch box · REST operation · reportenforcement engineverify · reserve · run · settleone decision: may this run, and who pays?plans & quotaswindows per surfacefunding sourcessubscription · walletsettlementone unit settles onceONE ECONOMICS MODEL · THE SAME ANSWER ON EVERY SURFACE
Fig. 3 — many surfaces, one engine; a nested guard degrades to verify-only.

04 The same work is never charged twice

A chat turn marks itself as the active parent economics scope while it runs the bundle core. A guard — or the search facade — entered inside that scope automatically degrades to verify-only: it checks feasibility but leaves the usage event in the parent turn, and the turn settles it. A guard outside any parent scope creates and settles its own operation scope. You do not wire this; a context variable carries it.

THE RULE

One unit of work settles once.

05 What your application actually writes

Becoming economics-enabled is extending one base (BaseEntrypointWithEconomics), which binds the runtime primitives the engine reuses. From there, guarding a paid surface is three decisions: resolve the subject (who pays), size the estimate (a few cents for most non-chat flows), pick EconomicsGuard or economic_preflight. The plans, wallets, quota windows, reservations, shortfall absorption, and settlement math stay in the engine.

Chat turns take their reservation floor from one app property:

{"economics": {"reservation": {"chat": 0.4}}}

A scalar USD amount; unset inherits the platform default from the economics descriptor's reservation.chat, and a value ≤ 0 disables the floor in favor of the token-based estimate.

And when the paid work is your own — not an LLM, embedding, or search, but a metered API you call — you make it countable with a tracker so the guard has a real cost to settle. That is a short, separate move, covered in the companion journal note and recipe. The alternate runtimes ride the same rails: a Claude Code turn is accounted as ordinary LLM usage — same tracker, provider="anthropic", a self-reported per-turn cost — priced right beside the built-in ReAct runtime's calls.

The result is a single answer to "may this run, and who pays?" that holds whether the paid call sits in a chat turn, a search box, a REST handler, or a job — and an application that spends a user's money only when the platform has agreed it can.

· Read more

KDCube Engineering
№ 2026-07-13 · kdcube.tech