Skip to content

feat(stelae): stage where the operator said, in both directions - #1191

Merged
scarmuega merged 5 commits into
mainfrom
feat/stelae-scratch-dir
Aug 11, 2026
Merged

feat(stelae): stage where the operator said, in both directions#1191
scarmuega merged 5 commits into
mainfrom
feat/stelae-scratch-dir

Conversation

@scarmuega

@scarmuega scarmuega commented Aug 11, 2026

Copy link
Copy Markdown
Member

Plan: plans/dolos-stelae-publisher-operability-scratch-dir.md (Trellis root Brain/txpipe, owner
org/coder), the first piece of the dolos-stelae-publisher-operability umbrella. Base: main at
0ff6e17d (#1188), which rewrote crates/snapshot/src/registry.rs.

The defect

registry::open passed scratch_dir: None to stelae::oci::Options. Shared::scratch is reached
from layer_sink on the way up and pull_blob_file on the way down, so every layer a publish built
and every layer a restore pulled was staged in the platform temporary directory — not always on a
volume with room for sixteen mainnet state shards. stelae::oci honoured the option all along in
both directions; nothing set it.

What changed

  • crates/snapshot/src/registry.rsopen takes the staging directory as a required PathBuf.
    Not an Option: a parameter nobody can omit cannot grow another None.
  • src/bin/dolos/common.rsstele_scratch_dir, one default (<storage.path>/scratch) for all
    four commands that open a repository, with a unit test on the default and the override.
  • --scratch-dir on snapshot publish (conflicting with --output-dir, which stages nothing) and
    on bootstrap stelae. snapshot verify and snapshot inspect take the default with no flag.
  • crates/core/src/config.rs, docs/content/configuration/schema.mdx, AGENTS.mdstorage.path
    documents scratch/.

The default is inside storage.path rather than beside it: on a dedicated data mount a sibling
lands on the parent filesystem, which is the small root volume the default exists to keep bytes off.
tempfile_in unlinks at creation, so scratch/ reads as empty even mid-transfer. Decided by
org/founder; the documentation change is part of the deliverable because it changes what an
operator sizing that volume has to count.

Tests

The unit test on stele_scratch_dir covers the default and that an explicit --scratch-dir is
taken literally, relative paths included. staging_stays_in_the_scratch_directory_and_leaves_nothing
in crates/stelae/tests/oci.rs already covers the transport honouring the option in both
directions. No CLI-level suite: a container-spawning integration test is out of proportion to a
PathBuf argument on two commands.

The shared registry fixture now names a TempDir of its own, so the #[ignore]d registry suites
stop staging in /tmp too.

Verification

On the committed toolchain (cargo +1.93), macOS aarch64.

$ cargo test --workspace --all-targets                      # 0 failed
$ cargo clippy --all-targets --all-features -- -D warnings   # clean
$ cargo +nightly fmt --all -- --check                        # clean
$ cargo deny check advisories                                # ok
$ cargo tree -p stelae -e normal --all-features | grep -E 'dolos(-|$| v)'   # no match

Help output and the flag conflict, checked by hand:

$ dolos snapshot publish --output-dir /tmp/x --scratch-dir /tmp/y
error: the argument '--output-dir <OUTPUT_DIR>' cannot be used with '--scratch-dir <DIR>'

The #[ignore]d registry suites were run against registry:2 in Docker, since this PR changes the
shared fixture they all use:

$ cargo test -p stelae --all-features --test oci -- --ignored                 # 10 passed
$ cargo test -p dolos-snapshot --features oci --test publish -- --ignored     # 7 passed
$ cargo test -p dolos-snapshot --features oci --test restore_registry -- --ignored  # 5 passed
$ cargo test -p dolos-snapshot --features oci --test snapshot_verify -- --ignored   # 6 passed

Notes

  • Not in this PR, per the umbrella's sequencing: preflight sizing, resumption, progress reporting.
  • Follow-up filed as plans/dolos-stelae-scratch-dir-diagnostics.md: an unusable --scratch-dir
    fails with a bare Not a directory (os error 20) because neither create_dir_all nor
    tempfile_in carries the path into its error. That is stelae::oci's to fix.
  • Reported rather than fixed: crates/snapshot/tests/snapshot_verify.rs, added by feat(stelae): give a publisher digest, verify and inspect #1188, is
    #[ignore]d with nothing running it — neither in registry.yml nor in AGENTS.md. Run by hand
    here and green.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added configurable scratch storage for temporary snapshot and registry transfer data.
    • Added --scratch-dir options for snapshot publishing and stelae bootstrapping.
    • Scratch storage defaults to the configured storage volume’s scratch/ directory.
    • Snapshot inspection, verification, publishing, and restoration now use consistent staging storage.
    • Publishing prevents conflicting use of --scratch-dir and --output-dir.
  • Documentation

    • Documented the scratch directory layout, supported workflows, overrides, and potentially large temporary storage requirements.

`registry::open` passed `scratch_dir: None` to `stelae::oci::Options`, and
that one `None` was the whole gap: every layer a publish built and every
layer a restore pulled was staged in the platform temporary directory,
which on a real host is not the volume with room for sixteen mainnet
state shards.

`--scratch-dir` on `snapshot publish` and on `bootstrap stelae`, defaulting
to `<storage.path>/scratch` — the volume already sized for the data. A
sibling of `storage.path` was rejected: on a dedicated mount it lands on
the parent filesystem, exactly the small root volume the default exists to
avoid. Staging inside the data directory is safe because scratch files are
unlinked at creation, so a backup or a directory listing sees an empty
`scratch/` and never a half-written shard — said in both flags' help and in
the `storage.path` documentation, because an operator who sizes or backs up
that directory is affected.

`open` now takes the directory as a plain `PathBuf` rather than an
`Option`: the defect was one omission at one call site, and a parameter
nobody can omit cannot grow another. `snapshot verify` streams every blob
through a staged file too and gets the same default; it grows no flag of
its own, because the commands an operator points at a volume are the
publish and the restore.

Two CLI-level tests, because the transport's own
`staging_stays_in_the_scratch_directory_and_leaves_nothing` passes just as
well against commands that never set the option. They drive the binary, and
each asserts both halves: the directory it was told to use appeared, and the
one it was told to use *instead of* did not. The restore test also pins the
`--force` ordering — the wipe of `storage.path` completes before the first
scratch file is created — by holding the end state against a `file://`
restore of the same stele, which stages nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 10965618-a9d2-4db6-98f5-ae4e2ff511bc

📥 Commits

Reviewing files that changed from the base of the PR and between 69f8007 and fb3cc6b.

📒 Files selected for processing (1)
  • crates/core/src/config.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/core/src/config.rs

📝 Walkthrough

Walkthrough

The change adds configurable scratch storage for OCI layer staging. Registry opening now requires a scratch path. Snapshot publishing, inspection, verification, and Stelae restoration resolve and pass scratch directories. Documentation and tests cover the new storage behavior.

Changes

OCI scratch-directory staging

Layer / File(s) Summary
Storage scratch-path resolution
src/bin/dolos/common.rs, crates/core/src/config.rs, AGENTS.md, docs/content/configuration/schema.mdx
The shared helper resolves explicit paths or defaults to <storage.path>/scratch. Storage documentation describes the staging directory and its use.
Registry transport scratch storage
crates/snapshot/src/registry.rs, crates/snapshot/tests/registry_fixture/mod.rs
registry::open accepts a PathBuf and configures OCI transport staging. Registry fixtures create and pass temporary scratch directories.
CLI publish and restore wiring
src/bin/dolos/bootstrap/stelae.rs, src/bin/dolos/snapshot/publish.rs, src/bin/dolos/snapshot/inspect.rs, src/bin/dolos/snapshot/verify.rs
Commands resolve scratch directories and pass them to registry opening. Publishing and Stelae restoration support --scratch-dir.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLICommand
  participant StorageConfig
  participant registry_open
  participant OCITransport
  CLICommand->>StorageConfig: resolve scratch directory
  StorageConfig->>registry_open: pass scratch_dir
  registry_open->>OCITransport: configure staging path
  OCITransport->>CLICommand: stage OCI transfer layers
Loading

Possibly related PRs

  • txpipe/dolos#1168: Adds the snapshot publishing workflow extended by this change.
  • txpipe/dolos#1169: Introduces the Stelae restoration flow extended by this change.
  • txpipe/dolos#1170: Introduces the OCI registry transport extended with scratch-directory staging.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title refers to Stelae staging in both directions, but its wording is unclear and does not describe configurable scratch directories. Use a clear title such as "feat(stelae): add configurable scratch directories for publish and restore".
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/stelae-scratch-dir

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/content/configuration/schema.mdx`:
- Around line 114-122: Document snapshot verification as a scratch-directory
consumer: in docs/content/configuration/schema.mdx:114-122, state that dolos
snapshot verify uses the default <storage.path>/scratch and does not expose
--scratch-dir; in crates/core/src/config.rs:550-558, include verification in the
StorageConfig::path scratch-directory contract; and in AGENTS.md:49-53, include
verification in the storage layout description.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7c6c9c5b-3c4a-4a47-9dba-6bd5ebeab596

📥 Commits

Reviewing files that changed from the base of the PR and between 0ff6e17 and 15688bb.

📒 Files selected for processing (12)
  • .github/workflows/registry.yml
  • AGENTS.md
  • crates/core/src/config.rs
  • crates/snapshot/src/registry.rs
  • crates/snapshot/tests/registry_fixture/mod.rs
  • docs/content/configuration/schema.mdx
  • src/bin/dolos/bootstrap/stelae.rs
  • src/bin/dolos/common.rs
  • src/bin/dolos/snapshot/inspect.rs
  • src/bin/dolos/snapshot/publish.rs
  • src/bin/dolos/snapshot/verify.rs
  • tests/stelae_scratch.rs

Comment thread docs/content/configuration/schema.mdx Outdated
Review fix on #1191. The `storage.path` documentation named the publish and
the restore and left out `snapshot verify`, which streams every blob through a
staged file and — unlike the other two — has no `--scratch-dir` to point
somewhere else. An operator sizing that volume off these three documents would
have sized it for two of the three commands that use it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@scarmuega

Copy link
Copy Markdown
Member Author

Review pass (86fe93d7): CodeRabbit's one comment applied, and it was right — snapshot verify streams every blob through a staged file and, unlike the publish and the restore, has no --scratch-dir to point elsewhere, so an operator sizing that volume off these documents would have sized it for two of the three commands that use it. Fixed in all three places it names: docs/content/configuration/schema.mdx, crates/core/src/config.rs's StorageConfig::path, and AGENTS.md's storage layout.

No code change; the gate was re-run green (cargo test --workspace --all-targets, cargo clippy --all-targets --all-features -- -D warnings, cargo +nightly fmt --all -- --check).

The change is one `None` at one call site plus a flag on two commands; the
commentary around it had grown to five separate retellings of the same three
facts. Each now has one home: `storage.path` documents `scratch/` in
`config.rs` and `schema.mdx`, the flags' help says where the default is, and
the rest is deleted. No behaviour, signature or assertion changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread crates/core/src/config.rs Outdated
Comment on lines +548 to +554
/// Root directory for storage files.
///
/// Besides the stores it holds `scratch/`, where a stele transfer over an
/// OCI registry stages the layers it is moving. That is the default
/// because this volume is already sized for the data; a mainnet transfer
/// stages gigabytes, which the platform temporary directory cannot be
/// assumed to fit.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is excessive docs about scratch, not the main focus of this field.

scarmuega and others added 2 commits August 11, 2026 16:43
A container-spawning integration suite, its CI leg and its AGENTS.md entry for
what is a `PathBuf` argument on two commands. The unit test on
`stele_scratch_dir` covers the default and the override; the transport's own
`staging_stays_in_the_scratch_directory_and_leaves_nothing` covers the option
being honoured.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review: the field's subject is the storage root, not the staging directory.
`schema.mdx` is where an operator reads the rest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@scarmuega
scarmuega merged commit 7286c48 into main Aug 11, 2026
17 checks passed
@scarmuega
scarmuega deleted the feat/stelae-scratch-dir branch August 11, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant