fix(self-update): guard against non-master branch and dirty tree#438
Merged
icebear0828 merged 1 commit intodevfrom May 4, 2026
Merged
fix(self-update): guard against non-master branch and dirty tree#438icebear0828 merged 1 commit intodevfrom
icebear0828 merged 1 commit intodevfrom
Conversation
applyProxySelfUpdate previously ran `git checkout -- .` followed by `git pull origin master` unconditionally. Two real consequences: 1. Any uncommitted local change was silently discarded. With dev server running under tsx watch, every restart triggered the 10s update check; if auto_update was on, the developer's in-flight edits were wiped within ~12s of save. 2. The pull merged master into whatever branch was checked out — on `dev` this corrupts the dev→master promote contract documented in CLAUDE.md. Add two safety guards before any destructive op: - Refuse to apply when current branch is not `master` / `main`. - Refuse to apply when `git status --porcelain` is non-empty. Drop the silent `git checkout -- .` entirely; if the tree is clean and on master, plain `git pull` is sufficient. Both refusals return the existing error envelope so the dashboard / API can surface the reason.
icebear0828
added a commit
that referenced
this pull request
May 5, 2026
The soak check measures `now - dev_HEAD_timestamp >= 24h`, which means every new merge into dev resets the clock. Under any non-trivial merge cadence, dev never satisfies the soak gate and master stagnates: PRs #437/#438/#439/#440/#442 all stacked on dev for a week with no promotion. Add a `force_skip_soak` boolean input to workflow_dispatch (default false). Schedule cron remains untouched and continues to enforce the 24h rule. Only manual triggers can bypass, and only when the operator explicitly sets the input to true — intended for sync-back / merge commits whose content has actually been on dev long enough but whose HEAD timestamp is misleadingly fresh. Test plan: yaml syntax verified via js-yaml. Functional verification will be the next manual workflow_dispatch run with the input set. Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com>
icebear0828
added a commit
that referenced
this pull request
May 5, 2026
applyProxySelfUpdate previously ran `git checkout -- .` followed by `git pull origin master` unconditionally. Two real consequences: 1. Any uncommitted local change was silently discarded. With dev server running under tsx watch, every restart triggered the 10s update check; if auto_update was on, the developer's in-flight edits were wiped within ~12s of save. 2. The pull merged master into whatever branch was checked out — on `dev` this corrupts the dev→master promote contract documented in CLAUDE.md. Add two safety guards before any destructive op: - Refuse to apply when current branch is not `master` / `main`. - Refuse to apply when `git status --porcelain` is non-empty. Drop the silent `git checkout -- .` entirely; if the tree is clean and on master, plain `git pull` is sufficient. Both refusals return the existing error envelope so the dashboard / API can surface the reason. Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com>
icebear0828
added a commit
that referenced
this pull request
May 5, 2026
The soak check measures `now - dev_HEAD_timestamp >= 24h`, which means every new merge into dev resets the clock. Under any non-trivial merge cadence, dev never satisfies the soak gate and master stagnates: PRs #437/#438/#439/#440/#442 all stacked on dev for a week with no promotion. Add a `force_skip_soak` boolean input to workflow_dispatch (default false). Schedule cron remains untouched and continues to enforce the 24h rule. Only manual triggers can bypass, and only when the operator explicitly sets the input to true — intended for sync-back / merge commits whose content has actually been on dev long enough but whose HEAD timestamp is misleadingly fresh. Test plan: yaml syntax verified via js-yaml. Functional verification will be the next manual workflow_dispatch run with the input set. Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
applyProxySelfUpdate之前会无条件git checkout -- .+git pull origin master。两个真实后果:dev 服跑着改代码时,tsx watch 每次重启触发 10s update check,开发者刚保存的改动会在 ~12s 内被git checkout -- .静默吞掉;并且即使在dev等非 master 分支上也照样把 master 合进来,破坏 dev→master promote 流程。本 PR 加双重护栏 + 移除危险的 checkout 调用。Changes
src/self-update.ts:applyProxySelfUpdate进入即先校验master/main,否则 abort 返回错误git status --porcelain必须为空,否则 abort 返回错误git checkout -- .;干净 master 上的git pull已足够tests/unit/self-update.test.ts:4 条新 case(干净 master 走完整流程并断言无 checkout 调用、dev 分支被拒、main 分支被接受、脏树被拒)tests/e2e/self-update.test.ts:5 条 mock 序列改为[branch, status, ...]适配新调用顺序CHANGELOG.md:[Unreleased] → Fixed第一条Test Plan
npx vitest run tests/unit/self-update.test.ts— 28 通过npx vitest run tests/e2e/self-update.test.ts— 15 通过 + 1 skippednpm test— 1657 通过 + 1 skippednpx tsc --noEmit— 无报错Notes
发现路径有点意思:起初是排查"开 dev server 改代码会被神秘覆盖",靠
sudo fs_usage抓到git.<pid>在写源码文件,回溯到src/self-update.ts:458的git checkout -- .。所有跑在 dev 分支并启用auto_update: true的开发者都会中招。