# 037 — Unify param declarations: one `Param` type, referenced by name from metrics ## Summary "Parameter" currently names two structurally near-identical but separate types: `ParamDeclaration` (`src/data_value.rs`, driven by the Params panel, used only to add a display column to the logs table) and `RegexToMetricPrimitiveMatcher` (`src/dto.rs`), embedded inline inside a metric declaration. A metric cannot reference an already-declared param by name — `src/engine.rs` says so explicitly ("referencing an already-declared `ParamDeclaration` by name isn't supported yet") — so the same regex/capture-group/kind gets redefined from scratch per metric, and nothing keeps a param declared in the Params panel consistent with a same-named matcher inside a metric. ## Scope - Collapse `ParamDeclaration` and `RegexToMetricPrimitiveMatcher` into one `ParamDeclaration` type: `{ name, extractor (regex+capture_group | json_field_path), kind }`. - Change `MetricDeclaration` to reference params by name instead of embedding its own extractor: `label_params: Vec`, `value_param: Option`. Role (label vs. value) becomes a property of how a metric uses a param, not a property of the param itself. - Update `apply_metric_to_log` (`src/engine.rs`) to resolve `label_params`/ `value_param` against the shared param declaration store instead of reading an inline matcher. - Update declare/validate paths (`validate_metric_request`, `engine.rs`) to reject a metric referencing an undeclared param name. - Update frontend types (`webapp/src/lib/api.ts`) and `Metrics.tsx`'s declaration form to pick existing declared params (e.g. a select populated from the Params panel) rather than re-entering a regex/capture-group/kind per metric. - Migration: existing stored `MetricDeclaration` records with inline matchers need their matchers turned into standalone `ParamDeclaration` entries (created implicitly, named e.g. `.` if no matching declared param exists) so existing profiles keep working after upgrade. ## Acceptance criteria - A param declared once in the Params panel can be selected as a label or value param by multiple metric declarations without re-entering its extractor. - Declaring a metric that references a nonexistent param name is rejected at declare-time with a clear error. - Existing profiles with metrics declared under the old inline-matcher shape load and behave identically after migration. - `Metrics.tsx` no longer has a separate "regex + capture group + kind" entry form duplicated from the Params panel's form. ## Depends on None. [038](038-duration-as-derived-param-kind.md) and [039](039-metric-param-query-resolves-declared-params.md) build on this.