# 038 — Make Duration an explicit derived-param kind, not a hidden case of Value ## Summary Today a `Value`-role param with `kind: Duration` silently means something different from every other kind: instead of parsing extracted text, it means "elapsed time since the previous same-labeled event" (`apply_metric_to_log`, `src/engine.rs`, backed by a `LastEventTimestamp` index entry). Same enum variant (`MetricPrimitiveKind::Duration`), two unrelated meanings depending on role — one is "parse this text as a duration," which doesn't apply here at all; the other is "compute elapsed time from event sequencing." This is a silent special case a reader has to already know about to understand the code. ## Scope - Add an explicit extractor variant, e.g. `Extractor::ElapsedSinceLast { grouped_by: Vec }`, distinct from `Regex`/`JsonPath`. - A param declared with this extractor is computed (elapsed time since the previous event sharing the given label set), never text-extracted. `MetricPrimitiveKind` no longer needs a role-dependent special case for `Duration`. - Update `apply_metric_to_log` to branch on extractor kind instead of on `(role, kind)` combination. - Update the Params panel / metric declaration UI (`Params.tsx`, `Metrics.tsx`) to offer "elapsed since previous event" as its own extractor option rather than a regex+kind combination that happens to mean something else. - Migration: existing declared/embedded params using `Value` role + `Duration` kind convert to the new extractor variant. ## Acceptance criteria - A "duration" param's behavior (elapsed time since last matching event) is selectable directly in the UI without going through a regex field that is never actually used. - `apply_metric_to_log` has no branch that changes meaning based on role for a given kind. - Existing profiles using the old Value+Duration combination behave identically after migration. ## Depends on [037](037-unify-param-declarations.md).