Skip to content

Commit b48abc4

Browse files
claude[bot]claude
andauthored
ci(board-snapshot): sync the snapshot directory so the R2 mirror matches the documented prefix (#18136)
Fixes #18049 ## What this changes One line in the R2 sync step of `.github/workflows/board-snapshot.yml`, plus the comment in that step that described the old source. The step synced the archive worktree ROOT (`aws s3 sync archive/ "$mirror"`) while the snapshot is written to `archive/board` (`SNAPSHOT_ARGS: --out=archive/board`, near line 237). With `mirror="s3://${R2_BUCKET}/objectstack/board/"`, that maps `archive/board/X` onto `objectstack/board/` + `board/X`, so the whole mirror sat one segment deeper than the `mirror` prefix on the line above it documents — the `objectstack/board/board/...` layout the card measured from the bucket side (10912 of 10913 objects, run 34765639736). Syncing `archive/board/` maps `archive/board/X` to `objectstack/board/X`. ## Migration: `--delete` does it, and the target is deliberately not widened `--delete` is kept, and it is what migrates the bucket: the stale `objectstack/board/board/` tree is inside the new sync target and has no local counterpart, so the first scheduled run after this merges removes it. No cleanup step is needed. The target is NOT widened to `objectstack/` to reach the same mapping — that spelling would put `objectstack/snapshots/` inside a `--delete` target and eat the daily tarballs, which is the failure the step's own comment already warns about. The daily tarball step is untouched: it writes its own key from `-C archive .` and still carries `./board/...`, self-describing. No secret name or value is touched, no secret is added, and the workflow's `permissions:` block is unchanged. ## The two `.git` excludes are dropped, and why They are dead after this change, not merely redundant. `archive/` is a linked worktree, so its `.git` is a FILE at `archive/.git`; aws-cli filter patterns are matched against each path relative to the SOURCE directory, and with the source now `archive/board/` that file is outside the source entirely. Nothing under `archive/board/` is or can be named `.git` — the snapshot script writes the board tree there. Dropping them is behaviour-neutral. Keeping them would have left a live-looking guard whose accompanying comment describes a path this step no longer reads, inside the very step whose comment/code disagreement is what this card is about. The tarball step's own `--exclude=.git` still applies to `-C archive .` and is left as it is. ## Acceptance, both directions Measured in the worktree at `9dfcfb46a`: | reading | before | after | |---|---|---| | `grep -n 'aws s3 sync archive/board/' .github/workflows/board-snapshot.yml` | 0 hits (exit 1) | 1 hit, line 364 | | `grep -c 'aws s3 sync archive/ ' .github/workflows/board-snapshot.yml` | 1 | 0 | | literal control, `grep -n 'mirror=' ...` | line 340 | line 340, byte-unchanged | | `git diff --stat origin/main` | — | 1 file changed, 21 insertions, 4 deletions | A `yaml.safe_load` of the file parses; the job still has 9 steps and every `if:` guard is byte-unchanged. The `set +e` / `code=$?` / `set -e` shape around the sync is byte-identical, so the step's exit-code capture is untouched. ## Verification the maintainer can run, once The bucket cannot be re-measured from this container (no R2 credentials), so the post-change layout is NOT MEASURED here. After the next scheduled run (`7 2,8,14,20 * * *`), one `ListObjectsV2` against prefix `objectstack/board/` should show `manifest.json`, `comments/`, `issues/` and `reviews/` at the top level of that prefix and no `board/` subtree under it, while `objectstack/snapshots/` still holds the daily tarballs. That first run's `deleted` count in the step summary should be roughly the object count of the old tree. ## Not reachable at PR time The R2 step is guarded by `if: github.event_name != 'pull_request'`, as are the archive checkout and the commit/push steps. A `pull_request` run therefore exercises the snapshot on a real runner (`--out=board --dry-run --limit=5 --max-requests=25`) and never touches the bucket. The changed line cannot be proven green by this PR's own CI; it is covered by the greps above and by the one-run verification described above. ## Gates Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths — it takes its own change set from the merge base) and run in the foreground, each exit code captured before any pipe: 36 derived families, 35 exit 0, reconciled with `--ran`. `pnpm check:pm-dispatch-gates` is NOT MEASURED here: its self-test suite streamed thousands of passing assertions and zero failures, but did not terminate inside a 520 s budget in this shared container. It runs in CI's required `Lint & Repo Gates` job. ## Changeset `skip-changeset`: no package's `files[]` ships `.github/**`, so this diff publishes nothing from any released package. ## Acceptance notes - Noted, not filed: the prose block above the step still reads "this step mirrors the archive CHECKOUT". It stays accurate in substance, because `board/` is the only entry the archive branch tree holds, but after this change the sync mirrors that subtree rather than the tree root. Left as written — rewriting it is prose polish, not a defect, and this card's surface is the sync step itself. _Generated by [Claude Code](https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8)_ --- _Generated by [Claude Code](https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 739ab52 commit b48abc4

1 file changed

Lines changed: 21 additions & 4 deletions

File tree

.github/workflows/board-snapshot.yml

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,14 +339,31 @@ jobs:
339339
endpoint="https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com"
340340
mirror="s3://${R2_BUCKET}/objectstack/board/"
341341
342-
# `archive/` is a linked worktree, so its `.git` is a FILE and the
343-
# pattern `.git/*` does not match it; both spellings are excluded.
342+
# The SOURCE is the snapshot directory, NOT the worktree root that
343+
# contains it. The snapshot above is written to `archive/board`, so
344+
# syncing `archive/` would map `archive/board/X` onto the `mirror`
345+
# prefix as `objectstack/board/` + `board/X` — one segment deeper
346+
# than the prefix on the line above says the mirror is, and visible
347+
# only from the bucket side. Syncing `archive/board/` maps
348+
# `archive/board/X` to `objectstack/board/X`, which is the layout a
349+
# restore driven from the documented path looks for.
350+
#
351+
# `--delete` is kept and needs no migration step of its own: the
352+
# stale `objectstack/board/board/` tree is inside this sync target
353+
# and has no local counterpart, so the first run after this change
354+
# removes it. ⛔ The target is never widened to `objectstack/` to
355+
# achieve the same mapping — that would put `objectstack/snapshots/`
356+
# inside a `--delete` target and eat the daily tarballs, the failure
357+
# the comment above already warns about.
358+
#
359+
# No `.git` filter is needed here: `archive/` is a linked worktree,
360+
# so its `.git` is a FILE at `archive/.git`, which is outside this
361+
# source (filters match paths relative to the source directory).
344362
# No pipe between the command and `$?` — see the snapshot step.
345363
set +e
346-
aws s3 sync archive/ "$mirror" \
364+
aws s3 sync archive/board/ "$mirror" \
347365
--endpoint-url "$endpoint" \
348366
--delete --no-progress \
349-
--exclude '.git' --exclude '.git/*' \
350367
> "$RUNNER_TEMP/r2-sync.log" 2>&1
351368
code=$?
352369
set -e

0 commit comments

Comments
 (0)