The bucket has a corpus in it now
Fourteen days after R2 was decided, the prefix still held zero objects. 886 files went up in 28 seconds and came back byte-identical.
The bucket has a corpus in it now
Why Care?
The R2-native substrate decision was made on 2026-08-08. An audit on 2026-08-22
found the configured prefix — r2://reach-edu/corpora/ — holding zero
objects, while the reach-edu corpus grew through an entirely separate path in
git. Not a plan being executed slowly; a plan the work was routing around.
This is the smallest move that changes that, and it took under a minute of transfer time.
What happened
886 files, 153.7 MiB, uploaded in 28 seconds. Then pulled back down into an empty directory and compared file-by-file:
counts: source 886 recovered 886
source manifest lines: 886
recovered manifest lines: 886
RESULT: IDENTICAL — every file's sha256 matches, byte-for-byte round tripThe file count is a useful cross-check on its own: 886 is exactly what
git ls-files corpus reports for the augment-reach-edu submodule, so what is
in the bucket is precisely what is tracked in git — no more, no less. The six
.DS_Store files in the working tree were excluded and account for the whole
difference from the 892 files on disk.
The property this was actually testing
live/ is not machinery. It is plain markdown written at plain keys, and its
whole value is that someone with rclone and no corpora-builder can reconstitute
a working corpus. That was a design intention until today. It is now measured:
| Check | Result |
| Recovered file count | 886 / 886 |
Per-file sha256 | all identical |
| Markdown files | 845 |
Files opening with --- frontmatter | 840 (the five without are README.md, AGENTS.md, and kin — correct) |
| Binaries (PDFs and friends) survived | 41 |
grep -rl "rural" strategies/ on the recovered tree | 46 hits |
That last row is the one that matters. A corpus you can grep with no tooling installed is the constraint the whole substrate argument rests on, and it holds.
scripts/mirror_corpus.sh
Shipped so this is repeatable rather than a one-time act.
./scripts/mirror_corpus.sh <source-dir> [--verify] [--dry-run]Three decisions worth stating, because each could reasonably have gone the other way:
rclone copy, neversync.syncdeletes at the destination to make it match the source. The destination is a client-owned bucket. A one-way mirror should not be able to remove anything there, and if pruning is ever wanted it should be its own explicit decision rather than a flag on this script.Credentials via
RCLONE_CONFIG_R2_*environment variables, read from.envat run time and never echoed. No remote is persisted to~/.config/rclone/rclone.conf, so running this leaves no new copy of an R2 secret on disk. (A persistent remote was created during the first manual run and has been removed.).DS_Storeexcluded, matching what git tracks.
Idempotent: a second run transfers nothing.
What this does not do
It does not make R2 authoritative. The laptop and git remain the source of truth. This is a mirror, one direction, laptop → bucket.
It is not scheduled. Run deliberately. Automating it is a separate decision with its own failure modes.
It does not give corpora-builder ownership of the corpus. That is a handover, and it is still open — see the plan.
Related
ai-labs/context-v/plans/Sync-Corpora-to-R2-and-Show-Clients-What-Changed.md— Phase 1, which this completescontext-v/specs/Storage-Seam.md— the seam that made the destination interchangeablelossless-monorepo/context-v/reminders/Check-The-Substrate-Before-Reasoning-On-Top-Of-It.md— the audit that prompted this
