Skip to content

feat: add volume commitment feature and analytics - #375

Open
GauravRawat369 wants to merge 9 commits into
mainfrom
add-volume-contracts-based-routing
Open

feat: add volume commitment feature and analytics#375
GauravRawat369 wants to merge 9 commits into
mainfrom
add-volume-contracts-based-routing

Conversation

@GauravRawat369

@GauravRawat369 GauravRawat369 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

This pull request introduces a new volume commitment scheduling system and related API endpoints, along with several supporting changes and improvements. The main focus is on adding a scheduler that periodically forecasts merchant volume commitments, exposes a dedicated server for scheduling, and integrates this functionality into the main application. Additional changes include enhancements to analytics, new API routes, and CI workflow optimizations.

Volume Commitment Scheduling and API Integration:

  • Added a new [volume_commitment] section in config/development.toml to configure the scheduler, including enabling/disabling the feature, scheduling intervals, and dedicated server settings.
  • Initialized volume commitment dependencies and started a dedicated scheduler server in src/bin/open_router.rs, ensuring it shares state with the main server. [1] [2]
  • Extended GlobalConfig to include VolumeCommitmentConfig for centralized configuration management.

New and Updated API Endpoints:

  • Added new API routes for volume commitment operations under /merchant-account/:merchant-id/volume-commitment (including /series, /audit, /impact), and a scheduler callback at /volume-commitment/run-forecast.
  • Introduced a batch evaluation endpoint at /routing/evaluate/batch.

Analytics and Flow Types:

  • Added a new FlowType::VolumeCommitmentForecast to track forecast runs and updated its string representation. [1] [2]
  • Centralized the payment amount extraction SQL expression as PAYMENT_AMOUNT_EXPR in src/analytics/clickhouse/common.rs and updated its usage in cost savings metrics. [1] [2]

CI/CD and Build Improvements:

  • Updated the PR CI workflow to detect file changes and conditionally run expensive E2E jobs only when relevant files are modified, using a new changes job and path filters. [1] [2]
  • Added installation of native dependencies for rdkafka in the push CI workflow to ensure successful builds.

Documentation:

  • Added comprehensive documentation for the migration dashboard, detailing endpoints, usage, environment configuration, and operational workflows.

prajjwalkumar17 and others added 5 commits August 18, 2026 17:38
…ng-rule machinery

Adds a typed DSL for expressing enterprise volume-commitment contracts
(PSP volume/GMV goals with lumpsum or tiered rebates) and stores it via
the existing euclid rule engine — no new tables, endpoints, or handlers:

- New StaticRoutingAlgorithm::VolumeContract variant carrying a
  VolumeContractConfig document (new src/euclid/volume_contract.rs), and
  a dedicated AlgorithmType::VolumeCommitment activation slot; the
  pairing is enforced by validate_routing_rule in both directions.
- Archetypes: lumpsum (A) and tiered (C) writable; min_commitment (B)
  parses — wire format frozen for forward compatibility — but is gated
  off by validation. A reserved per-contract `scope` field will later
  take euclid Comparison conditions for payment-cluster scoping.
- Write-time canonicalization: amounts accepted as integers or decimal
  strings in major/minor units and stored as integer minor currency
  units; tolerance accepted as "5pp"/"550bps"/bps and stored as bps.
  Unknown fields are rejected (manual Deserialize around serde-flatten),
  timezones validated against the IANA database (chrono-tz).
- /routing/update now canonicalizes and runs the same validation as
  create (previously updates were stored unvalidated).

Hot-path scoping fixes this feature depends on (pre-existing bugs for
payout/3DS rows): the /routing/evaluate mapper lookup and the
activate-time Redis cache write are now payment-scoped, so a merchant's
non-payment mapper rows can neither shadow nor poison live payment
routing; load_active_ab_test gets the same mapper filter. The ab_test
evaluator/preview reject volume-contract arms explicitly.

Covered by unit tests (serde round-trips, canonicalization, validation
catalog, slot pairing) and a Playwright API spec including the isolation
regression: activating a volume contract leaves same-merchant
/routing/evaluate untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… the volume-contract DSL

Shapes the DSL to what the routing engine consumes, still storing raw
contract facts only — no derived values (goals, rewards, period-end
dates, fractions) are computed or persisted; resolution stays the
engine's job:

- Merchant level: expected_daily_traffic (required, canonicalized like
  every other amount), and optional forecast_interval_secs /
  steering_interval_secs overrides (omit = engine's global default).
- One metric and one currency per document: metric and currency move
  from per-contract to the document root, since the engine has no
  concept of currencies and compares expected_daily_traffic against
  per-PSP goals in a single unit. Per-connector uniqueness of active
  contracts follows (the (connector, metric) pair rule is gone).
- Tiered contracts mark exactly one tier `targeted: true` (validated;
  must be a retroactive tier — a marginal tier's reward at its own
  threshold is zero), so the engine can read one (goal, reward) per PSP
  without interpreting the ladder.

Wire-format change is safe: schema_version 1 has never been stored
(same unmerged PR).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a Volume Contracts page (Routing section of the sidebar, beta badge)
for configuring volume-commitment contract documents through the existing
/routing/* endpoints with algorithm_for: volume_commitment:

- Builder covering the whole DSL: routing mode, tolerance (pp), metric,
  currency + amount units, expected daily traffic, optional
  forecast/steering interval overrides, and per-PSP contracts with
  lumpsum (target + flat/percentage reward) and tiered (rebate ladder
  with a single targeted retroactive tier, enforced in the form)
  archetypes, billing cycle + IANA timezone.
- Document list with active badge, expandable stored-JSON view, and the
  activate/deactivate/delete lifecycle with confirm dialogs, mirroring
  the Rule-Based page's patterns (SWR + POST fetchers, cache
  revalidation, permission gating via routing:write).
- Reuses the existing UI kit (Card/InsetPanel/Button/Badge/Combobox/
  SearchableSelect/ConfirmDialog/typography) so the page matches the
  rest of the dashboard.
- types/api.ts: VolumeContractConfig types + volume_contract in the
  algorithm type unions.
- EuclidRulesPage now excludes volume_contract documents from its rules
  list (they live on their own page).

Verified against a local backend: create canonicalizes (5pp -> 500 bps,
major -> minor units), activate/deactivate round-trips, tsc + vite build
green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SearchableSelect's compact cond-select trigger (built for the dense Euclid
condition builder) and unstyled Combobox inputs looked cramped next to the
regular form fields. SearchableSelect gains an opt-in triggerClassName prop
that swaps the compact trigger for full input styling (block-level, no 10rem
label truncation); existing call sites are untouched. The volume contracts
page passes its shared input class to every dropdown so selects, comboboxes
and text inputs render at identical height, padding and type size.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@GauravRawat369 GauravRawat369 self-assigned this Aug 25, 2026
Gaurav Rawat added 4 commits August 27, 2026 17:17
… add-volume-contracts-based-routing

# Conflicts:
#	src/euclid/handlers/routing_rules.rs
#	website/dist/decision-engine/index.html
#	website/dist/index.html
#	website/src/App.tsx
#	website/src/components/pages/AnalyticsPage.tsx
#	website/src/components/ui/SearchableSelect.tsx
@jagan-jaya
jagan-jaya changed the base branch from feat/volume-contract-ui to main August 31, 2026 12:27
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.

2 participants