@malloy-publisher/server 0.0.230 → 0.0.232

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.docker.md +4 -0
  2. package/dist/app/api-doc.yaml +74 -3
  3. package/dist/app/assets/{EnvironmentPage-wa_EPkwK.js → EnvironmentPage-DXEaZIPx.js} +1 -1
  4. package/dist/app/assets/{HomePage-jnCrupQp.js → HomePage-kofsqpZt.js} +1 -1
  5. package/dist/app/assets/{LightMode-DYbwNULZ.js → LightMode-CNhIlIlJ.js} +1 -1
  6. package/dist/app/assets/{MainPage-CuJLrPNI.js → MainPage-Bgqo8jCy.js} +1 -1
  7. package/dist/app/assets/{MaterializationsPage-D_67x2ee.js → MaterializationsPage-CgBlgGz2.js} +1 -1
  8. package/dist/app/assets/{ModelPage-D5JtAWqR.js → ModelPage-B0TjoDtf.js} +1 -1
  9. package/dist/app/assets/{PackagePage-BRwtqUSG.js → PackagePage-BL8vnFj1.js} +1 -1
  10. package/dist/app/assets/{RouteError-CBNNrnSD.js → RouteError-BzPby0X2.js} +1 -1
  11. package/dist/app/assets/{ThemeEditorPage-CTCeBneA.js → ThemeEditorPage-CTEP_9r3.js} +1 -1
  12. package/dist/app/assets/{WorkbookPage-SN6f1RBm.js → WorkbookPage-BwM3BmKw.js} +1 -1
  13. package/dist/app/assets/{core-Dp3q5Ieu.es-CD5FvM2s.js → core-CK68iv6w.es-CpRxXBt7.js} +1 -1
  14. package/dist/app/assets/{index-C_tJstcx.js → index-B33zGctF.js} +15 -15
  15. package/dist/app/assets/{index-DU4r7GdU.js → index-BabP-V-S.js} +346 -321
  16. package/dist/app/assets/{index-B3Nn8Vm2.js → index-BkiWKaAF.js} +266 -265
  17. package/dist/app/assets/{index-BLCx1EdC.js → index-CmkW1MiE.js} +1 -1
  18. package/dist/app/assets/{index-CfmBVB6M.js → index-tXJXwdyj.js} +1 -1
  19. package/dist/app/index.html +1 -1
  20. package/dist/instrumentation.mjs +2 -0
  21. package/dist/package_load_worker.mjs +11 -1
  22. package/dist/server.mjs +3186 -433
  23. package/package.json +12 -12
  24. package/scripts/bake-duckdb-extensions.js +4 -1
  25. package/src/config.spec.ts +39 -0
  26. package/src/config.ts +135 -0
  27. package/src/controller/materialization.controller.spec.ts +62 -0
  28. package/src/controller/materialization.controller.ts +15 -0
  29. package/src/controller/package.controller.spec.ts +6 -0
  30. package/src/controller/package.controller.ts +7 -2
  31. package/src/errors.ts +19 -0
  32. package/src/logger.spec.ts +18 -1
  33. package/src/logger.ts +3 -1
  34. package/src/materialization_metrics.spec.ts +89 -4
  35. package/src/materialization_metrics.ts +155 -5
  36. package/src/mcp/skills/skills_bundle.json +1 -1
  37. package/src/mcp/tools/embedding_index.spec.ts +1236 -0
  38. package/src/mcp/tools/embedding_index.ts +808 -0
  39. package/src/mcp/tools/get_context_eval.ts +194 -45
  40. package/src/mcp/tools/get_context_tool.spec.ts +295 -2
  41. package/src/mcp/tools/get_context_tool.ts +159 -10
  42. package/src/pg_helpers.spec.ts +201 -0
  43. package/src/pg_helpers.ts +44 -5
  44. package/src/server.ts +24 -0
  45. package/src/service/build_plan.spec.ts +128 -2
  46. package/src/service/build_plan.ts +239 -17
  47. package/src/service/connection.ts +263 -7
  48. package/src/service/connection_config.spec.ts +48 -0
  49. package/src/service/connection_config.ts +21 -8
  50. package/src/service/connection_federation.spec.ts +184 -0
  51. package/src/service/embedding_provider.spec.ts +329 -0
  52. package/src/service/embedding_provider.ts +236 -0
  53. package/src/service/environment.ts +274 -12
  54. package/src/service/environment_store.spec.ts +678 -3
  55. package/src/service/environment_store.ts +449 -33
  56. package/src/service/environment_store_clone.spec.ts +350 -0
  57. package/src/service/manifest_loader.spec.ts +68 -13
  58. package/src/service/manifest_loader.ts +67 -19
  59. package/src/service/materialization_build_session.spec.ts +435 -0
  60. package/src/service/materialization_build_session.ts +681 -0
  61. package/src/service/materialization_eligibility.spec.ts +158 -0
  62. package/src/service/materialization_eligibility.ts +305 -0
  63. package/src/service/materialization_serve_transform.spec.ts +1003 -0
  64. package/src/service/materialization_serve_transform.ts +779 -0
  65. package/src/service/materialization_service.spec.ts +774 -7
  66. package/src/service/materialization_service.ts +1107 -42
  67. package/src/service/materialization_test_fixtures.ts +7 -0
  68. package/src/service/model.spec.ts +207 -0
  69. package/src/service/model.ts +540 -52
  70. package/src/service/model_storage_serve.spec.ts +193 -0
  71. package/src/service/model_storage_serve_joins.spec.ts +193 -0
  72. package/src/service/package.spec.ts +196 -0
  73. package/src/service/package.ts +385 -17
  74. package/src/service/persistence_policy.spec.ts +109 -0
  75. package/src/storage/duckdb/schema.ts +37 -0
  76. package/tests/fixtures/xlsx/database.xlsx +0 -0
  77. package/tests/integration/first_boot/readiness_line.integration.spec.ts +177 -0
  78. package/tests/integration/materialization/manifest_binding.integration.spec.ts +104 -0
  79. package/tests/integration/mcp/mcp_get_context_semantic.integration.spec.ts +235 -0
