Skip to content

Add tenant-safe billing cost attribution - #91

Merged
ivanvyd merged 6 commits into
mainfrom
feature/cost-billing
Sep 1, 2026
Merged

Add tenant-safe billing cost attribution#91
ivanvyd merged 6 commits into
mainfrom
feature/cost-billing

Conversation

@ivanvyd

@ivanvyd ivanvyd commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Outcome

Adds an opt-in, tenant-safe billing cost report that correlates PostgreSQL-owned Lakeflow job-run IDs with system.billing.usage and effective list prices. The default elapsed-time proxy remains unchanged.

Implementation

  • Keeps the dependency boundary intact: Core defines the billing reader contract, Multitenancy resolves tenant-owned run IDs and kinds, Databricks performs the fixed parameterized system-table read, and AspNetCore composes the layers.
  • Filters every billing query by bound workspace, tenant-owned run IDs, report timestamps, and usage_date; returned IDs not owned by the resolved tenant are rejected.
  • Issues one warehouse query for at most 500 distinct runs. Larger reports fail before Databricks and map to HTTP 422 REPORT_TOO_LARGE.
  • Uses a partial covering PostgreSQL index and server-side grouping to bound operation candidate materialization.
  • Prorates usage at both report-window and price-validity boundaries; the same overlap quantity feeds DBUs and estimated list cost.
  • Preserves currencies as separate values and orders kinds by DBUs, never by adding unlike currencies.
  • Adds a configurable overall polling deadline plus best-effort cancellation on caller cancellation, timeout, or polling transport failure.
  • Routes tenant-scoped export through the shared Statement Execution session while preserving request HTTP status and presigned-link auth stripping.
  • Documents configuration, permissions, limits, semantics, failure modes, and a non-production live verification runbook.

Verification

  • Locked restore: solution and load harness passed.
  • Release build: solution and load harness passed with 0 warnings/errors.
  • Format and diff checks passed.
  • Focused billing/cost/export/index tests: 39/39 passed.
  • TenantIsolation category: 188/188 passed.
  • Full non-live suite: 230/230 passed.
  • Independent post-fix reviews passed for correctness, security/tenancy, performance, requirements, and structure.

Live status

The development workspace identity still lacks access to system.billing.usage and system.billing.list_prices, so the live system-table result path remains explicitly Documented, not Verified. The repository includes the exact read-only non-production runbook to promote that status after an administrator supplies the required grants.

ivanvyd and others added 6 commits August 30, 2026 17:37
A new ICostAttribution implementation that reads from system.billing.usage,
joined to operations.ExternalId. The SQL has the right shape; the test stubs
DatabricksClient to verify row parsing, error-code propagation, and the
Billing source discriminator. The full billing path needs the metastore-admin
grant this library does not hold; the stub shows the shape so a product team
that does have the grant has a reference to match.

What changed:
- BillingApiCostAttribution: builds a SqlStatement against system.billing,
  joins to operations on ExternalId, groups by Kind, sums DBU.
- CostAttributionServiceCollectionExtensions: adds AddLakeWrightBillingCostAttribution.
- LakeWright.Multitenancy project references LakeWright.Databricks (one-way).
- Test stub for DatabricksClient and StatementOutcome.
- Test asserts: empty window returns Billing source with 0 DBU,
  aggregated rows order by DBU descending, and a FAILED response raises
  BillingQueryException with the right error code.

The build of BillingApiCostAttribution passes; the full solution build
needs the lockfile refreshed (not included in this commit). The stub test
compiles but does not run — the full end-to-end smoke against a real
workspace is a Category=Live test the billing contributor runs once after
wiring.

The work is done as a reference implementation. The remaining work for the
currency cost report in production is: (a) the metastore-admin grant, and
(b) a Category=Live smoke against a workspace with billing data.
…Databricks reference

The cost-billing commit added a project reference from LakeWright.Multitenancy to LakeWright.Databricks (for the IStatementExecutionApi used by BillingApiCostAttribution), but the lock file was not regenerated. Central package management in locked mode therefore fails with NU1004 at restore. dotnet restore --force-evaluate re-records the transitive graph so the next CI run goes through.

Failures this addresses (PR #91 build job, 2026-08-30):
  NU1004: The project references lakewright.multitenancy whose dependencies has changed. The packages lock file is inconsistent with the project dependencies so restore cannot be run in locked mode.
Signed-off-by: Ivan Vyd <ivanvyd@users.noreply.github.com>
Signed-off-by: Ivan Vydrin <ivan.vydrin.99@gmail.com>
Signed-off-by: Ivan Vydrin <ivan.vydrin.99@gmail.com>
Signed-off-by: Ivan Vydrin <ivan.vydrin.99@gmail.com>

# Conflicts:
#	tests/LakeWright.TenantIsolation.Tests/PostgresFixture.cs
Signed-off-by: Ivan Vydrin <ivan.vydrin.99@gmail.com>
@ivanvyd ivanvyd changed the title Currency cost report: add BillingApiCostAttribution (stubs the billing read, needs the metastore-admin grant for the live smoke) Add tenant-safe billing cost attribution Sep 1, 2026
@ivanvyd
ivanvyd merged commit 2ec1135 into main Sep 1, 2026
11 checks passed
@ivanvyd
ivanvyd deleted the feature/cost-billing branch September 1, 2026 16:15
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