Publish and keep it fresh
The first successful run makes a table live. You decide how often it refreshes and who can read it.
The first succeeded run goes live
Section titled “The first succeeded run goes live”Studio promotes a never-promoted table on run_succeeded, whatever the mode. A complete sample counts. Studio dispatches no catch-up run for it. Everything before that point is workspace scratch. Probing, building, downloading and interrogating need no approval step. The only pause is a confirmation on a large run. Nothing has to run to enable the table.
A run never makes a demoted or archived table live again, and mr-data promote is how such a table returns. A promotion is also not evidence that a schedule is executing or that an idle period was filled.
Record the cadence
Section titled “Record the cadence”mr-data promote TABLE_ID --cadence "every 6h from 2026-09-03T02:40:00Z" --why "…" --json| Flag | What it does |
|---|---|
TABLE |
The table, by the identifier mr-data recipe printed when it registered one. |
--cadence CADENCE |
The refresh schedule to start from: a five-field cron expression, an interval such as every 6h or every 30m from 2026-09-03T12:20:00Z, or the word source to let Studio choose. |
--why WHY |
Why this schedule fits the source, in a sentence or two. Required unless you asked for source. |
--json |
One JSON object instead of human lines. |
--no-activity |
Do not tell the dataset page what this command is doing. |
This does not make the table readable. It records how often the table refreshes and why. It is idempotent on a table that is already live, and it is how a withdrawn table comes back.
Say what the source does: the times of day it posts and how often it changes. Say how long after the stated publication time the bytes appear. --why sits beside the table for whoever looks next.
The cadence is a seed, not a setting. Studio watches what each source does on every refresh and moves the schedule to match, so it corrects a wrong seed rather than obeying it.
The answer carries Studio’s state for the table and any continuation cursors. Studio accepting the schedule does not prove an idle period was caught up or that a scheduled refresh executed.
How the cadence is learned
Section titled “How the cadence is learned”The deployed mechanism is the v4 refresh loop. The worker compares the sha256 of each source’s acquired bytes against the predecessor receipt’s digest for that source. It reports one observation per source on run:succeeded, and it stops before the transform when nothing moved. Studio turns those observations into a schedule and applies it without an agent.
Three words mean different things.
- Poll cadence is when Studio chooses to probe a source.
- Publication cadence is the interval observed between digest-bound material changes.
- Publication delay is the interval between the publisher’s own stated publication time and the first observation of that edition.
A schedule is not settled until the table says it is. mr-data table TABLE_ID reports the state in plain words, the schedule in force, the next refresh, and what was asked for and why. Once there is one, it also reports the interval Studio measured and how many source updates that rests on. Never describe a schedule as learned, settled or confirmed while that command says otherwise. Detection time is not publication time. A plain HTTPS source that cannot prove how many editions a publisher released between two probes stays in a learning state however long it runs.
A window.snapshot source partitions a whole-source acquisition on the run’s own day. It has no
normal-refresh action, so Studio does not use the refresh loop to acquire later snapshots. Use an
explicit resync when you deliberately want to read that current state again.
Change the schedule without building anything
Section titled “Change the schedule without building anything”mr-data reschedule TABLE_ID --cadence "every 12h" --why "…" --lock --json| Flag | What it does |
|---|---|
TABLE |
The table. |
--cadence CADENCE |
Required. Same grammar as promote. |
--why WHY |
Why this schedule fits the source. |
--lock |
Keep exactly this schedule and stop adjusting it from what the source does. |
--unlock |
Go back to letting the schedule follow what the source actually does. |
--json |
One JSON object instead of human lines. |
Nothing is built and nothing is spent. The next refresh happens at the new time. A live table’s schedule can change this way without the demote-and-promote that would reset its bookkeeping and buy a catch-up run. A second promote on a live table is an idempotent replay that ignores the new cadence.
--lock is how a person overrides the evidence. Do not lock a schedule on your own judgement.
What a refresh actually does
Section titled “What a refresh actually does”A refresh runs only the next declared incremental slice from the last successful run. It never silently widens to a whole-source read.
Before it is admitted, Studio writes one predecessor-bound action for every source. The action is one of reuse_predecessor, acquire_incremental, or recorded. The run record carries that action plan, so the projected bytes describe the sources this run will acquire, not every source the recipe has ever used.
- A source with a declared incremental request window asks only for the new range and its stated lookback. Its merge replaces the affected partitions and preserves every other row.
- A closed source reuses the bytes and rows its predecessor sealed.
- A recorded stream continues after the bookmark its predecessor committed. It rewrites no earlier segment.
- A source with no normal-refresh action, including a snapshot or unwindowed source, is refused with
RESYNC_REQUIRED. Nothing is acquired, and the table continues serving its current version.
Studio also returns RESYNC_REQUIRED when the action shape has no bounded materializer. A normal
refresh materializes an all-recorded stream plan, or a plan carrying at least one direct request
window. A closed source sits beside those windows and reuses its sealed bytes. Several windows are
allowed when they agree on the materialization and the partition layout. Where the plan names more
than one source, each window’s merge.partition.column has to be a column the table declares. A
closed-only plan, a plan carrying a collection, and a window beside a recorded stream each require
an explicit resync. These checks happen before acquisition.
Only a source explicitly declared closed: true authorizes reuse_predecessor in a strict refresh plan. A 304 is an unchanged reply after Studio acquires a source, and the legacy settled-source heuristic does not authorize reuse in that plan. A refresh whose plan acquires no rows ends unchanged, writes no version, and uploads nothing.
Resync from sources is explicit
Section titled “Resync from sources is explicit”Use Resync from sources only when you intend to read source material again — for example after correcting a recipe, acquiring another snapshot, advancing an unwindowed source, or repairing known historical data. It is a separate operation, has its own idempotency key and spends through the same confirmation gate as any other large run. A resync can read a whole source; a normal or scheduled refresh cannot.
The dashboard offers this control only after an incremental refresh is refused. When a resync reaches the confirmation gate, it says that the operation re-reads every source and shows Studio’s projected data and runtime. It never changes a Refresh or Refresh all click into a resync.
Live pointer, immutable version, pin
Section titled “Live pointer, immutable version, pin”Every run that succeeds writes an immutable table version. The live pointer names which of those versions the public page, the Public Dataset API and the MCP tools read. It tracks the latest passing version by default, and a failed refresh never advances it.
mr-data pin TABLE_ID --version VERSION_ID --json # freeze the pointer for a rollback or a holdmr-data unpin TABLE_ID --json # resume tracking--version takes the version identifier, never the table_version_number printed beside it. Both commands report the resulting pointer state. Read that state rather than inferring from the command name. Neither proves a refresh is available or producing new versions.
Reproducible reading pins the version too. Record table_version_id and manifest_digest out of mr-data parts TABLE_ID --json and pass --version from then on.
Read what a table is serving
Section titled “Read what a table is serving”mr-data table TABLE_ID --jsonReports what the table is serving and when it refreshes next. It also reports what was asked for and why. It reports what the evidence since then settled on, and how many source updates that rests on. Reading this state does not prove a refresh worker executed.
Rename and retire
Section titled “Rename and retire”mr-data table rename TABLE_ID --name lkpr_daily_temperature --json--name is lowercase snake_case, at most 63 characters, and unique within its dataset. It follows the same rules as a recipe’s table.name, so the renamed table remains reproducible. Renaming does not rebuild the table. Every run, version and schedule remains attached to the same identifier. The write fences on the dataset’s version and retries once if somebody else wrote first.
Retiring is two commands rather than a loop, because a live table cannot be archived:
mr-data demote TABLE_ID TABLE_ID ... --jsonmr-data table archive TABLE_ID TABLE_ID ... --confirm DELETE --jsondemote withdraws the live pointer and any schedule the table owns. archive hides the table from the dataset and frees its name.
| Flag | What it does |
|---|---|
--confirm DELETE |
With archive, the word DELETE, typed exactly and nothing else. It confirms the identifiers you typed, so it retires one table or twenty, each under the name Studio is holding for it. |
--confirm-name NAME |
With archive, one table’s current name, typed out. It confirms which table you mean, so it takes one identifier and the client refuses more. |
Neither command deletes anything. Every version stays downloadable and queryable by its run. Neither command stops at the first refusal. Both attempt every table, print one outcome line for each, and exit non-zero if any did not move. Read the per-table outcomes, which --json carries as an array with counts beside it, rather than the exit code alone. Both refuse a table a run is still writing to until the run has finished.
Who can read the dataset
Section titled “Who can read the dataset”Going live is about the table. Who can see it is about the dataset.
mr-data dataset publish DATASET_ID --mode public --jsonmr-data dataset publish DATASET_ID --show --json--mode |
What it means |
|---|---|
public |
Listed in the public directory and served at an address anybody can read. The default when the flag is left off. |
link |
Served at an unlisted address, to whoever holds that address. |
private |
Back to the workspace. |
--show reports who can read the dataset now and changes nothing.
THIN_CLOUD_PUBLIC_SHARING_DISABLED means the organization does not allow public datasets. THIN_CLOUD_PUBLISHER_PROFILE_REQUIRED means the organization has no publisher name yet, and a public dataset is published under one. THIN_CLOUD_STEP_UP_REQUIRED means publishing needs a verification only a signed-in browser can finish. Open the dashboard address the refusal names and share it from that page.
What readers see
Section titled “What readers see”A public dataset page shows the dataset’s title, its primary category and topics, its description and its cover image. It also shows the sources card, the decision record, and each table’s live version with its schema and a preview.
The same tables answer the Public Dataset API and the MCP tools. Anonymous callers read dataset identity, the tables, each table’s schema and a bounded preview. A key lifts the query page size. The routes are in Public Dataset API, and For agents is the copy-paste ladder through them.
The table serves only the live version. A pinned table serves the pinned version. A demoted table serves nothing, though every version it built stays readable by its run.
What you may claim, and what you may not
Section titled “What you may claim, and what you may not”promote and reschedule record a schedule. They are not proof of data continuation. The worker executes a supported refresh, including declared source windows. It does not make a frozen date, a generic cursor or a file listing advance by inference. It does not attach or execute a warehouse schedule.
Another deployed component may do that work. Only its returned state and durable run evidence support a claim that a table is live, caught up, or refreshing. Where that evidence is absent, say that a schedule was recorded and that ongoing freshness is unavailable. Do not imply that recording it filled the gap.
Live streams for venues that have to be recorded before a build can read them. Fix a failed run for a refresh that stopped.