Skip to content

feat: inject project_id as system dimension on valid events#60

Merged
mattdjenkinson merged 4 commits into
mainfrom
feat/inject-project-id-dimension
Jun 24, 2026
Merged

feat: inject project_id as system dimension on valid events#60
mattdjenkinson merged 4 commits into
mainfrom
feat/inject-project-id-dimension

Conversation

@mattdjenkinson

@mattdjenkinson mattdjenkinson commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Amberflo usage events today carry no project context as a queryable dimension. The project name is already present in the CloudEvent subject (projects/{name}) and extracted by the consumer, but it is discarded after attribution. This means the cloud-portal has no way to ask Amberflo "show me usage for project X" — it can only filter by billing account, which loses per-project granularity when multiple projects share an account.

This PR injects project_id into EventData.Dimensions after central validation passes, before the enriched event is published to the valid NATS subject. Because the injection happens post-validation, it bypasses the INVALID_DIMENSIONS check — that check enforces emitter-supplied dimensions are declared in the MeterDefinition; project_id is a platform-level dimension that should not require per-meter declaration.

The downstream amberflo-provider already forwards data.Dimensions to Amberflo (via submission.go), so this change is sufficient to make project_id appear on every measurement in Amberflo without changes to any emitting service.

Test plan

  • TestUsageConsumer_HappyPath_PublishesToValid — asserts project_id=proj-abc in published event dimensions
  • TestUsageConsumer_DeprecatedMeter_PassesValidation — asserts project_id=proj-deprecated in published event dimensions
  • Full consumer package passes: go test ./internal/controller/consumer/...
  • Deploy to staging and confirm Amberflo measurements for a known project carry the project_id dimension

After central validation passes, decode the event's data payload and
write project_id (extracted from ce.Subject()) into Dimensions before
publishing to the valid NATS subject.

Key changes:
- Add internal/event import to consumer.go
- Decode EventData post-validate(), initialise Dimensions map if nil,
  set Dimensions["project_id"] = project, re-encode before publish
- Update happy-path and deprecated-meter tests to assert project_id
  is present in the published event's data dimensions

The injection is deliberately post-validation so it bypasses the
INVALID_DIMENSIONS check, which rejects emitter-supplied dimension
keys not declared in MeterDefinition.spec.measurement.dimensions.
project_id is a platform dimension that must not require per-meter
declaration.
The test previously forced the PM to Active before creating the
BillingAccount. The PM watch event fired while the account didn't yet
exist, making it a no-op. When the account was then created and
reconciled, the informer cache might still hold the stale (non-Active)
PM — no further event would drive a re-reconcile, so the condition
stayed False and the test timed out.

Fix: create the BillingAccount first, then set the PM to Active. The
watch event now fires while the account exists, enqueues a reconcile,
and the controller observes the Active phase on that reconcile.
Comment thread internal/controller/consumer/consumer.go Outdated
Comment thread internal/controller/consumer/consumer.go Outdated
@mattdjenkinson

Copy link
Copy Markdown
Contributor Author

@scotwells i'll change the dimension, no probs.

I didn't add it explicitly as the project will always be present on a valid cloud event. Should i add a "SystemDimensions" field to the meterDefinitionStatus to make it explicit?

@scotwells

Copy link
Copy Markdown
Contributor

@mattdjenkinson yeah we need some way of surfacing the system dimensions, otherwise the provider (e.g. amberflo) won't know to configure them when setting up the meter. The status is good for that.

Add SystemDimensionProjectName constant and SystemDimensions field to
MeterDefinitionStatus so providers (e.g. amberflo-provider) can discover
which dimensions the billing pipeline injects on every valid event and
configure them in downstream metering systems alongside
spec.measurement.dimensions.

Key changes:
- SystemDimensionProjectName constant in the API package; consumer and
  tests now reference the constant instead of the raw string
- SystemDimensions []string on MeterDefinitionStatus, populated by the
  MeterDefinition controller on every reconcile
- slicesEqual helper for the controller's change-detection early exit
@mattdjenkinson

Copy link
Copy Markdown
Contributor Author

@scotwells @JoseSzycho confirmed the changes based on your reviews work e2e.

@scotwells scotwells 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.

I'd expect some chainsaw end to end tests for this

@mattdjenkinson mattdjenkinson merged commit fe70945 into main Jun 24, 2026
7 checks passed
@mattdjenkinson mattdjenkinson deleted the feat/inject-project-id-dimension branch June 24, 2026 02: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.

3 participants