feat: meter kind-as-option + platform-infra price override#123
Merged
Conversation
Move the metric KIND from a required positional argument to a functional
option: ms.Meter(name string, opts ...MetricOption). ms.Counter / ms.Gauge
are now MetricOptions, so the call site reads unchanged —
ms.Meter("orders.placed", ms.Counter, ms.Unit("order"), ms.Price(50_000)).
Allow a reserved infra.*/platform.* name to be declared with ms.Price ONLY,
to override the customer passthrough (e.g. ms.Meter("infra.compute.ms",
ms.Price(0)) to absorb). Kind/unit on these is platform-owned.
Validation (panic at declaration, like ValidateName):
- a custom (non-reserved) name MUST pass exactly one kind — panic if missing
or if both ms.Counter and ms.Gauge are given;
- a reserved name may carry ms.Price ONLY — panic if a kind or unit option is
passed, AND panic if no ms.Price is given (a price-less reserved declaration
is a meaningless no-op that would pollute the manifest);
- duplicate metric name panics (unchanged).
ms.Record still rejects self-reporting a reserved infra.*/platform.* name —
a module may set its price but never fabricate the platform-measured quantity.
MetricOption is an interface (not a func type) so ms.Counter / ms.Gauge are
const-backed and cannot be reassigned from a third-party module (ms.Counter =
nil would otherwise silently break all later Meter calls — an API footgun on a
security boundary).
BREAKING: kind moves from positional arg to option. Deferred: platform-side
enforcement of the override + default cost×1.2 (PR #10).
Design ref: docs-temp/milestone-d-meter/design.md §3a (build rule 3), §4 Axis 1,
§5 (PR #1b).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Milestone D SDK follow-up (PR #1b), stacked logically on the merged declaration-first metering work (#1 / v0.2.2). Two changes to
ms.Meter, plus the validation that makes them safe.What changed
1. Kind is now an OPTION, not a positional argument.
ms.Meter(name string, opts ...ms.MetricOption).ms.Counter/ms.Gaugebecomems.MetricOptions that set the kind, so the call site reads exactly the same:ms.Unit/ms.Priceare unchanged.2. Platform-infra customer-price override.
A reserved
infra.*/platform.*name — previously rejected at declaration — may now be declared withms.Priceonly, to override what the module's customer is billed for that platform-measured infra:This is a pure Plane-2 (customer-facing) choice. Kind/unit on these names are platform-owned, and the developer still owes the platform the measured COGS regardless.
Validation (panic at declaration, like
ValidateName)ms.Counterandms.Gaugeare given;ms.PriceONLY → panic if a kind or unit option is passed on it, and panic if NO price is given (a price-less reserved declaration is a meaningless no-op that would pollute the manifest);ms.Record(ctx, name, value)continues to REJECT (return an error for) a reservedinfra.*/platform.*name: a module may declare its price but never self-report the platform-measured quantity.BREAKING
The metric kind moves from a positional argument to an option. The exported
ms.Kindtype and thems.Counter/ms.GaugeKindconstants are gone;ms.Counter/ms.Gaugeare nowms.MetricOptions. VERSION bumped 0.2.2 → 0.2.3.Deferred
Platform-side enforcement of the override + default cost × 1.2 for platform-infra metrics lands with PR #10.
Design ref
docs-temp/milestone-d-meter/design.md §3a (build rule 3), §4 Axis 1, §5 ("app-module-sdk") — PR #1b.
Review follow-ups (non-blocking, from go review)
Declcarries an unexportedkindDupfield; added a doc note that it must be constructed viaDeclFromOptions, not a struct literal (a hand-builtDeclwould skip the conflicting-kind guard). Addressed in this PR.meter/meter_test.goreserved-with-kind/unit subtests spread a local[]MetricOptionintoDeclFromOptions— correct, slightly unusual; no change.internal/core/resources.gomanifest write setsKind: string(d.Kind); for a reserved overrided.Kind == ""and theMetricDecl.Kindjson tag isomitempty, so it is omitted from the wire (correct per spec). No change.🤖 Generated with Claude Code