From 8763e4e22e2382d10e36a4a6fcc5de1a8ac147e1 Mon Sep 17 00:00:00 2001 From: Maksim Zayats Date: Sun, 31 May 2026 23:18:32 +0100 Subject: [PATCH 1/5] docs: add upstream sync slash command --- .agents/commands/upstream-sync.md | 221 ++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 .agents/commands/upstream-sync.md diff --git a/.agents/commands/upstream-sync.md b/.agents/commands/upstream-sync.md new file mode 100644 index 000000000..f1e333666 --- /dev/null +++ b/.agents/commands/upstream-sync.md @@ -0,0 +1,221 @@ +--- +description: Refresh the Superset upstream mirror and open a safe sync PR into main when needed +allowed-tools: Bash +argumentHint: "[--dry-run] [--mirror-only]" +--- + +# Upstream Sync + +Refresh `origin/upstream` from `superset-sh/superset:main`, then open a proxy-branch PR into `origin/main` only when O3 Code is actually behind upstream. + +This command is shared from `.agents/commands/`. `.claude/commands` and `.cursor/commands` are symlinks to that directory, so do not duplicate this file elsewhere. + +## Arguments + +- `--dry-run` — inspect and report only. Do not push, create branches, commit, or open PRs. +- `--mirror-only` — fast-forward `origin/upstream`, then stop before creating a PR. + +## Repository Model + +- `origin/main` is the O3 Code product branch. +- `superset/main` is the upstream Superset source branch. +- `origin/upstream` is a pure mirror of `superset/main`. +- Conflict resolution happens only on a proxy branch based on `origin/main`. + +`origin/upstream` must stay pure: never commit to it, never resolve conflicts on it, never rebase it, and never force-push it. + +## Hard Rules + +- Do not push directly to `main`. +- Do not use `--force` or `--force-with-lease`. +- Do not squash or rebase the sync PR. Merge it with a merge commit so `origin/upstream` remains in `main` history. +- Do not include agent attribution in branch names, commit messages, PR titles, PR bodies, or comments. +- If there are unrelated local changes, stop and report them before staging, switching branches, or merging. +- For database schema changes, never manually edit `packages/db/drizzle/`. Port schema changes in `packages/db/src/schema/` and follow the repo's Drizzle/Neon migration rules. + +## Workflow + +### 1. Parse Arguments + +Read `$ARGUMENTS` and set: + +```bash +DRY_RUN=0 +MIRROR_ONLY=0 +case " $ARGUMENTS " in + *" --dry-run "*) DRY_RUN=1 ;; +esac +case " $ARGUMENTS " in + *" --mirror-only "*) MIRROR_ONLY=1 ;; +esac +``` + +Reject unknown flags. + +### 2. Preflight + +Run: + +```bash +git status --short --branch +git remote get-url origin +git remote get-url superset +gh auth status +gh repo view --json nameWithOwner,defaultBranchRef +``` + +Expected remotes: + +- `origin`: `https://github.com/o3dotdev/o3-code.git` +- `superset`: `https://github.com/superset-sh/superset.git` + +If `superset` is missing, add it: + +```bash +git remote add superset https://github.com/superset-sh/superset.git +``` + +If the worktree is dirty, stop unless the only changes are the command files being intentionally edited for this slash command. For an upstream content sync, start from a clean worktree. + +### 3. Fetch And Compare + +Run: + +```bash +git fetch --no-tags origin main upstream +git fetch --no-tags superset main +git rev-list --left-right --count origin/main...origin/upstream +git rev-list --left-right --count origin/upstream...superset/main +git log --oneline origin/upstream..superset/main +git log --oneline origin/main..origin/upstream +``` + +Record: + +- current `origin/main` SHA +- current `origin/upstream` SHA +- current `superset/main` SHA +- upstream range being mirrored, if any + +### 4. Refresh The Mirror + +Before pushing the mirror, verify fast-forward ancestry: + +```bash +git merge-base --is-ancestor origin/upstream superset/main +``` + +If this fails, stop. `origin/upstream` has diverged from Superset and needs human review. + +If `--dry-run` was passed, do not push. Report whether `origin/upstream` can be fast-forwarded and continue with a simulated PR-needed check using `superset/main`. + +Otherwise run: + +```bash +git push origin refs/remotes/superset/main:refs/heads/upstream +git fetch --no-tags origin upstream main +``` + +If the push is rejected, fetch again and rerun the ancestry check. Retry only if `origin/upstream` is still an ancestor of `superset/main`. + +### 5. Decide Whether A PR Is Needed + +After refreshing the mirror, run: + +```bash +behind="$(git rev-list --count origin/main..origin/upstream)" +echo "$behind" +``` + +If `behind` is `0`, stop. `main` already contains upstream; do not create an empty PR. + +If `--mirror-only` was passed, stop after reporting `behind`. + +Check for an existing open sync PR: + +```bash +gh pr list --base main --state open --json number,title,headRefName,url \ + --jq '.[] | select(.headRefName == "upstream" or (.headRefName | startswith("sync/upstream-")))' +``` + +If one exists, inspect it and update that branch instead of opening a duplicate. + +### 6. Create The Proxy Branch + +Create the PR branch from `origin/main`. Use today's date in `YYYYMMDD` format; if the branch exists, append `-2`, `-3`, etc. + +```bash +git switch main +git pull --ff-only origin main +git switch -c sync/upstream-YYYYMMDD +git merge --no-ff --no-edit origin/upstream +``` + +Resolve conflicts only on the proxy branch. Keep upstream fixes, but preserve O3-specific choices. + +Fork-delta watch points: + +- Branding, package names, app names, CLI names, bundle IDs, deep links, paths, domains, and env prefixes stay O3 Code, not Superset. +- Fork-owned database baselines stay fork-owned. Do not import upstream generated Drizzle migrations directly. +- GitHub-only auth, O3 ports, O3 docs links, release channels, and deployment settings stay aligned with O3 Code infrastructure. +- Desktop Web Access means renderer, IPC, tRPC transport, storage, routing, sidebar state, and host-service networking changes need browser-mode compatibility checks. +- Next.js request interception files must be `proxy.ts`, not `middleware.ts`. + +Useful conflict checks: + +```bash +git status --short +git diff --check +git diff --name-only --diff-filter=U +git diff origin/main...HEAD --stat +``` + +### 7. Validate + +For an upstream content sync, run: + +```bash +bun run lint:fix +bun run lint +bun run typecheck +bun test +``` + +Run targeted tests for any conflict area. Run `bun run build` when upstream touches packaging, Next apps, Electron, shared config, or release workflows. + +If validation fails from an unrelated existing issue, capture the exact command and failure in the PR body. + +### 8. Open The PR + +Push the proxy branch: + +```bash +git push -u origin sync/upstream-YYYYMMDD +``` + +Create a PR into `main`: + +```bash +gh pr create --base main --head sync/upstream-YYYYMMDD \ + --title "Sync upstream Superset changes" \ + --body-file /tmp/upstream-sync-pr.md +``` + +The PR body must include: + +- Upstream range, for example `superset-sh/superset ..`. +- Whether `origin/upstream` was fast-forwarded. +- Conflict areas and fork-delta decisions. +- Validation commands and results. +- Deferred follow-up work, if any. + +### 9. Post-Merge Check + +After the PR merges: + +```bash +git fetch --no-tags origin main upstream +git merge-base --is-ancestor origin/upstream origin/main +``` + +The command must exit `0`. If it does not, the sync PR was merged incorrectly or the mirror advanced after the PR branch was created. From a3d655226ba1d08a74ee639dc0667bb01824d744 Mon Sep 17 00:00:00 2001 From: Maksim Zayats Date: Sun, 31 May 2026 23:24:35 +0100 Subject: [PATCH 2/5] docs: reference fork delta docs in sync command --- .agents/commands/upstream-sync.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.agents/commands/upstream-sync.md b/.agents/commands/upstream-sync.md index f1e333666..80f8b216b 100644 --- a/.agents/commands/upstream-sync.md +++ b/.agents/commands/upstream-sync.md @@ -31,7 +31,7 @@ This command is shared from `.agents/commands/`. `.claude/commands` and `.cursor - Do not squash or rebase the sync PR. Merge it with a merge commit so `origin/upstream` remains in `main` history. - Do not include agent attribution in branch names, commit messages, PR titles, PR bodies, or comments. - If there are unrelated local changes, stop and report them before staging, switching branches, or merging. -- For database schema changes, never manually edit `packages/db/drizzle/`. Port schema changes in `packages/db/src/schema/` and follow the repo's Drizzle/Neon migration rules. +- Follow the repository rules in `AGENTS.md`; do not duplicate those rules in this command. ## Workflow @@ -153,13 +153,12 @@ git merge --no-ff --no-edit origin/upstream Resolve conflicts only on the proxy branch. Keep upstream fixes, but preserve O3-specific choices. -Fork-delta watch points: +Before resolving conflicts, read the canonical fork-delta references: -- Branding, package names, app names, CLI names, bundle IDs, deep links, paths, domains, and env prefixes stay O3 Code, not Superset. -- Fork-owned database baselines stay fork-owned. Do not import upstream generated Drizzle migrations directly. -- GitHub-only auth, O3 ports, O3 docs links, release channels, and deployment settings stay aligned with O3 Code infrastructure. -- Desktop Web Access means renderer, IPC, tRPC transport, storage, routing, sidebar state, and host-service networking changes need browser-mode compatibility checks. -- Next.js request interception files must be `proxy.ts`, not `middleware.ts`. +- `AGENTS.md` for repo rules, including command placement, git/GitHub attribution, database migration handling, and Next.js request interception naming. +- `docs/internal/fork-deltas/registry.md` for O3-specific behavior that must be preserved when porting upstream changes. + +Treat those files as the source of truth. If a sync exposes a new intentional O3-vs-upstream behavior difference, update `docs/internal/fork-deltas/registry.md` in the sync PR instead of adding a one-off checklist here. Useful conflict checks: From 81120122f79821309ebea601cbc9b42d3f003103 Mon Sep 17 00:00:00 2001 From: Maksim Zayats Date: Mon, 1 Jun 2026 08:20:54 +0100 Subject: [PATCH 3/5] docs: fix upstream sync dry-run comparison --- .agents/commands/upstream-sync.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.agents/commands/upstream-sync.md b/.agents/commands/upstream-sync.md index 80f8b216b..9c334c895 100644 --- a/.agents/commands/upstream-sync.md +++ b/.agents/commands/upstream-sync.md @@ -120,14 +120,20 @@ If the push is rejected, fetch again and rerun the ancestry check. Retry only if ### 5. Decide Whether A PR Is Needed -After refreshing the mirror, run: +After refreshing the mirror, or after selecting the simulated comparison ref for `--dry-run`, run: ```bash -behind="$(git rev-list --count origin/main..origin/upstream)" +COMPARE_REF="origin/upstream" +if [ "$DRY_RUN" -eq 1 ]; then + COMPARE_REF="superset/main" +fi +behind="$(git rev-list --count "origin/main..$COMPARE_REF")" echo "$behind" ``` -If `behind` is `0`, stop. `main` already contains upstream; do not create an empty PR. +If `behind` is `0`, stop. `main` already contains the comparison ref; do not create an empty PR. + +If `--dry-run` was passed, report whether a PR would be needed and stop before checking out branches or opening a PR. If `--mirror-only` was passed, stop after reporting `behind`. From 0fb4941df0bd01c08ca1efff9480d1e3d4d4cc26 Mon Sep 17 00:00:00 2001 From: Maksim Zayats Date: Mon, 1 Jun 2026 08:24:28 +0100 Subject: [PATCH 4/5] docs: remove upstream sync dry-run mode --- .agents/commands/upstream-sync.md | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/.agents/commands/upstream-sync.md b/.agents/commands/upstream-sync.md index 9c334c895..f754594fe 100644 --- a/.agents/commands/upstream-sync.md +++ b/.agents/commands/upstream-sync.md @@ -1,7 +1,7 @@ --- description: Refresh the Superset upstream mirror and open a safe sync PR into main when needed allowed-tools: Bash -argumentHint: "[--dry-run] [--mirror-only]" +argumentHint: "[--mirror-only]" --- # Upstream Sync @@ -12,7 +12,6 @@ This command is shared from `.agents/commands/`. `.claude/commands` and `.cursor ## Arguments -- `--dry-run` — inspect and report only. Do not push, create branches, commit, or open PRs. - `--mirror-only` — fast-forward `origin/upstream`, then stop before creating a PR. ## Repository Model @@ -40,11 +39,7 @@ This command is shared from `.agents/commands/`. `.claude/commands` and `.cursor Read `$ARGUMENTS` and set: ```bash -DRY_RUN=0 MIRROR_ONLY=0 -case " $ARGUMENTS " in - *" --dry-run "*) DRY_RUN=1 ;; -esac case " $ARGUMENTS " in *" --mirror-only "*) MIRROR_ONLY=1 ;; esac @@ -88,6 +83,9 @@ git rev-list --left-right --count origin/main...origin/upstream git rev-list --left-right --count origin/upstream...superset/main git log --oneline origin/upstream..superset/main git log --oneline origin/main..origin/upstream +git show --no-patch --format='origin/main %H %s' origin/main +git show --no-patch --format='origin/upstream %H %s' origin/upstream +git show --no-patch --format='superset/main %H %s' superset/main ``` Record: @@ -96,6 +94,8 @@ Record: - current `origin/upstream` SHA - current `superset/main` SHA - upstream range being mirrored, if any +- whether `origin/upstream` already matches `superset/main` +- how many commits `origin/main` is missing from the refreshed mirror ### 4. Refresh The Mirror @@ -107,33 +107,26 @@ git merge-base --is-ancestor origin/upstream superset/main If this fails, stop. `origin/upstream` has diverged from Superset and needs human review. -If `--dry-run` was passed, do not push. Report whether `origin/upstream` can be fast-forwarded and continue with a simulated PR-needed check using `superset/main`. - -Otherwise run: +Run: ```bash git push origin refs/remotes/superset/main:refs/heads/upstream git fetch --no-tags origin upstream main +git show --no-patch --format='origin/upstream %H %s' origin/upstream ``` If the push is rejected, fetch again and rerun the ancestry check. Retry only if `origin/upstream` is still an ancestor of `superset/main`. ### 5. Decide Whether A PR Is Needed -After refreshing the mirror, or after selecting the simulated comparison ref for `--dry-run`, run: +After refreshing the mirror, run: ```bash -COMPARE_REF="origin/upstream" -if [ "$DRY_RUN" -eq 1 ]; then - COMPARE_REF="superset/main" -fi -behind="$(git rev-list --count "origin/main..$COMPARE_REF")" +behind="$(git rev-list --count origin/main..origin/upstream)" echo "$behind" ``` -If `behind` is `0`, stop. `main` already contains the comparison ref; do not create an empty PR. - -If `--dry-run` was passed, report whether a PR would be needed and stop before checking out branches or opening a PR. +If `behind` is `0`, stop. `main` already contains the refreshed upstream mirror; do not create an empty PR. If `--mirror-only` was passed, stop after reporting `behind`. From bf575a2c90e8cbe9f51f65ad8dfe5c540722e7fa Mon Sep 17 00:00:00 2001 From: Maksim Zayats Date: Mon, 1 Jun 2026 08:29:15 +0100 Subject: [PATCH 5/5] docs: harden upstream sync command flow --- .agents/commands/upstream-sync.md | 132 ++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 24 deletions(-) diff --git a/.agents/commands/upstream-sync.md b/.agents/commands/upstream-sync.md index f754594fe..472808604 100644 --- a/.agents/commands/upstream-sync.md +++ b/.agents/commands/upstream-sync.md @@ -26,10 +26,11 @@ This command is shared from `.agents/commands/`. `.claude/commands` and `.cursor ## Hard Rules - Do not push directly to `main`. +- Do not push to the `superset` remote. - Do not use `--force` or `--force-with-lease`. - Do not squash or rebase the sync PR. Merge it with a merge commit so `origin/upstream` remains in `main` history. - Do not include agent attribution in branch names, commit messages, PR titles, PR bodies, or comments. -- If there are unrelated local changes, stop and report them before staging, switching branches, or merging. +- Start from a clean worktree. If there are local changes, stop and report them before fetching, switching branches, or merging. - Follow the repository rules in `AGENTS.md`; do not duplicate those rules in this command. ## Workflow @@ -40,37 +41,55 @@ Read `$ARGUMENTS` and set: ```bash MIRROR_ONLY=0 -case " $ARGUMENTS " in - *" --mirror-only "*) MIRROR_ONLY=1 ;; -esac +for arg in $ARGUMENTS; do + case "$arg" in + --mirror-only) MIRROR_ONLY=1 ;; + "") ;; + *) + echo "Unknown argument: $arg" + exit 1 + ;; + esac +done ``` -Reject unknown flags. - ### 2. Preflight Run: ```bash git status --short --branch -git remote get-url origin -git remote get-url superset +origin_url="$(git remote get-url origin)" +superset_url="$(git remote get-url superset 2>/dev/null || true)" +if [ -z "$superset_url" ]; then + git remote add superset https://github.com/superset-sh/superset.git + superset_url="$(git remote get-url superset)" +fi gh auth status -gh repo view --json nameWithOwner,defaultBranchRef +repo_name="$(gh repo view --json nameWithOwner --jq .nameWithOwner)" +default_branch="$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name)" +printf 'origin=%s\nsuperset=%s\nrepo=%s\ndefault_branch=%s\n' \ + "$origin_url" "$superset_url" "$repo_name" "$default_branch" +if [ "$repo_name" != "o3dotdev/o3-code" ] || [ "$default_branch" != "main" ]; then + echo "Unexpected repository context; refusing upstream sync." + exit 1 +fi ``` -Expected remotes: - -- `origin`: `https://github.com/o3dotdev/o3-code.git` -- `superset`: `https://github.com/superset-sh/superset.git` - -If `superset` is missing, add it: +Then enforce a clean worktree before any mutating sync step: ```bash -git remote add superset https://github.com/superset-sh/superset.git +if [ -n "$(git status --porcelain)" ]; then + echo "Working tree is dirty. Commit, stash, or discard local changes before upstream sync." + git status --short + exit 1 +fi ``` -If the worktree is dirty, stop unless the only changes are the command files being intentionally edited for this slash command. For an upstream content sync, start from a clean worktree. +Expected remotes: + +- `origin`: `https://github.com/o3dotdev/o3-code.git` +- `superset`: `https://github.com/superset-sh/superset.git` ### 3. Fetch And Compare @@ -86,6 +105,9 @@ git log --oneline origin/main..origin/upstream git show --no-patch --format='origin/main %H %s' origin/main git show --no-patch --format='origin/upstream %H %s' origin/upstream git show --no-patch --format='superset/main %H %s' superset/main +origin_main_sha="$(git rev-parse origin/main)" +origin_upstream_before="$(git rev-parse origin/upstream)" +superset_main_sha="$(git rev-parse superset/main)" ``` Record: @@ -113,6 +135,8 @@ Run: git push origin refs/remotes/superset/main:refs/heads/upstream git fetch --no-tags origin upstream main git show --no-patch --format='origin/upstream %H %s' origin/upstream +origin_upstream_after="$(git rev-parse origin/upstream)" +test "$origin_upstream_after" = "$(git rev-parse superset/main)" ``` If the push is rejected, fetch again and rerun the ancestry check. Retry only if `origin/upstream` is still an ancestor of `superset/main`. @@ -137,24 +161,56 @@ gh pr list --base main --state open --json number,title,headRefName,url \ --jq '.[] | select(.headRefName == "upstream" or (.headRefName | startswith("sync/upstream-")))' ``` -If one exists, inspect it and update that branch instead of opening a duplicate. +If one exists, do not open a duplicate. If its head branch is `upstream`, stop: the mirror branch must stay pure, so that PR should be replaced by a proxy-branch sync PR. If its head branch starts with `sync/upstream-`, update that branch: + +```bash +existing_sync_branch="$(gh pr list --base main --state open --json headRefName \ + --jq '[.[] | select(.headRefName == "upstream" or (.headRefName | startswith("sync/upstream-")))][0].headRefName // ""')" +if [ -n "$existing_sync_branch" ]; then + if [ "$existing_sync_branch" = "upstream" ]; then + echo "Open sync PR uses mirror branch directly. Do not commit to upstream; replace it with a proxy branch." + exit 1 + fi + git fetch origin "$existing_sync_branch" + git switch "$existing_sync_branch" 2>/dev/null || \ + git switch -c "$existing_sync_branch" --track "origin/$existing_sync_branch" + sync_branch="$existing_sync_branch" + git merge --no-ff --no-edit origin/upstream +fi +``` ### 6. Create The Proxy Branch -Create the PR branch from `origin/main`. Use today's date in `YYYYMMDD` format; if the branch exists, append `-2`, `-3`, etc. +If `sync_branch` is already set from an existing proxy sync PR, skip branch creation and continue with the conflict/fork-delta review below. Otherwise, create the PR branch from `origin/main`. Use today's UTC date in `YYYYMMDD` format; if the branch exists locally or remotely, append `-2`, `-3`, etc. ```bash git switch main git pull --ff-only origin main -git switch -c sync/upstream-YYYYMMDD +sync_date="$(date -u +%Y%m%d)" +sync_branch="sync/upstream-$sync_date" +suffix=2 +while git show-ref --verify --quiet "refs/heads/$sync_branch" || \ + git ls-remote --exit-code --heads origin "$sync_branch" >/dev/null 2>&1; do + sync_branch="sync/upstream-$sync_date-$suffix" + suffix=$((suffix + 1)) +done +git switch -c "$sync_branch" git merge --no-ff --no-edit origin/upstream ``` -Resolve conflicts only on the proxy branch. Keep upstream fixes, but preserve O3-specific choices. +Resolve conflicts only on the proxy branch. Keep upstream fixes, but preserve O3-specific choices. If the merge reports conflicts, complete the merge after resolving them: + +```bash +git diff --name-only --diff-filter=U +git status --short +git add +git commit --no-edit +``` -Before resolving conflicts, read the canonical fork-delta references: +Before resolving conflicts and before treating a conflict-free merge as ready, read the canonical fork-delta references: - `AGENTS.md` for repo rules, including command placement, git/GitHub attribution, database migration handling, and Next.js request interception naming. +- `docs/internal/fork-deltas/README.md` for when fork-delta entries are required. - `docs/internal/fork-deltas/registry.md` for O3-specific behavior that must be preserved when porting upstream changes. Treat those files as the source of truth. If a sync exposes a new intentional O3-vs-upstream behavior difference, update `docs/internal/fork-deltas/registry.md` in the sync PR instead of adding a one-off checklist here. @@ -188,13 +244,41 @@ If validation fails from an unrelated existing issue, capture the exact command Push the proxy branch: ```bash -git push -u origin sync/upstream-YYYYMMDD +git push -u origin "$sync_branch" ``` +Create the PR body before opening the PR: + +```bash +cat >/tmp/upstream-sync-pr.md <}\` +- New mirror: \`${origin_upstream_after:-$(git rev-parse origin/upstream)}\` +- Superset range: \`${origin_upstream_before:-}..${origin_upstream_after:-$(git rev-parse origin/upstream)}\` + +## Conflict And Fork-Delta Notes +- Conflicts: +- Fork-delta registry updates: +- Merge method required: merge commit, not squash/rebase. + +## Validation +- + +## Follow-Ups +- +EOF +``` + +Replace any placeholder values before creating the PR if the SHA variables were not preserved in the shell session. + Create a PR into `main`: ```bash -gh pr create --base main --head sync/upstream-YYYYMMDD \ +gh pr create --base main --head "$sync_branch" \ --title "Sync upstream Superset changes" \ --body-file /tmp/upstream-sync-pr.md ```