Skip to content

emrg: 补 emrg/gui/package.json v0.2.3 版本同步(#407 遗漏) - #408

Merged
argszero merged 1 commit into
masterfrom
fix/gui-version-0.2.3
Aug 5, 2026
Merged

emrg: 补 emrg/gui/package.json v0.2.3 版本同步(#407 遗漏)#408
argszero merged 1 commit into
masterfrom
fix/gui-version-0.2.3

Conversation

@argszero

@argszero argszero commented Aug 5, 2026

Copy link
Copy Markdown
Owner

问题

#407 bump v0.2.3 时遗漏 emrg/gui/package.json(仍 0.2.2)。我曾在 #407 分支补过(7849bb5),但并发 merge 用旧 head(3071f3d)导致该 commit 丢失——master d55beb9 的 GUI 版本仍 0.2.2,与主版本不一致(rant #368 曾专门对齐过此问题)。

改动

emrg/gui/package.json:0.2.2 → 0.2.3(1 行)

验证

  • grep 确认 6 文件全 0.2.3(残留 0.2.2 仅在 make-installer.sh 注释中)
  • uv run pytest tests/ 通过(纯版本字符串)

后续

merge 后需重建 v0.2.3 tag(当前 tag 3071f3d 不含此修复)→ 触发 build-release.yml → 确认安装包内 GUI 版本 0.2.3

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle 20260805-1740

1 行纯版本字符串(gui/package.json 0.2.2 → 0.2.3),修复 #407 并发 merge 丢失的版本同步。CI test pass(37s)。merge 后需删 tag v0.2.3 重打触发重建(当前 tag 不含此修复)。

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle 20260805-1743

复审 diff:gui/package.json 0.2.2 → 0.2.3 单行变更,与 pyproject/init 对齐(master 上 gui 仍是 0.2.2 恰为本 PR 修复点)。CI pass。与 cycle 1740 的 LGTM 连续,无 ❌ 间隔。LGTM 2/3。

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle 20260805-1746

第三轮独立 review:gui/package.json 单行版本同步,与 pyproject/init 对齐,CI 全绿。连续 3 个不同 cycle 的 ✅(1740/1743/1746)且中间无 ❌——满足合并条件。merge 后需删除旧 v0.2.3 release + 删 tag 重打触发重建。

@argszero
argszero merged commit 3dea775 into master Aug 5, 2026
1 check passed
@argszero
argszero deleted the fix/gui-version-0.2.3 branch August 5, 2026 09:42
argszero added a commit that referenced this pull request Aug 5, 2026
#408 教训:bump 版本时遗漏 emrg/gui/package.json → 发布后发现
版本不一致 → 删 release + 删 tag + 重打 + 触发重建。

新增 tests/test_version_sync.py:从 emrg/__init__.py 取基准版本,
校验 6 处版本声明一致(pyproject / gui package.json / uv.lock /
make-installer.sh / build-runtime.sh fallback)。纯逻辑测试,
Windows CI 亦可执行(#406)。472 passed。

Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero pushed a commit that referenced this pull request Sep 10, 2026
…widen scratch ignore

Fixes the two findings from the cyc20260910-163037 review of PR #1119, both
reported by external contributors and reproduced independently here.

1. bump() short-circuited before validation (pm25coder). The
   already-at-target check ran *before* the pass-1 validation loop, so a
   tree whose base file already held the target while another source was
   stale printed "already at <target> — nothing to do" and exited 0, leaving
   the drift untouched:

       $ bump-version.py 0.2.93      -> exit 0, "nothing to do"
       $ bump-version.py --check     -> exit 1,
                                        emrg/gui/package.json: 0.0.1 != 0.2.93

   The repair mode silently disagreed with the check mode about the same
   tree, which is the #408 / #1065 shape this tool exists to prevent — and
   the natural way the mistake is made (hand-edit the base file, then run
   the tool). The no-op decision now happens *after* validation, so a
   drifted tree raises BumpError (exit 2) with the existing "sources are
   already inconsistent; run --check first" message, while a consistent
   tree still short-circuits to a no-op. Refusing is deliberate rather than
   repairing: pass 2 cannot repair anyway, since
   `m.group(0).replace(old, new)` is the identity when old == new.

2. `.emrg-*/` matched directories only (how2how2how2-arch), so a stray
   *file* named `.emrg-verify` stayed untracked-but-unignored and could
   still be swept in by `git add -A`. Widened to `.emrg-*`, which covers
   both forms and is equally safe (`git ls-files | grep '\.emrg-'` is
   empty). Also corrects the cycle id quoted in the .gitignore comment
   (`cyc20260910-150729` -> `cyc20260910-152337`) — the same wrong citation
   fixed in the guard last cycle but missed here.

Two regression tests pin the refusal in both shapes: another source drifted
while the base file holds the target, and the base file hand-edited forward
while the others lag. Each also asserts the refused bump modified nothing.
Agent.md Python test count 1272 -> 1274.
argszero added a commit that referenced this pull request Sep 10, 2026
…sing docs (#1119)

* emrg: add release version-bump tool (scripts/bump-version.py) with both-state tests

* emrg: close package-lock guard gap + --check positional validation (#1119 review)

* emrg: derive the --check CLI test's expected version from the tree under test

tests/test_bump_version.py pinned the literal 0.2.93 in the
--check-without-positional test, so the assertion only held while the
repository was at 0.2.93. Merging this branch into master (which now
ships 0.2.94) left the suite permanently red: 1 failed, 21 passed —
reproduced by merging 1a118c4 into 37d687e in a throwaway worktree, where
the tool correctly prints 0.2.94 and the test demanded 0.2.93.

Every other test in the file derives the version via
read_current_version(); this one now does too, so it is release-agnostic.
Verified in both states: 22 passed on a merged 0.2.94 tree, 25 passed
(bump-version + version-sync) on the branch's own 0.2.93 base.

* emrg: make the version tests independent of the repo's release version

Review follow-up (cycle cyc20260910-150727): my previous commit fixed the
one literal that was already wrong (0.2.93 in the --check CLI test), but the
file had three more version-dependent fixtures of the same class, and the
class itself was unguarded.

Measured, on real trees bumped with the tool:

  stamp equals the tree's version -> str.replace(old, new) is a no-op, no
  drift is created, and the test fails as if the tool had missed one
  (0 drifts on a tree stamped with its own version);

  bump target equals the tree's version -> bump() returns early
  ("already at ..."), so every test asserting a change fails.

Fixes the fixtures by derivation instead of by value:

* `_sentinel(base)` returns a version computed from the tree's own version,
  so a coinciding literal is structurally impossible;
* `TARGET` replaces the eleven hardcoded 9.9.9 bump targets;
* the half-miss lock test now doctors `packages[""]` by **anchor** rather than
  by `rpartition` on the last textual occurrence — the latter picks a
  dependency's version when the base (e.g. 1.0.0) appears among the 300+
  dependency entries, which is the same loose-anchor mistake this PR fixes in
  the guard.

Adds the guard for the whole class: test_version_literals_survive_the_next_release
predicts the version the repo will carry at its next release, bumps the
synthetic tree to it, and asserts every literal this file manipulates stays
distinct from the current version, that prediction, and every declared source
value. Both failure modes above were reproduced as mutations that the guard
catches, with actionable messages.

Verified: 26 passed in the two version test files on the PR base (0.2.93), and
26 passed on trees bumped to 0.2.94, 0.2.95, 0.3.0, 1.0.0, 0.0.1, 1.1.1 and
9.9.9; full suite 1266 passed / 1 skipped; Agent.md count synced to 1267.

* emrg: drop scratch tree from the branch and correct a wrong mechanism note

Two defects in c93d85c, both mine:

1. It committed `.emrg-cmp2/` — a scratch tree I had bumped with the tool while
   measuring the failure modes. Eight files of test fixtures that do not belong
   on the branch. Removed, and `.emrg-cmp*` / `.emrg-verify/` are now in
   `.git/info/exclude` so a measurement tree cannot be staged again.

2. One docstring still asserted the mechanism I had already disproved in the
   same session: that an `0.0.1` stamp on a `0.2.94` tree is "partially
   rewritten to 0.9.9". It is not — `'0.0.1'.replace('0.2.94', '9.9.9')`
   returns `'0.0.1'` unchanged. The real mechanism is that the substitution is
   a *no-op* when the stamp equals the tree's version, so no drift is created
   at all. The note now states the measured behaviour.

* emrg: close the scratch-tree leak class at its root, not just the instance

External contributor report (how2how2how2-arch, PR #1119): c93d85c committed
`.emrg-cmp2/` — ~272 KB / 5518 lines of a duplicated version tree. My cleanup
commit removed the files, but the review was right that removal alone leaves
the class open. Two root causes, both fixed here.

1. `.gitignore` said `.emrg`, which is an exact match and therefore does NOT
   cover `.emrg-cmp2` (or `.emrg-cmp`, `.emrg-wt-*`, `.emrg-verify`) — the
   scratch trees this repo's own release workflow creates. `git add -A` swept
   one in. Widened to `.emrg-*/`; verified no tracked path starts with `.emrg`,
   so nothing intended is swept.

2. Nothing detected the leak, structurally: the version guards use fixed paths
   (`VERSION_SOURCES`), so duplicate declarations under another directory never
   enter their scope, and CI stayed green on a branch carrying a second copy of
   uv.lock. `tests/test_no_duplicate_sources.py` adds the missing check by
   *content*: no tracked file outside the 8 canonical sources may restate the
   repo's own version. Anchored on content rather than directory names, so the
   next naming scheme is covered too. A companion test fails if the allowlist
   goes stale (a renamed source would otherwise be reported as pollution).

Verified in both states, using the exact leak shape (a copy of all eight
sources): the guard names all 8 leaked files including `.emrg-cmp2/uv.lock`
and `pyproject.toml` (which the first version of the guard missed — the marker
list is now enumerated per source format: `__version__ =`, `version =`,
`"version":`, `|| echo`); clean tree passes; untracked scratch trees stay
invisible to git status. Full suite 1268 passed / 1 skipped, Agent.md count
synced to 1269, import + CLI green.

* emrg: fix #1119 review findings — leak guard detects real leaks, bump() is atomic

Fixes the four findings from the cyc20260910-161233 review of PR #1119.

1. tests/test_no_duplicate_sources.py did not detect its own stated
   motivating leak. The rule built markers from the repo's *current*
   version, but `.emrg-cmp2/` had been bumped to 1.1.1, so no marker could
   ever match: a reconstructed leak shape scored 0/8 detections while the
   only file flagged was the guard itself. Detection is now two orthogonal
   rules — a version-independent path rule (a tracked path that ends with a
   canonical source path) and a content rule (declaration in a declaration
   position) — so bumped copies are caught by path and un-bumped renamed
   copies by content. The real leak shape now scores 8/8; the path rule has
   0 false positives across the tracked tree.

2. The guard false-positived on its own file. It quoted concrete version
   literals and matched them as bare substrings, so whenever the repo
   version equalled a quoted literal the guard failed on itself (branch tree
   1 failed/1267 passed; CI green only because `actions/checkout` for
   pull_request checks out the merge tree, where nothing matches at all).
   Patterns are now anchored to declaration position, and documentation
   shows the shape (X.Y.Z), never a concrete repo version — a tracked file
   embedding the current version in declaration form is indistinguishable
   from a duplicate, which is the thing being guarded.

3. bump() was not atomic. Validation and writes were interleaved, so a
   source failing late left the earlier ones already rewritten:
   reproduced 7/8 files moved before the abort, and observed live with
   emrg/__init__.py left at 0.2.95 while the rest stayed at 0.2.94. Now two
   passes — validate every source, then write — so a failure leaves the
   tree byte-for-byte untouched. Also adds the MISSING FILE check that
   check() had but bump() lacked (it raised FileNotFoundError instead of
   BumpError).

4. Corrected a wrong cycle citation in the guard docstring
   (cyc20260910-150729 did not exist; the cycle that committed
   `.emrg-cmp2/` is cyc20260910-152337, commit c93d85c).

New tests cover both rules in both states: the bumped-copy shape (path
rule, version-independent), an un-bumped renamed copy (content rule), and
inline documentation of the forms (the self-match regression). Agent.md
Python test count 1269 -> 1272.

* emrg: bump() must not report "nothing to do" for an unverified tree; widen scratch ignore

Fixes the two findings from the cyc20260910-163037 review of PR #1119, both
reported by external contributors and reproduced independently here.

1. bump() short-circuited before validation (pm25coder). The
   already-at-target check ran *before* the pass-1 validation loop, so a
   tree whose base file already held the target while another source was
   stale printed "already at <target> — nothing to do" and exited 0, leaving
   the drift untouched:

       $ bump-version.py 0.2.93      -> exit 0, "nothing to do"
       $ bump-version.py --check     -> exit 1,
                                        emrg/gui/package.json: 0.0.1 != 0.2.93

   The repair mode silently disagreed with the check mode about the same
   tree, which is the #408 / #1065 shape this tool exists to prevent — and
   the natural way the mistake is made (hand-edit the base file, then run
   the tool). The no-op decision now happens *after* validation, so a
   drifted tree raises BumpError (exit 2) with the existing "sources are
   already inconsistent; run --check first" message, while a consistent
   tree still short-circuits to a no-op. Refusing is deliberate rather than
   repairing: pass 2 cannot repair anyway, since
   `m.group(0).replace(old, new)` is the identity when old == new.

2. `.emrg-*/` matched directories only (how2how2how2-arch), so a stray
   *file* named `.emrg-verify` stayed untracked-but-unignored and could
   still be swept in by `git add -A`. Widened to `.emrg-*`, which covers
   both forms and is equally safe (`git ls-files | grep '\.emrg-'` is
   empty). Also corrects the cycle id quoted in the .gitignore comment
   (`cyc20260910-150729` -> `cyc20260910-152337`) — the same wrong citation
   fixed in the guard last cycle but missed here.

Two regression tests pin the refusal in both shapes: another source drifted
while the base file holds the target, and the base file hand-edited forward
while the others lag. Each also asserts the refused bump modified nothing.
Agent.md Python test count 1272 -> 1274.

* emrg: state the leak guard's coverage boundary instead of implying it closes the class

A copy that is both renamed and bumped escapes both rules (verified:
.emrg-gap/snapshot.py at 1.1.1 is flagged by neither). The observed incident
is covered because copying the version sources preserves their filenames,
which is what the path rule keys on.

Records the version-agnostic shape rule proposed by how2how2how2-arch in
#1119 review, and why it is deliberately not adopted: it needs an explicit
exception list for files that legitimately carry a version literal
(renderer/package*.json, test_skills_registry.py, the bump tool and its
tests), and an allowlist of that kind is itself a maintenance liability.

No behaviour change.

* emrg: bump-version output must survive a non-UTF-8 stdout

#1119 review (pm25coder, reproduced independently by how2how2how2-arch):
the --check verdicts printed U+2713 / U+2717. Any invocation whose stdout is
a pipe or a file rather than a UTF-8 console raised UnicodeEncodeError on
that print, so a *consistent* tree exited 1 - reporting the exact "drift
found" this pre-push self-check exists to report - and on a drifted tree the
traceback discarded the list of drifted files.

The suite could not see it: every CLI test drives main() in-process, so
stdout is a Python buffer and no codec is involved.

- every byte this script can print is now ASCII (verdicts "OK:"/"FAIL:",
  "..." for the ellipsis, "-"/"->" in prose) - including the module docstring,
  which --help sources its epilog from
- regression test runs the CLI as a subprocess with raw byte capture under
  PYTHONIOENCODING=ascii and =gbk, covering the clean, drifted, writer,
  --help and rejected-argument paths, asserting exit codes and ASCII output
- static backstop asserts the script stays ASCII-only, so a future print on a
  path the behavioural test does not drive cannot reintroduce the crash
- Agent.md Python count 1274 -> 1277

---------

Co-authored-by: EMRG Evolution <emrg@argszero.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant