Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .claude/skills/catalog-deploy/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ The catalog realm (`/catalog/`) serves boxel-catalog's files, and its cards impo
- **Before the release** (**Deploy the pinned catalog before the release**). The check runs against the boxel production still runs, so this ships the catalog changes the new boxel needs (a boxel pull request that says `Merges after: cardstack/boxel-catalog#N`), and refuses when the range has a catalog change that needs the new boxel. A refusal or failure here is only a notice and doesn't hold back the release.
- **After the release** (**Deploy the pinned catalog after the release**). This ships the rest, such as catalog changes pinned by the boxel pull request that brings the code they need. If it fails or refuses, the job goes red: production then runs the new boxel against an older catalog.

This deploys the whole catalog at the pin, so boxel's Lint Catalog lints the whole catalog at the pin against every boxel change, not only the subset files boxel's tests load. A boxel change that breaks the catalog pins the head of the catalog pull request that fixes it, which merges right after the boxel one (the `catalog-pairing` skill). Once that pull request has merged, `dispatch-catalog-deploy.sh` deploys its merge commit in place of the pinned head, with a notice naming both, whatever the merge method. The head branches off before production's catalog, so the check would refuse it as diverged, and after a squash or rebase it isn't on `main` at all.

When production's catalog is already at the pin, both do nothing. When a single range holds catalog changes the new boxel needs _and_ ones that need the new boxel, the run before the release refuses, so the first kind reaches production only after the release.

- **Ahead of boxel, by hand.** A catalog change that needs nothing new from boxel doesn't have to wait for a boxel deploy. Run **Deploy to production** with `revision` empty, which deploys catalog `main`'s head, or with a catalog `main` SHA. Start it from Discord (see below) or from boxel-catalog's Actions tab.
Expand Down
23 changes: 19 additions & 4 deletions .claude/skills/catalog-pairing/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: catalog-pairing
description: How a boxel pull request and a boxel-catalog pull request that depend on each other are paired — a `Merges before:` / `Merges after:` line in each description naming the other, declared from both sides — and which merges first. Covers when a change needs a pair (a boxel change the catalog's cards must follow, such as renaming or removing a host tool, command, base export or type the catalog imports; or a catalog definition boxel's tests need first), the declaration syntax and the rules a declaration must meet, merge order in each direction and in the three-PR flow, what boxel's Lint Catalog does with the pairing (it lints the paired catalog pull request's head and refuses to let catalog main be left broken behind a pull request that isn't ready), and how to read its failures. Use before opening or editing any pull request in cardstack/boxel-catalog; before opening a boxel pull request that changes something boxel-catalog's cards import or that pins or tests a catalog change; whenever Lint Catalog fails; and whenever a check says `pairing:`, "doesn't name … back", "waiting on cardstack/boxel-catalog#… to merge", "is not approved yet", "pair the two", "Merges before" / "Merges after", "which predates it", or "can't contain it yet".
description: How a boxel pull request and a boxel-catalog pull request that depend on each other are paired — a `Merges before:` / `Merges after:` line in each description naming the other, declared from both sides — and which merges first. Covers when a change needs a pair (a boxel change the catalog's cards must follow, such as renaming or removing a host tool, command, base export or type the catalog imports; or a catalog definition boxel's tests need first), the declaration syntax and the rules a declaration must meet, merge order in each direction and in the three-PR flow, what boxel's Lint Catalog does with the pairing (it lints the paired catalog pull request's head, refuses to let catalog main be left broken behind a pull request that isn't ready, and fails on any error the change adds to the whole catalog at the revision boxel pins), why a boxel-first change pins its catalog pull request's head, and how to read its failures. Use before opening or editing any pull request in cardstack/boxel-catalog; before opening a boxel pull request that changes something boxel-catalog's cards import or that pins or tests a catalog change; whenever Lint Catalog fails; and whenever a check says `pairing:`, "doesn't name … back", "waiting on cardstack/boxel-catalog#… to merge", "is not approved yet", "pair the two", "Merges before" / "Merges after", "which predates it", or "can't contain it yet".
---

# Pairing boxel and boxel-catalog pull requests
Expand All @@ -11,7 +11,7 @@ boxel-catalog's cards import boxel (host tools, `@cardstack/base`, runtime types

## When a change needs a pair

- **A boxel change the catalog has to follow.** Renaming or removing a host tool or command (`@cardstack/boxel-host/tools/*`), a base export, a field or a type that catalog cards import, or tightening a type or lint rule they trip. The boxel pull request merges first, and the catalog pull request that adapts the cards merges right after it.
- **A boxel change the catalog has to follow.** Renaming or removing a host tool or command (`@cardstack/boxel-host/tools/*`), a base export, a field or a type that catalog cards import, or tightening a type or lint rule they trip. The boxel pull request merges first, and the catalog pull request that adapts the cards merges right after it. The boxel pull request also pins the catalog pull request's head (see [The pin covers the whole catalog](#the-pin-covers-the-whole-catalog)).
- **A catalog change boxel's tests need.** A new or changed definition in the catalog test subset (the `catalog-test-subset` skill). The catalog pull request merges first, and the boxel pull request that re-pins and tests it merges after.
- **Both at once: the three-PR flow.** A catalog definition that needs new platform code, and whose boxel tests need the new definition. Platform pull request A merges, then catalog pull request C, then boxel pull request B, which re-pins and tests. C is tested against B's head, and that head needs A's platform code. So B carries A by merging A's branch into it and following A until A merges. B may target `main` with A merged in, or be stacked on A (below) and be retargeted to `main` once A merges. Stacked, B can't pass the catalog-main gate as a `Merges before` side until it's retargeted, since merging it lands it on A's branch, not `main`.

Expand Down Expand Up @@ -63,10 +63,25 @@ Edit a description with `gh pr edit <n> --repo <owner/repo> --body-file <file>`

**boxel-catalog's Boxel Test Subset** pairs by branch name: it tests a catalog pull request against the boxel branch with the same name, or against boxel `main` if there is none. So give the two branches the same name as well, and push the boxel branch first.

**boxel's Catalog Test Subset** pin check needs no declaration. The pinned commit identifies its catalog pull request, and the check fails until that pull request merges.
4. It lints the whole catalog at the revision `packages/catalog/test-subset.json` pins against the change, and compares it with the base branch's pin linted against the base branch. Every error the change adds there fails, paired or not (the failure title is `catalog lint (pin)`). The pairing only decides which revision the error tells you to pin instead. When the pin is the revision step 2 or 3 already linted, that recording is reused.

**boxel's Catalog Test Subset** pin check reads the pairing too. It compares only the subset files at the pin with catalog `main`, so it passes a pin from a catalog pull request that touches no subset file without looking at the pull request at all. When a subset file at the pin differs from `main`, the pinned commit identifies its catalog pull request, and the check fails until that pull request merges, with one exception. The exception is a pin at the head of the catalog pull request this change says `Merges before:`, while that pull request is open, ready for review and approved, neither side is stacked, and no `Merges after:` pair of this change is still open. A pin at any other commit of that pull request fails, because the head is what lands. The check re-runs when the description is edited, but not when the catalog pull request is approved, so re-run it by hand then. Either way, the approval gate for a boxel-first pair is Lint Catalog's catalog-main step (step 3), which fails until the catalog pull request is approved.

## The pin covers the whole catalog

Manual Deploy [boxel] to production deploys the catalog at the revision the deployed boxel commit pins (the `catalog-deploy` skill). So the pin has to mean "this boxel works with the whole catalog at this revision", not only with the subset files boxel's tests load. Lint Catalog's step 4 enforces that.

For a boxel-first pair, this means the boxel pull request pins the catalog pull request's head. The old pin is a catalog revision that the boxel change breaks, and production would deploy the two together. The steps:

1. Open the catalog pull request with the fix, paired with the boxel pull request in both descriptions.
2. In the boxel pull request, set `revision` in `packages/catalog/test-subset.json` to the catalog pull request's head, run `pnpm --dir packages/catalog catalog:test-subset`, run the manifest's tests, and commit the new pin. Re-pin each time the catalog pull request gets new commits.
3. Get the catalog pull request approved, then re-run the boxel pull request's Lint Catalog, and its Catalog Test Subset check if that one ran.
4. Merge the boxel pull request, then the catalog pull request right after it. Once it has merged, the lockstep deploy (`dispatch-catalog-deploy.sh`) deploys its merge commit in place of the pinned head, whatever the merge method: the head branches off before production's catalog, which the deploy check refuses, and after a squash or rebase it isn't on catalog `main` at all. The merge commit carries the same change and everything `main` had when it merged.

Before the boxel pull request merges, the pin is a commit catalog `main` doesn't have yet. Until the catalog pull request merges, any other boxel pull request that touches the manifest fails `--check-pin`, waiting on it. That's one more reason to merge the catalog pull request right after.

## Merging

- **Boxel first:** merge the boxel pull request only once its catalog pull request is approved and neither one is stacked, then merge the catalog one right after. Until the catalog one merges, catalog `main` fails against boxel `main`, and boxel-catalog CI is red for everyone.
- **Boxel first:** the boxel pull request pins the catalog pull request's head. Merge the boxel pull request only once its catalog pull request is approved and neither one is stacked, then merge the catalog one right after. Until the catalog one merges, catalog `main` fails against boxel `main`, and boxel-catalog CI is red for everyone.
- **Catalog first:** merge the catalog pull request, re-pin the boxel pull request onto catalog `main` (`pnpm --dir packages/catalog catalog:test-subset --bump`), re-run its checks, then merge it. Lint Catalog enforces the re-pin: it fails the boxel pull request that declares `Merges after:` the catalog pull request until that has merged and the pin contains its merge commit, since production deploys the catalog at the revision boxel pins.
- **Each environment gets the catalog on its own schedule.** Staging syncs catalog `main` on every catalog merge. Production gets only what boxel-catalog's "Deploy to production" deploys: the revision boxel pins, before and after Manual Deploy [boxel] to production releases, or a catalog `main` revision someone deploys by hand. That deploy refuses while a catalog pull request in it says `Merges after:` a boxel pull request production doesn't run. So a catalog change that needs boxel code declares its pair even when Lint Catalog wouldn't require one. The `catalog-deploy` skill covers the deploy and its refusals.
Loading
Loading