@@ -19,6 +19,40 @@ export type MaterializationMode = "auto" | "orchestrated";
19
19
  export type MaterializationOutcome = "success" | "failed" | "cancelled";
20
20
  /** Manifest bind outcome: timeout is split out from generic failure on purpose. */
21
21
  export type ManifestBindOutcome = "success" | "failure" | "timeout";
22
+ /**
23
+ * Which engine a source build / table drop ran against: the source's own
24
+ * warehouse (colocated, in-warehouse CTAS) or a DuckDB/DuckLake `storage=`
25
+ * destination (federated passthrough CTAS). The two have very different latency
26
+ * and failure profiles, so build/drop metrics are labeled with it rather than
27
+ * pooling the two into one series.
28
+ */
29
+ export type StorageBuildEngine = "storage" | "in_warehouse";
30
+ /** Why a source was refused materialization into a storage destination. */
31
+ export type EligibilityRefusalReason =
32
+ | "free_parameter"
33
+ | "given"
34
+ | "authorize"
35
+ | "not_duckdb_portable"
36
+ | "public_surface_unknown";
37
+ /**
38
+ * How a chained `storage=` source (one that reads a storage-materialized
39
+ * upstream) was built: `parent_reuse` = built by reading the upstream's stored
40
+ * lake table ("stack on the parent" — reuses the parent's work and is
41
+ * consistent-by-construction); `inline_fallback` = stacking was ineligible/failed
42
+ * so the upstream was recomputed from raw against the warehouse (non-strict);
43
+ * `strict_refused` = stacking was ineligible under `strictUpstreams`, so
44
+ * the build failed loudly rather than silently recomputing. This is the headline
45
+ * signal for how far the parent-reuse path gets us in practice.
46
+ */
47
+ export type ChainedStorageBuildOutcome =
48
+ | "parent_reuse"
49
+ | "inline_fallback"
50
+ | "strict_refused"
51
+ // The parent-reuse attempt failed on infrastructure (attach, CTAS, the
52
+ // destination being unreachable) rather than on shape. Distinct from
53
+ // `inline_fallback` because it is an outage, not a modelling limit: the build
54
+ // fails rather than recomputing from raw against the same destination.
55
+ | "infra_failure";
22
56
 
