Skip to content

feat: account files carry priority, latency targets and prices - #2075

Merged
hachall merged 6 commits into
mainfrom
feat/account-policy-files
Oct 21, 2026
Merged

hachall merged 6 commits into
mainfrom
feat/account-policy-files

Conversation

@hachall

@hachall hachall commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

Account files (model_provisioning.account_limits_directory) can now hold one account's whole serving deal, per model and per serving class:

account: acme
priority: 100                     # account default
models:
  example/chat-model:
    priority: 300                 # model override
    tariffs: [...]                # batch prices only
    classes:
      standard:
        realtime_inflight: 200
        tariffs: [...]            # realtime / playground prices
        cache_tariff: {...}
        ttft_ms: 1000
        itl_ms: 30
        priority: 500             # class override
  • The old top-level realtime_inflight shape is still accepted and means classes.standard.realtime_inflight. If both name the same model, the two limits must match.
  • Only standard can be configured until models carry other classes.
  • Limits, realtime prices and cache tariffs live per class. Model-level tariffs take batch prices only.
  • An account/model pair may be configured in its account file or in an organisation overlay, not both. Startup checks this, and so does validate-account-limits --org-overlays.
  • New dwctl-model-provisioning account-schema command.

How

  • Migration (additive): nullable users.scheduling_priority, plus a new account_model_policies table (account, model, optional class: priority, ttft_ms, itl_ms). Both have notify triggers. Older images ignore both.
  • Reconcile: the account files are applied in one transaction under the existing advisory lock.
    • Limits keep their whole-table semantics.
    • Priorities, policies and prices are owned row by row via the account-catalog provisioning source:
      • hand-written prices are adopted only when the pair is declared;
      • omitted prices retire, keeping their history;
      • prices owned by the organisation catalog are refused.
    • The retire-omitted-prices step is shared with the organisation catalog.
  • Gateway: the sync flattens class → model → account priority, and the per-class targets, into the onwards overlay and account. Onwards stamps them as nvext.agent_hints.priority / nvext.router.{ttft,itl}_target on realtime requests to dynamo members.
    • These are hints: the request keeps its billed class, unlike legacy overlay targets, which still make it custom.
    • Daemon (batch/flex) traffic keeps its deadline priority.
    • Members that refuse scheduling fields get nothing.

Design choices worth a look

  1. The account-wide toleration preset stays where it is today, set in the console. These files don't touch it; per-model/class toleration overrides come in a follow-up.
  2. The account default priority is written only by the files; there is no console control.
  3. The limits table has no class dimension yet. Changing its key in place would break older pods' upserts mid-rollout, so the class column comes later as expand/contract, when non-standard classes exist.

Rollout

Dormant. Today's files reconcile to exactly what they do now, because they only use the old limits shape. Nothing changes until a file uses the new fields.

Tests

  • just lint rust: green.
  • just test rust: 4236 passed.
  • New tests cover:
    • format validation;
    • the cross-catalogue conflict check;
    • priorities, policies, limits and prices written, re-applied idempotently and cleared;
    • personal accounts;
    • price adoption, and the refusal of prices owned by the organisation catalog;
    • gateway sync of account priority and policy;
    • onwards hint stamping.

🤖 Generated with Claude Code

View guided diff Turn on auto-fix

The interactive/throughput presets, per-account class grants and account or
overlay default classes are unused. Removing them now keeps the routing path
small before model class routing lands.

- Onwards resolves only overlay targets (`custom`) or nothing (`standard`)
  and the self-hosted restriction; class suffixes are no longer parsed.
- dwctl no longer strips or interprets realtime class suffixes. Flex,
  background and batch uploads still discard a model suffix after a shape
  check, unchanged.
- The admin API drops the grant and default-class fields; the organisation
  serving view and model overlays keep targets and self_hosted_only.
- The model catalog accepts `serving_classes` only as an empty map. The
  organisation catalog prices `standard` and `custom` only, and retires any
  rows it owned under the old class names.
- The dashboard drops the grant, default-class and preset views.

Stored onwards configuration that still carries the old fields loads with
them ignored. Database columns are left in place for a later migration.
Assert that a PATCH carrying the retired grant and default-class fields is
accepted, writes neither column and returns neither field. Restrict the
organisation pricing view to the classes billing can select (standard, and
custom when an overlay's targets apply), so a manual price under a retired
class name is no longer shown as if it applied.
Each account file can now hold one account's whole serving deal, per model and
per serving class, alongside its realtime in-flight limits:

- an account-wide scheduling priority, with model and class overrides;
- ttft/itl latency targets per class;
- batch prices per model, realtime/playground prices and a cache tariff per
  class.

The older top-level `realtime_inflight` shape is still accepted and means
`classes.standard.realtime_inflight`. Only `standard` can be configured until
models carry other classes.

The account files are reconciled in one transaction: limits keep their
whole-table semantics; priorities, policies and prices are owned per row by
the `account-catalog` source, so hand-written rows are adopted only when the
pair is declared and rows owned by the organisation catalog are refused. An
account/model pair may be configured in an account file or an organisation
overlay, not both.

Onwards stamps the resolved priority and targets on realtime requests to
dynamo members as hints that keep the request billed as its own class;
legacy overlay targets keep their custom-class behaviour and daemon traffic
keeps its deadline priority.

The migration is additive (a nullable users column and a new table); older
images ignore both, and today's files reconcile to exactly what they do now.
Copilot AI balanced review requested due to automatic review settings October 21, 2026 14:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Deploying control-layer with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0b0e3fc
Status: ✅  Deploy successful!
Preview URL: https://abafc3ad.control-layer.pages.dev
Branch Preview URL: https://feat-account-policy-files.control-layer.pages.dev

View logs

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Running ultrareview automatically — this PR appears to change a database schema or migrate data, where a missed bug can corrupt or lose records, so a deeper multi-pass review is worth running. I'll post findings when complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ultrareview ran automatically — this PR appears to change a database schema or migrate data, where a missed bug can corrupt or lose records, so a deeper multi-pass review is worth running.

All reported issues were addressed across 16 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread docs/src/reference/model-provisioning.md Outdated
Comment thread onwards/src/serving.rs
Comment thread dwctl/src/account_limits.rs Outdated
Comment thread dwctl/src/account_limits.rs
Comment thread docs/src/reference/model-provisioning.md Outdated
Comment thread onwards/src/serving.rs Outdated
Reject the background tier's reserved priority and latency targets that do
not fit the stored integer, and refuse to overwrite a policy row another
writer owns (unowned rows are adopted, as manual prices are). Clarify that
latency targets apply to realtime requests only and when account-file
failures stop startup.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 3 files (changes from recent commits).

Requires human review: Large feature extending account files with per-model priority, latency targets and prices: new DB table and column, gateway sync changes, and scheduling hints stamped on realtime requests. This is a cross-cutting production-request-path change requiring human review.

View guided diff | Turn on auto-fix | Re-trigger cubic

@hachall
hachall added this pull request to the merge queue Oct 21, 2026
Merged via the queue into main with commit a2f91a6 Oct 21, 2026
27 checks passed
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.

3 participants