Skip to content

Commit 3d0e16b

Browse files
committed
docs: document upstream rebrand workflow
1 parent 07d5069 commit 3d0e16b

1 file changed

Lines changed: 116 additions & 0 deletions

File tree

scripts/upstream-sync/README.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Upstream sync
2+
3+
This workflow imports Kimi Code releases into Pythinker Code without changing the Pythinker product identity. `blackbox/refrence` is the read-only Kimi upstream checkout; Pythinker development and releases stay in this repository.
4+
5+
## Brand boundary
6+
7+
- Never merge `blackbox/refrence/main` directly into Pythinker `main`.
8+
- Import a full upstream tree through `rebrand.mjs`, commit that tree on `vendor/upstream`, then merge `vendor/upstream` into a fresh sync branch.
9+
- Keep Pythinker names, package scopes, URLs, logos, managed-service policy, and retained fork features.
10+
- Keep deliberate Kimi/Moonshot provider data: `api.moonshot.*`, `api.kimi.com`, `platform.kimi.*`, `kimi-k*` models, `kimi-for-coding`, `moonshot-*` provider IDs, and `MOONSHOT_API_KEY`.
11+
- Merge the pull request with a merge commit. Squash or rebase removes the vendor ancestry that future three-way merges need.
12+
13+
## Import a release
14+
15+
Run each step from the Pythinker repository root unless the command uses `git -C`.
16+
17+
1. Fetch Kimi and select the release commit.
18+
19+
```sh
20+
git -C blackbox/refrence fetch origin
21+
git -C blackbox/refrence log --oneline --decorate origin/main
22+
git -C blackbox/refrence show --stat <release-commit>
23+
```
24+
25+
2. Export and rebrand the selected tree. Both output locations must be disposable task-local directories because `rebrand.mjs` replaces its output directory.
26+
27+
```sh
28+
export_root="$(mktemp -d "${TMPDIR:-/tmp}/pythinker-upstream.XXXXXX")"
29+
rebrand_root="$(mktemp -d "${TMPDIR:-/tmp}/pythinker-rebrand.XXXXXX")"
30+
export_dir="$export_root/tree"
31+
rebrand_dir="$rebrand_root/tree"
32+
mkdir "$export_dir"
33+
git -C blackbox/refrence archive <release-commit> | tar -x -C "$export_dir"
34+
node scripts/upstream-sync/rebrand.mjs "$export_dir" "$rebrand_dir"
35+
```
36+
37+
3. Replace the `vendor/upstream` snapshot in a dedicated worktree and commit it.
38+
39+
```sh
40+
worktree_root="$(mktemp -d "${TMPDIR:-/tmp}/pythinker-vendor.XXXXXX")"
41+
vendor_worktree="$worktree_root/worktree"
42+
git worktree add "$vendor_worktree" vendor/upstream
43+
test "$(git -C "$vendor_worktree" branch --show-current)" = "vendor/upstream"
44+
rsync --archive --delete --exclude .git "$rebrand_dir/" "$vendor_worktree/"
45+
git -C "$vendor_worktree" status --short
46+
git -C "$vendor_worktree" add -A
47+
git -C "$vendor_worktree" commit -m "vendor: rebrand Kimi Code <release>"
48+
```
49+
50+
4. Create a fresh sync branch from current Pythinker `main`, then merge the vendor snapshot. Keep rerere enabled so recorded conflict resolutions replay.
51+
52+
```sh
53+
git switch main
54+
git pull --ff-only
55+
git switch -c sync/upstream-<release>
56+
git config rerere.enabled true
57+
git merge --no-ff vendor/upstream
58+
```
59+
60+
5. Resolve only genuine new conflicts. Retain Pythinker branding and fork features; do not restore upstream managed-account behavior.
61+
62+
## Post-merge checks
63+
64+
Run these checks in order.
65+
66+
1. Find silently deleted files and compare them with the vendor tree. Restore a path that exists in `vendor/upstream` unless it is an intentional Pythinker deletion.
67+
68+
```sh
69+
git diff --name-only ORIG_HEAD..HEAD --diff-filter=D
70+
git ls-tree -r --name-only vendor/upstream
71+
```
72+
73+
2. Require zero camel-case rename residue.
74+
75+
```sh
76+
rg 'dynamic_workflow[A-Z]'
77+
```
78+
79+
3. Audit every brand match. Only the provider values listed in [Brand boundary](#brand-boundary) can remain.
80+
81+
```sh
82+
rg -in 'kimi|moonshot'
83+
```
84+
85+
4. Verify that upstream did not restore the removed managed service.
86+
87+
```sh
88+
node scripts/upstream-sync/check-managed.mjs
89+
```
90+
91+
5. Run the full gates separately and record each exit status.
92+
93+
```sh
94+
pnpm run typecheck
95+
pnpm run lint
96+
pnpm test
97+
pnpm -C apps/vscode run typecheck
98+
pnpm -C apps/vscode test
99+
nix build .#pythinker-code
100+
node scripts/check-nix-workspace.mjs
101+
node scripts/upstream-sync/check-managed.mjs
102+
```
103+
104+
If `pnpm-lock.yaml` changed, update the `pnpmDeps` hash in `flake.nix` and rerun the Nix build. Treat a full-suite failure as red until the exact failing file passes in isolation and the load-related difference is documented.
105+
106+
## Pull request
107+
108+
Use a Conventional Commit title, fill the pull request template, run `gen-changesets`, and run the local review CLI when the diff exceeds the hosted reviewer limit. Merge only after required checks pass and every review conversation is resolved. Use a merge commit so `main` retains `vendor/upstream` ancestry.
109+
110+
## Known traps
111+
112+
- 3-way merges silently delete files our history removed but upstream didn't touch — always diff vendor file list vs worktree after a merge.
113+
- Git rename detection pairs upstream `vis` with `dashboard` — gone now, but watch for similar pairings.
114+
- Prose rename rules corrupt identifiers; the camel regex (`swarm(?=[A-Z])`) must stay ahead of the snake fallback in rebrand.mjs. Vendor snapshots built before the fix still carry `dynamic_workflowX` residue — sweep after merging.
115+
- Merged package.json/vite.config lose our test tooling (jsdom, @vue/test-utils, test block) — re-check after every web merge.
116+
- Vendor tree carries managed-service code back in on every sync — the D5 strip must be rerere-recorded deletions, plus the grep gate as a backstop.

0 commit comments

Comments
 (0)