@malloy-publisher/skills 0.1.21 → 0.1.22
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.
- package/package.json +1 -1
- package/skills/eval-answer/SKILL.md +1 -1
- package/skills/eval-diagnose/SKILL.md +1 -1
- package/skills/eval-import/SKILL.md +1 -1
- package/skills/eval-improve/SKILL.md +1 -1
- package/skills/eval-judge/SKILL.md +1 -1
- package/skills/eval-loop/SKILL.md +1 -1
- package/skills/eval-report/SKILL.md +1 -1
- package/skills/malloy/SKILL.md +1 -1
- package/skills/malloy-analysis/SKILL.md +1 -1
- package/skills/malloy-analysis-pitfalls/SKILL.md +2 -2
- package/skills/malloy-analysis-report/SKILL.md +1 -1
- package/skills/malloy-analyze/SKILL.md +1 -1
- package/skills/malloy-charts/SKILL.md +1 -1
- package/skills/malloy-dashboards/SKILL.md +1 -1
- package/skills/malloy-debug/SKILL.md +1 -1
- package/skills/malloy-define/SKILL.md +1 -1
- package/skills/malloy-discover/SKILL.md +1 -1
- package/skills/malloy-document/SKILL.md +1 -1
- package/skills/malloy-getting-started/SKILL.md +1 -1
- package/skills/malloy-gotchas-modeling/SKILL.md +1 -1
- package/skills/malloy-gotchas-queries/SKILL.md +43 -24
- package/skills/malloy-gotchas-rendering/SKILL.md +1 -1
- package/skills/malloy-html-data-app-embedding/SKILL.md +1 -1
- package/skills/malloy-html-data-app-runtime/SKILL.md +2 -2
- package/skills/malloy-html-data-apps/SKILL.md +1 -1
- package/skills/malloy-lookml-review/SKILL.md +1 -1
- package/skills/malloy-lookml-review/reference/curate-visibility.md +1 -1
- package/skills/malloy-materialization/SKILL.md +3 -3
- package/skills/malloy-materialization-tuning/SKILL.md +2 -2
- package/skills/malloy-model/SKILL.md +51 -17
- package/skills/malloy-model-as-you-go/SKILL.md +1 -1
- package/skills/malloy-modeling/SKILL.md +1 -1
- package/skills/malloy-notebook-chat/SKILL.md +1 -1
- package/skills/malloy-notebooks/SKILL.md +2 -2
- package/skills/malloy-patterns/SKILL.md +1 -1
- package/skills/malloy-phrase-detection/SKILL.md +1 -1
- package/skills/malloy-publish/SKILL.md +2 -2
- package/skills/malloy-queries/SKILL.md +11 -12
- package/skills/malloy-review/SKILL.md +1 -1
- package/skills/malloy-scope/SKILL.md +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eval-answer
|
|
3
3
|
description: 'Score one analytical answer against a verified golden, and score which of the entities the golden depends on retrieval delivered to the answerer. Run the contamination checklist, re-execute the submitted query yourself, then spawn a judge subagent per skill:eval-judge. Append attempt, tool_call, score, and retrieval_score events to the file ledger (reference/ledger-schema.md). Never explain the failure (eval-diagnose) or edit the model (eval-improve). Use when asked whether an answer was correct, to score a run, or to baseline a model.'
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Evaluate One Answer
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eval-diagnose
|
|
3
3
|
description: 'Diagnose why a scored answer failed and who owns the fix, then cluster the failures by shared root cause. Walk dataset, agent-call, get_context/model, get_context/retrieval, construction, then model-definition. Append issue events to the file ledger, linked by traceId, one per cluster. Use after eval-answer, when triaging a run, or before changing a model. Does not edit the model (eval-improve).'
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Diagnose One Answer
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eval-import
|
|
3
3
|
description: 'Turn a list of questions into an eval set, whatever shape it arrived in: a JSONL a customer sent, a CSV, a spreadsheet export, a markdown doc, an email thread, or a pull from production logs. Classify each item by what came WITH the question (a query, a number, prose criteria, or nothing), write cases.jsonl and set.json per reference/case-format.md, keep the file as it arrived, and seal each question so a later edit is detectable. Never marks a value-bearing golden verified and never invents a question. Use when questions arrive from outside and need to become a set, or before the first run against a set nobody here authored.'
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Import questions into an eval set
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eval-improve
|
|
3
3
|
description: 'Make the smallest safe Malloy model edit that closes a diagnosed model-owned gap, with a probe receipt for every factual claim. Use after eval-diagnose, or when asked to fix a model so an agent can discover the right answer. Never accepts its own edit; the acceptance check belongs to eval-loop. Does not decide whether an answer was wrong (eval-answer) or why (eval-diagnose).'
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Improve the Model
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eval-judge
|
|
3
3
|
description: 'Decide whether ONE answer matches its golden, and say whether you believe the golden. Read this before emitting any verdict. Covers containment, column pairing, near_match, refusals, and the gold_status judgement. Use when scoring an attempt in an evaluation run; never to conduct a run (eval-loop), diagnose a failure (eval-diagnose) or edit a model (eval-improve).'
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# The judge
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eval-loop
|
|
3
3
|
description: 'Conduct a local Publisher evaluation loop in five steps: scrape/run, eval, diagnose, improve, checkpoint. You are the conductor: import cases into the file ledger, spawn a blind answerer, then run eval-answer, eval-diagnose, and eval-improve. Persistence is plain files under the model package''s evals/ directory; checkpoints are git commits of the model repo. Use to score a model, diagnose failures, improve behind an acceptance check, or roll back a bad direction.'
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# The Evaluation Loop
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eval-report
|
|
3
3
|
description: 'Write the summary a person reads after an evaluation run: what ran, what it scored, which failures were the MODEL and which were the EVAL itself (out of turns, contaminated, unestablished golden, unreadable judge), what was learned, and what to do next. Every claim links to the artifact behind it. Use at the end of any run, before quoting a number to anyone. Never scores an answer (eval-answer) or decides who owns a failure (eval-diagnose).'
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Report a Run
|
package/skills/malloy/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy
|
|
3
3
|
description: Index of all Malloy skills. Use when user asks "malloy help", "what malloy skills are available", "how do I use malloy", or needs guidance on which Malloy skill to use.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!-- Copyright (c) Credible Data Inc. SPDX-License-Identifier: MIT -->
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-analysis
|
|
3
3
|
description: The workflow for answering a data question over a Malloy semantic model - a metric, breakdown, trend or chart - from get_context discovery through execute_query to verified delivery.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- Copyright (c) Credible Data Inc. SPDX-License-Identifier: MIT -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-analysis-pitfalls
|
|
3
3
|
description: Checks to run on a query and its numbers before a result is presented - wrong grain, fan-out, invented field names, mismatched filters, count vs distinct. The common data-analysis pitfalls.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!-- Copyright (c) Credible Data Inc. SPDX-License-Identifier: MIT -->
|
|
7
7
|
|
|
@@ -22,7 +22,7 @@ That check reads in ONE direction only. `count(joined.field)` is a distinct coun
|
|
|
22
22
|
run: flights -> {
|
|
23
23
|
aggregate:
|
|
24
24
|
all_rows is count()
|
|
25
|
-
missing is count() { where: aircraft.aircraft_models.seats
|
|
25
|
+
missing is count() { where: aircraft.aircraft_models.seats is null }
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-analysis-report
|
|
3
3
|
description: Combine validated Malloy queries into a notebook report or dashboard. Use when the user asks to "create a report", "build a dashboard", "combine these into a report", or wants a persistent multi-query artifact.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-analyze
|
|
3
3
|
description: Open-ended exploration with no specific question to answer, and building views/dashboards/notebooks on an existing model. Use when the user asks "what's interesting?", "explore this data", "find insights", "look for patterns", "build a dashboard", or "create views". Not for a specific data question - answering one is `malloy-analysis`, and writing down what the answer assumed is `malloy-model-as-you-go`. For exploration start at Step 1; for views on an existing model jump to View Patterns.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-charts
|
|
3
3
|
description: Chart selection for a Malloy view, plus the renderer reference for bar_chart, line_chart, scatter_chart, maps and layouts. For choosing a visualization or adding a chart annotation.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-dashboards
|
|
3
3
|
description: "Build or modify a Malloy Publisher dashboard, a tagged .malloy file in a package's dashboards/ directory, with auto-rendered filter controls, a grid layout, and # drill click-through. Use when the user asks for a dashboard, a filterable operational view, or drill-through between views, and no code is wanted."
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!--
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-debug
|
|
3
3
|
description: Fix Malloy compile errors and understand error messages. Use when encountering errors in .malloy files, user says "fix this error", "malloy error", "compile error", "syntax error", or sees 20+ cascading errors.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-define
|
|
3
3
|
description: Propose a source plan and field definitions for a Malloy semantic model. Covers picking which sources to model and at what grain, then proposing the specific renames, dimensions, and measures per source, every proposal backed by querying the data.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-discover
|
|
3
3
|
description: Silent data discovery for Malloy modeling. Used at Step 1 of the modeling workflow. Scans tables, columns, distributions, and relationships without user interaction. The agent builds an internal picture before presenting anything.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-document
|
|
3
3
|
description: 'Add documentation with #(doc) tags to Malloy models so fields and sources are described in plain language. Use when user asks to "add documentation", "add doc tags", "document the model", or wants fields and sources described for natural-language search and discovery. For declaring parameterizable filters with #(filter), see the malloy-model skill. Filters are a runtime/modeling construct (governance, latency, correctness), not a documentation tag.'
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-getting-started
|
|
3
3
|
description: First steps for using a Malloy Publisher deployment through its MCP tools. Use when connecting to Publisher for the first time, when you do not yet know the available environments, packages, or models, or when a user asks what data they can explore. Covers verifying the server, discovering data with get_context, and running a first grounded query.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-gotchas-modeling
|
|
3
3
|
description: Common Malloy modeling mistakes, for writing source definitions, dimensions, measures or joins - reserved words, NULL checks, date functions, type casts, field management (extend except/accept/rename vs include public/internal/private), query-based source gotchas.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-gotchas-queries
|
|
3
3
|
description: Common Malloy query and view mistakes, for writing views, queries or notebooks - chart constraints, aggregate filters, joined field aliasing, method syntax, time truncation vs extraction.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -95,6 +95,28 @@ aggregate: avg_price is avg(price), statuses is count(status)
|
|
|
95
95
|
|
|
96
96
|
Check the field's type in the `get_context` result before aggregating it. A name that reads numeric (`order_number`, `zip`, `account_id`) is very often typed string.
|
|
97
97
|
|
|
98
|
+
## A Measure Is Already an Aggregate
|
|
99
|
+
|
|
100
|
+
```malloy
|
|
101
|
+
// WRONG: "Aggregate expression cannot be aggregate" - flight_count is a measure
|
|
102
|
+
run: flights -> { aggregate: busiest is max(flight_count) }
|
|
103
|
+
// RIGHT: aggregate per group, then take the max in a second stage
|
|
104
|
+
run: flights -> { group_by: carrier, aggregate: n is flight_count } -> { aggregate: busiest is max(n) }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The message does not name the field. When it appears, look for a model measure you wrapped in another aggregate. If you only need the top row, skip the second stage: `order_by: n desc` with `limit: 1`.
|
|
108
|
+
|
|
109
|
+
## Window Braces Bind to the Function
|
|
110
|
+
|
|
111
|
+
```malloy
|
|
112
|
+
// WRONG: "`partition_by` is not supported for this kind of expression"
|
|
113
|
+
calculate: share is sum_cumulative(n) / region_total { partition_by: region, order_by: n desc }
|
|
114
|
+
// RIGHT: the brace goes directly after the window function call
|
|
115
|
+
calculate: share is sum_cumulative(n) { partition_by: region, order_by: n desc } / region_total
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
For a within-group share, compute the denominator in `aggregate:` (`region_total is all(count(), region)`). A window's `{ partition_by }` does not apply to `all()`.
|
|
119
|
+
|
|
98
120
|
## Dotted Paths Must Name a Declared Join
|
|
99
121
|
|
|
100
122
|
```malloy
|
|
@@ -157,36 +179,33 @@ where: is_us = true, party ? 'Democrat' | 'Republican'
|
|
|
157
179
|
|
|
158
180
|
`and` works in some arrangements (when the alternation is the second operand) but produces a confusing `'logical operator' Can't use type string` compile error when the alternation comes first. The comma form is unambiguous in every position, so just use it.
|
|
159
181
|
|
|
160
|
-
##
|
|
161
|
-
|
|
162
|
-
Do not use trailing commas between query clauses. Each clause goes on its own line.
|
|
182
|
+
## Strings: Apostrophes and Concatenation
|
|
163
183
|
|
|
164
184
|
```malloy
|
|
165
|
-
// WRONG:
|
|
166
|
-
|
|
167
|
-
// RIGHT
|
|
168
|
-
|
|
169
|
-
group_by: status
|
|
170
|
-
aggregate: n is count()
|
|
171
|
-
limit: 10
|
|
172
|
-
}
|
|
173
|
-
```
|
|
185
|
+
// WRONG: "no viable alternative at input 's'" - the apostrophe ends the literal
|
|
186
|
+
where: name = 'Mac's Diner'
|
|
187
|
+
// RIGHT
|
|
188
|
+
where: name = "Mac's Diner"
|
|
174
189
|
|
|
175
|
-
|
|
190
|
+
// WRONG: "unexpected '+'" / "no viable alternative at input '||'"
|
|
191
|
+
group_by: route is origin ++ '-' ++ destination
|
|
192
|
+
// RIGHT: there is no concatenation operator
|
|
193
|
+
group_by: route is concat(origin, '-', destination)
|
|
194
|
+
```
|
|
176
195
|
|
|
177
|
-
##
|
|
196
|
+
## A Semicolon Inside a Clause Ends It
|
|
178
197
|
|
|
179
|
-
|
|
198
|
+
Between clauses a newline, comma or `;` all work. Within one clause, separate fields with commas or newlines: a `;` closes the clause, and the next field is orphaned.
|
|
180
199
|
|
|
181
200
|
```malloy
|
|
182
|
-
// WRONG:
|
|
201
|
+
// WRONG: "no viable alternative at input 'charters'"
|
|
183
202
|
run: schools -> { aggregate: total is count(); charters is count() { where: is_charter } }
|
|
184
|
-
// RIGHT
|
|
203
|
+
// RIGHT
|
|
185
204
|
run: schools -> { aggregate: total is count(), charters is count() { where: is_charter } }
|
|
186
|
-
// ...or newlines
|
|
187
|
-
run: schools -> {
|
|
188
|
-
aggregate:
|
|
189
|
-
total is count()
|
|
190
|
-
charters is count() { where: is_charter }
|
|
191
|
-
}
|
|
192
205
|
```
|
|
206
|
+
|
|
207
|
+
The same message appears for an unnamed aggregate after the first: `aggregate: n, max(x)` fails at `max`. Name every entry.
|
|
208
|
+
|
|
209
|
+
## Compiles, Then Refused by the Warehouse
|
|
210
|
+
|
|
211
|
+
`Query execution failed: ...` means the Malloy compiled and the warehouse rejected the SQL, often over a type. The position it quotes is in the generated SQL, not in your query. BigQuery, for example, will not partition a window function on a FLOAT64 column. `partition_by:` takes only a field name, so cast in `group_by:` (`season_key is season::string`) and partition on `season_key`, or fix the type in the model.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-gotchas-rendering
|
|
3
3
|
description: Common Malloy renderer mistakes, for adding chart annotations and formatting tags or building dashboards - tag syntax, scale rules, sparkline setup, big_value patterns.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-html-data-app-embedding
|
|
3
3
|
description: Embed an in-package HTML data app into a host page or another application, including auto-sizing and auth. Read when embedding a Publisher page via Publisher.embed.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-html-data-app-runtime
|
|
3
3
|
description: The JavaScript that drives an in-package HTML data app - calling Publisher.query, building queries from filter state, handling results and errors. For writing the page's data code.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -156,7 +156,7 @@ If you validate the rendered page in a headless browser (Playwright or Puppeteer
|
|
|
156
156
|
| Promise rejects, message starts `Publisher.query:` | Read `error.status` and `error.response` for the server's reason (compile error, missing required parameter, permission). |
|
|
157
157
|
| Empty array when you expect rows | Filter value mismatch (case, spelling, type, or a non-ASCII character like `≤` or an en-dash in the literal). Copy the literal verbatim from the model, do not retype the user's paraphrase, and confirm it with a distinct-values query (`run: src -> { group_by: the_dimension }`). Quote strings, use `@` for dates. |
|
|
158
158
|
| 400 on a given (ungated source) | An unknown given name (check spelling; names are case-sensitive), a required given left unset, or a value that doesn't fit the declared type. Malloy rejects it when preparing the query; supply declared givens via `opts.givens` with the right shape (see the givens type table). |
|
|
159
|
-
| 403 on a query that should be allowed, when passing givens to a gated source | On a source
|
|
159
|
+
| 403 on a query that should be allowed, when passing givens to a gated source | On a gated source, a bad given (unknown name or wrong-typed value) fails closed, so it looks like access denied rather than validation. A `#(authorize)` lock also answers 403 for a caller it simply does not admit. Check the given names and values against the model. |
|
|
160
160
|
| KPI shows `undefined` | The result is an array. Read `rows[0].field` (or destructure `const [k] = ...`), not `rows.field`. |
|
|
161
161
|
| Page loads in dev but is not listed or not served | The file is not under the package's `public/` directory. Publisher serves only `public/`; a page written anywhere else (for example `/tmp`) is never reachable at `/environments/<env>/packages/<pkg>/<file>`. |
|
|
162
162
|
| Queries fail only when embedded cross-origin | Cookies are not sent cross-site. Serve same-origin, or pass a bearer token. |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-html-data-apps
|
|
3
3
|
description: Build or modify an in-package HTML data app for a Malloy Publisher package (a public/ directory the package serves). Use when the user wants a hand-authored HTML dashboard or web page backed by a package's Malloy models, with no build step.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-lookml-review
|
|
3
3
|
description: Analyze LookML files as prior art for Malloy modeling. Used during Step 1 (DISCOVER) when .lkml files are present. Coordinates reference files that extract business logic, relationships, and curation decisions. Works with or without a database connection.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -58,7 +58,7 @@ source: revenue is conn.table('…') include {
|
|
|
58
58
|
|
|
59
59
|
Give the mask a **different name** from the private raw column (`amount` vs `raw_amount`), reusing the name is a redefinition. If the mask must carry the raw column's *exact* original name, that forces a `rename:`, which pushes you onto the `extend { rename }` path. That path composes with `include {}`, but only in one order (the `extend { rename: }` first, then `include {}` naming the post-rename field; see `skill:malloy-gotchas-modeling`), and you still have to move the raw column out of the way before the mask can take its name. Prefer a distinct mask name and keep the raw `private:` unless the exact original name is required.
|
|
60
60
|
|
|
61
|
-
**This is NOT per-viewer access control.** LookML `required_access_grants` gates on the *viewing user's* attributes; Malloy models have no per-viewer context, so a model-layer `pick` can only redact based on row data or a parameter. To gate a field by *caller identity/role* (the real `required_access_grants` equivalent), use `#(authorize)` on the source, driven by trusted attributes in Malloy Publisher (see `skill:malloy-model` § Access Control).
|
|
61
|
+
**This is NOT per-viewer access control.** LookML `required_access_grants` gates on the *viewing user's* attributes; Malloy models have no per-viewer context, so a model-layer `pick` can only redact based on row data or a parameter. To gate a field by *caller identity/role* (the real `required_access_grants` equivalent), use `#(authorize)` on the source, driven by trusted attributes in Malloy Publisher (see `skill:malloy-model` § Access Control). `#(authorize)` refuses a caller it does not admit with a 403; `#(access_filter)` is the row-scoping sibling. Masking and these gates are independent layers; use the mask for "everyone sees a coarsened value," a gate for "only some callers see the field at all."
|
|
62
62
|
|
|
63
63
|
## Pattern: Long→wide custom-field pivot
|
|
64
64
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-materialization
|
|
3
3
|
description: Add and debug Malloy Persistence materializations in a package - persist an expensive source so queries read a pre-built table. Read this whenever the user wants to materialize a source, add a persist annotation, speed up a slow source, or asks why a persist source isn't building.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -95,7 +95,7 @@ source: persist_smoke is smoke_raw -> { aggregate: n is count() }
|
|
|
95
95
|
|
|
96
96
|
Delete the smoke file and drop its table afterward.
|
|
97
97
|
|
|
98
|
-
## Persisting
|
|
98
|
+
## Persisting a `#(access_filter)`-gated source
|
|
99
99
|
|
|
100
100
|
A gated source **can** be persisted, but only on one tier and only in one shape, and the thing to be
|
|
101
101
|
careful about is not refused by anything - you have to decide it.
|
|
@@ -173,4 +173,4 @@ bound on how long a revoked row keeps being served.
|
|
|
173
173
|
- **Quote the name** - a bare `name=` always hard-stops the build.
|
|
174
174
|
- **Republishing unchanged persist logic reuses the table** - reuse is keyed on the content-addressed `sourceEntityId`, not the `name=`.
|
|
175
175
|
- **Removing a persist source (or a smoke test) does not drop its table** - physical-table cleanup is the caller's responsibility; drop it yourself.
|
|
176
|
-
- **
|
|
176
|
+
- **A `#(access_filter)`-gated source freezes its gating column when persisted** - the gate still runs live, but a revoked row keeps being served under its old access decision until the next rebuild. `storage=` and `#@ preaggregate` refuse a gated source outright. See **Persisting a `#(access_filter)`-gated source**.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-materialization-tuning
|
|
3
3
|
description: Optimize a package's Malloy Persistence materializations for cost and performance using the malloy-pub CLI and the materialization history. Recommend what to persist, what to stop persisting, and how to schedule/scope it. Use when the user asks to make a package cheaper or faster, tune persistence, decide what to materialize, or review persist/schedule choices.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!--
|
|
@@ -60,7 +60,7 @@ Look across several runs, not one: the pattern over the recent history (how ofte
|
|
|
60
60
|
|
|
61
61
|
Weigh rebuild cost against query benefit. Common findings:
|
|
62
62
|
|
|
63
|
-
- **Persist candidate:** an expensive, frequently-queried source that is _not_ persisted (recomputed on every query). Recommend adding `#@ persist name="…"`. Strongest when the source is a heavy aggregate/join reused by many queries and its inputs change slowly. If the source carries
|
|
63
|
+
- **Persist candidate:** an expensive, frequently-queried source that is _not_ persisted (recomputed on every query). Recommend adding `#@ persist name="…"`. Strongest when the source is a heavy aggregate/join reused by many queries and its inputs change slowly. If the source carries a `#(access_filter)` gate, check which case it is first. A gate reached only through a `join_*`, or inherited from a base it cannot be attributed to, makes the colocated persist **refuse with a 422** - so do not recommend persisting it at all. Where the gate is provably the source's own row filter the persist is admitted, and then only recommend it alongside a freshness window (`freshness.fallback="live"`): the gating column freezes at build time, so without one a revoked row can be served under its old access decision indefinitely (see `skill:malloy-materialization`, which also covers where that window does and does not bind).
|
|
64
64
|
- **Removal candidate:** a persisted source that is cheap to compute, rarely queried, or rebuilt far more often than it is read. Recommend dropping the `#@ persist` annotation (and its table): the storage + rebuild cost is not buying anything.
|
|
65
65
|
- **Cadence mismatch:** a `SCHEDULER` cadence out of step with how fast the data changes or how long a build takes. If most scheduled runs are all-reused (nothing changed), the cron is too frequent, so loosen it. If queries routinely read stale data, tighten it. If the build's `durationMs` approaches the interval, the cadence is too aggressive.
|
|
66
66
|
- **Scope mismatch:** `scope: version` re-materializes per published version (right when versions must be isolated, e.g. a schedule); `scope: package` reuses one lineage across versions (cheaper when versions can share). A schedule _requires_ `version`. If a package carries a schedule it does not need, clearing the schedule frees it to use the cheaper package scope.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-model
|
|
3
3
|
description: Build Malloy semantic models with base source and joined source files. Use when creating or modifying .malloy files, user asks to "create a malloy model", "add dimensions", "add measures", "create a source", or any Malloy model authoring task.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -225,7 +225,7 @@ A given is **declared bare** but **referenced with a `$` sigil** in expressions
|
|
|
225
225
|
- **Givens don't auto-inject a `where:`.** Unlike `#(filter)`, you write the filter expression that references the given yourself (e.g. `where: dimension ~ $given_name`).
|
|
226
226
|
- **Not every filter maps cleanly.** A filter with no neutral match-all literal default - e.g. a scalar date/number range like `> @2020-01-01` - is not a good `given:`; keep those on `#(filter)`. Two more cases keep using `#(filter)`: mandatory scoping filters (`required`) and system-injected row-level filters (`implicit`), both below.
|
|
227
227
|
|
|
228
|
-
Givens are also the substrate for access control - see "Access Control:
|
|
228
|
+
Givens are also the substrate for access control - see "Access Control: `#(authorize)` and `#(access_filter)`" below.
|
|
229
229
|
|
|
230
230
|
## Legacy: Parameterizable Filters with `#(filter)`
|
|
231
231
|
|
|
@@ -296,38 +296,72 @@ Publisher formats values based on the dimension's data type, `string` → `'valu
|
|
|
296
296
|
|
|
297
297
|
Pass `bypass_filters=true` (REST) or `bypassFilters: true` (POST body) to skip filter injection entirely. Use sparingly, required-filter governance only works if bypass is restricted to trusted callers.
|
|
298
298
|
|
|
299
|
-
## Access Control:
|
|
299
|
+
## Access Control: `#(authorize)` and `#(access_filter)`
|
|
300
300
|
|
|
301
|
-
Gate query access to a source
|
|
301
|
+
Gate query access to a source over declared `given:` values (`given:` is Malloy's native runtime-parameter mechanism, the going-forward replacement for `#(filter)`). **Two annotations, one question each, and the name tells you which:**
|
|
302
|
+
|
|
303
|
+
| Annotation | The question | Body it takes | A denial is |
|
|
304
|
+
| --- | --- | --- | --- |
|
|
305
|
+
| `#(authorize)` | may this caller reach this source at all? | `'literal' <op> $GIVEN`, plus the `true`/`false` sentinels | **403** |
|
|
306
|
+
| `#(access_filter)` | which rows may they see, once they may? | `field_path <op> $GIVEN` | **200**, with their rows |
|
|
307
|
+
|
|
308
|
+
Either is an annotation on its own line directly above the `source:` line, carrying a **narrow grammar publisher parses itself, not an arbitrary Malloy expression**: one or more terms joined only by `and`, with `<op>` fixed by the given's declared arity (`in` for a list, `=` for a scalar).
|
|
309
|
+
|
|
310
|
+
**Nothing is inferred from the body.** The annotation you write declares which question you are answering, and a body that does not fit is refused at load naming the other annotation. A source with no annotation of either kind, own or inherited, is unrestricted.
|
|
311
|
+
|
|
312
|
+
The lock is DECIDED, before the caller's query compiles: a caller it does not admit gets a 403, never a row count or a `NULL` aggregate over data they were refused. The filter is GRAFTED onto the query as a `where:`, so a caller it matches nowhere gets a 200 with an empty result. The lock runs first; a caller it refuses never reaches the filter. A 403 also covers either gate failing to apply at all (a field the entry point dropped, a given nobody supplied).
|
|
302
313
|
|
|
303
314
|
```malloy
|
|
304
315
|
##! experimental.givens
|
|
305
316
|
|
|
306
317
|
given:
|
|
307
318
|
ROLE :: string
|
|
319
|
+
ORG_IDS :: string[]
|
|
308
320
|
|
|
309
|
-
#(authorize)
|
|
321
|
+
#(authorize) 'analyst' = $ROLE
|
|
322
|
+
#(access_filter) org_id in $ORG_IDS
|
|
310
323
|
source: orders is duckdb.table('orders.parquet') extend {
|
|
311
324
|
measure: order_count is count()
|
|
312
325
|
}
|
|
313
326
|
```
|
|
314
327
|
|
|
315
|
-
- **
|
|
316
|
-
- **
|
|
317
|
-
-
|
|
318
|
-
- **
|
|
319
|
-
- **
|
|
320
|
-
- **
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
328
|
+
- **Nothing outside the two term shapes above parses.** No `or`, `not`, `!=`, `<`/`>`/`<=`/`>=`, function calls, bare field/boolean references, or a literal on the right of a row-level term. `org_id in $GROUPS` and `region = $REGION and org_id in $GROUPS` are legal; `upper(region) = $REGION`, `(org_id in $GROUPS or region = $REGION)`, and a bare `#(access_filter) authorized` are all refused at load with a named cause (see your deployment's reference documentation for the full list).
|
|
329
|
+
- **Writing a term on the wrong annotation is refused, both ways.** `#(authorize) org_id in $GROUPS` is refused naming `#(access_filter)`; `#(access_filter) 'finance' in $GROUPS` is refused naming `#(authorize)`. The second matters: a constant predicate grafted as a row filter would serve a refused caller 200 with zero rows, which is the answer the lock exists to replace.
|
|
330
|
+
- **A source may declare more than one note on a route: repeats AND together.** `#(access_filter) region = $REGION` stacked with a second `#(access_filter) org_id in $GROUPS` both apply, and a caller must satisfy every term across every note. `or` is still refused wherever it appears, so there is no way to spell "admit if either" inside one gate or across a source's gates; use two extension sources instead, one per admitted population (see the admin pattern below).
|
|
331
|
+
- **Two exceptions to "every term references a given", and both live on the lock.** `#(authorize) false` is a deny-all: that is how you lock a base. `#(authorize) true` is an admit-all, and it is what an extension of a locked base needs in order to be open: a source declaring no gate of its own **inherits** its ancestor's, so leaving the annotation off an extension of a `false` base inherits the lock rather than lifting it. Neither sentinel is legal on `#(access_filter)`. `false` may not share a source with another note at all; `true` may not share the lock route with one, but is live beside an `#(access_filter)` (`#(authorize) true` with `#(access_filter) org_id in $GROUPS` re-opens a locked base while still scoping the rows). Neither is a term: `true and org_id in $GROUPS` is read as an ordinary two-term body whose first term is malformed.
|
|
332
|
+
- **Inheritance is per route.** Both inherit through `extend` the same way, own wins over ancestor on that route only, so a source can be "own" for one and "inherited" for the other. The API reports them separately, each under the field named for its own annotation: `Source.authorize` and `Source.accessFilter`.
|
|
333
|
+
- **Generate the admin escape hatch as another extension over the locked base, never as a bypass.** When a model needs an ordinary population plus a wider one, add a second extension whose rule is a lock on the caller:
|
|
334
|
+
|
|
335
|
+
```malloy
|
|
336
|
+
given:
|
|
337
|
+
ORG_IDS :: string[]
|
|
338
|
+
GROUPS :: string[]
|
|
339
|
+
|
|
340
|
+
#(authorize) false
|
|
341
|
+
source: orders_base is duckdb.table('orders.parquet') extend {}
|
|
342
|
+
|
|
343
|
+
#(authorize) true
|
|
344
|
+
#(access_filter) org_id in $ORG_IDS
|
|
345
|
+
source: orders is orders_base extend {}
|
|
346
|
+
|
|
347
|
+
#(authorize) 'admin' in $GROUPS
|
|
348
|
+
source: orders_admin is orders_base extend {}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Each extension replaces the base's `false` on the lock route with its own rule. `orders` is open to everyone and scoped per row; `orders_admin` is locked to the admin group and, carrying no filter, serves every row to whoever passes. This is the shape to generate whenever an author wants a role to see everything: another extension source, not a flag that skips the gate.
|
|
352
|
+
- **Both only gate from the `source:` line.** The same annotation on a `dimension:`/`measure:`/`join_*:`/`view:` line, or on a top-level `query:`, is refused at load naming the position rather than silently protecting nothing.
|
|
353
|
+
- **Every given the gate references must be declared on the entry model's own surface, and must carry no default.** A given the model cannot resolve is refused at load. So is a referenced given declared *with* a default: a caller who supplies nothing would get that default and be admitted or excluded by a value the gate's own line never shows, so it is refused rather than reasoned about case by case.
|
|
354
|
+
- **A scalar/array mismatch between the operator and the given's declared type is a load-time refusal**, not a request-time warehouse error: `org_id in $GROUPS` requires `GROUPS` to be array-typed, `region = $REGION` requires `REGION` scalar. Negation is likewise refused outright, so there is no empty-given inversion surprise to warn about.
|
|
355
|
+
- **Entry point only: not joined, but inherited through `extend`.** The gate applies to the source a query enters through. A gate on a source reached only via `join_*` **never fires**, at any depth, so anything ungated that joins a locked base hands the base's rows to every caller. A source that `extend`s a locked base and declares no gate of its own **does** carry the base's gate; declaring its own annotation replaces it. A source derived from a locked base via a query (`source: z is locked -> { … }`) instead **always carries the base's gate in addition to its own**: the derivation recurses into the base unconditionally, so an own gate does not replace it, and the two combine as separate AND'd entries. Pair a locked base with curated extension sources, using access modifiers (`include { public: …, private: * }`), so an extension re-exposes only a curated column surface, and keep sensitive sources out of ungated joins.
|
|
356
|
+
- **A derivation that drops a column the gate reads fails CLOSED.** `extend { except: org_id }`, or an `accept:` that omits it, leaves the grafted filter unable to compile, so the request is denied rather than served ungated. The one hole to know: dropping the gated column and then `rename:`-ing a *different* column onto that exact name grafts successfully and binds the gate to the wrong column. Narrow, but real, so don't recycle a gated column's name. If a derivation's own projection needs to drop the column a row-level term would read, use a source-level term (`'literal' in/= $GIVEN`) instead, since it never depends on any projected column.
|
|
357
|
+
- **The quoted-string and file-level forms are refused at load and no longer exist.** A quoted expression on the `source:` line, in either quote, a file-level `##(…) "<expr>"` applying to every source in the file, and the earlier `internal dimension: authorized is <expr>` form are all retired; the load names the rewrite. Every `.malloy` file in a package compiles at load and any failure aborts the package, so a retired-form gate anywhere in the package is refused. Only a declaring file *outside* the package escapes that: it loads and denies every request instead, with no compile-time hint. See your deployment's reference documentation.
|
|
324
358
|
- **A gated source can be persisted, but the gating column freezes.** `storage=` and `#@ preaggregate` refuse a gated source outright; a colocated `#@ persist` is admitted when the gate is provably the entry point's own row filter. The gate still runs live on every query, so rows come back filtered - but the column it filters ON is frozen at build time, so a row whose access decision changes keeps being served under the old decision until the next rebuild. Pair `#@ persist` on a gated source with a freshness window (`fallback="live"`), which is the only control that bounds that - and read `skill:malloy-materialization` for where that window binds, because on a standalone Publisher it does not.
|
|
325
359
|
|
|
326
|
-
> **Trust caveat.** Givens are **caller-asserted**, anyone who can reach the query API can claim a favorable given, e.g. `{"ROLE":"admin"}`.
|
|
360
|
+
> **Trust caveat.** Givens are **caller-asserted**, anyone who can reach the query API can claim a favorable given, e.g. `{"ROLE":"admin"}`. Neither annotation is a real boundary unless it sits behind a trusted tier that sets givens from its own verified context, never directly from an untrusted caller. Neither is, on its own, end-user authentication.
|
|
327
361
|
>
|
|
328
|
-
> **Forward direction.** Givens are how access control is built here, and the planned next step is **identity-bound ("secure") givens** - reserved values a trusted tier populates from a verified token or proxy header, which the caller cannot override - turning
|
|
362
|
+
> **Forward direction.** Givens are how access control is built here, and the planned next step is **identity-bound ("secure") givens** - reserved values a trusted tier populates from a verified token or proxy header, which the caller cannot override - turning these gates into a standalone boundary. Model access on `given:` + these two annotations now; it is the surface that carries forward.
|
|
329
363
|
|
|
330
|
-
Full syntax, inheritance rules, validation, and the error contract are covered in your deployment's
|
|
364
|
+
Full syntax, inheritance rules, validation, and the error contract are covered in your deployment's authorize reference documentation.
|
|
331
365
|
|
|
332
366
|
## Join Syntax
|
|
333
367
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-model-as-you-go
|
|
3
3
|
description: After answering a data question, write down what the answer assumed so the next reader can trust the number. A field with a #(doc) in the model when you can edit it, an extend in the notebook when you can only author reports, or a stated assumption plus a Malloy snippet when you can only chat. Use after every answered question that rested on a judgment call, and whenever a question is asked against tables that have no model yet.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!--
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-modeling
|
|
3
3
|
description: Build semantic models with Malloy for the Malloy Publisher. Read this skill whenever the user asks about modeling data or specifically mentions Malloy.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-notebook-chat
|
|
3
3
|
description: Steps to follow when the chat is bound to a notebook or saved report. The notebook's cells are the agent's primary context, answer from it, run its queries, and only reach for get_context when the user asks about something outside it.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-notebooks
|
|
3
3
|
description: Create Malloy notebooks (.malloynb) for interactive dashboards and data stories. Use when user asks to "create a notebook", "make a dashboard notebook", "write a malloynb", "data story", or needs to build reports/visualizations.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -111,7 +111,7 @@ source: spotlight_carrier is duckdb.table('data/carriers.parquet') extend {
|
|
|
111
111
|
}
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
Declare givens at the **top of the model file**, before the source that uses them, not in the notebook. `malloy-model` § Access Control covers the syntax and the `#(authorize)` gating story built on top of givens.
|
|
114
|
+
Declare givens at the **top of the model file**, before the source that uses them, not in the notebook. `malloy-model` § Access Control covers the syntax and the `#(authorize)`/`#(access_filter)` gating story built on top of givens.
|
|
115
115
|
|
|
116
116
|
## Legacy: `#(filter)` annotations
|
|
117
117
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-patterns
|
|
3
3
|
description: An index of what search_malloy_docs covers - language reference, common patterns (YoY, cohorts, percent of total), rendering - for picking a topic worth searching before querying the docs.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-phrase-detection
|
|
3
3
|
description: How to phrase search_text on a get_context call so retrieval returns the fields you need instead of a truncated catalog. Covers target-type classification and decomposition patterns.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!-- Copyright (c) Credible Data Inc. SPDX-License-Identifier: MIT -->
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-publish
|
|
3
3
|
description: Package Malloy models for serving by Malloy Publisher. Use when user asks to "publish", "package", "deploy", or wants to share models with others.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -77,7 +77,7 @@ Two optional fields opt the package into curation:
|
|
|
77
77
|
|
|
78
78
|
**Why curate here:** declaring `explores` routes agents to the well-documented curated sources instead of raw tables, and `queryableSources: "declared"` keeps them from reaching the hidden sources by name. The two axes compose: list a file in `explores` for its models to be discoverable, and `export` a source within that file for it to be a landing point.
|
|
79
79
|
|
|
80
|
-
> **Not access control.** `queryableSources` gates the query surface (the query endpoints, REST and MCP alike), not compile and not raw file retrieval by exact path: `/compile` and `compile_model` are deliberately exempt, because compile is the authoring loop and the boundary is discovery curation. It doesn't restrict *who* may query, only *what* is queryable by name. Queryable sources are the union of every `explores`-listed file's `export {}` closure, whichever listed model path a query addresses them through. To gate access by caller-supplied identity/role, use `#(authorize)` on the source, see `skill:malloy-model` § Access Control and `docs/authorize.md`. Discovery curation and
|
|
80
|
+
> **Not access control.** `queryableSources` gates the query surface (the query endpoints, REST and MCP alike), not compile and not raw file retrieval by exact path: `/compile` and `compile_model` are deliberately exempt, because compile is the authoring loop and the boundary is discovery curation. It doesn't restrict *who* may query, only *what* is queryable by name. Queryable sources are the union of every `explores`-listed file's `export {}` closure, whichever listed model path a query addresses them through. To gate access by caller-supplied identity/role, use `#(authorize)` on the source (and `#(access_filter)` to scope rows), see `skill:malloy-model` § Access Control and `docs/authorize.md`. Discovery curation and these gates are independent layers.
|
|
81
81
|
|
|
82
82
|
The manifest also carries a `scope` field (`"package"` | `"version"`, default `"package"`) controlling whether persisted/materialized artifacts are shared across published versions or owned by a single version, and a `materialization` field configuring that persistence policy (a cron `schedule` or a `freshness` window). Both are unrelated to discovery curation; there is no per-source `sharing` or `schedule` field, that was retired in favor of the single package-level `scope` and `materialization`.
|
|
83
83
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-queries
|
|
3
3
|
description: Malloy query patterns and syntax, for writing or debugging a query - dates, aggregates vs dimensions, join paths, filters, string matching, chart annotations, and the errors a SQL habit produces.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -87,10 +87,10 @@ Wrong: `pick('Premium') { ... }` (that's not Malloy syntax).
|
|
|
87
87
|
**Window functions with `calculate:`:** running totals, `lag()`, `lead()`, and other window operations belong in `calculate:`, not `aggregate:`.
|
|
88
88
|
```malloy
|
|
89
89
|
run: source -> {
|
|
90
|
-
group_by:
|
|
90
|
+
group_by: order_month is order_date.month
|
|
91
91
|
aggregate: revenue
|
|
92
92
|
calculate: prev_month_revenue is lag(revenue)
|
|
93
|
-
order_by:
|
|
93
|
+
order_by: order_month
|
|
94
94
|
}
|
|
95
95
|
```
|
|
96
96
|
|
|
@@ -128,15 +128,15 @@ where: order_date >= @2020-01-01
|
|
|
128
128
|
|
|
129
129
|
### Truncation accessors return timestamps, not integers
|
|
130
130
|
|
|
131
|
-
`order_date.month` returns a month-truncated timestamp (e.g., `2025-06-01 00:00:00`), useful for `group_by:`. It is NOT a 1-12 integer
|
|
131
|
+
`order_date.month` returns a month-truncated timestamp (e.g., `2025-06-01 00:00:00`), useful for `group_by:`. It is NOT a 1-12 integer.
|
|
132
132
|
|
|
133
|
-
Available truncations: `.year`, `.quarter`, `.month`, `.week`, `.day`, `.hour`, `.minute`, `.second`.
|
|
133
|
+
Available truncations: `.year`, `.quarter`, `.month`, `.week`, `.day`, `.hour`, `.minute`, `.second`.
|
|
134
134
|
|
|
135
|
-
### `month`, `year`, `day`, `quarter` are reserved
|
|
135
|
+
### `month`, `year`, `day`, `quarter` are reserved as names
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
They cannot name an output field. The functions are fine: `month(order_date)` extracts 1-12 anywhere, including `where:`.
|
|
138
138
|
|
|
139
|
-
Wrong: `group_by: month is order_date.month` →
|
|
139
|
+
Wrong: `group_by: month is order_date.month` → `'month' is a reserved word, so to use it as a name you must quote it`
|
|
140
140
|
Right: `group_by: order_month is order_date.month`
|
|
141
141
|
Right (when a column is literally named `month`): `` group_by: `month` ``
|
|
142
142
|
|
|
@@ -252,7 +252,7 @@ run: source -> {
|
|
|
252
252
|
}
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
-
Charts render only the **first** aggregate. For multiple measures on one chart, place `# y` above the `aggregate:` keyword or use the `y=['a','b']` shorthand. A
|
|
255
|
+
Charts render only the **first** aggregate. For multiple measures on one chart, place `# y` above the `aggregate:` keyword or use the `y=['a','b']` shorthand. A chart annotation left as the last line inside `{ }` fails with *"Parser enountered unexpected statement type 'unimplemented'"* (the compiler's spelling); one after the closing `}` fails with *"Object annotation not connected to any object"*.
|
|
256
256
|
|
|
257
257
|
Read the `malloy-charts` skill for chart types, properties, data shape requirements, and selection guidance.
|
|
258
258
|
|
|
@@ -263,11 +263,10 @@ Read the error against the tables above and below. Most failures match a known p
|
|
|
263
263
|
| Error message | Likely cause / fix |
|
|
264
264
|
|---|---|
|
|
265
265
|
| `Cannot compare a timestamp to a number` | Comparing `date.year` to an integer. Use `date >= @2020-01-01` instead. |
|
|
266
|
-
| `no viable alternative at input '<word>'` |
|
|
266
|
+
| `no viable alternative at input '<word>'` | Often a `;` between fields within one clause - fields under one `aggregate:`/`group_by:` are comma- or newline-separated (the error points at the field right after the `;`). |
|
|
267
267
|
| `'<field_name>' is not defined` | Field doesn't exist in the source. Re-check against the model definition; you may have stripped a join prefix. |
|
|
268
|
-
| `missing {DAY, HOUR, MINUTE, MONTH, QUARTER, SECOND, WEEK, YEAR}` | Chained date property too deep (e.g., `.month.something`). Stop at the first truncation. |
|
|
269
268
|
| `field is a bar chart, but is not a repeated record` | Chart annotation placed inside `{ }`. Move `# bar_chart` above `run:` / `view:` / `nest:`. |
|
|
270
|
-
| `Parser
|
|
269
|
+
| `Parser enountered unexpected statement` | Spelled that way by the compiler. Most often a chart annotation left as the last line inside `{ }` - move it above `run:`. Also syntax Malloy doesn't allow in that position (e.g., `pick` inside a nested view). |
|
|
271
270
|
| Query silently returns zero rows | Filter value mismatch (case, spelling, format). Run a distinct-values query on the dimension to confirm the literal. |
|
|
272
271
|
|
|
273
272
|
## Syntax Help
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-review
|
|
3
3
|
description: Malloy semantic-model code review. Invoke when the user asks to review, audit, or critique a `.malloy` file, a folder of Malloy models, or a GitHub PR that touches Malloy. Enforces project modeling standards and emits a navigable review file.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
<!--
|
|
7
7
|
Copyright (c) Credible Data Inc.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: malloy-scope
|
|
3
3
|
description: Present discovery findings and propose an analytical scope before modeling. Use after inspecting a package's model and data, to classify tables and recommend an analytical focus the user can pick from.
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.22
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!--
|