23
57
  const resetHooks: (() => void)[] = [];
24
58
 
@@ -99,6 +133,39 @@ const scheduledFireCounter = lazyCounter(
99
133
  "Standalone-scheduler attempts to fire a package's materialization.schedule. " +
100
134
  "Label: outcome ('fired'|'conflict'|'error').",
101
135
  );
136
+ const storageServeRoutingCounter = lazyCounter(
137
+ "publisher_storage_serve_routing_total",
138
+ "storage= serve routing decisions. Label: outcome ('storage'|'live_fallback'|'runtime_live_fallback').",
139
+ );
140
+ const storageBuildFailureCounter = lazyCounter(
141
+ "publisher_storage_build_failures_total",
142
+ "storage= build failures (federation/passthrough/attach/CTAS), distinct from " +
143
+ "in-warehouse build failures. Label: destination (connection name).",
144
+ );
145
+ const eligibilityRefusedCounter = lazyCounter(
146
+ "publisher_materialization_eligibility_refused_total",
147
+ "storage= materialization-eligibility refusals. Label: reason " +
148
+ "('free_parameter'|'given'|'authorize'|'not_duckdb_portable'|" +
149
+ "'public_surface_unknown').",
150
+ );
151
+ const serveShapeTierDropCounter = lazyCounter(
152
+ "publisher_storage_serve_shape_tier_drop_total",
153
+ "storage serve-shape compile escalations: a refinement tier failed to " +
154
+ "compile and the riskiest category was dropped. Label: tier (the failed " +
155
+ "tier index, 0=full).",
156
+ );
157
+ const serveShapeTypeFallbackCounter = lazyCounter(
158
+ "publisher_storage_serve_shape_type_fallback_total",
159
+ "Captured DuckDB column types mapped to json in the serve shape (type " +
160
+ "fidelity loss). Label: kind ('array'|'unrecognized').",
161
+ );
162
+ const chainedStorageBuildCounter = lazyCounter(
163
+ "publisher_storage_chained_build_total",
164
+ "Chained storage= source builds (a source reading a storage-materialized " +
165
+ "upstream). Label: outcome ('parent_reuse'|'inline_fallback'|" +
166
+ "'strict_refused'). The parent_reuse share is the headline signal for how " +
167
+ "far the stack-on-the-parent path gets us vs recompute-from-raw.",
168
+ );
102
169
 
