mostlyright-data 0.23.0__tar.gz → 0.24.0__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.23.0 → mostlyright_data-0.24.0}/PKG-INFO +28 -12
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/README.md +27 -11
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/pyproject.toml +1 -1
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/SKILL.md +3 -1
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/6-build-one-run-sized-to-acquire-every-measured-source-whole.md +14 -8
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/commands.md +17 -2
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/live-run.md +8 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/promote.md +10 -7
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/reference-pages.md +3 -2
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/sources.md +20 -13
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/page_coverage.py +4 -4
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/recipe.py +173 -6
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/router.py +5 -1
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/stream_venue.py +199 -8
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4.py +55 -6
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_runs.py +160 -16
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_tables.py +573 -14
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/render.py +26 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/.gitignore +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/scripts/hatch_build.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/agents/openai.yaml +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/1-open-the-page-and-the-link-to-it-in-the-first-message.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/2-brief-two-to-four-questions-each-with-a-recommended-answer.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/3-probe-read-a-source-before-committing-to-it.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/4-decide-say-what-you-chose-what-you-refused-and-ask-one-question.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/5-draft-one-recipe-document-one-call.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/7-interrogate-ask-the-run-what-it-actually-delivered.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/8-fix-revise-the-document-and-register-it-again.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/9-present-only-what-survived-inspection-with-caveats.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/agent-protocol.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/autonomous-delivery.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/before-the-first-tool-call.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/boundaries.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/cloud-authentication-preflight.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/cross-repository-protocol-reference.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/installation-parity.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/narrating-the-run.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/not-hosted-yet.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/one-install.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/prediction-labels.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/readers.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/receipts.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/recording-a-stream-venue.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/recovering-an-import-failure.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/required-protocol.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/source-credentials.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/the-one-thing-to-say-about-the-skill-itself.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/transforms.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/user-communication-contract.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/writing-a-decision-record.md +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/scripts/write_research_notebook.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/__init__.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/agent_protocol.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/canonical.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/formats.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/key_seam.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/part_check_evidence.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/session_probes.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/skill_assets.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/table_manifest.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/__init__.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/acquire.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/activity.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/approvals.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/categories.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/commands.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/dataset-categories-v1.json +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/download.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/narrative.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/parity.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/probe.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/progress_vocabulary.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/propose.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/recipe_brief.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/recipe_lint.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/research.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/runs.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/session.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/stream.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/transport.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/user_agent.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_artifacts.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_catalog.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_connections.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_dataset_covers.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_datasets.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_handoff.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_narrative.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_query.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_reader.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_secrets.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/v4_stream.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/__init__.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/attendance.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/clarification.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/commands/clarify.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/credentials.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/login.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
- {mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/ux/remediation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mostlyright-data
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.24.0
|
|
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/
|
|
@@ -89,6 +89,17 @@ can reissue supported platform execution failures without changing the recipe.
|
|
|
89
89
|
|
|
90
90
|
Use the identifiers returned by registration and run submission. `mr-data dataset create`
|
|
91
91
|
creates a dataset page before a recipe is ready. `mr-data watch RUN_ID` follows a submitted run.
|
|
92
|
+
A scheduled refresh runs only Studio's persisted bounded source-action plan; it never silently
|
|
93
|
+
falls back to a mutable whole-source fetch. `mr-data table resync TABLE_ID --request-id UUID`
|
|
94
|
+
explicitly requests a full source reread when that is needed. Choose and retain the UUID before
|
|
95
|
+
submitting: if the response is lost, repeat that exact command with the same UUID rather than
|
|
96
|
+
starting another reread. A persisted spend hold is still an accepted resync: its receipt names
|
|
97
|
+
the run, projection and exact `mr-data run --confirm-held RUN_ID` action. If it is a sample-first
|
|
98
|
+
preview, confirm that preview first, then release its linked full
|
|
99
|
+
only after the preview succeeds. `mr-data recipe readiness` reads Studio's paginated,
|
|
100
|
+
immutable-revision inventory before a production-wide schedule sweep: predecessor,
|
|
101
|
+
incremental-materialization and differential-proof readiness, together with each source's next
|
|
102
|
+
action. It reports Studio's persisted facts; it does not authorize a schedule.
|
|
92
103
|
|
|
93
104
|
To request an offline replay of retained inputs with a registered revision:
|
|
94
105
|
|
|
@@ -100,16 +111,20 @@ Studio must have replay enabled and the named successful run must belong to the
|
|
|
100
111
|
its raw inputs still retained. Replay compares against that run and never becomes the live version.
|
|
101
112
|
Studio returns a typed refusal when replay is unavailable; the CLI does not fetch sources locally.
|
|
102
113
|
|
|
103
|
-
The hosted engine executes sample, full and refresh runs.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
The hosted engine executes sample, full and refresh runs. Studio's action classifier can name
|
|
115
|
+
closed-source reuse, request-window or collection acquisition, and recorded stream input, but the
|
|
116
|
+
current worker has only two executable normal-refresh materializers: an exact single direct
|
|
117
|
+
partition request-window plan with a compatible predecessor, and an all-recorded-stream plan.
|
|
118
|
+
Closed-only, collection, and mixed plans return `RESYNC_REQUIRED` before acquisition, as does a
|
|
119
|
+
mutable snapshot or other unwindowed source. Nothing is revalidated or re-acquired whole as an
|
|
120
|
+
implicit fallback. Use `mr-data table resync TABLE_ID --request-id UUID` when a deliberate full
|
|
121
|
+
source reread is intended, retaining that UUID through an uncertain response. URL windows may use
|
|
122
|
+
declared query parameters or path placeholders; a fixed date URL does not advance automatically.
|
|
123
|
+
Configure a correction lookback where the publisher can revise earlier observations.
|
|
124
|
+
|
|
125
|
+
A source exposing only its current snapshot cannot supply a historical delta. It is supported only
|
|
126
|
+
through an explicit table resync; refresh does not turn its whole current result into an
|
|
127
|
+
incremental update. Recorded streams use their registered capture and continuation semantics.
|
|
113
128
|
|
|
114
129
|
See [Recipe documents](docs/RECIPE-DOCUMENT.md) for source-window and bootstrap contracts.
|
|
115
130
|
A table's first succeeded run goes live on its own, whatever mode it was; `mr-data promote
|
|
@@ -135,7 +150,8 @@ worker executables or image publisher.
|
|
|
135
150
|
- [Recipe examples](https://mostlyright.md/docs/recipes/)
|
|
136
151
|
- [Join market settlements](https://mostlyright.md/docs/recipes/market-settlement-join/)
|
|
137
152
|
- [Compare a forecast with observations](https://mostlyright.md/docs/recipes/forecast-vs-observation/)
|
|
138
|
-
- [
|
|
153
|
+
- [Model a snapshot source](https://mostlyright.md/docs/recipes/snapshot-window/) — normal refresh
|
|
154
|
+
is unavailable until its bounded materializer ships; use explicit table resync today
|
|
139
155
|
- [Union many weather stations](https://mostlyright.md/docs/recipes/many-station-weather/)
|
|
140
156
|
- [Aggregate a stream into bars](https://mostlyright.md/docs/recipes/stream-to-bars/)
|
|
141
157
|
- [Use a public dataset](https://mostlyright.md/docs/guides/use-public-datasets/)
|
|
@@ -77,6 +77,17 @@ can reissue supported platform execution failures without changing the recipe.
|
|
|
77
77
|
|
|
78
78
|
Use the identifiers returned by registration and run submission. `mr-data dataset create`
|
|
79
79
|
creates a dataset page before a recipe is ready. `mr-data watch RUN_ID` follows a submitted run.
|
|
80
|
+
A scheduled refresh runs only Studio's persisted bounded source-action plan; it never silently
|
|
81
|
+
falls back to a mutable whole-source fetch. `mr-data table resync TABLE_ID --request-id UUID`
|
|
82
|
+
explicitly requests a full source reread when that is needed. Choose and retain the UUID before
|
|
83
|
+
submitting: if the response is lost, repeat that exact command with the same UUID rather than
|
|
84
|
+
starting another reread. A persisted spend hold is still an accepted resync: its receipt names
|
|
85
|
+
the run, projection and exact `mr-data run --confirm-held RUN_ID` action. If it is a sample-first
|
|
86
|
+
preview, confirm that preview first, then release its linked full
|
|
87
|
+
only after the preview succeeds. `mr-data recipe readiness` reads Studio's paginated,
|
|
88
|
+
immutable-revision inventory before a production-wide schedule sweep: predecessor,
|
|
89
|
+
incremental-materialization and differential-proof readiness, together with each source's next
|
|
90
|
+
action. It reports Studio's persisted facts; it does not authorize a schedule.
|
|
80
91
|
|
|
81
92
|
To request an offline replay of retained inputs with a registered revision:
|
|
82
93
|
|
|
@@ -88,16 +99,20 @@ Studio must have replay enabled and the named successful run must belong to the
|
|
|
88
99
|
its raw inputs still retained. Replay compares against that run and never becomes the live version.
|
|
89
100
|
Studio returns a typed refusal when replay is unavailable; the CLI does not fetch sources locally.
|
|
90
101
|
|
|
91
|
-
The hosted engine executes sample, full and refresh runs.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
The hosted engine executes sample, full and refresh runs. Studio's action classifier can name
|
|
103
|
+
closed-source reuse, request-window or collection acquisition, and recorded stream input, but the
|
|
104
|
+
current worker has only two executable normal-refresh materializers: an exact single direct
|
|
105
|
+
partition request-window plan with a compatible predecessor, and an all-recorded-stream plan.
|
|
106
|
+
Closed-only, collection, and mixed plans return `RESYNC_REQUIRED` before acquisition, as does a
|
|
107
|
+
mutable snapshot or other unwindowed source. Nothing is revalidated or re-acquired whole as an
|
|
108
|
+
implicit fallback. Use `mr-data table resync TABLE_ID --request-id UUID` when a deliberate full
|
|
109
|
+
source reread is intended, retaining that UUID through an uncertain response. URL windows may use
|
|
110
|
+
declared query parameters or path placeholders; a fixed date URL does not advance automatically.
|
|
111
|
+
Configure a correction lookback where the publisher can revise earlier observations.
|
|
112
|
+
|
|
113
|
+
A source exposing only its current snapshot cannot supply a historical delta. It is supported only
|
|
114
|
+
through an explicit table resync; refresh does not turn its whole current result into an
|
|
115
|
+
incremental update. Recorded streams use their registered capture and continuation semantics.
|
|
101
116
|
|
|
102
117
|
See [Recipe documents](docs/RECIPE-DOCUMENT.md) for source-window and bootstrap contracts.
|
|
103
118
|
A table's first succeeded run goes live on its own, whatever mode it was; `mr-data promote
|
|
@@ -123,7 +138,8 @@ worker executables or image publisher.
|
|
|
123
138
|
- [Recipe examples](https://mostlyright.md/docs/recipes/)
|
|
124
139
|
- [Join market settlements](https://mostlyright.md/docs/recipes/market-settlement-join/)
|
|
125
140
|
- [Compare a forecast with observations](https://mostlyright.md/docs/recipes/forecast-vs-observation/)
|
|
126
|
-
- [
|
|
141
|
+
- [Model a snapshot source](https://mostlyright.md/docs/recipes/snapshot-window/) — normal refresh
|
|
142
|
+
is unavailable until its bounded materializer ships; use explicit table resync today
|
|
127
143
|
- [Union many weather stations](https://mostlyright.md/docs/recipes/many-station-weather/)
|
|
128
144
|
- [Aggregate a stream into bars](https://mostlyright.md/docs/recipes/stream-to-bars/)
|
|
129
145
|
- [Use a public dataset](https://mostlyright.md/docs/guides/use-public-datasets/)
|
|
@@ -77,7 +77,9 @@ merely to obtain a green run. Read [recovery details](references/agent-protocol.
|
|
|
77
77
|
9. Any truncated source means a preview, not the requested complete dataset. Inspect coverage
|
|
78
78
|
even when the run succeeded. A null coverage window does not mean all history was acquired.
|
|
79
79
|
Repair only evidenced faults on the same dataset/table and verify the revision again.
|
|
80
|
-
Record cadence only when authorized
|
|
80
|
+
Record cadence only when authorized and `mr-data recipe readiness --json` reports the current
|
|
81
|
+
revision refresh-ready. A blocked mutable snapshot requires an explicit table resync, not a
|
|
82
|
+
scheduled whole-source fallback. Do not promise freshness without evidence.
|
|
81
83
|
Download and verify artifacts when the user requested bytes.
|
|
82
84
|
10. Report rows and coverage actually verified, checks, limitations and the stable dataset link.
|
|
83
85
|
Read [delivery](references/9-present-only-what-survived-inspection-with-caveats.md) for details.
|
|
@@ -181,11 +181,17 @@ the record — `mr-data run --recipe RECIPE_ID --digest RECIPE_DIGEST --full --c
|
|
|
181
181
|
held answer prints back as `confirm_command`. Any authenticated surface of the paying workspace may
|
|
182
182
|
settle it. `mr-data run --cancel RUN_ID` stops a run that is queued or running.
|
|
183
183
|
|
|
184
|
-
Do not treat the accepted command vocabulary as execution evidence.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
184
|
+
Do not treat the accepted command vocabulary as execution evidence. Before proposing a schedule,
|
|
185
|
+
classify every source under one truthful continuation strategy and record the supporting evidence.
|
|
186
|
+
Current normal refresh materializes only an exact single direct `window.request` source with a
|
|
187
|
+
compatible partitioned predecessor, or an all-recorded-stream recipe. The classifier may name
|
|
188
|
+
closed reuse or collection continuation, but closed-only, collection-only, and mixed plans return
|
|
189
|
+
`RESYNC_REQUIRED` before acquisition because their bounded table materializers do not exist yet. A
|
|
190
|
+
`window.snapshot` or unwindowed mutable source is likewise resync-only. Explicit resync is full,
|
|
191
|
+
has no predecessor, and a collection starts from the beginning. Never hide one behind conditional
|
|
192
|
+
revalidation, generic pagination, or a whole-source comparison. Research publisher cursors,
|
|
193
|
+
revision identities, listings, corrections, and deletions, but use only deployed recipe grammar
|
|
194
|
+
that represents the proven strategy. For each incremental source, record the affected key or
|
|
195
|
+
partition and a fixture proving
|
|
196
|
+
that applying its delta to the predecessor produces the same rows as a full build over
|
|
197
|
+
predecessor-plus-delta. A `backfill` may be refused before acquisition; the refusal says so.
|
{mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/commands.md
RENAMED
|
@@ -14,7 +14,7 @@ gap rather than doing anything, and `export-hosted-candidate`, which is a backen
|
|
|
14
14
|
| `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; a saved write whose public sync fails exits 2 and reports `public_projection_synced: false` — use `dataset sync ID` to retry that sync without rewriting Studio; `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. |
|
|
15
15
|
| `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. The document is read first and every fault comes back in one refusal, each with the JSON pointer that names it; `--no-lint` sends it as written instead. Registration refuses `THIN_BRIEF_MISSING` when the dataset's record carries no answered question and no delegation, and `THIN_RECIPE_DATASET_UNBOUND` when the document names no `dataset.id`; `--delegated "their words"` writes the delegation onto the dataset and registers in the same command, and clears the first of those two and never the second. `mr-data recipe show ID` reads one back. |
|
|
16
16
|
| `mr-data cover` | Generate and attach one branded 1200×630 dataset cover. Give it the dataset ID and what the image should depict; Studio fixes the model, single-color style, curated random palette, dimensions and storage. |
|
|
17
|
-
| `mr-data run` | Start one run against a registered recipe, named as `--recipe RECIPE_ID --digest RECIPE_DIGEST` — both required, neither positional, and the digest is the bare hex the registration receipt printed. The mode is one of six: `sample`, `full`, `refresh`, `backfill`, `compact` and `replay`. Four have a shorthand flag (`--sample`, `--full`, `--refresh`, `--backfill`) and two do not, so write `--mode MODE`, which is accepted for every one of them. A refresh
|
|
17
|
+
| `mr-data run` | Start one run against a registered recipe, named as `--recipe RECIPE_ID --digest RECIPE_DIGEST` — both required, neither positional, and the digest is the bare hex the registration receipt printed. The mode is one of six: `sample`, `full`, `refresh`, `backfill`, `compact` and `replay`. Four have a shorthand flag (`--sample`, `--full`, `--refresh`, `--backfill`) and two do not, so write `--mode MODE`, which is accepted for every one of them. A refresh executes only Studio's persisted strict source-action plan. Although the classifier may name closed reuse, a request-window or collection delta, or recorded input, current normal refresh materializes only an exact single direct partition request-window plan with a compatible predecessor, or an all-recorded-stream plan. Closed-only, collection, mixed, snapshot, and unwindowed plans return `RESYNC_REQUIRED` before acquisition. Use `mr-data table resync TABLE_ID --request-id UUID` for an explicit full source reread, retaining that UUID if the response is uncertain. `--backfill` states the exact window with `--window START END`. `--mode replay --sources-from RUN_ID` asks Studio to run the registered revision against the RETAINED RAW INPUTS of one named successful run of the same table: nothing is fetched from this computer, nothing is acquired again, the result is compared against that run and never becomes the live version, and it neither asks for nor records an approval. Where Studio has replay switched off, or the named run is not successful, not the same table, or no longer retains its inputs, it answers a typed refusal — report the code rather than retrying in another mode. `--sources-from` on any other mode is refused `THIN_ARGUMENT_INVALID` before anything is sent. `--max-rows` and `--max-source-bytes` bound ONE SOURCE rather than the finished table. A large run is held for a spend confirmation, which `--confirm` settles and whose printed `confirm_command` re-states every argument the request carried. `--approve-full RUN_ID` releases the full a sample-first pair is holding once its preview has succeeded, naming either half of the pair; where the deployment still wants a person at a browser it answers `THIN_INTERACTIVE_HUMAN_REQUIRED` and names the run page. `--retry RUN_ID` tries one failed run again when its triple carries `room_fault: true`, re-stating that run's own coordinate under a byte ceiling that cannot narrow it, and refuses with the triple when the recipe was at fault. `--cancel RUN` stops one. |
|
|
18
18
|
| `mr-data status` | Report which of the seven states one run is in, what it delivered and whether a ceiling cut it short, and — on a failure — what failed, where, and whether the fault was the execution room's rather than the recipe's. Exits non-zero on a failed run. |
|
|
19
19
|
| `mr-data runs` | Report this workspace's own runs: identifier, mode, state and creation time, plus the failure triple of any that failed and whether that failure was the execution room's. `--status` and `--mode` narrow it and are refused `THIN_ARGUMENT_INVALID` for a word outside the seven states or the six modes; `--limit` says how many, and pages are followed to reach it. A narrow filter over a workspace of thousands of runs reads a long way to find its matches, and a listing that does not end says how many were read and suggests a smaller `--limit`. |
|
|
20
20
|
| `mr-data watch` | Stream one run's live progress under the durable event type of each stage, resuming across stream cuts. Exits non-zero when the run failed. |
|
|
@@ -29,7 +29,7 @@ gap rather than doing anything, and `export-hosted-candidate`, which is a backen
|
|
|
29
29
|
| `mr-data diff` | Compare two runs and say what changed. |
|
|
30
30
|
| `mr-data connections` | List saved workspace connections and their current recipe coordinates; `--dataset ID` filters to connections granted to that dataset. No credential values are returned. |
|
|
31
31
|
| `mr-data keys` | Enrol a source credential by name, list the names with their created and rotated times, and delete one. `keys set` reads the value from a file or from standard input and never from the command line; no command prints a value back. |
|
|
32
|
-
| `mr-data stream` | Record a public `wss://` venue so a build can read it. `stream document register --file F` admits the connector document, `stream registry create --digest D` admits a set of them, `stream probe` listens briefly and seals nothing, `stream capture --seconds N` records a bounded window, `stream subscribe` keeps recording
|
|
32
|
+
| `mr-data stream` | Record a public `wss://` venue so a build can read it. `stream document register --file F` admits the connector document, `stream registry create --digest D` admits a set of them, `stream probe` listens briefly and seals nothing, `stream capture --seconds N` records a bounded window, and `stream subscribe` keeps recording. `stream subscription {show|pause|resume|stop} ID` retains the legacy full-record interface. `stream subscription quiescence ID` reads the bounded server-computed proof; `pause-cas` and `resume-cas` read its ETag and make one conditional bounded write. An ambiguous CAS failure is not retried until a fresh invocation observes the resource again. `stream status ID` reads a capture or probe, and `stream recordings --document-digest D` names what a build could read and until when. `--seconds` is at most 600. `mr-data run` takes no duration: a build reads sealed batches and is bounded by them. |
|
|
33
33
|
| `mr-data open` | Mint a single-use, short-lived address that continues this session in a browser at one dashboard path, and print it. `--open` hands it to the platform opener. The credential decides who mints: a device credential — what `mr-data login` stores — mints at Cloud, and a personal access token mints at Studio. |
|
|
34
34
|
| `mr-data promote` | Record the cadence one table refreshes on and the reasoning behind it. A table's first succeeded run goes live on its own, so this is not what makes it readable; it is idempotent on a table that is already live, and it is how a withdrawn table is put back. The Harness worker does not perform the catch-up or scheduled refresh; report those only when another deployed component returns durable evidence that it did. |
|
|
35
35
|
| `mr-data reschedule` | Change how often one live table refreshes, without the demote and promote that would reset its bookkeeping and buy a catch-up run. `--cadence` takes a cron expression or an interval such as `every 6h`; `--why` records the reasoning. It starts no run. `--lock` freezes the schedule so Studio stops adjusting it; `--unlock` lets it follow the source again. |
|
|
@@ -38,6 +38,21 @@ gap rather than doing anything, and `export-hosted-candidate`, which is a backen
|
|
|
38
38
|
| `mr-data unpin` | Ask Studio to resume pointer tracking; read the returned state before claiming it resumed. |
|
|
39
39
|
| `mr-data demote` | Ask Studio to withdraw the pointer and any schedule it owns, for one table or for as many as you name: `demote TABLE [TABLE ...]` withdraws them one after another, attempts every one of them whatever the one before it answered, prints a line for each, and exits non-zero if any is still live. Pair it with `table archive` when you are retiring a set: a live table cannot be archived, so it is withdraw-then-archive, two commands rather than a loop. |
|
|
40
40
|
|
|
41
|
+
### Strict refresh controls
|
|
42
|
+
|
|
43
|
+
`mr-data recipe readiness` pages Studio's immutable-revision inventory and reports predecessor,
|
|
44
|
+
incremental-materialization, and differential-proof readiness, every source's classified next
|
|
45
|
+
action, and blocking source names. It reads persisted facts; it does not authorize a schedule.
|
|
46
|
+
|
|
47
|
+
A refresh executes only Studio's persisted source-action plan. The classifier may name closed
|
|
48
|
+
reuse, a request window or collection delta, or recorded input, but current normal refresh
|
|
49
|
+
materializes only an exact single direct partition request-window plan with a compatible
|
|
50
|
+
predecessor, or an all-recorded-stream plan. Closed-only, collection, mixed, snapshot, and
|
|
51
|
+
unwindowed plans return `RESYNC_REQUIRED` before acquisition. `mr-data table resync TABLE --request-id UUID` is the explicit
|
|
52
|
+
full reread; retain and reuse the caller-generated UUID after a lost response. A held resync receipt
|
|
53
|
+
prints `mr-data run --confirm-held RUN_ID` for that exact run. A sample-first resync instead uses
|
|
54
|
+
`--approve-full` only after its preview succeeds.
|
|
55
|
+
|
|
41
56
|
`auth`, `login`, `whoami` and `clarify` are the same implementation in both profiles, and
|
|
42
57
|
`clarify` alone reaches nothing at all. The other twenty-eight answer from Studio. Twelve only
|
|
43
58
|
read: `status`, `runs`, `watch`, `peek`, `receipt`, `checks`, `download`, `verify`, `parts`,
|
{mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/live-run.md
RENAMED
|
@@ -57,6 +57,14 @@ full of a sample-first pair: its bounded preview must seal a downloadable table
|
|
|
57
57
|
though it could. Keep the raw state internal: say what product decision is needed and give the
|
|
58
58
|
person the single action that lets the build continue.
|
|
59
59
|
|
|
60
|
+
**`build_scope` says what the build covers, not what it is doing.** A `failed` or `cancelled` run
|
|
61
|
+
covers nothing and says so. A `succeeded` one reports what `coverage.truncated` recorded. Anything
|
|
62
|
+
else states the bound it ran under — a `sample` its ceilings, a `full` the whole dataset, and a
|
|
63
|
+
`full` at `awaiting_sample_approval` the whole dataset plus the preview it waits on. The mode
|
|
64
|
+
alone never establishes a truncation, which is the rule reference 6 states: a sample sized above
|
|
65
|
+
every measured source cut nothing and is the build. It is absent on `refresh`, `backfill`,
|
|
66
|
+
`compact` and `replay`, and it is never evidence that a run is executing; `status` is.
|
|
67
|
+
|
|
60
68
|
**A failed run always carries the same three members** — `failure_code`, `failure_detail` and
|
|
61
69
|
`failed_stage` — on three surfaces: the run record, the terminal event on the stream, and every
|
|
62
70
|
refusal a command raises about it. `mr-data status` and `mr-data runs` add a fourth reading beside
|
{mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/promote.md
RENAMED
|
@@ -44,13 +44,16 @@ Studio stops adjusting it, which is how a person overrides the evidence; `--unlo
|
|
|
44
44
|
the source again. Do not lock a schedule on your own judgement — it is the same kind of decision as
|
|
45
45
|
the cadence itself, and it belongs to the user.
|
|
46
46
|
|
|
47
|
-
This call records a schedule; it is not proof of data continuation.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
This call records a schedule; it is not proof of data continuation. Schedule only a current recipe
|
|
48
|
+
that `mr-data recipe readiness --json` reports as refresh-ready. Studio must have a persisted bounded
|
|
49
|
+
action for every source. The classifier may name closed reuse, a request-window or collection
|
|
50
|
+
delta, or recorded stream input, but current normal refresh executes only an exact single direct
|
|
51
|
+
partition request-window plan with a compatible predecessor, or an all-recorded-stream plan.
|
|
52
|
+
Closed-only, collection, mixed, snapshot, and unwindowed plans return `RESYNC_REQUIRED` before
|
|
53
|
+
acquisition. Use `mr-data table resync TABLE_ID --request-id UUID` when a full reread is
|
|
54
|
+
genuinely needed; it is an explicit run, not a schedule fallback. Only returned state and durable
|
|
55
|
+
run evidence support a claim that the table is caught up or refreshing. If that evidence is absent,
|
|
56
|
+
report that a schedule was recorded and that ongoing freshness is unavailable.
|
|
54
57
|
|
|
55
58
|
`mr-data pin TABLE_ID --version VERSION_ID` freezes the pointer on an exact version for a rollback
|
|
56
59
|
or a hold, `mr-data unpin TABLE_ID` resumes tracking, and `mr-data demote TABLE_ID` detaches the
|
|
@@ -24,8 +24,9 @@ https://mostlyright.md/docs/recipes/ lists all thirteen: `city-temperatures`, `c
|
|
|
24
24
|
CSV file, one table), `json-api` (records pointer and pagination), `html-collection` (many HTML
|
|
25
25
|
pages, one table), `document-extraction` (PDF projection), `weather-grib` (GRIB2 and the scientific
|
|
26
26
|
Readers), `websocket-stream` (a `wss://` venue), `multi-source-join` (two sources joined, with
|
|
27
|
-
checks), `market-settlement-join`, `forecast-vs-observation`, `snapshot-window` (a
|
|
28
|
-
|
|
27
|
+
checks), `market-settlement-join`, `forecast-vs-observation`, `snapshot-window` (a point-in-time
|
|
28
|
+
source whose normal refresh currently requires explicit resync), `many-station-weather` (twenty
|
|
29
|
+
station feeds unioned) and `stream-to-bars`.
|
|
29
30
|
|
|
30
31
|
The build guides run one per stage, at https://mostlyright.md/docs/build/NAME/ where NAME is
|
|
31
32
|
`probe-sources`, `write-a-recipe`, `run-and-inspect`, `publish-and-refresh`, `credentials`,
|
{mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/skills/mr-data-build/references/sources.md
RENAMED
|
@@ -20,15 +20,23 @@
|
|
|
20
20
|
- Preserve event time, available time, acquisition time, source revision, and timezone. Do not use
|
|
21
21
|
post-cutoff information in targets, labels, features, joins, or validation decisions.
|
|
22
22
|
- When the question is **what changed over time**, or the table needs point-in-time features, and
|
|
23
|
-
the source answers only with the present,
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
the source answers only with the present, a `snapshot` window expresses the intended future
|
|
24
|
+
daily partition model. It is not executable as normal refresh in this release: Studio returns
|
|
25
|
+
`RESYNC_REQUIRED` before acquisition. Explicit resync is full with no predecessor and replaces
|
|
26
|
+
the table with the current observation; it does not retain earlier days. Once the bounded
|
|
27
|
+
snapshot materializer ships, compute a transition with
|
|
26
28
|
`lag(column) over (partition by <identity> order by <snapshot column>)` and keep
|
|
27
29
|
the rows where the two are `is distinct from` each other. Never diff two sealed versions by hand;
|
|
28
30
|
a version is not a date, and nothing outside the seal can be replayed.
|
|
29
31
|
|
|
30
32
|
### Authoring a collection source
|
|
31
33
|
|
|
34
|
+
Current execution boundary: an initial full or explicit table resync may acquire a collection,
|
|
35
|
+
but collection-only and mixed normal refreshes return `RESYNC_REQUIRED` before acquisition. An
|
|
36
|
+
explicit resync is full, has no predecessor, and starts collection discovery from the beginning.
|
|
37
|
+
The ledger continuation rules below describe historical receipts and a future bounded materializer,
|
|
38
|
+
not a current normal-refresh action.
|
|
39
|
+
|
|
32
40
|
A corpus published as an index plus many detail pages is **one** source through
|
|
33
41
|
`public.https.collection@2.0.0`, not one source per page. Source count and publisher count are
|
|
34
42
|
unaffected by how many pages sit behind it: 2,819 pages is one source, one publisher, one line on
|
|
@@ -79,17 +87,16 @@ column reaches the transform as `VARCHAR`; selecting `page_ordinal` bare while d
|
|
|
79
87
|
`TIMESTAMP WITH TIME ZONE` and nothing else.
|
|
80
88
|
|
|
81
89
|
**A listing that could not be read says so.** The coverage block carries `discovery_failure`:
|
|
82
|
-
`null`, or the code and one sentence for the first listing request the run was refused. A
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
is empty.
|
|
90
|
+
`null`, or the code and one sentence for the first listing request the run was refused. A full
|
|
91
|
+
resync whose listing is refused has nothing to continue from and fails with
|
|
92
|
+
`COLLECTION_DISCOVERY_FAILED` rather than sealing an empty corpus. If a run reports zero
|
|
93
|
+
discovered, read that member before concluding the publisher's index is empty.
|
|
87
94
|
|
|
88
|
-
**
|
|
89
|
-
SUCCEEDS; its coverage block reports `complete: false` and names the budget that ended it.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
**A partial full/resync result must be reported as partial.** A run that spends its fetch budget
|
|
96
|
+
still SUCCEEDS; its coverage block reports `complete: false` and names the budget that ended it.
|
|
97
|
+
Do not call that a backfill in progress: no current normal refresh can continue the ledger, and a
|
|
98
|
+
later explicit resync starts discovery over. Report it as an incomplete corpus and either accept
|
|
99
|
+
that limitation or revise the bounded recipe before another explicit resync.
|
|
93
100
|
|
|
94
101
|
A page that disappears from the index deletes nothing. A page answering with different content
|
|
95
102
|
replaces exactly its own rows, increments `page_revision`, and keeps the previous digest: that is
|
{mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/page_coverage.py
RENAMED
|
@@ -37,9 +37,9 @@ __all__ = [
|
|
|
37
37
|
#: ``{"code", "detail"}`` of the first listing request this run could not read. It is stated
|
|
38
38
|
#: because a discovery that failed and a corpus that is empty produce the same counts, and a
|
|
39
39
|
#: reader with only the counts cannot tell an unreachable index from a publisher who has stopped
|
|
40
|
-
#: publishing. A run
|
|
41
|
-
#: ``COLLECTION_DISCOVERY_FAILED
|
|
42
|
-
#: rows.
|
|
40
|
+
#: publishing. A full/resync run with no listing and no rows fails under
|
|
41
|
+
#: ``COLLECTION_DISCOVERY_FAILED``. Historical refresh receipts may carry the member after keeping
|
|
42
|
+
#: predecessor rows, but current collection refresh is refused before acquisition.
|
|
43
43
|
PAGE_COVERAGE_FIELDS: tuple[str, ...] = (
|
|
44
44
|
"discovered",
|
|
45
45
|
"discovery_requests",
|
|
@@ -103,5 +103,5 @@ def page_coverage_sentence(block: Mapping[str, Any]) -> str:
|
|
|
103
103
|
parts.append(f"the page listing could not be read ({listing['code']})")
|
|
104
104
|
if failed:
|
|
105
105
|
parts.append(f"{failed:,} failed")
|
|
106
|
-
parts.append("
|
|
106
|
+
parts.append("requires another explicit resync, which starts from the beginning")
|
|
107
107
|
return "; ".join(parts)
|
{mostlyright_data-0.23.0 → mostlyright_data-0.24.0}/src/mostlyright/data_harness/thin/recipe.py
RENAMED
|
@@ -61,6 +61,7 @@ COMMAND_HELP = "register one recipe document and print the identifiers the serve
|
|
|
61
61
|
|
|
62
62
|
REGISTER_SCHEMA = f"{THIN_SCHEMA_PREFIX}-recipe.v1"
|
|
63
63
|
SHOW_SCHEMA = f"{THIN_SCHEMA_PREFIX}-recipe-read.v1"
|
|
64
|
+
READINESS_SCHEMA = f"{THIN_SCHEMA_PREFIX}-recipe-readiness.v1"
|
|
64
65
|
|
|
65
66
|
#: The bound on the document. The same number the authoring lane bounded one of its six documents
|
|
66
67
|
#: by -- four times the contract's own 262144-byte ceiling on a canonical recipe -- rather than a
|
|
@@ -111,6 +112,14 @@ NAMED_UNDESCRIBED_COLUMNS = 12
|
|
|
111
112
|
#: The word that selects the read-back form. A positional rather than a flag because
|
|
112
113
|
#: `mr-data recipe show ID` is how a person says it out loud.
|
|
113
114
|
SHOW = "show"
|
|
115
|
+
READINESS = "readiness"
|
|
116
|
+
# Studio evaluates the exact persisted admission proof for each recipe revision. Keep this
|
|
117
|
+
# inventory page small enough that a normal production workspace completes each bounded request
|
|
118
|
+
# inside the thin client's request deadline, while preserving the established 40,000-item
|
|
119
|
+
# inventory bound through cursor aggregation.
|
|
120
|
+
READINESS_PAGE_SIZE = 25
|
|
121
|
+
MAX_READINESS_ITEMS = 40_000
|
|
122
|
+
MAX_READINESS_PAGES = MAX_READINESS_ITEMS // READINESS_PAGE_SIZE
|
|
114
123
|
|
|
115
124
|
|
|
116
125
|
def declare_arguments(parser: argparse.ArgumentParser) -> None:
|
|
@@ -125,8 +134,9 @@ def declare_arguments(parser: argparse.ArgumentParser) -> None:
|
|
|
125
134
|
"target",
|
|
126
135
|
metavar="FILE",
|
|
127
136
|
help=(
|
|
128
|
-
"the recipe document to register, as a path to a JSON file;
|
|
129
|
-
"followed by a recipe identifier, to read one back"
|
|
137
|
+
"the recipe document to register, as a path to a JSON file; the word `show`, "
|
|
138
|
+
"followed by a recipe identifier, to read one back; or `readiness` to inventory "
|
|
139
|
+
"whether current tables may schedule a bounded incremental refresh"
|
|
130
140
|
),
|
|
131
141
|
)
|
|
132
142
|
parser.add_argument(
|
|
@@ -618,6 +628,149 @@ def show(
|
|
|
618
628
|
}
|
|
619
629
|
|
|
620
630
|
|
|
631
|
+
def _readiness_row(record: Any) -> dict[str, Any]:
|
|
632
|
+
"""One immutable recipe revision, checked before an audit receipt repeats it."""
|
|
633
|
+
|
|
634
|
+
if not isinstance(record, Mapping):
|
|
635
|
+
raise ThinLaneError(
|
|
636
|
+
"THIN_RESPONSE_INVALID", "Studio returned a non-object readiness record"
|
|
637
|
+
)
|
|
638
|
+
recipe_id = identifier(record.get("recipe_id"), "recipe identifier")
|
|
639
|
+
dataset_id = identifier(record.get("dataset_id"), "dataset identifier")
|
|
640
|
+
table_id = identifier(record.get("table_id"), "table identifier")
|
|
641
|
+
digest = record.get("recipe_digest")
|
|
642
|
+
if not isinstance(digest, str) or not digest:
|
|
643
|
+
raise ThinLaneError(
|
|
644
|
+
"THIN_RESPONSE_INVALID", "Studio returned readiness without recipe_digest"
|
|
645
|
+
)
|
|
646
|
+
current = record.get("is_current")
|
|
647
|
+
predecessor_ready = record.get("predecessor_ready")
|
|
648
|
+
incremental_materialization_ready = record.get("incremental_materialization_ready")
|
|
649
|
+
differential_proof_ready = record.get("differential_proof_ready")
|
|
650
|
+
ready = record.get("refresh_ready")
|
|
651
|
+
table_status = record.get("table_status")
|
|
652
|
+
if not all(
|
|
653
|
+
isinstance(value, bool)
|
|
654
|
+
for value in (
|
|
655
|
+
current,
|
|
656
|
+
predecessor_ready,
|
|
657
|
+
incremental_materialization_ready,
|
|
658
|
+
differential_proof_ready,
|
|
659
|
+
ready,
|
|
660
|
+
)
|
|
661
|
+
):
|
|
662
|
+
raise ThinLaneError(
|
|
663
|
+
"THIN_RESPONSE_INVALID",
|
|
664
|
+
"Studio returned readiness without its required boolean readiness facts",
|
|
665
|
+
)
|
|
666
|
+
if table_status not in {"live", "not_live"}:
|
|
667
|
+
raise ThinLaneError("THIN_RESPONSE_INVALID", "Studio returned an unknown table_status")
|
|
668
|
+
sources = record.get("sources")
|
|
669
|
+
blocking = record.get("blocking_source_names")
|
|
670
|
+
if not isinstance(sources, list) or not isinstance(blocking, list):
|
|
671
|
+
raise ThinLaneError(
|
|
672
|
+
"THIN_RESPONSE_INVALID",
|
|
673
|
+
"Studio returned readiness without source classifications and blocking source names",
|
|
674
|
+
)
|
|
675
|
+
parsed_sources: list[dict[str, str]] = []
|
|
676
|
+
for source in sources:
|
|
677
|
+
if not isinstance(source, Mapping):
|
|
678
|
+
raise ThinLaneError(
|
|
679
|
+
"THIN_RESPONSE_INVALID", "Studio returned a non-object source readiness"
|
|
680
|
+
)
|
|
681
|
+
name = source.get("source_name")
|
|
682
|
+
classification = source.get("classification")
|
|
683
|
+
next_action = source.get("next_action")
|
|
684
|
+
if (
|
|
685
|
+
not isinstance(name, str)
|
|
686
|
+
or not name
|
|
687
|
+
or classification not in {"closed", "window", "collection", "recorded", "resync_only"}
|
|
688
|
+
or next_action
|
|
689
|
+
not in {"reuse_predecessor", "acquire_incremental", "recorded", "resync_required"}
|
|
690
|
+
):
|
|
691
|
+
raise ThinLaneError(
|
|
692
|
+
"THIN_RESPONSE_INVALID", "Studio returned an invalid source readiness"
|
|
693
|
+
)
|
|
694
|
+
parsed_sources.append(
|
|
695
|
+
{"source_name": name, "classification": classification, "next_action": next_action}
|
|
696
|
+
)
|
|
697
|
+
if any(not isinstance(name, str) or not name for name in blocking):
|
|
698
|
+
raise ThinLaneError(
|
|
699
|
+
"THIN_RESPONSE_INVALID", "Studio returned an invalid blocking source name"
|
|
700
|
+
)
|
|
701
|
+
return {
|
|
702
|
+
"recipe_id": recipe_id,
|
|
703
|
+
"recipe_digest": digest,
|
|
704
|
+
"dataset_id": dataset_id,
|
|
705
|
+
"table_id": table_id,
|
|
706
|
+
"is_current": current,
|
|
707
|
+
"table_status": table_status,
|
|
708
|
+
"predecessor_ready": predecessor_ready,
|
|
709
|
+
"incremental_materialization_ready": incremental_materialization_ready,
|
|
710
|
+
"differential_proof_ready": differential_proof_ready,
|
|
711
|
+
"refresh_ready": ready,
|
|
712
|
+
"sources": parsed_sources,
|
|
713
|
+
"blocking_source_names": list(blocking),
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
def readiness(
|
|
718
|
+
args: argparse.Namespace, *, client: StudioV4DatasetClient | None = None
|
|
719
|
+
) -> dict[str, Any]:
|
|
720
|
+
"""Inventory every recipe revision's deterministic incremental-refresh readiness."""
|
|
721
|
+
|
|
722
|
+
selected = client or _client(args)
|
|
723
|
+
rows: list[dict[str, Any]] = []
|
|
724
|
+
cursor: str | None = None
|
|
725
|
+
seen_cursors: set[str] = set()
|
|
726
|
+
pages = 0
|
|
727
|
+
while True:
|
|
728
|
+
pages += 1
|
|
729
|
+
if pages > MAX_READINESS_PAGES:
|
|
730
|
+
raise ThinLaneError(
|
|
731
|
+
"THIN_RESPONSE_INVALID",
|
|
732
|
+
f"Studio's readiness inventory did not end within {MAX_READINESS_PAGES} pages",
|
|
733
|
+
)
|
|
734
|
+
page = selected.recipe_readiness(cursor=cursor, limit=READINESS_PAGE_SIZE)
|
|
735
|
+
if page.get("workspace_id") != str(selected.session.workspace_id):
|
|
736
|
+
raise ThinLaneError(
|
|
737
|
+
"THIN_RESPONSE_INVALID",
|
|
738
|
+
"Studio returned a readiness inventory for a different workspace",
|
|
739
|
+
)
|
|
740
|
+
listed = page.get("recipes")
|
|
741
|
+
if not isinstance(listed, list):
|
|
742
|
+
raise ThinLaneError(
|
|
743
|
+
"THIN_RESPONSE_INVALID", "Studio returned readiness without recipes"
|
|
744
|
+
)
|
|
745
|
+
rows.extend(_readiness_row(item) for item in listed)
|
|
746
|
+
next_cursor = page.get("next_cursor")
|
|
747
|
+
if next_cursor is None:
|
|
748
|
+
break
|
|
749
|
+
cursor = identifier(next_cursor, "next recipe cursor")
|
|
750
|
+
if cursor in seen_cursors:
|
|
751
|
+
raise ThinLaneError(
|
|
752
|
+
"THIN_RESPONSE_INVALID",
|
|
753
|
+
"Studio repeated a readiness cursor, so the inventory cannot be completed safely",
|
|
754
|
+
)
|
|
755
|
+
seen_cursors.add(cursor)
|
|
756
|
+
current = [row for row in rows if row["is_current"]]
|
|
757
|
+
blocked = [row for row in current if not row["refresh_ready"]]
|
|
758
|
+
return {
|
|
759
|
+
"schema_version": READINESS_SCHEMA,
|
|
760
|
+
"status": "recipe_readiness_listed",
|
|
761
|
+
"lane": "hosted",
|
|
762
|
+
"recipes": numbered("recipe", rows),
|
|
763
|
+
"count": len(rows),
|
|
764
|
+
"current_count": len(current),
|
|
765
|
+
"current_not_ready_count": len(blocked),
|
|
766
|
+
"pages_read": pages,
|
|
767
|
+
"note": (
|
|
768
|
+
"Only Studio's persisted readiness classification may authorize a scheduled refresh. "
|
|
769
|
+
"A resync-only source requires table resync; it is never widened by a schedule."
|
|
770
|
+
),
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
|
|
621
774
|
def recipe(
|
|
622
775
|
args: argparse.Namespace, *, client: StudioV4DatasetClient | None = None
|
|
623
776
|
) -> dict[str, Any]:
|
|
@@ -630,7 +783,7 @@ def recipe(
|
|
|
630
783
|
with a directory in front of it.
|
|
631
784
|
"""
|
|
632
785
|
|
|
633
|
-
if args.target
|
|
786
|
+
if args.target in {SHOW, READINESS}:
|
|
634
787
|
given = [
|
|
635
788
|
flag
|
|
636
789
|
for destination, flag in _REGISTER_ONLY_FLAGS
|
|
@@ -639,14 +792,22 @@ def recipe(
|
|
|
639
792
|
if given:
|
|
640
793
|
raise ThinLaneError(
|
|
641
794
|
"THIN_REQUEST_INVALID",
|
|
642
|
-
f"mr-data recipe
|
|
795
|
+
f"mr-data recipe {args.target} is read-only and registers nothing, so "
|
|
643
796
|
f"{', '.join(given)} cannot mean anything here",
|
|
644
797
|
)
|
|
645
|
-
|
|
798
|
+
if args.target == SHOW:
|
|
799
|
+
return show(args, client=client)
|
|
800
|
+
if args.recipe_id:
|
|
801
|
+
raise ThinLaneError(
|
|
802
|
+
"THIN_REQUEST_INVALID",
|
|
803
|
+
"mr-data recipe readiness takes no recipe identifier",
|
|
804
|
+
)
|
|
805
|
+
return readiness(args, client=client)
|
|
646
806
|
if args.recipe_id:
|
|
647
807
|
raise ThinLaneError(
|
|
648
808
|
"THIN_REQUEST_INVALID",
|
|
649
|
-
f"mr-data recipe takes one document to register,
|
|
809
|
+
f"mr-data recipe takes one document to register, `show` and a recipe identifier, "
|
|
810
|
+
f"or `readiness`; "
|
|
650
811
|
f"{args.target!r} is neither",
|
|
651
812
|
)
|
|
652
813
|
return register(args, client=client)
|
|
@@ -656,9 +817,14 @@ __all__ = [
|
|
|
656
817
|
"COMMAND_HELP",
|
|
657
818
|
"DRAINED_SOURCE_BYTE_CEILING",
|
|
658
819
|
"MAX_DOCUMENT_BYTES",
|
|
820
|
+
"MAX_READINESS_ITEMS",
|
|
821
|
+
"MAX_READINESS_PAGES",
|
|
659
822
|
"NAMED_UNDESCRIBED_COLUMNS",
|
|
660
823
|
"NDJSON_SOURCE_BYTE_CEILING",
|
|
661
824
|
"READER_SOURCE_BYTE_CEILING",
|
|
825
|
+
"READINESS",
|
|
826
|
+
"READINESS_PAGE_SIZE",
|
|
827
|
+
"READINESS_SCHEMA",
|
|
662
828
|
"REGISTER_SCHEMA",
|
|
663
829
|
"REQUIRED_DOCUMENT_MEMBERS",
|
|
664
830
|
"SHOW",
|
|
@@ -670,6 +836,7 @@ __all__ = [
|
|
|
670
836
|
"columns_without_description",
|
|
671
837
|
"declare_arguments",
|
|
672
838
|
"read_document",
|
|
839
|
+
"readiness",
|
|
673
840
|
"recipe",
|
|
674
841
|
"record_delegation",
|
|
675
842
|
"register",
|