From 43f07ee0395e2c397b2b6b7d0b448b612cb765d8 Mon Sep 17 00:00:00 2001 From: troytt <47798984@qq.com> Date: Tue, 22 Sep 2026 03:40:50 +0000 Subject: [PATCH] perf(r3): parallelize Gitea asset upload and issue comment pipeline --- scripts/execute-r3-all-221-skills.ts | 177 +++++++++++++++++---------- 1 file changed, 113 insertions(+), 64 deletions(-) diff --git a/scripts/execute-r3-all-221-skills.ts b/scripts/execute-r3-all-221-skills.ts index a945142..4186cd1 100644 --- a/scripts/execute-r3-all-221-skills.ts +++ b/scripts/execute-r3-all-221-skills.ts @@ -488,18 +488,38 @@ async function main(): Promise { // Step 1: Capture all 221 genuine Chromium screenshots const telemetryBySkill = await captureAll221ScreenshotsInHeadlessChrome(entries) - // Step 2: Execute strict isolated git worktree lifecycle for every skill - let processedInBatch = 0 - for (let i = 0; i < entries.length; i += 1) { - const entry = entries[i]! + // Step 2: Execute strict isolated git worktree lifecycle for every remaining skill + const remaining = entries.filter(entry => { + const id3 = String(entry.skillId).padStart(3, '0') + const implRelPath = `src/game/skills/impl/${entry.charClass}/skill-${id3}-${entry.slug}.ts` + const testRelPath = `tests/skills/${entry.charClass}/skill-${id3}-${entry.slug}.test.ts` + return !existsSync(resolve(REPO_ROOT, implRelPath)) || !existsSync(resolve(REPO_ROOT, testRelPath)) + }) + + console.log(`Remaining skills to complete via isolated worktree + Gitea upload/comment/merge: ${String(remaining.length)} / ${String(entries.length)}`) + + // Precompute all evaluation results and upload PNG + post comment + close issue in parallel (12-way concurrency) + const precomputed = new Map< + number, + { + id3: string + skill: SkillRecord + implRelPath: string + testRelPath: string + ev1: ReturnType + ev10: ReturnType + ev20: ReturnType + synSkillId: number | null + ev20WithSyn: ReturnType + } + >() + + for (const entry of remaining) { const id3 = String(entry.skillId).padStart(3, '0') const skill = registry.getSkillById(entry.skillId)! const implRelPath = `src/game/skills/impl/${entry.charClass}/skill-${id3}-${entry.slug}.ts` const testRelPath = `tests/skills/${entry.charClass}/skill-${id3}-${entry.slug}.test.ts` - const mainImplAbsPath = resolve(REPO_ROOT, implRelPath) - const mainTestAbsPath = resolve(REPO_ROOT, testRelPath) - // Precompute exact 1.13c numbers for slvl 1, 10, 20 + blvl synergy const s1 = new UnitStatList() s1.setBaseSkillLevel(skill.id, 1) const ev1 = evaluateSkillCore113c({ registry, skill, slvl: 1, blvl: 1, statList: s1 }) @@ -519,40 +539,29 @@ async function main(): Promise { if (synSkillId !== null) s20Syn.setBaseSkillLevel(synSkillId, 20) const ev20WithSyn = evaluateSkillCore113c({ registry, skill, slvl: 20, blvl: 20, statList: s20Syn }) - const alreadyOnMain = existsSync(mainImplAbsPath) && existsSync(mainTestAbsPath) - if (!alreadyOnMain) { - const wtPath = `/usr/local/google/home/taodao/wt-skill-${id3}` - const branchName = `feat/skill-${id3}` + precomputed.set(entry.skillId, { + id3, + skill, + implRelPath, + testRelPath, + ev1, + ev10, + ev20, + synSkillId, + ev20WithSyn, + }) + } - // Clean any stale worktree/branch before creating - try { - if (existsSync(wtPath)) { - runGit(['worktree', 'remove', '--force', wtPath]) - } - } catch {} - try { - runGit(['branch', '-D', branchName]) - } catch {} - - // 1. Create isolated git worktree from main - runGit(['worktree', 'add', wtPath, '-b', branchName, 'main']) - - // 2. Write implementation & Vitest file inside worktree - const wtImplAbs = resolve(wtPath, implRelPath) - const wtTestAbs = resolve(wtPath, testRelPath) - mkdirSync(resolve(wtPath, `src/game/skills/impl/${entry.charClass}`), { recursive: true }) - mkdirSync(resolve(wtPath, `tests/skills/${entry.charClass}`), { recursive: true }) - writeFileSync(wtImplAbs, generateSkillImplSource(entry, skill, id3)) - writeFileSync(wtTestAbs, generateSkillTestSource(entry, skill, id3, ev1, ev10, ev20, synSkillId, ev20WithSyn)) - - // 3. Stage and commit on branch feat/skill- - runGit(['add', implRelPath, testRelPath], wtPath) - runGit( - ['commit', '-m', `feat(skill-${id3}): implement 1.13c ${skill.name} module and Vitest suite (#${String(entry.issueNumber)})`], - wtPath, - ) - - // 4. Upload PNG screenshot & post verification comment on Gitea issue + // 2a. 12-way parallel Gitea screenshot upload + comment + closure for remaining skills + const CONCURRENCY = 12 + let cursor = 0 + let uploadedCount = 0 + async function giteaWorker(): Promise { + while (cursor < remaining.length) { + const idx = cursor++ + const entry = remaining[idx]! + const data = precomputed.get(entry.skillId)! + const { id3, skill, implRelPath, testRelPath, ev1, ev10, ev20, ev20WithSyn } = data const pngPath = `${SCREENSHOT_DIR}/skill-${id3}-${entry.slug}.png` const asset = await uploadPngToGiteaIssue(entry.issueNumber, pngPath) const snap = telemetryBySkill[entry.skillId] @@ -580,32 +589,72 @@ async function main(): Promise { ![Skill #${id3} ${skill.name}](${asset.browser_download_url}) ` await postGiteaIssueComment(entry.issueNumber, commentMd) - - // 5. Merge feat/skill- into main (--no-ff, fixes #) - runGit([ - 'merge', - '--no-ff', - branchName, - '-m', - `feat(skills): implement 1.13c ${skill.name} [Skill #${id3}] (fixes #${String(entry.issueNumber)})`, - ]) - - // 6. Immediately remove worktree and branch - runGit(['worktree', 'remove', wtPath]) - runGit(['branch', '-d', branchName]) - - // Ensure issue is closed on Gitea await closeGiteaIssue(entry.issueNumber) - processedInBatch += 1 - } - - if (processedInBatch >= 25 || i === entries.length - 1) { - if (processedInBatch > 0) { - runGit(['push', 'origin', 'main']) - processedInBatch = 0 + uploadedCount += 1 + if (uploadedCount % 25 === 0 || uploadedCount === remaining.length) { + console.log(` [Gitea Upload+Comment+Close] ${String(uploadedCount)}/${String(remaining.length)} completed`) } - updateProgressFile(i + 1, entries.length, `[Skill #${id3}] ${skill.name} (Issue #${String(entry.issueNumber)})`) - console.log(` [R3 Worktree+Gitea+Merge] Completed ${String(i + 1)}/${String(entries.length)} (latest: #${id3} ${skill.name} -> Issue #${String(entry.issueNumber)})`) + } + } + + await Promise.all(Array.from({ length: CONCURRENCY }, () => giteaWorker())) + + // 2b. Execute isolated git worktree add -> write -> commit -> merge --no-ff -> worktree remove -> branch -d + let completedTotal = entries.length - remaining.length + let batchSincePush = 0 + for (let i = 0; i < remaining.length; i += 1) { + const entry = remaining[i]! + const data = precomputed.get(entry.skillId)! + const { id3, skill, implRelPath, testRelPath, ev1, ev10, ev20, synSkillId, ev20WithSyn } = data + const wtPath = `/usr/local/google/home/taodao/wt-skill-${id3}` + const branchName = `feat/skill-${id3}` + + try { + if (existsSync(wtPath)) runGit(['worktree', 'remove', '--force', wtPath]) + } catch {} + try { + runGit(['branch', '-D', branchName]) + } catch {} + + // 1. Create isolated git worktree from main + runGit(['worktree', 'add', wtPath, '-b', branchName, 'main']) + + // 2. Write implementation & Vitest file inside worktree + const wtImplAbs = resolve(wtPath, implRelPath) + const wtTestAbs = resolve(wtPath, testRelPath) + mkdirSync(resolve(wtPath, `src/game/skills/impl/${entry.charClass}`), { recursive: true }) + mkdirSync(resolve(wtPath, `tests/skills/${entry.charClass}`), { recursive: true }) + writeFileSync(wtImplAbs, generateSkillImplSource(entry, skill, id3)) + writeFileSync(wtTestAbs, generateSkillTestSource(entry, skill, id3, ev1, ev10, ev20, synSkillId, ev20WithSyn)) + + // 3. Stage and commit on branch feat/skill- + runGit(['add', implRelPath, testRelPath], wtPath) + runGit( + ['commit', '-m', `feat(skill-${id3}): implement 1.13c ${skill.name} module and Vitest suite (#${String(entry.issueNumber)})`], + wtPath, + ) + + // 4. Merge feat/skill- into main (--no-ff, fixes #) + runGit([ + 'merge', + '--no-ff', + branchName, + '-m', + `feat(skills): implement 1.13c ${skill.name} [Skill #${id3}] (fixes #${String(entry.issueNumber)})`, + ]) + + // 5. Immediately remove worktree and branch + runGit(['worktree', 'remove', wtPath]) + runGit(['branch', '-d', branchName]) + + completedTotal += 1 + batchSincePush += 1 + + if (batchSincePush >= 25 || i === remaining.length - 1) { + runGit(['push', 'origin', 'main']) + batchSincePush = 0 + updateProgressFile(completedTotal, entries.length, `[Skill #${id3}] ${skill.name} (Issue #${String(entry.issueNumber)})`) + console.log(` [R3 Worktree+Merge+Push] Completed ${String(completedTotal)}/${String(entries.length)} (latest: #${id3} ${skill.name} -> Issue #${String(entry.issueNumber)})`) } }