mostlyright-data 0.30.4__tar.gz → 0.30.6__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.30.4 → mostlyright_data-0.30.6}/PKG-INFO +1 -1
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/6-build-one-run-sized-to-acquire-every-measured-source-whole.md +35 -10
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/making-a-table-incremental.md +1 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/recipe-test.md +8 -1
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe.py +250 -26
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe_explain.py +11 -6
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/transport.py +3 -1
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_stream.py +14 -3
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/.gitignore +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/README.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/pyproject.toml +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/scripts/hatch_build.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/SKILL.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/agents/openai.yaml +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/1-open-the-page-and-the-link-to-it-in-the-first-message.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/2-brief-two-to-four-questions-each-with-a-recommended-answer.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/3-probe-read-a-source-before-committing-to-it.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/4-decide-say-what-you-chose-what-you-refused-and-ask-one-question.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/5-draft-one-recipe-document-one-call.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/7-interrogate-ask-the-run-what-it-actually-delivered.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/8-fix-revise-the-document-and-register-it-again.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/9-present-only-what-survived-inspection-with-caveats.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/agent-protocol.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/autonomous-delivery.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/before-the-first-tool-call.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/boundaries.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/cloud-authentication-preflight.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/commands.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/cross-repository-protocol-reference.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/installation-parity.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/live-run.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/narrating-the-run.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/not-hosted-yet.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/one-install.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/patterns.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/prediction-labels.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/preparing-table-search.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/promote.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/readers.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/receipts.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/recording-a-stream-venue.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/recovering-an-import-failure.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/reference-pages.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/required-protocol.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/source-credentials.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/sources.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/the-one-thing-to-say-about-the-skill-itself.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/transforms.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/user-communication-contract.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/writing-a-decision-record.md +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/scripts/write_research_notebook.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/__init__.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/agent_protocol.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/canonical.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/formats.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/key_seam.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/page_coverage.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/part_check_evidence.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/session_probes.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/skill_assets.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/table_manifest.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/__init__.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/acquire.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/activity.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/approvals.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/backoff.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/categories.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/commands.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/dataset-categories-v1.json +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/download.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/fast_features.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/narrative.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/parity.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/probe.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/progress_rate.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/progress_vocabulary.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/propose.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe_brief.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe_forecast.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe_lint.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe_test.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/refresh_rehearsal.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/release_check.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/research.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/router.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/run_diagnose.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/run_prefix.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/runs.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/session.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/stream.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/stream_venue.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/studio_capabilities.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/support.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/table_search_contract.json +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/user_agent.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_artifacts.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_catalog.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_connected.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_connections.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_dataset_covers.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_datasets.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_handoff.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_narrative.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_public.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_query.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_reader.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_runs.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_search.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_search_contract.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_secrets.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_tables.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/__init__.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/attendance.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/clarification.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/commands/clarify.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/credentials.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/login.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/remediation.py +0 -0
- {mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/render.py +0 -0
|
@@ -146,19 +146,44 @@ projected to a few columns decodes to a few hundred kilobytes; an 8.6 MB table r
|
|
|
146
146
|
to 8.6 MB. The fetched size predicts nothing on its own, and a source over either bound is refused
|
|
147
147
|
`READER_BUDGET`, which names both.
|
|
148
148
|
|
|
149
|
-
**How far a source may fetch depends on how it will be read.**
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
149
|
+
**How far a source may fetch depends on whether it is staged, and then on how it will be read.**
|
|
150
|
+
Studio collects the bytes of a `public.https` source at an `https_url` that names no credential,
|
|
151
|
+
has a `public` classification and states the rights basis `public_domain_asserted`. A Generic API
|
|
152
|
+
or a page collection is not one. Studio writes a collected object to the run's scratch disk and
|
|
153
|
+
decodes it from that file, instead of holding it in memory, when the source is also read whole,
|
|
154
|
+
with no `window`, and is either unpinned or pinned to a Reader with a file decoder. That is a
|
|
155
|
+
staged source. Delimited text and Parquet have a file decoder, and so do the gzip, tar and zip
|
|
156
|
+
archive Readers (not `archive.tar@2.0.0` or `archive.zip@2.0.0`), `meteorology.grib`,
|
|
157
|
+
`meteorology.bufr` and the statistical microdata Readers; `json.tabular` has one in 1.1.0 and
|
|
158
|
+
1.2.0, and only when it reads `ndjson`. The spreadsheet, XML, HTML, NetCDF and `weather.grib2`
|
|
159
|
+
Readers have none, and a pin to one of them is fetched whole. A staged source is read up to 4 GiB,
|
|
160
|
+
bounded by the `limits.max_source_bytes` you declare, with no other member to set. A sample that
|
|
161
|
+
truncates rows (`--sample` with `--max-rows`) is never staged: a source that would be staged is
|
|
162
|
+
read from memory instead, under the cap below.
|
|
163
|
+
|
|
164
|
+
Every other `public.https` source is held in memory as it is fetched, and a Reader-pinned one, or an
|
|
165
|
+
unpinned `csv` one, fetches up to 256 MiB. An unpinned `ndjson` source fetches up to what one
|
|
166
|
+
confined request carries, about 36 MB. An unpinned `json` or `parquet` source keeps 16 MiB on either
|
|
167
|
+
route, because neither has a row-at-a-time reader and both are read whole inside the clean room —
|
|
168
|
+
pinning a Reader is the way past that. The exception is a source pinned to `parquet.tabular@1.1.0`,
|
|
169
|
+
which fetches by range, up to 1 GiB.
|
|
170
|
+
|
|
171
|
+
The rights basis is a statement about your right to use the source, and it is recorded with the
|
|
172
|
+
run. It is not a size setting: state the one that is true, and let the ceiling follow.
|
|
173
|
+
|
|
174
|
+
What a source that is not staged may DECODE to is its Reader family's output budget, narrowed to at
|
|
175
|
+
most 1 GiB, because the whole decoded relation is held in memory while it is classified and sealed.
|
|
176
|
+
A staged source is decoded to a file and is not narrowed to that 1 GiB. On either route the decoded
|
|
177
|
+
table is also held to the source's own `limits.max_source_bytes`, so when a source inflates, as a
|
|
178
|
+
compressed archive does, declare that at the decoded size and not at the size of the download. A
|
|
179
|
+
wide source is still best narrowed by projection, which is what shrinks the decoded relation; a
|
|
180
|
+
long source can still be split.
|
|
157
181
|
|
|
158
182
|
`limits.max_source_bytes` states where fetching STOPS rather than how big the source is, so the
|
|
159
183
|
preflight does not refuse a large one. Registration puts one sentence on the receipt under
|
|
160
|
-
`warnings` when the declared number is larger than
|
|
161
|
-
formats that stop earlier. Read that as "go
|
|
184
|
+
`warnings` when the declared number is larger than the route its source takes can reach, and the
|
|
185
|
+
sentence names the route, the ceiling it used and the formats that stop earlier. Read that as "go
|
|
186
|
+
and check this one", not as a failure.
|
|
162
187
|
|
|
163
188
|
**Which remedy applies depends on which way the source is too big, and lowering the ceiling is
|
|
164
189
|
never it** — that truncates the preview or refuses the full build rather than fetching less. A WIDE
|
|
@@ -209,6 +209,7 @@ source and the pointer to change.
|
|
|
209
209
|
| `REFRESH_WORKER_UNAVAILABLE` | This Studio has no refresh worker for the plan. | `wait_for_platform`: report "not available on this Studio yet". |
|
|
210
210
|
| `REBUILD_DISCARDS_SNAPSHOT_HISTORY` | A table declares `rebuild` beside a snapshot source. | `split_table`: keep the snapshot source in a table with no `rebuild`. |
|
|
211
211
|
| `ROW_REQUEST_ANSWERS_NEVER_EXPIRE` | Advisory. A per-row request names no date parameter and its answers are reused with no bound. | `declare_revisit_interval` or `read_answers_fresh`, both in [Needs Studio 4.14](#needs-studio-414). |
|
|
212
|
+
| `PREDECESSOR_TRUNCATED` | The live version is a `sample` that a row or window clamp cut short, so a refresh would seal over rows it never fetched. Needs Studio 4.33. | `resync_once`: run one full build. |
|
|
212
213
|
|
|
213
214
|
A `permanence` of `predecessor` clears after one full. `estate` is the platform's state, not the
|
|
214
215
|
recipe's. Report it and do not revise the document for it. `document` needs a revision.
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/recipe-test.md
RENAMED
|
@@ -24,7 +24,14 @@ What it reads:
|
|
|
24
24
|
- A per-row source that presents a credential gets no requests unless `--allow-paid` is set. It
|
|
25
25
|
is reported as skipped, and its relation reaches the transform empty. Its provider's
|
|
26
26
|
per-request price is the reason, so forecast it and ask the user before adding the flag.
|
|
27
|
-
- Generic API walks and whole-file sources are bounded only by the 256 MiB
|
|
27
|
+
- Generic API walks and whole-file sources are bounded only by the test's own clamp of 256 MiB
|
|
28
|
+
on source bytes. A whole file larger than that is refused by the test, although the full reads a
|
|
29
|
+
staged source up to 4 GiB
|
|
30
|
+
([how far a source may fetch](6-build-one-run-sized-to-acquire-every-measured-source-whole.md)).
|
|
31
|
+
`mr-data run --full` runs this test first, so a staged source over 256 MiB stops it at
|
|
32
|
+
`run_stopped_by_test`. That stop comes from the clamp and not from anything wrong in the recipe;
|
|
33
|
+
`--skip-test`, below, is how the user starts that full once they have decided to. A whole file
|
|
34
|
+
that is not staged is refused by the full as well, and `--skip-test` does not help it.
|
|
28
35
|
|
|
29
36
|
Read `status`:
|
|
30
37
|
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe.py
RENAMED
|
@@ -69,7 +69,7 @@ from mostlyright.data_harness.thin.session import (
|
|
|
69
69
|
open_studio_session,
|
|
70
70
|
sessions_for,
|
|
71
71
|
)
|
|
72
|
-
from mostlyright.data_harness.thin.transport import ThinLaneError
|
|
72
|
+
from mostlyright.data_harness.thin.transport import ThinLaneError, UrlLibTransport
|
|
73
73
|
from mostlyright.data_harness.thin.v4 import identifier
|
|
74
74
|
from mostlyright.data_harness.thin.v4_datasets import (
|
|
75
75
|
StudioV4DatasetClient,
|
|
@@ -114,7 +114,9 @@ REQUIRED_DOCUMENT_MEMBERS: tuple[str, ...] = (
|
|
|
114
114
|
|
|
115
115
|
#: The declared ``limits.max_source_bytes`` above which one source is worth a word, in bytes --
|
|
116
116
|
#: for a source that is read through descriptors, which is a Reader-pinned one or an unpinned
|
|
117
|
-
#: ``csv`` one. That is the hosted
|
|
117
|
+
#: ``csv`` one -- and that is not STAGED (:func:`_is_staged`). That is the hosted whole-read cap,
|
|
118
|
+
#: ``hosted_crawler.MAX_RAW_RESPONSE_BYTES``: the most a fetch that holds the body in memory may
|
|
119
|
+
#: take.
|
|
118
120
|
READER_SOURCE_BYTE_CEILING = 268_435_456
|
|
119
121
|
|
|
120
122
|
#: The same ceiling for an unpinned ``ndjson`` source. It has an inline streaming pass and no
|
|
@@ -127,6 +129,71 @@ NDJSON_SOURCE_BYTE_CEILING = 37_745_664
|
|
|
127
129
|
#: Pinning a Reader is what moves a source off this ceiling.
|
|
128
130
|
DRAINED_SOURCE_BYTE_CEILING = 16_777_216
|
|
129
131
|
|
|
132
|
+
#: A source pinned to ``parquet.tabular@1.1.0`` is read by range, and its declared
|
|
133
|
+
#: ``max_source_bytes`` bounds the bytes that read fetches -- the footer and the selected column
|
|
134
|
+
#: chunks -- rather than the object, which may be far larger. Its ceiling is the ranged read's own
|
|
135
|
+
#: (``readers.budgets.MAX_RANGED_READ_BYTES``), not the hosted cap, and the coordinate is
|
|
136
|
+
#: ``readers.parquet_tabular.RANGED_PARQUET_COORDINATE``. Stated here for the reason below.
|
|
137
|
+
RANGED_READ_SOURCE_BYTE_CEILING = 1_073_741_824
|
|
138
|
+
RANGED_READER_COORDINATE = ("parquet.tabular", "1.1.0")
|
|
139
|
+
|
|
140
|
+
#: The same threshold for a STAGED source: one that Studio collects, reads whole and decodes from a
|
|
141
|
+
#: file (:func:`_is_staged`). That object is written to the run's scratch disk instead of being
|
|
142
|
+
#: held, so the whole-read cap does not bind it (Studio #1989, ADR 0099);
|
|
143
|
+
#: ``hosted_crawler.MAX_COLLECTED_FILE_SOURCE_BYTES`` does.
|
|
144
|
+
#:
|
|
145
|
+
#: ⚠ STATED HERE, NOT IMPORTED FROM STUDIO, AND HELD EQUAL TO IT BY A TEST. This client is
|
|
146
|
+
#: standard-library only and the crawler is part of the engine it must never carry, so it cannot
|
|
147
|
+
#: read the ceilings off the module that enforces them. The cross-repository suite
|
|
148
|
+
#: (``tests/test_thin_worker_contract_constants.py``) reads that module's source and fails when
|
|
149
|
+
#: either ceiling here, the ranged one or the table below stops being Studio's. It needs a Studio
|
|
150
|
+
#: checkout and so does not run in CI: run ``make verify-cross-repo`` after a change to any of
|
|
151
|
+
#: them. The sentence that said every Reader-pinned source stops at 256 MiB went on being printed
|
|
152
|
+
#: for days after ADR 0099, because the guard compared the figure with the wrong constant
|
|
153
|
+
#: (mostlyrightmd/mostlyright-planning#1576).
|
|
154
|
+
STAGED_SOURCE_BYTE_CEILING = 4 * 1024**3
|
|
155
|
+
|
|
156
|
+
#: Under this execution policy a staged read has no fixed ceiling: ``limits.max_source_bytes``
|
|
157
|
+
#: bounds it, narrowed by what the run's capacity admits (ADR 0099).
|
|
158
|
+
_BOUNDED_STREAMING_POLICY = "bounded-streaming.v1"
|
|
159
|
+
|
|
160
|
+
#: The Reader coordinates a staged file can be decoded by. A pin to any other is decoded from bytes
|
|
161
|
+
#: held in memory, however the source is collected. Restated from ``acquisition.file_decoding``
|
|
162
|
+
#: (the keys of ``_FILE_FAMILIES`` joined with those of ``_SCRATCH_FILE_FAMILIES``) for the reason
|
|
163
|
+
#: above, and held equal to them by a test in both directions: Studio #2050 added
|
|
164
|
+
#: ``archive.zip@3.0.0`` to the table while the change that first restated it was in review.
|
|
165
|
+
#: ``json.tabular`` has a decoder only for ``ndjson`` (:func:`_reads_ndjson`). Among the certified
|
|
166
|
+
#: coordinates without one are ``spreadsheet.xlsx``, ``xml.tabular``, ``html.web_extract``,
|
|
167
|
+
#: ``scientific.netcdf`` and ``weather.grib2``.
|
|
168
|
+
FILE_DECODER_COORDINATES: frozenset[tuple[str, str]] = frozenset(
|
|
169
|
+
(family, version)
|
|
170
|
+
for family, versions in {
|
|
171
|
+
"archive.gzip": ("1.0.0", "1.1.0", "2.0.0"),
|
|
172
|
+
"archive.tar": ("1.0.0", "1.1.0", "3.0.0"),
|
|
173
|
+
"archive.zip": ("1.0.0", "1.1.0", "1.2.0", "1.3.0", "1.4.0", "1.5.0", "3.0.0"),
|
|
174
|
+
"delimited_text": ("1.0.0", "1.1.0", "2.0.0"),
|
|
175
|
+
"geoparquet.vector": ("1.0.0",),
|
|
176
|
+
"json.tabular": ("1.1.0", "1.2.0"),
|
|
177
|
+
"meteorology.bufr": ("1.0.0",),
|
|
178
|
+
"meteorology.grib": ("1.0.0",),
|
|
179
|
+
"microdata.sas_xpt": ("1.0.0",),
|
|
180
|
+
"microdata.spss_sav": ("1.0.0",),
|
|
181
|
+
"microdata.stata_dta": ("1.0.0",),
|
|
182
|
+
"official.pcaxis_px": ("1.0.0",),
|
|
183
|
+
"parquet.tabular": ("1.0.0", "1.1.0"),
|
|
184
|
+
"raster.geospatial": ("1.0.0",),
|
|
185
|
+
"satellite.himawari_hsd_complete": ("1.0.0",),
|
|
186
|
+
"satellite.msg_seviri_l15": ("1.0.0",),
|
|
187
|
+
"satellite.sentinel_safe": ("1.0.0",),
|
|
188
|
+
"satellite.xrit_image": ("1.0.0",),
|
|
189
|
+
"scientific.fits": ("1.0.0",),
|
|
190
|
+
"scientific.hdf5": ("1.0.0",),
|
|
191
|
+
"scientific.zarr": ("1.0.0",),
|
|
192
|
+
"xbrl.facts": ("1.0.0",),
|
|
193
|
+
}.items()
|
|
194
|
+
for version in versions
|
|
195
|
+
)
|
|
196
|
+
|
|
130
197
|
#: How many undescribed columns the warning names before it counts the rest. A table plan admits
|
|
131
198
|
#: 512 columns, and a sentence that spelt every one of them out would be the wall the `numbered`
|
|
132
199
|
#: receipt member exists to avoid. The receipt carries the whole count as a number beside it, so
|
|
@@ -159,10 +226,10 @@ PROPOSE = "propose"
|
|
|
159
226
|
EXPLAIN = recipe_explain.EXPLAIN
|
|
160
227
|
FORECAST = "forecast"
|
|
161
228
|
TEST = recipe_test.TEST
|
|
162
|
-
# Studio evaluates the exact persisted admission proof for each recipe revision.
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
229
|
+
# Studio evaluates the exact persisted admission proof for each recipe revision. A page of 25 is
|
|
230
|
+
# quick on most workspaces; where one revision takes minutes the walk halves the page down to a
|
|
231
|
+
# single row under READINESS_REQUEST_TIMEOUT_SECONDS, at the cost of the timed-out attempts first.
|
|
232
|
+
# Cursor aggregation keeps the established 40,000-item inventory bound.
|
|
166
233
|
READINESS_PAGE_SIZE = 25
|
|
167
234
|
MAX_READINESS_ITEMS = 40_000
|
|
168
235
|
MAX_READINESS_PAGES = MAX_READINESS_ITEMS // READINESS_PAGE_SIZE
|
|
@@ -175,6 +242,11 @@ MAX_READINESS_HALVINGS = 5
|
|
|
175
242
|
#: (the transport's deadline), or a gateway that gave up waiting for Studio.
|
|
176
243
|
READINESS_TIMEOUT_STATUSES = frozenset({502, 503, 504})
|
|
177
244
|
|
|
245
|
+
#: How long one readiness page may take. Studio evaluates each revision's persisted admission
|
|
246
|
+
#: proof, and on a large production workspace a single revision has taken about 110 seconds, past
|
|
247
|
+
#: the thirty seconds an ordinary request gets: no page, however halved, could come back.
|
|
248
|
+
READINESS_REQUEST_TIMEOUT_SECONDS = 300.0
|
|
249
|
+
|
|
178
250
|
#: How long the walk waits before it asks a page again after one of those statuses, doubling to the
|
|
179
251
|
#: ceiling, each wait jittered over the upper half of its step. A gateway that answered at once
|
|
180
252
|
#: names an overloaded Studio, and every client in the walk asking straight back adds to the load.
|
|
@@ -419,7 +491,7 @@ def check_document(document: dict[str, Any]) -> None:
|
|
|
419
491
|
check_dataset_binding(document["dataset"])
|
|
420
492
|
|
|
421
493
|
|
|
422
|
-
def source_byte_warnings(sources: Any) -> list[str]:
|
|
494
|
+
def source_byte_warnings(sources: Any, *, execution_policy: Any = None) -> list[str]:
|
|
423
495
|
"""One sentence per source whose declared ceiling is larger than the hosted lane fetches.
|
|
424
496
|
|
|
425
497
|
⚠ WARNINGS, AND NOT A GATE, FOR THE REASON :data:`READER_SOURCE_BYTE_CEILING` GIVES: the
|
|
@@ -428,6 +500,18 @@ def source_byte_warnings(sources: Any) -> list[str]:
|
|
|
428
500
|
decides anything; it tells the agent that wrote the number that the hosted lane will not honour
|
|
429
501
|
it.
|
|
430
502
|
|
|
503
|
+
⚠ "THE HOSTED LANE" IS SEVERAL ROUTES, AND A SOURCE IS HELD TO THE CEILING OF THE ONE IT TAKES.
|
|
504
|
+
A staged source is written to disk and read to :data:`STAGED_SOURCE_BYTE_CEILING`, a ranged
|
|
505
|
+
Parquet read has its own, and every other source is held to
|
|
506
|
+
:data:`READER_SOURCE_BYTE_CEILING` (:func:`_source_byte_ceiling`). Telling a staged source that
|
|
507
|
+
its fetch stops at 256 MiB sent authors off to shrink sources that read in full
|
|
508
|
+
(mostlyrightmd/mostlyright-planning#1574), and this client's build skill said the same
|
|
509
|
+
(mostlyrightmd/mostlyright-planning#1576).
|
|
510
|
+
|
|
511
|
+
⚠ UNDER ``bounded-streaming.v1`` A STAGED READ HAS NO CEILING TO OVERSTATE, so it is not
|
|
512
|
+
warned about: the declared number alone bounds it. That policy is a member of the document, not
|
|
513
|
+
of a source, which is why it is passed in beside the sources.
|
|
514
|
+
|
|
431
515
|
⚠ THE LARGEST SOURCE DECIDES, NOT THE SUM. One source is fetched at a time, so the sentence is
|
|
432
516
|
about the one that overstates its ceiling rather than about the total.
|
|
433
517
|
|
|
@@ -448,7 +532,10 @@ def source_byte_warnings(sources: Any) -> list[str]:
|
|
|
448
532
|
declared = limits.get("max_source_bytes")
|
|
449
533
|
if type(declared) is not int:
|
|
450
534
|
continue
|
|
451
|
-
|
|
535
|
+
held = _source_byte_ceiling(source, execution_policy=execution_policy)
|
|
536
|
+
if held is None:
|
|
537
|
+
continue
|
|
538
|
+
ceiling, why, sooner = held
|
|
452
539
|
if declared <= ceiling:
|
|
453
540
|
continue
|
|
454
541
|
named = source.get("name")
|
|
@@ -457,10 +544,7 @@ def source_byte_warnings(sources: Any) -> list[str]:
|
|
|
457
544
|
f"source {where} declares limits.max_source_bytes of {declared:,} bytes, and {why} "
|
|
458
545
|
f"stops at {ceiling:,}. That is a ceiling on fetching rather than a measurement of "
|
|
459
546
|
"the source, so this registers and runs, and the fetch stops there whatever the "
|
|
460
|
-
"document says.
|
|
461
|
-
f"{NDJSON_SOURCE_BYTE_CEILING:,} and one that answers json or parquet at "
|
|
462
|
-
f"{DRAINED_SOURCE_BYTE_CEILING:,}, and pinning a Reader is what moves it off "
|
|
463
|
-
"those. Declare what the source actually weighs"
|
|
547
|
+
f"document says. {sooner}. Declare what the source actually weighs"
|
|
464
548
|
)
|
|
465
549
|
return said
|
|
466
550
|
|
|
@@ -1013,24 +1097,156 @@ def sample_span_warnings(sources: Any) -> list[str]:
|
|
|
1013
1097
|
return [". ".join(said)]
|
|
1014
1098
|
|
|
1015
1099
|
|
|
1016
|
-
def
|
|
1017
|
-
"""The
|
|
1100
|
+
def _stated_parameters(source: Mapping[str, Any]) -> dict[str, Any]:
|
|
1101
|
+
"""The ``connector.parameters`` one source states, by name.
|
|
1018
1102
|
|
|
1019
|
-
A
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
whatever its wire format. An unpinned source is held to the same cap here, and the sentence
|
|
1023
|
-
says which formats stop earlier, because that is decided by bytes this client has not seen.
|
|
1103
|
+
A parameter whose name is not text names nothing, so it is left out and never hashed: the
|
|
1104
|
+
schema refuses it and the server says so, and this runs before the server has been asked
|
|
1105
|
+
(``--no-lint`` lets a document that fails the schema reach it).
|
|
1024
1106
|
"""
|
|
1025
1107
|
|
|
1026
1108
|
connector = source.get("connector")
|
|
1027
1109
|
parameters = connector.get("parameters") if isinstance(connector, Mapping) else None
|
|
1028
|
-
if isinstance(parameters, list)
|
|
1029
|
-
|
|
1110
|
+
if not isinstance(parameters, list):
|
|
1111
|
+
return {}
|
|
1112
|
+
return {
|
|
1113
|
+
parameter["name"]: parameter.get("value")
|
|
1030
1114
|
for parameter in parameters
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1115
|
+
if isinstance(parameter, Mapping) and isinstance(parameter.get("name"), str)
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
def _is_collected(source: Mapping[str, Any]) -> bool:
|
|
1120
|
+
"""Whether Studio's shared fetch lane collects this source's bytes.
|
|
1121
|
+
|
|
1122
|
+
Five members of the document decide it: the adapter is exactly ``public.https``, the connector
|
|
1123
|
+
names no credential, the locator is an https URL, the classification is ``public`` and the
|
|
1124
|
+
rights basis is ``public_domain_asserted``. The worker reads these five
|
|
1125
|
+
(``hosted_run_worker._uses_collected_source_fetch``, beside a ``window`` and what the job
|
|
1126
|
+
delegated) and so does Studio's route matrix. A ``public.https`` source that fails one of them
|
|
1127
|
+
is not collected. Collected is not staged: that is :func:`_is_staged`'s question.
|
|
1128
|
+
|
|
1129
|
+
⚠ THE FIVE ARE HELD TO THE WORKER'S, not merely to this docstring:
|
|
1130
|
+
``tests/test_thin_worker_contract_constants.py`` reads the members that function compares and
|
|
1131
|
+
fails when they change.
|
|
1132
|
+
"""
|
|
1133
|
+
|
|
1134
|
+
connector = source.get("connector")
|
|
1135
|
+
locator = source.get("locator")
|
|
1136
|
+
rights = source.get("rights_claim")
|
|
1137
|
+
return (
|
|
1138
|
+
isinstance(connector, Mapping)
|
|
1139
|
+
and connector.get("adapter_id") == "public.https"
|
|
1140
|
+
and connector.get("credential_mode") == "none"
|
|
1141
|
+
and isinstance(locator, Mapping)
|
|
1142
|
+
and locator.get("kind") == "https_url"
|
|
1143
|
+
and source.get("data_classification") == "public"
|
|
1144
|
+
and isinstance(rights, Mapping)
|
|
1145
|
+
and rights.get("claimed_basis") == "public_domain_asserted"
|
|
1146
|
+
)
|
|
1147
|
+
|
|
1148
|
+
|
|
1149
|
+
def _reads_ndjson(options: Any) -> bool:
|
|
1150
|
+
"""Whether a ``reader.decode_options`` value, a JSON text, says ``document_format: "ndjson"``.
|
|
1151
|
+
|
|
1152
|
+
``json.tabular`` has a file decoder only for newline-delimited documents
|
|
1153
|
+
(``acquisition.file_decoding.file_decode_supported``), and its ``document_format`` defaults to
|
|
1154
|
+
``json``. Text that is not canonical JSON, or not an object, reads as not ndjson: the server
|
|
1155
|
+
validates the options, and this only decides which ceiling to name.
|
|
1156
|
+
|
|
1157
|
+
⚠ IT MUST NOT RAISE, because it runs before the server has been asked and the preflight lets
|
|
1158
|
+
a long, hostile-looking pin through: the schema admits 262,144 characters. The parser refuses
|
|
1159
|
+
most bad text with its own error, but text nested a few thousand levels deep escapes it as a
|
|
1160
|
+
``RecursionError`` and an integer of more than 4,300 digits as a ``ValueError``, and either
|
|
1161
|
+
would turn a registration into ``THIN_COMMAND_FAILED`` before Studio could say what is wrong.
|
|
1162
|
+
"""
|
|
1163
|
+
|
|
1164
|
+
if not isinstance(options, str):
|
|
1165
|
+
return False
|
|
1166
|
+
try:
|
|
1167
|
+
stated = parse_json(options)
|
|
1168
|
+
except (RecursionError, ValueError):
|
|
1169
|
+
# `CanonicalJSONError` is a `ValueError`, so this is the parser's own refusal as well.
|
|
1170
|
+
return False
|
|
1171
|
+
return isinstance(stated, Mapping) and stated.get("document_format") == "ndjson"
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
def _is_staged(source: Mapping[str, Any], stated: Mapping[Any, Any]) -> bool:
|
|
1175
|
+
"""Whether a run reads this source from a file staged on the scratch disk, not from memory.
|
|
1176
|
+
|
|
1177
|
+
ADR 0099 stages a COLLECTED object (:func:`_is_collected`) and decodes it from that file, on
|
|
1178
|
+
two more conditions the document states. The source is read whole, so it has no ``window``
|
|
1179
|
+
member: a windowed read is fetched a window at a time. And it is either unpinned -- ``csv`` and
|
|
1180
|
+
``ndjson`` stage -- or pinned to a Reader with a file decoder (:data:`FILE_DECODER_COORDINATES`,
|
|
1181
|
+
and ``json.tabular`` only when it reads ``ndjson``). A pin to any other Reader is decoded from
|
|
1182
|
+
bytes held in memory, however the source is collected. The table also holds the ranged Parquet
|
|
1183
|
+
coordinate; :func:`_source_byte_ceiling` has already given that pin its own ceiling.
|
|
1184
|
+
|
|
1185
|
+
⚠ A DOCUMENT-LEVEL ANSWER, FOR THE FULL READ. What a run holds is not in the document: a
|
|
1186
|
+
scratch disk, and a truncating row clamp (a sample), which is read whole and never staged. A
|
|
1187
|
+
source this calls staged is staged by a full run, and that is the read the ceiling is warned
|
|
1188
|
+
against.
|
|
1189
|
+
"""
|
|
1190
|
+
|
|
1191
|
+
if not _is_collected(source) or source.get("window") is not None:
|
|
1192
|
+
return False
|
|
1193
|
+
if "reader.family_id" not in stated:
|
|
1194
|
+
return True
|
|
1195
|
+
family = stated.get("reader.family_id")
|
|
1196
|
+
version = stated.get("reader.family_version")
|
|
1197
|
+
# A value the schema refuses (a list, a number) is not a coordinate: it must not reach the
|
|
1198
|
+
# table, where an unhashable one would raise before the server could answer with its 422.
|
|
1199
|
+
if not isinstance(family, str) or not isinstance(version, str):
|
|
1200
|
+
return False
|
|
1201
|
+
if (family, version) not in FILE_DECODER_COORDINATES:
|
|
1202
|
+
return False
|
|
1203
|
+
return family != "json.tabular" or _reads_ndjson(stated.get("reader.decode_options"))
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
def _source_byte_ceiling(
|
|
1207
|
+
source: Mapping[str, Any], *, execution_policy: Any = None
|
|
1208
|
+
) -> tuple[int, str, str] | None:
|
|
1209
|
+
"""Where fetching one declared source stops, the phrase that names it, and what stops sooner.
|
|
1210
|
+
|
|
1211
|
+
``None`` when nothing but the declared number does: a staged read under
|
|
1212
|
+
``bounded-streaming.v1``.
|
|
1213
|
+
|
|
1214
|
+
A document declares a Reader pin on ``connector.parameters`` and declares no wire format at
|
|
1215
|
+
all: the format is what the response turns out to be. So what this client reads off the
|
|
1216
|
+
document is the ROUTE a source takes, and whether it is pinned, and to what. A ranged Parquet
|
|
1217
|
+
pin bounds the bytes its ranged read fetches, at the ranged ceiling; that read is never
|
|
1218
|
+
staged, so it is checked first. A staged source is read to the staged ceiling. Every other
|
|
1219
|
+
source is held to the whole-read cap here, pinned or not, and the sentence says which unpinned
|
|
1220
|
+
formats stop earlier, because that is decided by bytes this client has not seen.
|
|
1221
|
+
|
|
1222
|
+
The third member is that sentence, because which formats stop sooner depends on the route: a
|
|
1223
|
+
staged unpinned ``csv`` or ``ndjson`` source is read from the file, so only ``json`` and
|
|
1224
|
+
``parquet`` stop early; fetched whole, ``ndjson`` stops early as well.
|
|
1225
|
+
"""
|
|
1226
|
+
|
|
1227
|
+
stated = _stated_parameters(source)
|
|
1228
|
+
whole_read_sooner = (
|
|
1229
|
+
f"An unpinned source that answers ndjson stops at {NDJSON_SOURCE_BYTE_CEILING:,} and one "
|
|
1230
|
+
f"that answers json or parquet at {DRAINED_SOURCE_BYTE_CEILING:,}, and pinning a Reader "
|
|
1231
|
+
"is what moves it off those"
|
|
1232
|
+
)
|
|
1233
|
+
if (
|
|
1234
|
+
stated.get("reader.family_id"),
|
|
1235
|
+
stated.get("reader.family_version"),
|
|
1236
|
+
) == RANGED_READER_COORDINATE:
|
|
1237
|
+
return RANGED_READ_SOURCE_BYTE_CEILING, "a ranged Parquet read", whole_read_sooner
|
|
1238
|
+
if _is_staged(source, stated):
|
|
1239
|
+
if execution_policy == _BOUNDED_STREAMING_POLICY:
|
|
1240
|
+
return None
|
|
1241
|
+
return (
|
|
1242
|
+
STAGED_SOURCE_BYTE_CEILING,
|
|
1243
|
+
"a collected source's staged read",
|
|
1244
|
+
"An unpinned source that answers json or parquet stops at "
|
|
1245
|
+
f"{DRAINED_SOURCE_BYTE_CEILING:,}, and pinning a Reader is what moves it off that",
|
|
1246
|
+
)
|
|
1247
|
+
if "reader.family_id" in stated:
|
|
1248
|
+
return READER_SOURCE_BYTE_CEILING, "a Reader-pinned source's fetch", whole_read_sooner
|
|
1249
|
+
return READER_SOURCE_BYTE_CEILING, "an unpinned source's fetch", whole_read_sooner
|
|
1034
1250
|
|
|
1035
1251
|
|
|
1036
1252
|
def columns_without_description(table: Any) -> list[str]:
|
|
@@ -1253,7 +1469,9 @@ def register(
|
|
|
1253
1469
|
undescribed = columns_without_description(document.get("table"))
|
|
1254
1470
|
uncontinued = sources_without_continuation(document.get("sources"))
|
|
1255
1471
|
declared_sources = document.get("sources")
|
|
1256
|
-
warnings = source_byte_warnings(
|
|
1472
|
+
warnings = source_byte_warnings(
|
|
1473
|
+
declared_sources, execution_policy=document.get("execution_policy")
|
|
1474
|
+
)
|
|
1257
1475
|
warnings += continuation_warnings(
|
|
1258
1476
|
uncontinued, len(declared_sources) if isinstance(declared_sources, list) else 0
|
|
1259
1477
|
)
|
|
@@ -1614,7 +1832,9 @@ def readiness(
|
|
|
1614
1832
|
recipe_id = identifier(recipe_id, "recipe identifier")
|
|
1615
1833
|
if client is None:
|
|
1616
1834
|
sessions = sessions or open_renewable_session(resolve_cloud_credentials())
|
|
1617
|
-
selected = StudioV4DatasetClient(
|
|
1835
|
+
selected = StudioV4DatasetClient(
|
|
1836
|
+
sessions.session, transport=UrlLibTransport(timeout=READINESS_REQUEST_TIMEOUT_SECONDS)
|
|
1837
|
+
)
|
|
1618
1838
|
else:
|
|
1619
1839
|
selected = client
|
|
1620
1840
|
sessions = sessions or sessions_for(selected.session)
|
|
@@ -2015,6 +2235,7 @@ __all__ = [
|
|
|
2015
2235
|
"COMMAND_HELP",
|
|
2016
2236
|
"DRAINED_SOURCE_BYTE_CEILING",
|
|
2017
2237
|
"EXPLAIN",
|
|
2238
|
+
"FILE_DECODER_COORDINATES",
|
|
2018
2239
|
"FIRST_READINESS_RETRY_SECONDS",
|
|
2019
2240
|
"FORECAST",
|
|
2020
2241
|
"MAX_DOCUMENT_BYTES",
|
|
@@ -2028,6 +2249,8 @@ __all__ = [
|
|
|
2028
2249
|
"NDJSON_SOURCE_BYTE_CEILING",
|
|
2029
2250
|
"PROPOSE",
|
|
2030
2251
|
"PROPOSE_SCHEMA",
|
|
2252
|
+
"RANGED_READER_COORDINATE",
|
|
2253
|
+
"RANGED_READ_SOURCE_BYTE_CEILING",
|
|
2031
2254
|
"READER_SOURCE_BYTE_CEILING",
|
|
2032
2255
|
"READINESS",
|
|
2033
2256
|
"READINESS_FILTERS_SINCE",
|
|
@@ -2037,6 +2260,7 @@ __all__ = [
|
|
|
2037
2260
|
"REQUIRED_DOCUMENT_MEMBERS",
|
|
2038
2261
|
"SHOW",
|
|
2039
2262
|
"SHOW_SCHEMA",
|
|
2263
|
+
"STAGED_SOURCE_BYTE_CEILING",
|
|
2040
2264
|
"TEST",
|
|
2041
2265
|
"UNREFRESHABLE_PLAN_TAIL",
|
|
2042
2266
|
"SampleSpan",
|
|
@@ -81,6 +81,9 @@ RECORDING_CONTINUATION_PENDING = "RECORDING_CONTINUATION_PENDING"
|
|
|
81
81
|
REFRESH_WORKER_UNAVAILABLE = "REFRESH_WORKER_UNAVAILABLE"
|
|
82
82
|
REBUILD_DISCARDS_SNAPSHOT_HISTORY = "REBUILD_DISCARDS_SNAPSHOT_HISTORY"
|
|
83
83
|
ROW_REQUEST_ANSWERS_NEVER_EXPIRE = "ROW_REQUEST_ANSWERS_NEVER_EXPIRE"
|
|
84
|
+
#: Contract 4.33.0 (planning#1337): a refresh whose predecessor is a sample a row or window clamp
|
|
85
|
+
#: cut short. It needs a sealed predecessor, so the mirror never claims it.
|
|
86
|
+
PREDECESSOR_TRUNCATED = "PREDECESSOR_TRUNCATED"
|
|
84
87
|
|
|
85
88
|
RULE_CODES: tuple[str, ...] = (
|
|
86
89
|
NO_SEALED_PREDECESSOR,
|
|
@@ -98,10 +101,11 @@ RULE_CODES: tuple[str, ...] = (
|
|
|
98
101
|
REFRESH_WORKER_UNAVAILABLE,
|
|
99
102
|
REBUILD_DISCARDS_SNAPSHOT_HISTORY,
|
|
100
103
|
ROW_REQUEST_ANSWERS_NEVER_EXPIRE,
|
|
104
|
+
PREDECESSOR_TRUNCATED,
|
|
101
105
|
)
|
|
102
106
|
|
|
103
107
|
#: The codes the mirror can observe from a document alone, and so the codes a disagreement is
|
|
104
|
-
#: judged over. The other
|
|
108
|
+
#: judged over. The other seven need a predecessor or the deployment (a sealed version, a table
|
|
105
109
|
#: format, a certified worker, a recording bookmark), and the mirror never claims them.
|
|
106
110
|
#: ``REFRESH_WORKER_UNAVAILABLE`` is judged only where it names sources: the snapshot fence, which
|
|
107
111
|
#: ``capabilities.snapshot_refresh`` states; the certified-worker case names none.
|
|
@@ -1249,8 +1253,11 @@ def explain_document_at_studio(
|
|
|
1249
1253
|
except ThinLaneError as refusal:
|
|
1250
1254
|
if route_unavailable(refusal):
|
|
1251
1255
|
return None
|
|
1252
|
-
keyless = [
|
|
1253
|
-
|
|
1256
|
+
keyless = [
|
|
1257
|
+
pointer
|
|
1258
|
+
for pointer, capability in gated_grammar(document)
|
|
1259
|
+
if capability == "keyless_window"
|
|
1260
|
+
]
|
|
1254
1261
|
if keyless and getattr(refusal, "http_status", None) == 422:
|
|
1255
1262
|
# Older API schemas reject the document before they can answer capabilities.
|
|
1256
1263
|
# A schema rejection is never evidence that this grammar is served.
|
|
@@ -1393,9 +1400,7 @@ def registration_gate(client: StudioV4Client, document: Mapping[str, Any]) -> li
|
|
|
1393
1400
|
return grammar_gate(document, answer)
|
|
1394
1401
|
|
|
1395
1402
|
|
|
1396
|
-
def grammar_gate(
|
|
1397
|
-
document: Mapping[str, Any], answer: Mapping[str, Any] | None
|
|
1398
|
-
) -> list[str]:
|
|
1403
|
+
def grammar_gate(document: Mapping[str, Any], answer: Mapping[str, Any] | None) -> list[str]:
|
|
1399
1404
|
"""Admit only grammar explicitly served by an explanation; perform no writes."""
|
|
1400
1405
|
|
|
1401
1406
|
gated = gated_grammar(document)
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/transport.py
RENAMED
|
@@ -105,7 +105,9 @@ class UrlLibTransport:
|
|
|
105
105
|
under a two-second clock for the same reason. Two clients pass a LONGER one, because each calls
|
|
106
106
|
a Cloud route that waits on Studio before it answers: ``v4_public.PublicQueryClient`` (a public
|
|
107
107
|
query) and ``v4_artifacts.CloudArtifactSessionClient`` (the metered signed-read mints, where
|
|
108
|
-
Cloud allows Studio sixty seconds)
|
|
108
|
+
Cloud allows Studio sixty seconds), and ``recipe readiness`` waits five minutes for a page
|
|
109
|
+
Studio evaluates revision by revision. Others pass their own clocks too; read each caller's
|
|
110
|
+
constant.
|
|
109
111
|
|
|
110
112
|
⚠ AND IT MAY BE A CALLABLE, WHICH IS THE SAME PARAMETER SAYING A DIFFERENT KIND OF THING. A
|
|
111
113
|
constant bounds each request separately, so N requests cost N times the clock; a callable is
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_stream.py
RENAMED
|
@@ -255,8 +255,9 @@ def watch(
|
|
|
255
255
|
rates = RateTracker()
|
|
256
256
|
|
|
257
257
|
def _observe(body: Mapping[str, Any], frame_name: str) -> bool:
|
|
258
|
-
nonlocal seen_any
|
|
258
|
+
nonlocal seen_any, quiet_since
|
|
259
259
|
seen_any = True
|
|
260
|
+
quiet_since = clock()
|
|
260
261
|
if announce:
|
|
261
262
|
print(render_v4_frame(body, frame_name), flush=True)
|
|
262
263
|
moved = rates.observe(body)
|
|
@@ -271,10 +272,20 @@ def watch(
|
|
|
271
272
|
|
|
272
273
|
def _quiet() -> bool:
|
|
273
274
|
# Asked on every heartbeat of a quiet stream. Never stops the watch; it only says, once
|
|
274
|
-
# per quiet
|
|
275
|
+
# per quiet interval, what was (and was not) observed. Heartbeats prove only
|
|
276
|
+
# stream connectivity, never worker liveness or progress.
|
|
275
277
|
nonlocal quiet_since
|
|
276
278
|
now = clock()
|
|
277
|
-
if announce and
|
|
279
|
+
if announce and now - quiet_since >= QUIET_NOTE_SECONDS:
|
|
280
|
+
if seen_any:
|
|
281
|
+
print(
|
|
282
|
+
f"no new progress report for {int(now - quiet_since)} seconds: "
|
|
283
|
+
"work may still be running; stream connectivity is not worker progress; "
|
|
284
|
+
"ETA unknown",
|
|
285
|
+
flush=True,
|
|
286
|
+
)
|
|
287
|
+
quiet_since = now
|
|
288
|
+
return False
|
|
278
289
|
waited = int(now - started)
|
|
279
290
|
print(
|
|
280
291
|
f"nothing reported yet after {waited} seconds: the run was {run.get('status')} "
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/boundaries.md
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/commands.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/live-run.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/one-install.md
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/patterns.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/promote.md
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/readers.md
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/receipts.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/sources.md
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/skills/mr-data-build/references/transforms.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/agent_protocol.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/canonical.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/key_seam.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/page_coverage.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/session_probes.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/skill_assets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/table_manifest.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/acquire.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/activity.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/approvals.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/backoff.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/categories.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/commands.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/download.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/narrative.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/parity.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/probe.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/propose.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe_lint.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/recipe_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/research.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/router.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/run_prefix.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/runs.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/session.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/stream.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/support.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/user_agent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_catalog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_datasets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_handoff.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_public.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_query.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_reader.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_runs.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_search.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_secrets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/v4_tables.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/thin/vocabulary.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/attendance.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/clarification.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/cloud_auth.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/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.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/credentials.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/login.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/path_kind.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/plain_file.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/remediation.py
RENAMED
|
File without changes
|
{mostlyright_data-0.30.4 → mostlyright_data-0.30.6}/src/mostlyright/data_harness/ux/render.py
RENAMED
|
File without changes
|