Summary
The semantic-layer query engine rejects ordinary aggregate expressions that don't name a source — count(*), count(1), and bare-column aggregates like sum(amount) — with:
Measure expr 'count(*)' does not reference any source
The SL has no FROM clause and infers sources only from fully-qualified source.column refs (see python/ktx-sl/CLAUDE.md), so any measure that contains no source.column reference is refused in python/ktx-sl/semantic_layer/planner.py (_resolve_measure_string / _resolve_measure_dict, "does not reference any source").
Impact
count(*) is the most natural way for a data agent to count rows, so agents hit this repeatedly and retry blindly. It is the single most common semantic-query rejection across anonymous usage telemetry. Today the agent must instead know to use a pre-defined count measure (e.g. orders.order_count) or count(orders.id).
Repro
# any single-source model
uv run python -m semantic_layer.cli --model /tmp/model.yaml \
-q '{"measures":["count(*)"],"dimensions":["orders.status"]}'
# -> ValueError: Measure expr 'count(*)' does not reference any source
Suggested direction (needs an SL-semantics decision)
When the query already unambiguously determines a single source (via its dimensions and/or other measures), infer that source for a source-less aggregate like count(*)/count(1) instead of rejecting it. If inference is ambiguous, keep rejecting but with an actionable message that names the candidate sources and the count(source.pk) / pre-defined-measure alternatives.
Notes
Separate from the telemetry-classification fix in #335 (which stops these expected rejections from being filed as ktx faults). This issue is about the rejection itself being an avoidable UX gap.
Summary
The semantic-layer query engine rejects ordinary aggregate expressions that don't name a source —
count(*),count(1), and bare-column aggregates likesum(amount)— with:The SL has no
FROMclause and infers sources only from fully-qualifiedsource.columnrefs (seepython/ktx-sl/CLAUDE.md), so any measure that contains nosource.columnreference is refused inpython/ktx-sl/semantic_layer/planner.py(_resolve_measure_string/_resolve_measure_dict, "does not reference any source").Impact
count(*)is the most natural way for a data agent to count rows, so agents hit this repeatedly and retry blindly. It is the single most common semantic-query rejection across anonymous usage telemetry. Today the agent must instead know to use a pre-defined count measure (e.g.orders.order_count) orcount(orders.id).Repro
Suggested direction (needs an SL-semantics decision)
When the query already unambiguously determines a single source (via its dimensions and/or other measures), infer that source for a source-less aggregate like
count(*)/count(1)instead of rejecting it. If inference is ambiguous, keep rejecting but with an actionable message that names the candidate sources and thecount(source.pk)/ pre-defined-measure alternatives.Notes
Separate from the telemetry-classification fix in #335 (which stops these expected rejections from being filed as ktx faults). This issue is about the rejection itself being an avoidable UX gap.