chore: Metric Views typegen#433
Conversation
build-time type generator for UC Metric Views — reads config/queries/metric-views.json (entity-first metricViews map per the #429 schema; executor app_service_principal|user -> internal sp/obo lane), runs DESCRIBE TABLE EXTENDED ... AS JSON per declared view, and emits two artifacts: the MetricRegistry .d.ts augmentation (metric.d.ts: MeasureKey/DimensionKey/MetricRow/TimeGrain) and the metrics.metadata.json semantic-metadata bundle (entries { measures, dimensions }, frontend-safe). Absent config = fully dormant (zero artifacts, zero logs). Per-key DESCRIBE failures warn-and-continue and ship empty allowlists (arms the runtime fail-closed gate, next PR in chain); broken config throws loudly. Vite plugin: metricOutFile/metricMetadataOutFile options + watcher regen on metric-views.json edits. Re-implemented from #341 (a7bd698) on current main (post-#406 non-blocking preflight surface); 3rd PR of the #341 decomposition after #427/#429. Co-authored-by: Isaac Signed-off-by: Atila Fassina <atila@fassina.eu>
There was a problem hiding this comment.
Pull request overview
Adds build-time type generation for Unity Catalog Metric Views, emitting a MetricRegistry module augmentation plus a frontend-safe semantic metadata bundle when config/queries/metric-views.json is present.
Changes:
- Introduces metric-view config parsing/validation + DESCRIBE-driven schema extraction, emitting
metric.d.tsandmetrics.metadata.json. - Extends the Vite typegen plugin with metric output options and watcher support for
metric-views.jsonchanges. - Adds extensive unit + snapshot coverage for metric registry generation and plugin option plumbing.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/appkit/src/type-generator/vite-plugin.ts | Adds metric output options and triggers regeneration on metric-views.json edits. |
| packages/appkit/src/type-generator/index.ts | Wires metric-view generation into generateFromEntryPoint and exports metric artifact constants/types. |
| packages/appkit/src/type-generator/metric-registry.ts | Implements metric config resolution, DESCRIBE parsing, type/metadata emission, and sync failure reporting. |
| packages/appkit/src/type-generator/tests/vite-plugin.test.ts | Tests watcher behavior for metric-views.json and option plumbing for metric outputs. |
| packages/appkit/src/type-generator/tests/index.test.ts | Tests end-to-end emission/dormancy behavior for metric artifacts in generateFromEntryPoint. |
| packages/appkit/src/type-generator/tests/metric-registry.test.ts | Adds comprehensive unit tests for config validation, extraction, time grains, and metadata formatting. |
| packages/appkit/src/type-generator/tests/snapshots/metric-registry.test.ts.snap | Snapshot coverage for emitted metric.d.ts and metrics.metadata.json. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…c failure logs Copilot review response (#433): (1) the metric emit block now gates DESCRIBEs on warehouse state in non-blocking mode — one read-only status GET (never starts a warehouse); when not RUNNING (or the probe fails) it skips all DESCRIBEs and emits degraded artifacts (every configured key with empty measures/dimensions) that the vite plugin's warehouse-watch regen (blocking mode) refreshes once the warehouse is up. Blocking mode and injected metricFetcher bypass the gate. (2) syncMetrics is now log-free: the three internal per-failure warns are removed and the generateFromEntryPoint caller owns surfacing failures exactly once. Co-authored-by: Isaac Signed-off-by: Atila Fassina <atila@fassina.eu>
…aded metric types permissively Signed-off-by: Atila Fassina <atila@fassina.eu>
…preflight Signed-off-by: Atila Fassina <atila@fassina.eu>
Signed-off-by: Atila Fassina <atila@fassina.eu>
…d last-known-good degradation Signed-off-by: Atila Fassina <atila@fassina.eu>
Signed-off-by: Atila Fassina <atila@fassina.eu>
|
Pushed 4 new commits adding SQL-state-machine parity for the metric path (plus one small docs commit, 6d0953a, documenting the convergence contract on the typegen options). The metric DESCRIBE path now behaves like the query path's #406 warehouse state machine: a cold or starting warehouse is classified as degraded (permissive types now, retry-flagged cache entries that converge on the next describe-capable pass — the dev warehouse watch triggers that automatically) instead of being misreported as per-view failure; the whole pass shares a single lazily-constructed
This resolves the three review findings: (1) cold-warehouse misdiagnosed as failure, (2) no metric cache, (3) sequential DESCRIBEs. This pull request and its description were written by Isaac. |
… validation D′ retry semantics (transient vs sticky failure classes via MetricSyncFailure.transient), sticky-hit warn notice, state-aware non-blocking gate (DELETED becomes sticky), DELETED-mid-wait rides TypegenFatalError, cache pruning with forced save on config shrink, structural validation of revived cache entries. Signed-off-by: Atila Fassina <atila@fassina.eu>
Caps (200 metric views, 255/segment + 767 FQN, 100 decimal places clamp), explicit metricViews:null rejection, backtick-quoted DESCRIBE segments (hyphen-legal FQNs now work; '--' neutralized), null-prototype bundle builder, basename-exact watcher match, shared code-unit key comparator for deterministic artifact ordering. Signed-off-by: Atila Fassina <atila@fassina.eu>
|
Second review round (multi-model debate, 2026-06-12) dispatched — two hardening commits pushed; this closes the round's accepted findings. Accepted → shipped
Rejected
Deferred
Suite count: 2946 tests (+44 this round). This pull request and its description were written by Isaac. |
Behavior-preserving cleanup (snapshots byte-identical): failure-outcome helper tables D' classification; unified renderer block builders; currency map; parse-flag collapse; revival validator + cache-hash helper move into cache.ts; parallel-array removal; hoisted allowlists; stale phase-comment sweep. One semantic alignment: the Vite plugin now defers metric artifact defaults to the generator (sibling-of-outFile) instead of resolving its own, so plugin- and CLI-driven runs agree when outFile is customized. Signed-off-by: Atila Fassina <atila@fassina.eu>
|
Simplification pass ( One deliberate semantic alignment folded in: the Vite plugin no longer resolves its own metric artifact defaults — it defers to the generator's sibling-of- Queued post-merge (deliberately not churning the reviewed diff): extracting the metric orchestration out of This pull request and its description were written by Isaac. |
Build-time type generation for UC Metric Views.
When
config/queries/metric-views.jsonis present, the type generator runsDESCRIBE TABLE EXTENDED ... AS JSONper declared metric view and emits two artifacts:shared/appkit-types/metric.d.ts— theMetricRegistrymodule augmentation. Each entry carries typedmeasures/dimensionsrow fields plusmeasureKeys/dimensionKeys/timeGrainsliteral unions, the base theMeasureKey<K>/DimensionKey<K>/MetricRow<K>/TimeGrain<K>helpers derive from on the appkit-ui side.shared/appkit-types/metrics.metadata.json— the semantic-metadata bundle, entries shaped{ measures, dimensions }(display names, format specs, descriptions, time-grain hints). Frontend-safe by construction: UC FQNs and execution lanes are deliberately excluded.Note
Dormancy invariant: absent config means nothing executes — zero artifacts, zero logs, no fallback to any legacy filename. Apps that never adopt metric views see no change, which is what keeps merging this incrementally safe ahead of the runtime.
Config contract (already merged)
config/queries/metric-views.json, entity-firstmetricViewsmap per the #429metric-sourceschema:{ "metricViews": { "revenue": { "source": "main.finance.revenue_metrics" }, "customer_metrics": { "source": "main.cs.customer_metrics", "executor": "user" } } }executorisapp_service_principal(default) oruser(per-user OBO); the internal sp/obo lane is derived at the parse boundary, so downstream code only ever sees lanes.Failure semantics
Vite plugin grows
metricOutFile/metricMetadataOutFileoptions, and the dev watcher regenerates onmetric-views.jsonedits through the exact same single-flight regen flow as.sqlfiles.SQL feature parity (post-review)
Review of the metric path surfaced three gaps versus the query path's #406 warehouse state machine: (1) a cold/starting warehouse was misdiagnosed as per-view failure (baking empty
neverallowlists into.d.ts), (2) no cache — every pass re-described every view, and (3) DESCRIBEs ran sequentially. Parity with the query path's state machine is the shipping bar; four commits close it:.d.tsrendering. Non-terminal DESCRIBE outcomes (warehouse not ready, transient errors) classify as degraded:measureKeys/dimensionKeys/timeGrainsopen tostringand row fields toRecord<string, unknown>so app code keeps compiling until a successful pass refreshes them. Accurateneverunions are reserved for confirmed-empty views; bundle shape is unchanged ({ measures: {}, dimensions: {} }).WorkspaceClientper generation pass (status probe, preflight, and default DESCRIBE fetcher share one lazy instance; warm/no-op passes construct zero clients) + blocking-mode metric preflight mirroring the query flow (probe → decide → wait / start+wait). Deliberately split from the query preflight — queries and metric views may bind to different warehouses in the future. Fatal-on-DELETED rides the sameTypegenFatalErrorpath.Promise.allSettled, order-preserving results, per-key failure isolation unchanged.metricscache section in.appkit-types-cache.json(no cache version bump — query entries untouched). Entries hash asmd5(source|lane); degraded results persistretry: trueand converge via the existing warehouse watch; last-known-good schemas are served while the warehouse is down;noCacheis now meaningful for metrics; fully-warm passes make zero warehouse calls.Suite is now 2900 tests; 98 new metric-path test blocks across the three touched test files.
This pull request and its description were written by Isaac.