103
170
  /**
104
171
  * Record a standalone-scheduler fire attempt. `fired` = a SCHEDULER run started;
@@ -180,14 +247,97 @@ export function recordManifestBindDegraded(): void {
180
247
  manifestBindDegradedCounter().add(1);
181
248
  }
182
249
 
183
- /** Record the wall-clock duration of building one persist source's table. */
184
- export function recordSourceBuildDuration(durationMs: number): void {
185
- sourceBuildDuration().record(durationMs);
250
+ /**
251
+ * Record the wall-clock duration of building one persist source's table,
252
+ * labeled by engine so the DuckDB passthrough path and the in-warehouse CTAS
253
+ * path (very different latency profiles) don't pool into one series.
254
+ */
255
+ export function recordSourceBuildDuration(
256
+ durationMs: number,
257
+ engine: StorageBuildEngine,
258
+ ): void {
259
+ sourceBuildDuration().record(durationMs, { engine });
186
260
  }
187
261
 
188
262
  /** Record a best-effort physical-table drop on materialization delete. */
189
- export function recordDropTables(outcome: "success" | "failure"): void {
190
- dropTablesCounter().add(1, { outcome });
263
+ export function recordDropTables(
264
+ outcome: "success" | "failure",
265
+ engine: StorageBuildEngine,
266
+ ): void {
267
+ dropTablesCounter().add(1, { outcome, engine });
268
+ }
269
+
270
+ /**
271
+ * Record a `storage=` build failure (federation / passthrough / attach / CTAS),
272
+ * counted separately from in-warehouse build failures because the storage path
273
+ * has its own failure modes and destination axis.
274
+ */
275
+ export function recordStorageBuildFailure(destination: string): void {
276
+ storageBuildFailureCounter().add(1, { destination });
277
+ }
278
+
279
+ /**
280
+ * Record a materialization-eligibility refusal (a source that can't be safely
281
+ * materialized into a storage destination). The `given` reason is a security
282
+ * refusal (a frozen given-filtered table would leak rows across tenants); worth
283
+ * tracking how often authors attempt it.
284
+ */
285
+ export function recordEligibilityRefused(
286
+ reason: EligibilityRefusalReason,
287
+ ): void {
288
+ eligibilityRefusedCounter().add(1, { reason });
289
+ }
290
+
291
+ /**
292
+ * Record a serve-shape compile escalation: the refinement tier at `failedTier`
293
+ * did not compile, so the riskiest category was dropped and the shape retried.
294
+ * A systematically-dropping source tells authors which refinements aren't
295
+ * servable from storage.
296
+ */
297
+ export function recordServeShapeTierDrop(failedTier: number): void {
298
+ serveShapeTierDropCounter().add(1, { tier: String(failedTier) });
299
+ }
300
+
301
+ /**
302
+ * Record a captured DuckDB column type that could not map onto a Malloy basic
303
+ * type and was carried as json in the serve shape — a type-fidelity loss
304
+ * specific to the storage tier. `array` = a collection/array type; `unrecognized`
305
+ * = an unknown/nested/struct/enum/blob type.
306
+ */
307
+ export function recordServeShapeTypeFallback(
308
+ kind: "array" | "unrecognized",
309
+ ): void {
310
+ serveShapeTypeFallbackCounter().add(1, { kind });
311
+ }
312
+
313
+ /**
314
+ * Record a `storage=` serve-routing decision: `storage` = the query was served
315
+ * from the materialized table via the virtual-source transform; `live_fallback`
316
+ * = the transform was ineligible for this query (a refinement it can't
317
+ * reproduce, an unbound source, mode not `on`) so it was served live;
318
+ * `runtime_live_fallback` = the query DID route to storage and the store then
319
+ * failed underneath it, and every binding's `freshnessFallback=live` allowed it
320
+ * to degrade. That last one is the operationally interesting label: it means the
321
+ * tier is broken while queries still succeed, which is invisible in the hit rate
322
+ * alone. This hit rate is the headline KPI of the storage tier — otherwise the
323
+ * fallback side is only a DEBUG log.
324
+ */
325
+ export function recordStorageServeRouting(
326
+ outcome: "storage" | "live_fallback" | "runtime_live_fallback",
327
+ ): void {
328
+ storageServeRoutingCounter().add(1, { outcome });
329
+ }
330
+
331
+ /**
332
+ * Record how a chained `storage=` source was built (see
333
+ * {@link ChainedStorageBuildOutcome}). Only fired for a source that actually
334
+ * reads a storage-materialized upstream — a single-source build emits nothing
335
+ * here. The parent_reuse : inline_fallback ratio is the spike's key learning.
336
+ */
337
+ export function recordChainedStorageBuild(
338
+ outcome: ChainedStorageBuildOutcome,
339
+ ): void {
340
+ chainedStorageBuildCounter().add(1, { outcome });
191
341
  }
192
342
 
193
343
  /** Visible for tests. Drops cached instruments so a fresh MeterProvider can capture emissions. */