mostlyright-data 0.19.0__tar.gz → 0.19.2__tar.gz
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.
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/PKG-INFO +7 -5
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/README.md +6 -4
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/pyproject.toml +1 -1
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/skills/mr-data-build/SKILL.md +283 -149
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/skills/mr-data-build/agents/openai.yaml +1 -1
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/.gitignore +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/scripts/hatch_build.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/skills/mr-data-build/scripts/write_research_notebook.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/__init__.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/canonical.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/formats.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/key_seam.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/page_coverage.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/part_check_evidence.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/session_probes.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/skill_assets.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/table_manifest.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/__init__.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/acquire.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/activity.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/approvals.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/categories.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/commands.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/dataset-categories-v1.json +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/download.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/narrative.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/parity.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/probe.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/progress_vocabulary.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/propose.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/recipe.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/research.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/router.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/runs.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/session.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/stream.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/stream_venue.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/transport.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/user_agent.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_artifacts.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_catalog.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_connections.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_dataset_covers.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_datasets.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_handoff.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_narrative.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_query.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_runs.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_secrets.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_stream.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_tables.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/__init__.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/attendance.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/clarification.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/commands/clarify.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/credentials.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/login.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/remediation.py +0 -0
- {mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/render.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mostlyright-data
|
|
3
|
-
Version: 0.19.
|
|
3
|
+
Version: 0.19.2
|
|
4
4
|
Summary: Mostly Right hosted CLI for reviewed datasets
|
|
5
5
|
Project-URL: Homepage, https://mostlyright.md/
|
|
6
6
|
Project-URL: Documentation, https://mostlyright.md/docs/guides/cli/
|
|
@@ -111,10 +111,12 @@ worker executables or image publisher.
|
|
|
111
111
|
|
|
112
112
|
## Documentation
|
|
113
113
|
|
|
114
|
-
- [
|
|
115
|
-
- [
|
|
116
|
-
- [
|
|
117
|
-
- [
|
|
114
|
+
- [Install and sign in](https://mostlyright.md/docs/start/install/)
|
|
115
|
+
- [Build your first dataset](https://mostlyright.md/docs/start/first-dataset/)
|
|
116
|
+
- [CLI reference](https://mostlyright.md/docs/reference/cli/)
|
|
117
|
+
- [Recipe reference](https://mostlyright.md/docs/reference/recipe/)
|
|
118
|
+
- [Recipe examples](https://mostlyright.md/docs/recipes/)
|
|
119
|
+
- [Use a public dataset](https://mostlyright.md/docs/guides/use-public-datasets/)
|
|
118
120
|
- [Certified document extraction](docs/DOCUMENT-EXTRACTION.md)
|
|
119
121
|
|
|
120
122
|
Use `mr-data --help` for the full command list and options. Commands that support
|
|
@@ -99,10 +99,12 @@ worker executables or image publisher.
|
|
|
99
99
|
|
|
100
100
|
## Documentation
|
|
101
101
|
|
|
102
|
-
- [
|
|
103
|
-
- [
|
|
104
|
-
- [
|
|
105
|
-
- [
|
|
102
|
+
- [Install and sign in](https://mostlyright.md/docs/start/install/)
|
|
103
|
+
- [Build your first dataset](https://mostlyright.md/docs/start/first-dataset/)
|
|
104
|
+
- [CLI reference](https://mostlyright.md/docs/reference/cli/)
|
|
105
|
+
- [Recipe reference](https://mostlyright.md/docs/reference/recipe/)
|
|
106
|
+
- [Recipe examples](https://mostlyright.md/docs/recipes/)
|
|
107
|
+
- [Use a public dataset](https://mostlyright.md/docs/guides/use-public-datasets/)
|
|
106
108
|
- [Certified document extraction](docs/DOCUMENT-EXTRACTION.md)
|
|
107
109
|
|
|
108
110
|
Use `mr-data --help` for the full command list and options. Commands that support
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mr-data-build
|
|
3
|
-
description: Build and verify a reproducible Parquet dataset from a data question and supported sources on the hosted Mostly Right backend. Use whenever a user asks to use, test, smoke-test, demonstrate, or debug the Mostly Right Harness or mr-data CLI by producing, reviewing, or verifying a dataset.
|
|
3
|
+
description: Build and verify a reproducible Parquet dataset from a data question and supported sources on the hosted Mostly Right backend. Use whenever a user asks to use, test, smoke-test, demonstrate, or debug the Mostly Right Harness or mr-data CLI by producing, reviewing, or verifying a dataset. The published reference at https://mostlyright.md/docs/ is the contract.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Mostly Right Data Build
|
|
@@ -81,16 +81,49 @@ work, follow it, and read what the backend proved. Studio is the hosted release
|
|
|
81
81
|
|
|
82
82
|
The product is hosted-only and the client is thin. The engine runs on the backend; `mr-data` is a
|
|
83
83
|
pure-Python client that submits work and reads the records Studio holds.
|
|
84
|
-
[
|
|
84
|
+
[Install and sign in](https://mostlyright.md/docs/start/install/) states that one install and where
|
|
85
|
+
a command's work actually runs.
|
|
85
86
|
|
|
86
87
|
Read this document in two parts. Everything except [Not hosted yet](#not-hosted-yet) uses only
|
|
87
88
|
commands this product runs. [Not hosted yet](#not-hosted-yet) is the internal capability map for
|
|
88
89
|
the one command with no implementation behind it.
|
|
89
90
|
|
|
90
|
-
Every
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
Every link below is a page of the published reference at https://mostlyright.md/docs/, and every
|
|
92
|
+
one of them can be fetched from here. This document is installed on its own and remains the whole
|
|
93
|
+
of what a build needs; each page is the longer, current reference behind one section of it.
|
|
94
|
+
|
|
95
|
+
## Reference pages
|
|
96
|
+
|
|
97
|
+
The published reference at https://mostlyright.md/docs/ carries the current contract for every
|
|
98
|
+
field, flag, code and ceiling this document names. Fetch the page for the shape in front of you
|
|
99
|
+
BEFORE drafting it, never guess a field name, and where a page disagrees with what you remember of
|
|
100
|
+
an older version, the page is right.
|
|
101
|
+
|
|
102
|
+
| What you are about to do | Fetch |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| Write a recipe document | https://mostlyright.md/docs/reference/recipe/ |
|
|
105
|
+
| Declare a check | https://mostlyright.md/docs/reference/checks/ |
|
|
106
|
+
| Plan a transform step | https://mostlyright.md/docs/reference/transforms/ |
|
|
107
|
+
| Name a unit | https://mostlyright.md/docs/reference/units/ |
|
|
108
|
+
| Choose a connector, a source kind or a connector parameter | https://mostlyright.md/docs/reference/sources/ |
|
|
109
|
+
| Pin a Reader | https://mostlyright.md/docs/reference/readers/ |
|
|
110
|
+
| Read any command's flags and `--json` shape | https://mostlyright.md/docs/reference/cli/ , then the group page: `auth`, `dataset`, `recipe`, `run`, `read`, `table`, `stream` under `/docs/reference/cli/` |
|
|
111
|
+
| Read an error code, a refusal or a run state | https://mostlyright.md/docs/reference/run-states-and-errors/ |
|
|
112
|
+
| Check a ceiling before starting a run | https://mostlyright.md/docs/reference/limits/ |
|
|
113
|
+
| Follow the whole lifecycle end to end | https://mostlyright.md/docs/start/how-it-works/ |
|
|
114
|
+
| Install the client and sign in | https://mostlyright.md/docs/start/install/ |
|
|
115
|
+
|
|
116
|
+
Read the worked recipe closest to the source in hand before writing your own.
|
|
117
|
+
https://mostlyright.md/docs/recipes/ lists all eight: `city-temperatures` (daily city
|
|
118
|
+
temperatures), `csv-snapshot` (one CSV file, one table), `json-api` (records pointer and
|
|
119
|
+
pagination), `html-collection` (many HTML pages, one table), `document-extraction` (PDF
|
|
120
|
+
projection), `weather-grib` (GRIB2 and the scientific Readers), `websocket-stream` (a `wss://`
|
|
121
|
+
venue), `multi-source-join` (two sources joined, with checks).
|
|
122
|
+
|
|
123
|
+
The build guides run one per stage of the loop below, each at https://mostlyright.md/docs/build/NAME/
|
|
124
|
+
where NAME is `probe-sources`, `write-a-recipe`, `run-and-inspect`, `publish-and-refresh`,
|
|
125
|
+
`credentials`, `live-streams`, `collections`, `documents` or `troubleshooting`; the list itself is
|
|
126
|
+
at https://mostlyright.md/docs/build/ and the reference index at https://mostlyright.md/docs/reference/.
|
|
94
127
|
|
|
95
128
|
## One install
|
|
96
129
|
|
|
@@ -117,7 +150,7 @@ gap rather than doing anything, and `export-hosted-candidate`, which is a backen
|
|
|
117
150
|
| `mr-data login` | Complete device approval and store a device credential. `login --force` is the compatibility alias for safe `auth rotate`, never an in-place truncate. |
|
|
118
151
|
| `mr-data whoami` | Use the compatibility alias for the remotely validated `auth status` answer. |
|
|
119
152
|
| `mr-data clarify` | Say whether one clarifying question may be put to the user right now, and compose the record of their answer. It reaches nothing, asks nobody and waits for nothing. Exits non-zero when no person can answer or when a recipe is already registered. |
|
|
120
|
-
| `mr-data probe` |
|
|
153
|
+
| `mr-data probe` | `probe SOURCE_ID QUESTION_ID --dataset DATASET_ID [--kind source_inspect\|sample_rows\|profile_columns\|evaluate_expression]` asks one already-registered source one question and prints the answer. **Do not plan a source inspection around it.** Both positionals are identifiers — `QUESTION_ID` is a question identifier, which no v4 registration receipt returns — and the command rides the frozen `/v3/sessions` routes, which a deployment may have switched off. Read a source instead by registering the recipe and taking an unwindowed sample under `--max-rows`, then `peek`, `query` and `receipt`. |
|
|
121
154
|
| `mr-data catalog` | `catalog search "QUESTION"` asks the sealed public-source catalogue which of its entries might answer a question and ranks them best first. Every ranked entry comes back with the disposition its own facts earned — `admitted`, `human_escalation_required` or `refused` — because an entry the catalogue could not vouch for is still a finding. `--format csv` states the one data format the question requires — one token per question, never repeated — and it is not a filter: an entry that does not declare that format still comes back ranked, with disposition `refused` and `filters_match` false, so nothing is held back; `--limit N` ranks at most N, up to 25. It fetches nothing and registers nothing. The catalogue holds one provider (Data.gov) and only part of it, so it is never exhaustive and an empty answer is not evidence that no such source exists. When the answer is `catalog_unavailable`, this deployment has no catalogue to search: record the lane and carry on. |
|
|
122
155
|
| `mr-data dataset` | Bring the dataset page into existence before there is anything on it, then fill it in while somebody watches. `dataset create --name TEXT` mints it and prints the `dataset_id`; `dataset show ID` reads it back; `dataset set ID --name TEXT --topics "a,b,c" --license ID --description-file F` writes the title, the descriptive tags, the SPDX licence and the description under the version it was read at, retrying once if somebody else wrote first, and an empty `--topics` or `--license` takes that value off the page; `dataset note ID --heading H --blocks-file B` writes one cell of the decision record that OUTLIVES every run, and `--list` reads it back; `dataset watch ID` follows the page's own event stream; `dataset activity ID --phase P --message TEXT` says what is happening right now, silently, and is never a chat message and never a cell; `dataset publish ID [--mode public|link|private]` says who can read the dataset — `public` lists it in the public directory and serves it at an address anybody can read, `link` serves it at an unlisted address, `private` takes it back to the workspace — and `dataset publish ID --show` reads that back without changing it; `dataset archive ID --confirm-name TITLE` retires the page and frees its title, deleting nothing. |
|
|
123
156
|
| `mr-data recipe` | Register one recipe document — dataset, question, table plan, sources, transform, checks and units — in one call, and print the identifiers the server derived. `mr-data recipe show ID` reads one back. |
|
|
@@ -160,7 +193,7 @@ step between a run finishing and reading it: `download`, `receipt`, `checks`, `p
|
|
|
160
193
|
answer about a run that is still workspace scratch exactly as they answer about one somebody has
|
|
161
194
|
since made live.
|
|
162
195
|
|
|
163
|
-
[The recipe document](
|
|
196
|
+
[The recipe document](https://mostlyright.md/docs/reference/recipe/) is the reference for what
|
|
164
197
|
`mr-data recipe FILE` sends. Two rules in it are worth knowing before you write one: no fractional
|
|
165
198
|
number appears anywhere in the document, and you neither compute nor state a digest — the server
|
|
166
199
|
canonicalizes the document, digests it, and answers with every identifier it derived. Sending the
|
|
@@ -172,8 +205,9 @@ signed something on a person's own computer, or they were named for a step the p
|
|
|
172
205
|
performs — asking a person before the work starts, reading back a separate body of evidence,
|
|
173
206
|
opening a session before a question could be asked. For a while each still typed and answered with
|
|
174
207
|
where its work went; that ended when the refusing names outnumbered the working ones two to one.
|
|
175
|
-
[
|
|
176
|
-
the
|
|
208
|
+
[Install and sign in](https://mostlyright.md/docs/start/install/) states the one install and the
|
|
209
|
+
whole surface it carries; the deleted names and what replaced each of them are written down only in
|
|
210
|
+
the Harness repository's own `docs/HOSTED-PARITY.md`, which is not installed beside this document.
|
|
177
211
|
|
|
178
212
|
Most of the survivors take a run identifier where the deleted local twin took a folder. That is
|
|
179
213
|
the whole difference in the vocabulary: a hosted build has no folder, and the run identifier is
|
|
@@ -216,7 +250,7 @@ machine that is only using the product installs from `pip` instead.
|
|
|
216
250
|
## Cloud authentication preflight
|
|
217
251
|
|
|
218
252
|
Authentication begins only when the next command will contact the Mostly Right cloud. Immediately
|
|
219
|
-
before hosted `mr-data
|
|
253
|
+
before hosted `mr-data dataset create` or `mr-data recipe`, run
|
|
220
254
|
`mr-data whoami --json` and read its `status`, and it intentionally does not report
|
|
221
255
|
`MOSTLYRIGHT_API_KEY`: when the variable is set, `whoami` validates that effective environment
|
|
222
256
|
credential and reports stored-device metadata separately. It never prints the environment value and
|
|
@@ -394,23 +428,30 @@ provider or bypass it.
|
|
|
394
428
|
reason codes only after the discovery lanes and source comparisons are complete. Claim
|
|
395
429
|
`unsupported` only after every typed-refusal chain ends `lawful_routes_exhausted`.
|
|
396
430
|
|
|
397
|
-
Reading
|
|
431
|
+
**Reading the bytes is the sample run, not `mr-data probe`.** `probe SOURCE_ID QUESTION_ID
|
|
432
|
+
--dataset DATASET_ID` takes two identifiers rather than a question in words, and the question
|
|
433
|
+
identifier is one no v4 registration receipt returns; the command also rides the frozen
|
|
434
|
+
`/v3/sessions` routes, which a deployment may have switched off. So the reading path on a hosted
|
|
435
|
+
workspace is the ordinary loop, one stage early: register the recipe, start an unwindowed sample
|
|
436
|
+
under a row ceiling, and read what came back.
|
|
398
437
|
|
|
399
438
|
```sh
|
|
400
|
-
mr-data
|
|
439
|
+
mr-data run --recipe RECIPE_ID --digest RECIPE_DIGEST --mode sample --max-rows 500 --json
|
|
440
|
+
mr-data peek RUN --json # the columns and types the run sealed
|
|
441
|
+
mr-data query RUN "select count(*) from run_table" --json
|
|
442
|
+
mr-data receipt RUN --json # what was fetched and what those bytes hashed to
|
|
401
443
|
```
|
|
402
444
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
445
|
+
That is stages 4 through 6 run once to settle the shape, and a sample that already meets the
|
|
446
|
+
requirements is the table a full run would seal. Where the deployment does answer a probe, keep its
|
|
447
|
+
status, reason code and exit value internal; when a probe result affects a source decision, describe
|
|
448
|
+
only what it settled about the data.
|
|
407
449
|
|
|
408
|
-
**
|
|
409
|
-
evidence is repealed. Every acquisition
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
session
|
|
413
|
-
around a probe from an hour ago still being warm.
|
|
450
|
+
**An acquisition's answer is evidence, and it is cheap to reuse.** The v3 doctrine that a probe was
|
|
451
|
+
never evidence is repealed. Every acquisition produces a receipt, and acquisitions are cacheable by
|
|
452
|
+
source, query digest and window, so a fetch feeds a later build in the same warm session without
|
|
453
|
+
paying for the bytes twice. In v4.0 that cache is session-scoped by owner ruling: it lives for the
|
|
454
|
+
session's lifetime and no longer, so do not plan around a fetch from an hour ago still being warm.
|
|
414
455
|
|
|
415
456
|
Where a source needs a credential, enrol it by name first — see
|
|
416
457
|
[Source credentials](#source-credentials) — and reference the name from the recipe document. Where
|
|
@@ -480,7 +521,7 @@ mr-data recipe RECIPE.json --json
|
|
|
480
521
|
One call. The server canonicalizes the bytes, computes the digest, and registers the dataset, the
|
|
481
522
|
question, the sources, the connector configs and the table plan in one transaction, answering with
|
|
482
523
|
`recipe_id`, `recipe_digest`, `dataset_id`, `table_id` and `source_ids`. Read
|
|
483
|
-
[The recipe document](
|
|
524
|
+
[The recipe document](https://mostlyright.md/docs/reference/recipe/) for the shape of every member.
|
|
484
525
|
|
|
485
526
|
**Name the dataset the recipe binds to.** The document's `dataset` member takes an optional `id`,
|
|
486
527
|
and it is the identifier stage 1 printed. With it, the registration attaches to the page somebody
|
|
@@ -596,7 +637,8 @@ seconds -- not a paragraph, and not a report. Use exactly this shape, in this or
|
|
|
596
637
|
section out only when there is genuinely nothing to say (shown indented here; the document
|
|
597
638
|
itself carries the headings at column one):
|
|
598
639
|
|
|
599
|
-
Two plain sentences: what
|
|
640
|
+
Two or three plain sentences: what the data is about, why it is worth a look, and what a
|
|
641
|
+
reader can see or do with it.
|
|
600
642
|
|
|
601
643
|
## Coverage
|
|
602
644
|
- **Window:** the exact dates and the time zone.
|
|
@@ -618,17 +660,45 @@ itself carries the headings at column one):
|
|
|
618
660
|
|
|
619
661
|
That is six sections: the opening paragraph, and the five headings under it.
|
|
620
662
|
|
|
621
|
-
**Opening paragraph
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
663
|
+
**Opening paragraph** (everything before the first `##` heading)
|
|
664
|
+
|
|
665
|
+
Two or three short sentences, 120 to 280 characters, written for somebody who has never heard of
|
|
666
|
+
the source, the venue or the format. Sentence one says what the data is about and what makes it
|
|
667
|
+
worth a look, in at most 110 characters. The rest says, in the same plain words, what a reader can
|
|
668
|
+
see or do with it.
|
|
669
|
+
|
|
670
|
+
1. No tickers, station codes, series codes, format names, publisher names, row definitions or row
|
|
671
|
+
counts here. Every one of those facts is in the sections below, which is where a reader who
|
|
672
|
+
wants it will look.
|
|
673
|
+
2. No Markdown: no bold, no links, no bullets, no code.
|
|
674
|
+
3. A hook is an interesting fact stated plainly, never a pitch. Banned outright: comprehensive,
|
|
675
|
+
rich, valuable, powerful, unlock, explore, dive into, perfect for, insights, "this dataset", a
|
|
676
|
+
rhetorical question, an exclamation mark.
|
|
677
|
+
4. Every number in it must be one the run established. "About every half hour" and "thousands of
|
|
678
|
+
markets" are claims, and a claim that is not on the run does not go here.
|
|
679
|
+
5. The stranger test, before anything else is written: read sentence one alone under the title. If
|
|
680
|
+
a curious non-specialist could not say what the data is about and would not want the next line,
|
|
681
|
+
rewrite it.
|
|
682
|
+
|
|
683
|
+
One airport weather table, the shape to avoid and the shape to write. To avoid:
|
|
684
|
+
|
|
685
|
+
Each row is one METAR or SPECI weather report from Beijing (ZBAA), since January 2020, via
|
|
686
|
+
Iowa Environmental Mesonet. 117,876 reports of temperature, wind, pressure, visibility with
|
|
687
|
+
the day's highest and lowest reading.
|
|
688
|
+
|
|
689
|
+
To write:
|
|
690
|
+
|
|
691
|
+
Beijing's weather about every half hour since 2020, with each day's official high and low on
|
|
692
|
+
the same row. Temperature, wind, pressure and visibility as the airport recorded them, ready
|
|
693
|
+
to test a forecast against what actually happened.
|
|
694
|
+
|
|
695
|
+
The station code, the report types, the publisher and the count all moved down to Coverage and to
|
|
696
|
+
Source and rights, where a reader who wants them looks. "About every half hour" stays only because
|
|
697
|
+
Coverage puts a month at 1,302 to 1,591 rows, which is one row every 27 to 33 minutes. "On the same
|
|
698
|
+
row" stays because it says what a reader can see; the row definition rule 1 bans is the sentence
|
|
699
|
+
that begins `Each row is`. Two ways to fail: the pitch (`Unlock real-time insights into how
|
|
700
|
+
prediction markets price the weather!`) and the bare subject with no reason to care (`Beijing
|
|
701
|
+
weather data.`).
|
|
632
702
|
|
|
633
703
|
**Body rules** (the five sections under the headings)
|
|
634
704
|
1. Every sentence must stay true and complete when quoted alone, away from the page. Never
|
|
@@ -644,14 +714,16 @@ That is six sections: the opening paragraph, and the five headings under it.
|
|
|
644
714
|
Rules that keep it readable: short sentences; no sentence over about twenty-five words; bullets
|
|
645
715
|
rather than comma lists; no tables, no code blocks, no links to internal tools, no headings beyond
|
|
646
716
|
the ones above. Spell out the names a reader would search for -- the place, the identifiers in
|
|
647
|
-
every common form, the programme and the publisher -- once each,
|
|
648
|
-
never as a keyword list. A one-line description is a defect to fix in the
|
|
649
|
-
choice. Give `table.description` the grain and the window.
|
|
717
|
+
every common form, the programme and the publisher -- once each, under Coverage and under
|
|
718
|
+
Source and rights, and never as a keyword list. A one-line description is a defect to fix in the
|
|
719
|
+
revision, not a style choice. Give `table.description` the grain and the window.
|
|
650
720
|
|
|
651
721
|
**Check before writing.** Fix and re-check until every line passes:
|
|
652
722
|
- title: at most 60 characters, contains the place, contains no colon, pipe or exclamation mark,
|
|
653
723
|
no brand, no "dataset" or "data", no version number, no run date
|
|
654
|
-
- opening paragraph:
|
|
724
|
+
- opening paragraph: two or three sentences, 120 to 280 characters, first full stop before
|
|
725
|
+
character 110, no Markdown, no identifier, publisher name, row count or row definition, no
|
|
726
|
+
banned word
|
|
655
727
|
- category: exactly one fixed ID saved and verified before recipe registration
|
|
656
728
|
- topics: 3 to 8 descriptive tags, no duplicates, lowercase, at most 40 characters each
|
|
657
729
|
- licence: an SPDX identifier the sources actually grant, or `--license` left off
|
|
@@ -737,25 +809,36 @@ contradicts what the column declared. A `bucket` the span outgrew is not one of
|
|
|
737
809
|
is widened and the chart stays yours. So `none` is the right answer to write for a column you
|
|
738
810
|
already know has no shape, and a wide date range is worth a thought before you promise a timeline.
|
|
739
811
|
|
|
740
|
-
[The recipe document](
|
|
741
|
-
the defaults are, and the two members only some charts take.
|
|
812
|
+
[The recipe document](https://mostlyright.md/docs/reference/recipe/) carries which types each
|
|
813
|
+
chart admits, what the defaults are, and the two members only some charts take.
|
|
742
814
|
|
|
743
815
|
### What the statement must actually return
|
|
744
816
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
817
|
+
The last step's relation is projected into the declared columns: every declared column must come
|
|
818
|
+
back BY NAME, in an engine type that narrows into the declared one. A returned column the table does
|
|
819
|
+
not declare is dropped; a declared column no statement returns is `TRANSFORM_PLAN_INVALID` before a
|
|
820
|
+
row exists.
|
|
821
|
+
|
|
822
|
+
A source's `binding` decides what its columns are typed as. `text` — the default, and what leaving
|
|
823
|
+
the member out means — binds every column `VARCHAR` whatever the file said, so each declared type is
|
|
824
|
+
an explicit cast you write. `typed` keeps the types the bytes carry. Under either one the cast is
|
|
825
|
+
checked against what the engine returns:
|
|
748
826
|
|
|
749
827
|
| Declared | The engine type the statement must return |
|
|
750
828
|
| --- | --- |
|
|
751
829
|
| `string` | `VARCHAR` |
|
|
752
830
|
| `integer` | `TINYINT`, `SMALLINT`, `INTEGER`, `BIGINT` — not the widest |
|
|
753
|
-
| `decimal` | `DECIMAL(p,s)` — never `FLOAT` or `DOUBLE` |
|
|
831
|
+
| `decimal` | `DECIMAL(p,s)` with `p` at most 38 — never `FLOAT` or `DOUBLE` |
|
|
832
|
+
| `float` | `DOUBLE`, `FLOAT` |
|
|
754
833
|
| `boolean` | `BOOLEAN` |
|
|
755
834
|
| `date` | `DATE` |
|
|
756
835
|
| `timestamp` | `TIMESTAMP WITH TIME ZONE` |
|
|
757
836
|
| `json` | `JSON` or `VARCHAR` |
|
|
758
837
|
|
|
838
|
+
`decimal` refusing the floating types is the point of that split: an average or a division over
|
|
839
|
+
exact decimals comes back `DOUBLE`, so end the expression in `CAST(… AS DECIMAL(p,s))` where the
|
|
840
|
+
column is exact, and declare `float` where it is genuinely approximate.
|
|
841
|
+
|
|
759
842
|
`TRANSFORM_COLUMN_TYPE_MISMATCH: column obs_time is declared timestamp and the statement returns
|
|
760
843
|
TIMESTAMP` is the time-zone row, and it names the same word twice because the difference is the zone
|
|
761
844
|
rather than the type. Build one from an epoch with `to_timestamp(CAST(x AS BIGINT))`, or from text by
|
|
@@ -792,12 +875,22 @@ ones, so a caller cannot assert a digest for its own bytes even by trying; the d
|
|
|
792
875
|
is the server's reading of what it canonicalized. Registration is idempotent by that digest:
|
|
793
876
|
identical bytes register one recipe rather than two.
|
|
794
877
|
|
|
795
|
-
Before
|
|
796
|
-
[Prediction labels](#prediction-labels). Declare what each measured column measures as a
|
|
797
|
-
from the accepted subset — `
|
|
798
|
-
[Units](
|
|
799
|
-
|
|
800
|
-
|
|
878
|
+
Before writing a step, read [Transforms](#transforms); before proposing a future outcome, read
|
|
879
|
+
[Prediction labels](#prediction-labels). Declare what each measured column measures as a UCUM code
|
|
880
|
+
from the accepted subset — `Cel`, `ug/m3`, `km/h`, `hPa`, `{count}` and the rest of it are written
|
|
881
|
+
out in [Units](https://mostlyright.md/docs/reference/units/). Write the code rather than a name:
|
|
882
|
+
`ug/m3` composes and `microgram_per_cubic_meter` does not.
|
|
883
|
+
|
|
884
|
+
**Nothing resolves the code, so there is no `UNIT_*` refusal to lean on.** The recipe schema bounds
|
|
885
|
+
the length of `unit` and nothing else; registration checks only that `units[].column` names a
|
|
886
|
+
declared column and answers `422 RECIPE_DOCUMENT_INCOHERENT` at `/units/N/column` when it does not;
|
|
887
|
+
the run never reads `units` at all. A code outside the subset therefore costs nothing at build time
|
|
888
|
+
and costs every reader afterwards, and a column declared in metres that holds feet is caught by
|
|
889
|
+
nothing. Convert in the statement, then declare the unit of what the column ends up holding. Leave a
|
|
890
|
+
column out of `units` rather than declare something approximate — a density, a rate, anything whose
|
|
891
|
+
unit is genuinely new. `none` is not a unit and does not become one. Remember that the two
|
|
892
|
+
temperature scales are offsets rather than multipliers, so `Cel` composes with nothing: `Cel/m` and
|
|
893
|
+
`mCel` are both outside the subset.
|
|
801
894
|
|
|
802
895
|
### 5. Build — take an unwindowed sample first
|
|
803
896
|
|
|
@@ -855,7 +948,7 @@ one", not as a failure: a document declaring 8 MiB over a feed that answers 40 K
|
|
|
855
948
|
ceiling on that source:** that does not fetch less data, it truncates the sample or refuses the
|
|
856
949
|
full run. Split the window across several sources — one per month, per region, or per whatever the
|
|
857
950
|
publisher paginates on — and union them in a first transform step. A recipe names up to 256
|
|
858
|
-
sources, which is a great many windows. [The recipe document](
|
|
951
|
+
sources, which is a great many windows. [The recipe document](https://mostlyright.md/docs/reference/recipe/)
|
|
859
952
|
carries the measured numbers behind the ceiling.
|
|
860
953
|
|
|
861
954
|
**A corpus of many pages behind one index is a COLLECTION, not many sources.** See
|
|
@@ -1321,9 +1414,9 @@ access is denied, say the current account cannot view the build evidence and ask
|
|
|
1321
1414
|
to an authorized account or request access.
|
|
1322
1415
|
|
|
1323
1416
|
A flag that cannot mean what it means locally is accepted and reported, never refused.
|
|
1324
|
-
`mr-data
|
|
1325
|
-
that
|
|
1326
|
-
nothing. Only flags actually passed are reported.
|
|
1417
|
+
`mr-data status RUN_ID --receipts` runs, reports the run, and reports under `flags_without_effect`
|
|
1418
|
+
that a run's digests, sources, timings and checks are already on the record. Read that key before
|
|
1419
|
+
repeating an argument that did nothing. Only flags actually passed are reported.
|
|
1327
1420
|
|
|
1328
1421
|
### Asking the table a question
|
|
1329
1422
|
|
|
@@ -1351,7 +1444,7 @@ Two things are currently broken here and are not worth diagnosing again:
|
|
|
1351
1444
|
version digest in `source.connection`, with the query in `parameter_values` and a valid response
|
|
1352
1445
|
reader; set `dataset.id` to the granted dataset. Do not ask the user to re-enter an already saved
|
|
1353
1446
|
credential under Keys. If it is not granted, explain that an owner or administrator must allow
|
|
1354
|
-
the dataset in Settings → Connections & secrets. See [Saved connections](
|
|
1447
|
+
the dataset in Settings → Connections & secrets. See [Saved connections](https://mostlyright.md/docs/build/credentials/)
|
|
1355
1448
|
for the proposal shape. Studio resolves it into the canonical recipe and enforces access during
|
|
1356
1449
|
execution. Named secrets below remain available for sources without saved connections.
|
|
1357
1450
|
|
|
@@ -1615,8 +1708,9 @@ or network search. If every registered, lawful alternative is deterministically
|
|
|
1615
1708
|
record and report the typed impossibility. Do not loop forever, fabricate a dataset, or turn a
|
|
1616
1709
|
refusal into permission.
|
|
1617
1710
|
|
|
1618
|
-
Never download source bytes directly. Never
|
|
1619
|
-
|
|
1711
|
+
Never download source bytes directly. Never transform data on this computer: the transform is the
|
|
1712
|
+
recipe's own `duckdb_sql` steps, run on the backend, and Python, shell or a local SQL engine reading
|
|
1713
|
+
the same bytes is not that. Never create Parquet outside a Harness Build. Never report a standalone Parquet file as a Build.
|
|
1620
1714
|
Do not report completion unless the run succeeded, its declared checks were read, and any artifacts
|
|
1621
1715
|
the user asked for came back with their digests checked.
|
|
1622
1716
|
|
|
@@ -1743,20 +1837,24 @@ the records pointer names an array, and whether `discovery.max_requests` plus
|
|
|
1743
1837
|
they are the four that are cheapest to get right before a run spends anybody's rate limit.
|
|
1744
1838
|
|
|
1745
1839
|
The full contract, including every bound and the coverage block's members, is
|
|
1746
|
-
[
|
|
1840
|
+
[Many-page sources](https://mostlyright.md/docs/build/collections/), with the connector coordinate
|
|
1841
|
+
and its parameters under
|
|
1842
|
+
[Source kinds and connectors](https://mostlyright.md/docs/reference/sources/).
|
|
1747
1843
|
|
|
1748
1844
|
## Readers
|
|
1749
1845
|
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1846
|
+
[Readers](https://mostlyright.md/docs/reference/readers/) defines Reader behavior. Certified
|
|
1847
|
+
Readers may be pinned on a hash-pinned
|
|
1848
|
+
`user.file` artifact, on a credential-free public HTTPS source, or on a bounded ordered public HTTPS
|
|
1849
|
+
collection, which applies one exact pin to every member. A Recipe pins the exact Reader name and
|
|
1850
|
+
version. Unsupported versions refuse by name. A version change is a recipe revision.
|
|
1754
1851
|
|
|
1755
1852
|
**Direct CSV supports publisher CSV aliases, including Eurostat SDMX-CSV.**
|
|
1756
1853
|
Accepted labels include `text/csv`, `text/plain`, `application/csv`, `application/x-csv`,
|
|
1757
1854
|
`text/x-csv`, and `application/vnd.sdmx.data+csv`. For title rows, alternate encodings,
|
|
1758
1855
|
headerless files, or padded columns, pin `delimited_text@2.0.0` and configure the layout; see
|
|
1759
|
-
|
|
1856
|
+
[Readers](https://mostlyright.md/docs/reference/readers/). A publisher needing another format can
|
|
1857
|
+
use its matching Reader.
|
|
1760
1858
|
|
|
1761
1859
|
**A v4 recipe pins a Reader through `connector.parameters`, under three reserved names.**
|
|
1762
1860
|
`declared_source` is closed and has no member for a decoder, so the pin rides on the parameter array
|
|
@@ -1776,38 +1874,35 @@ field and finding none does not mean v4 cannot pin one.
|
|
|
1776
1874
|
}
|
|
1777
1875
|
```
|
|
1778
1876
|
|
|
1779
|
-
A parameter under `reader.` that is not one of those three is refused rather than ignored.
|
|
1877
|
+
A parameter under `reader.` that is not one of those three is refused rather than ignored. All three
|
|
1878
|
+
or none: there is no other place a Reader is named. Read the pin grammar and the closed registry of
|
|
1879
|
+
48 coordinates at [Readers](https://mostlyright.md/docs/reference/readers/).
|
|
1880
|
+
|
|
1881
|
+
**No command tries a Reader against a URL.** `mr-data peek` reads the preview one hosted run sealed,
|
|
1882
|
+
and its `--reader`, `--reader-options`, `--format` and `--json-*` flags are accepted and print `no
|
|
1883
|
+
effect here; the hosted preview arrives already decoded`. A Reader is settled the way every other
|
|
1884
|
+
part of the document is settled: pin the coordinate in the recipe, register it, take an unwindowed
|
|
1885
|
+
sample under `--max-rows`, and read the columns back with `peek` and the decode evidence with
|
|
1886
|
+
`receipt`. A wrong coordinate or a wrong settings object is a typed refusal on that run naming the
|
|
1887
|
+
source, which is the answer — change the pin and register the revision.
|
|
1780
1888
|
|
|
1781
1889
|
**`reader.decode_options` is the canonical JSON text of the options the family itself admits**, with
|
|
1782
1890
|
every family-defaulted key filled in. A stated subset digests differently from the pin the worker
|
|
1783
|
-
reconstructs and is refused.
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
from mostlyright.data_harness.canonical import canonical_json_bytes
|
|
1788
|
-
admitted = JsonTabularReaderV1_1().validate_options(
|
|
1789
|
-
{"columns": [{"name": "icao_id", "pointer": "/icaoId"}]}
|
|
1790
|
-
)
|
|
1791
|
-
value = canonical_json_bytes(admitted).decode()
|
|
1792
|
-
```
|
|
1891
|
+
reconstructs and is refused. This client ships no Reader code to derive the value with: copy the
|
|
1892
|
+
family's complete default object from [Readers](https://mostlyright.md/docs/reference/readers/),
|
|
1893
|
+
change only the keys the source needs, keep every other key at its default, and write it as
|
|
1894
|
+
canonical JSON — keys sorted, no whitespace.
|
|
1793
1895
|
|
|
1794
1896
|
A column that may be absent from a record must state `"required": false`. Publishers routinely omit
|
|
1795
1897
|
a key rather than sending null, and a required column that is missing refuses the record.
|
|
1796
1898
|
|
|
1797
|
-
**Open defect: an empty string in the admitted options is refused at the acquisition boundary with
|
|
1798
|
-
`TEXT`, and the refusal names no source.** `records_pointer: ""` is the RFC 6901 pointer for a
|
|
1799
|
-
root-level array, which is what `json.tabular` admits by default and what every API returning a bare
|
|
1800
|
-
JSON array needs, so this blocks that whole class of source. The request-side screen applies the
|
|
1801
|
-
identifier rule — where an empty string is a missing one — to JSON values, where it is not. Fixed by
|
|
1802
|
-
harness PR #503; until that reaches the deployed worker image, a root-array JSON source cannot be
|
|
1803
|
-
pinned. Confirm the deployed worker carries the fix before planning a build around one.
|
|
1804
|
-
|
|
1805
1899
|
When you pin a Reader for a source nobody has approved yet, name the family's highest certified
|
|
1806
1900
|
version rather than its base version. The base version refuses a publisher that merely declined
|
|
1807
1901
|
to describe its file, and a weak-label widening lands as a new coordinate precisely so an
|
|
1808
1902
|
approved recipe is not moved under review's feet -- which makes the base version the wrong
|
|
1809
|
-
default for a source that has no approval to protect.
|
|
1810
|
-
|
|
1903
|
+
default for a source that has no approval to protect. The registry table at
|
|
1904
|
+
[Readers](https://mostlyright.md/docs/reference/readers/) lists every certified coordinate of a
|
|
1905
|
+
family; take the highest within the major you want. For a family whose major version has moved, the highest coordinate is
|
|
1811
1906
|
a different output contract rather than a wider door onto the same one, so choose it
|
|
1812
1907
|
deliberately: `weather.grib2@2.0.0` emits columns `1.0.0` does not.
|
|
1813
1908
|
|
|
@@ -1887,78 +1982,117 @@ response matches the family's exact media-type, settings, and budget contract.
|
|
|
1887
1982
|
|
|
1888
1983
|
## Transforms
|
|
1889
1984
|
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1985
|
+
**A v4 transform is SQL, not an operation vocabulary.** The member is
|
|
1986
|
+
`{"engine": "duckdb_sql", "steps": [...]}`, and each step is `{"step_id": "…", "sql": "…"}` with an
|
|
1987
|
+
optional `description`: at most 64 steps, each statement at most 65536 characters. There is no node
|
|
1988
|
+
graph, no closed operation set and nothing to work around — the statement is the plan. The schema
|
|
1989
|
+
also admits `engine: "none"`, and that document registers and then refuses its first run
|
|
1990
|
+
`TRANSFORM_PLAN_INVALID`, as an empty `steps` array does, because neither says what a build
|
|
1991
|
+
produces. Fetch [Transforms](https://mostlyright.md/docs/reference/transforms/) before writing one:
|
|
1992
|
+
it carries the admitted function table, the worked shapes and every refusal code.
|
|
1993
|
+
|
|
1994
|
+
**What a step reads.** One relation per source, under the source's own `name`, and one relation per
|
|
1995
|
+
earlier step, under its `step_id`. Steps run in array order, never sorted, so a later step reads an
|
|
1996
|
+
earlier one by writing its id. A `step_id` equal to a source `name` is refused
|
|
1997
|
+
`TRANSFORM_STEP_SHADOWS_SOURCE` and two steps sharing an id are `TRANSFORM_STEP_DUPLICATE`. Quote a
|
|
1998
|
+
name that is also a SQL keyword.
|
|
1999
|
+
|
|
2000
|
+
**What the columns are typed as.** The relation carries the ordered header acquisition recorded, and
|
|
2001
|
+
the source's `binding` decides the types: `text` — the default, and what leaving the member out
|
|
2002
|
+
means — binds every column `VARCHAR`, and `typed` keeps what the bytes carry. Under `text` every
|
|
2003
|
+
declared type is a cast you write, which keeps casting an act of the recipe. Two relations are not
|
|
2004
|
+
declared anywhere: a recorded stream source presents one of two fixed text headers — eight
|
|
2005
|
+
columns `epoch`, `event_id`, `event_time`, `message`, `message_class`, `message_type`,
|
|
2006
|
+
`received_at`, `sequence`, or those plus `member` after `event_time` when the connector declares a
|
|
2007
|
+
member field — and a collection source presents the pinned Reader's columns plus seven reserved
|
|
2008
|
+
`page_*` columns.
|
|
2009
|
+
|
|
2010
|
+
**What the last step must return** is under
|
|
2011
|
+
[What the statement must actually return](#what-the-statement-must-actually-return). Row order is
|
|
2012
|
+
the table's `grain` and then every remaining declared column in declaration order, so an `order by`
|
|
2013
|
+
you write is not the sealed order.
|
|
2014
|
+
|
|
2015
|
+
```json
|
|
2016
|
+
"transform": {
|
|
2017
|
+
"engine": "duckdb_sql",
|
|
2018
|
+
"steps": [
|
|
2019
|
+
{
|
|
2020
|
+
"step_id": "readings",
|
|
2021
|
+
"sql": "select station, cast(concat(valid, ':00+00') as timestamp with time zone) as observed_at, cast((try_cast(tmpf as decimal(6,2)) - 32) * 5 / 9 as decimal(6,2)) as air_temp_c from asos_observations where valid is not null and valid <> ''"
|
|
2022
|
+
},
|
|
2023
|
+
{
|
|
2024
|
+
"step_id": "hourly",
|
|
2025
|
+
"sql": "select station, time_bucket(interval 1 hour, observed_at) as hour_start, cast(avg(air_temp_c) as decimal(6,2)) as mean_air_temp_c, count(*) as reading_count from readings group by station, time_bucket(interval 1 hour, observed_at)"
|
|
2026
|
+
}
|
|
2027
|
+
]
|
|
2028
|
+
}
|
|
2029
|
+
```
|
|
2030
|
+
|
|
2031
|
+
`asos_observations` is a source's `name`; `readings` is the first step read by the second. The outer
|
|
2032
|
+
`cast` on each measured column is what makes it a `DECIMAL(6,2)` — without it the division and the
|
|
2033
|
+
`avg` both return `DOUBLE` and the column is refused.
|
|
2034
|
+
|
|
2035
|
+
**One read-only `SELECT` per step.** The engine classifies the statement: more than one is
|
|
2036
|
+
`TRANSFORM_STATEMENT_NOT_SINGLE`, and anything that is not a `SELECT` is
|
|
2037
|
+
`TRANSFORM_STATEMENT_NOT_SELECT` — so `ATTACH`, `COPY`, `INSTALL`, `LOAD`, `PRAGMA`, `CREATE`,
|
|
2038
|
+
`INSERT`, `UPDATE` and `DELETE` are all refused. Common table expressions, `UNION`, `QUALIFY`,
|
|
2039
|
+
`UNPIVOT`, `VALUES` and `SELECT DISTINCT` are each one `SELECT` and are admitted, which is how a
|
|
2040
|
+
long-format reshape, a join, a deduplication and a time bucket are written.
|
|
2041
|
+
|
|
2042
|
+
**The result has to re-derive, and the engine decides that rather than a word list.** A sealed table
|
|
2043
|
+
is rebuilt and compared byte for byte, so a step may read nothing the recipe and the acquired bytes
|
|
2044
|
+
do not fix. The engine's own function catalog is asked about every name the statement references:
|
|
2045
|
+
anything it does not report as re-derivable, anything with side effects, and anything it does not
|
|
2046
|
+
carry at all is refused `TRANSFORM_PLAN_INVALID` before the step runs. That catches `current_date`,
|
|
2047
|
+
`current_timestamp`, `now()`, `today()`, `random()`, `gen_random_uuid()` and anything written in
|
|
2048
|
+
terms of them. The date-granular ones are the dangerous ones: both executions inside one build agree
|
|
2049
|
+
and the table seals, and tomorrow's refresh can never reproduce it. Reach a column a publisher
|
|
2050
|
+
happened to spell like one of those names by qualifying it — `observations.current_date`.
|
|
2051
|
+
|
|
2052
|
+
**The engine reaches nothing.** It is given this run's own source files and scratch directory, then
|
|
2053
|
+
external access is switched off and the settings are locked, so it can open no file, fetch no URL
|
|
2054
|
+
and load no extension. There is no denylist of names in any of it, by design: a source is reached by
|
|
2055
|
+
naming its relation and never by opening its address again. Where that confinement cannot be
|
|
2056
|
+
established the code is `TRANSFORM_ENGINE_UNCONFINED` and no step was attempted.
|
|
2057
|
+
|
|
2058
|
+
**Every table is built in `UTC`**, established before a statement is read. A recipe declaring
|
|
2059
|
+
another `timezone` registers and then refuses its first run `RUN_RECIPE_INVALID`. `ICU` is not
|
|
2060
|
+
loaded, so `AT TIME ZONE` is unavailable; write the conversion into the statement.
|
|
2061
|
+
|
|
2062
|
+
A step the engine itself refused comes back as `RUN_EXECUTION_FAILED` carrying DuckDB's own code and
|
|
2063
|
+
words — `step daily_mean would not run: BINDER_ERROR: …`. Read the detail, not the code. Every
|
|
2064
|
+
transform code reports `failed_stage: "transform"`.
|
|
2065
|
+
|
|
2066
|
+
`units` is declared beside the table, and nothing in the transform reads it or checks the arithmetic
|
|
2067
|
+
against it. Convert in the statement, then declare the unit of what the column ends up holding, per
|
|
2068
|
+
the paragraph under [What each check kind requires](#what-each-check-kind-requires).
|
|
1935
2069
|
|
|
1936
2070
|
## Prediction labels
|
|
1937
2071
|
|
|
1938
|
-
|
|
1939
|
-
something the harness can construct.
|
|
1940
|
-
refuse a graph naming it, with a typed `OPERATION_RETIRED` refusal.
|
|
2072
|
+
There is no prediction-label member in a v4 recipe document and no operation that produces one. Do
|
|
2073
|
+
not offer a future outcome as something the harness can construct.
|
|
1941
2074
|
|
|
1942
|
-
The
|
|
1943
|
-
|
|
1944
|
-
the
|
|
1945
|
-
and none is owed.
|
|
2075
|
+
The horizon such a label needs is a statement about what somebody intends to model, and nothing in
|
|
2076
|
+
the sources says what it should be. A target belongs to the step that consumes the dataset, not to
|
|
2077
|
+
the dataset. There is no replacement, and none is owed.
|
|
1946
2078
|
|
|
1947
|
-
Do not reconstruct it either.
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
outcome, say that the
|
|
1951
|
-
|
|
2079
|
+
Do not reconstruct it in the statement either. A window function that shifts a measured value
|
|
2080
|
+
forward in time and a self join that reads a later row are the same claim under another spelling,
|
|
2081
|
+
and no check catches either — the transform engine refuses what cannot re-derive, not what is
|
|
2082
|
+
modelled. Where a request asks for a future outcome, say that the build seals the observed table and
|
|
2083
|
+
that the horizon is chosen downstream.
|
|
1952
2084
|
|
|
1953
|
-
Work sealed
|
|
1954
|
-
|
|
1955
|
-
|
|
2085
|
+
Work sealed before the retirement is unaffected: such a table still verifies and replays, and such a
|
|
2086
|
+
Recipe still runs.
|
|
2087
|
+
[Units and vocabulary](https://mostlyright.md/docs/reference/units/) records the withdrawal and what
|
|
2088
|
+
a reader of such a Build should expect from it.
|
|
1956
2089
|
|
|
1957
2090
|
## Boundaries
|
|
1958
2091
|
|
|
1959
|
-
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2092
|
+
- The transform's `duckdb_sql` steps are the only executable text a Recipe carries, and they run on
|
|
2093
|
+
the backend under the confinement above. Everything else in the document stays declarative: no
|
|
2094
|
+
Python, no shell, no plugins, no redirects, no callables.
|
|
2095
|
+
- Use only contract-supported connectors, Readers, checks and resource bounds.
|
|
1962
2096
|
- Do not claim that recipe registration fetched a source, that a declared check released a table
|
|
1963
2097
|
version, or that agent output executed a transformation.
|
|
1964
2098
|
- Preserve the cause and acceptance condition for blocker, critical, and high findings. This
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Mostly Right Data Build"
|
|
3
3
|
short_description: "Build and verify reviewed datasets"
|
|
4
|
-
default_prompt: "Use $mr-data-build to autonomously deliver the requested dataset outcome before inspecting CLI help, documentation, schemas, fixtures, examples, prior runs, or installed package details whenever the request uses, tests, demonstrates, or debugs the Harness. If the host requires a skill-use disclosure, send only one outcome-specific sentence naming $mr-data-build before the first tool call; otherwise start silently. Never narrate preparation, skill loading, CLI discovery, authentication, document or contract lookup, example searches, package versions, command batches, or acquisition-document authoring. Never narrate skill instructions, commands, receipts, events, protocols, status codes, service behavior, or notebook mechanics. Open the request's canonical Dataset page first when that address can be minted, and carry on without it rather than blocking. Keep routine work silent unless the host requires periodic status; then send concise outcome-oriented updates without mechanics or internal language, grounded in domain-specific observed evidence, a decision, required user action, or the verified outcome."
|
|
4
|
+
default_prompt: "Use $mr-data-build to autonomously deliver the requested dataset outcome before inspecting CLI help, documentation, schemas, fixtures, examples, prior runs, or installed package details whenever the request uses, tests, demonstrates, or debugs the Harness. If the host requires a skill-use disclosure, send only one outcome-specific sentence naming $mr-data-build before the first tool call; otherwise start silently. Never narrate preparation, skill loading, CLI discovery, authentication, document or contract lookup, example searches, package versions, command batches, or acquisition-document authoring. Never narrate skill instructions, commands, receipts, events, protocols, status codes, service behavior, or notebook mechanics. Open the request's canonical Dataset page first when that address can be minted, and carry on without it rather than blocking. Keep routine work silent unless the host requires periodic status; then send concise outcome-oriented updates without mechanics or internal language, grounded in domain-specific observed evidence, a decision, required user action, or the verified outcome. Fetch the published reference at https://mostlyright.md/docs/ for the recipe field, connector, Reader, transform, check, unit, command flag, error code, ceiling or worked example in front of you before drafting it; it is the contract, it wins over any memory of an older version, and fetching it is preparation you never narrate."
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/canonical.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/key_seam.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/page_coverage.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/session_probes.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/skill_assets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/table_manifest.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/acquire.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/activity.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/approvals.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/categories.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/commands.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/download.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/narrative.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/parity.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/probe.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/propose.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/recipe.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/research.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/router.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/runs.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/session.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/stream.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/transport.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/user_agent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_catalog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_datasets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_handoff.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_query.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_runs.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_secrets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_stream.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/v4_tables.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/thin/vocabulary.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/attendance.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/clarification.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/cloud_auth.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/commands/auth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/credentials.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/login.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/path_kind.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/plain_file.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/remediation.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.0 → mostlyright_data-0.19.2}/src/mostlyright/data_harness/ux/render.py
RENAMED
|
File without changes
|