wow-data-query · diff
git:20261011.b2ea410 to git:20261021.c4d0125
32 added, 23 removed. Audit A to A.
---
name: "wow-data-query"
- description: "Answer business data questions from a running Wow service: read its query capability descriptor, run read-only snapshot, event-stream or dataset (wide-table) queries, and explain counts, lists, breakdowns or trends with the exact query and caveats. Use when the deliverable is numbers from live data, not code or a view. Exclude query code (wow-client), failing-query diagnosis (wow-develop), and non-Wow databases."
+ description: "Answer business data questions from a running Wow V10 service: read a query model's capability descriptor, run read-only snapshot, events or dataset queries, and explain counts, lists, breakdowns or trends with the exact query and caveats. Use when the deliverable is numbers from live data, not code or a view. Exclude query code (wow-client), failing-query diagnosis (wow-develop), and non-Wow databases."
---
# wow-data-query
- The deliverable is an answer: numbers, rows or a breakdown, what they mean for the question, the query that produced them, and what could make them misleading. It is never application code.
+ The job: someone asks a business question ("how many orders shipped late last week, by warehouse?") and the answer is in a running Wow V10 service. The deliverable is an answer: numbers, rows or a breakdown, what they mean for the question, the query that produced them, and what could make them misleading. It is never application code.
+ ## Three query models
+
+ | Model | One record is | Route | Use for |
+ | --- | --- | --- | --- |
+ | `snapshot` | One aggregate's current state | `/{context}/{aggregate}/snapshot/query` | "How many orders are paid now", "which carts are open" |
+ | `events` | One commit: the events one command appended | `/{context}/{aggregate}/events/query` | "When did this order change", history and timelines |
+ | Dataset | A row of a wide or warehouse table the service publishes | `/wow/dataset/{context}/{dataset}/query`, listed by `GET /wow/dataset` | Questions across aggregates or contexts (orders by customer segment) |
+
+ `POST` on a route queries (the body's `kind` names the operation); **`GET` on the same route is its capability descriptor**, with its version as the `ETag`. One aggregate's state at a version or a time is `GET /{context}/{aggregate}/{id}/state?version=` or `?at=`, only when the user asked about that aggregate.
+
## Before any query
- 1. **Pick the environment with the user.** Use a development or staging service by default. Querying production needs the user's explicit consent in this conversation; a production URL found in config, docs or history is not consent.
- 2. **Credentials come from the environment** (an exported token, a configured CLI or proxy). Never ask the user to paste a password or token into the chat, and never print one.
- 3. **Read the descriptor first**: `GET {base}/{aggregate}/snapshot/schema` (or `event/schema` for event history). Record its `version`. Load `references/descriptor.md` for how to read it.
- - A dataset (a wide table across aggregates, or a warehouse table) has its own routes: `GET {base}/dataset` lists them, and `GET {base}/dataset/{context}/{dataset}/schema` is one's descriptor.
+ 1. **Pick the environment with the user.** A development or staging service by default. Querying production needs the user's explicit consent in this conversation; a production URL in config, docs or history is not consent.
+ 2. **Credentials come from the environment** (an exported token, a configured CLI or proxy). Never ask for a password or token in chat, never print one. The service reads the tenant and the caller from them; a query reads the caller's tenant only.
+ 3. **Read the descriptor first** and record its `version`. Load `references/descriptor.md` for how to read it and the request shapes.
## Workflow
- 1. Restate the question as a query plan in business terms: which aggregate or dataset, snapshot state or event history, which records, which measure, which breakdown and period. A question across aggregates (orders by customer segment) is a dataset's if one serves it; never join two queries' results by hand.
- 2. Map every field in the plan to a descriptor `path` (or one of its `aliases`). A field the descriptor does not list does not exist for querying; never invent or guess one. Say what is missing instead.
- 3. Stay inside what the descriptor grants: only listed `filter.operators`, `sort.paged` or `sort.cursor`, `aggregate.groups` and metric kinds, and the `limits`. Never widen a capability. If the question needs something not granted, say so and offer the closest granted alternative.
- 4. Respect protection. A field with `sensitivity` is masked in results. A CONFIDENTIAL field (`comparable: false`) cannot be filtered, sorted or searched, and no protected field can be grouped or used as a metric. Do not try to recover masked values through filters, ranges or search.
- 5. On event streams, a condition on one event's payload goes inside an `ELEMENT_MATCH` on `body`, together with its `bodyType` (see `variants`), so that both apply to the same event; the predicate's paths are relative to the event (`bodyType`, `body.<field>`). A stream is one command's events: say whether a number counts streams or events.
- 6. Avoid `deprecated` fields; use the field its message points to. Mention it if the user named the deprecated one.
- 7. A share, running total, moving average, comparison with the previous period or top N within each group is a derived metric's window when `analysis.windows` lists its function (`TOTAL`, `RUNNING`, `PREVIOUS`, `RANK`): the server computes it over every group before `having` and `limit`, so it is right where a hand computation over the returned rows is not. Without the function, compute nothing across groups from cut rows; say what is missing.
- 8. Build the smallest query that answers the question: `count` for "how many", `aggregation` for breakdowns and trends, `list`, `paged` or `cursor` with a projection for examples. Write filters as `FilterExpression` (`{"op", "field", …}`). Use the read-only query routes only (see the reference). Never call command routes, the snapshot `PUT` regeneration routes or the schema refresh route.
- 9. Run it. If it is rejected, read `bindingErrors[0].code` and `name`, fix the query within the descriptor, and retry once. If it still fails, or a result looks wrong, stop: that is a diagnosis for `wow-develop`.
- 10. Answer in business terms first, then the evidence.
+ 1. Restate the question as a query plan in business terms: which model (and aggregate or dataset), which records, which measure, which breakdown, which period and time zone. A question across aggregates is a dataset's if one serves it; never join two queries' results by hand.
+ 2. Map every field to a descriptor `path` (or one of its `aliases`). A field the descriptor does not list does not exist for querying; never invent one, say what is missing.
+ 3. Stay inside what the descriptor grants: the field's `filter.operators`, `sort.paged`/`sort.cursor`, `aggregate` groups and functions, `analysis`, `limits` and `constraints`. The same question can be fine on one backend and refused on another; the descriptor of this service is the authority.
+ 4. Respect protection: a field with `sensitivity` is masked in results; a `comparable: false` one cannot be filtered or sorted; no protected field is grouped or aggregated. Never try to recover masked values through filters, ranges or search.
+ 5. **Events:** a condition on an event's payload is one `ELEMENT_MATCH` on `events` holding the event's `name` and the payload condition (paths relative to the event: `name`, `body.<field>`). Only payload fields of events still at revision 1 can be filtered or grouped (the descriptor says so). A record is a commit: say whether a number counts commits or events.
+ 6. **Time:** relative-time operators (`TODAY`, `RECENT_DAYS`, `LAST_MONTH`, …) and `DATE_HISTOGRAM` read their days in UTC unless the query gives `zoneId`/`timeZone`. Ask or infer the business's zone, set it, and state it in the answer.
+ 7. Build the smallest query: `count` for "how many", `aggregate` for breakdowns and trends, `list`, `paged` or `cursor` with a projection for examples. Only the read-only routes above; never a command route, the snapshot rebuild route, the ops routes, or anything that writes.
+ 8. Run it. On a refusal, read the problem's `code` and its `violations` (`code`, `path`, `message`), fix the query within the descriptor and retry once. A 429 `wow.query.busy` waits for `Retry-After`; a 409 `wow.query.dataset-unavailable` means the dataset is being revised (try later or another source); a 504 `wow.query.timeout` means narrow the query. A second refusal, a 5xx, or a result that contradicts the data is a diagnosis for `wow-develop`.
+ 9. Answer in business terms first, then the evidence.
## Answer checklist
- The direct answer, with units, the time zone of any date grouping and the period covered.
- Caveats that change the meaning:
+ - a count or a paged total with `exact: false` is a lower bound ("at least 10000");
- metrics listed in `analysis.approximate` are estimates;
- - fields in a `NULL_OR_EMPTY_AS_MISSING` constraint treat null and empty as missing;
- masked fields show masked values;
- - a limit or top-N may have cut the rows;
+ - a `limit` or top N may have cut the rows;
- the default deletion scope hides deleted aggregates unless the query selects them;
- - a dataset is a copy (a BI wide table): say that its data lags the source by its refresh.
- - The evidence: environment, descriptor `version`, and the exact query JSON sent.
+ - snapshots lag commits by moments; a dataset lags its sources by its refresh.
+ - The evidence: environment, descriptor `version`, and the exact request body sent.
## References
- - `references/descriptor.md`: reading the descriptor, the read-only query routes, query shapes, and rejection codes. Load it before building the first query.
+ - `references/descriptor.md`: reading the descriptor, the request shapes of each `kind`, filters, aggregation and windows, events, datasets, and the problem codes. Load it before the first query.
## Related Skills
- - $wow-client: write TypeScript code that queries a Wow service.
- - $wow-develop: diagnose a rejected query that should be valid, a wrong result, or a failing query route.
+ - $wow-client: TypeScript code that queries a Wow service.
+ - $wow-view-definition: a view people open again and again instead of a one-off answer.
+ - $wow-develop: a refused query that should be valid, a wrong result, or a failing query route.