fix(ci): run Web tests and preserve audit evidence (successor to #169) - #198
Conversation
The Web CI job ran npm audit but never ran npm test, leaving the six vitest files under web/src/ without pipeline coverage. The audit step also failed the entire Web leg on the first transient registry error (503, timeout, ECONNRESET) with zero retries. - ci.yml: add "Run unit tests" step (npm test) after audit - audit-retry.mjs: distinguish network errors (retry up to 3x with 10s backoff) from real vulnerability reports (fail immediately) - web/package.json: route audit script through audit-retry.mjs
spawnSync returns null status when npm is killed by signal or not found on PATH. Three return sites in runWithRetry passed null through to process.exit, which Node treats as 0 — failing the audit gate silently. Add `?? 1` at the two unguarded sites (:67, :85) and remove the redundant 4th spawnSync after loop exhaustion (review finding #1), reusing the last loop result with the same `?? 1` guard. All three sites now aligned.
The 60s ATTEMPT_TIMEOUT_MS kills npm before its default 300s fetch-timeout fires, so the retry logic never sees "network timeout" for slow registry hangs. Adding --fetch-timeout=45000 to both audit args lets npm report the timeout within the 60s budget, making isNetworkError catch it and trigger retries as designed.
- Assert vite.config.ts includes audit-retry.test.mjs so removing it fails the suite instead of silently dropping 35 tests. - Assert --fetch-timeout < spawn timeout so the dead-zone fix stays enforced if either constant drifts.
Captures git head, npm_execpath probe, full npm run audit output, and exit code. Must be run from cmd.exe (not WSL) to prove the win32 branch in audit-retry.mjs:117 receives npm_execpath.
Windows cmd.exe requires CRLF; LF-only caused every line to be misread as an unknown command.
(cherry picked from commit 11e02e2)
|
Independent automated preflight — PASS, bounded audit/CI fix at This successor preserves the exact authored source tree reviewed on #169. Independent reviewer Ohm reproduced successful-audit output loss on the old implementation, verified stdout/stderr retention on this candidate, and passed all 37 focused tests. Native Windows CI independently shows four process-fixture passes, including exit-code and missing-CALL/ENDLOCAL negative controls; this is not live-registry Windows audit qualification. The shared lockfile is identical to reviewed #192, with no threshold or retry-policy waiver. Coordinator rechecked the canonical successor's latest CI, acceptance, and security: all 20 concrete current checks succeed, including CodeQL go, python, javascript-typescript and aggregate CodeQL. The historical skipped fork placeholder is not counted as proof of any of those required contexts. No security workflow permissions were changed to obtain this result. No new blocker was found in the scoped fix. This is automated evidence, not human APPROVE or merge authorization. The original #169 stays open until the replacement's normal review/merge completes; old votes are not inherited. |
Suggested Improvements1. Fixed backoff interval risks thundering herd
Suggestion: Add exponential backoff + jitter: const baseDelay = BACKOFF_MS * 2 ** (attempt - 1);
const jitter = Math.random() * 5_000;
await wait(baseDelay + jitter);Worst-case total wait goes from 20s to ~45s, still well within the CI timeout budget. 2. Vulnerability detection regex may silently break on minor npm output changes
Suggestion: Broaden the match: const VULNERABILITY_PATTERNS = [
"found[:\\s]+\\d+ vulnerabilit",
"npm audit report",
"vulnerabilities found",
];3.
|
The step log was the only copy of the audit report, and an attempt that
retried left no trace at all. Tee the transcript under RUNNER_TEMP, upload
it, and echo each retried attempt to stderr before backing off.
The tee runs under shell: bash on purpose: the default bash -e {0} shell has
no pipefail, so tee's exit status would have turned the dependency gate
fail-open.
Resolves the only collision, in CHANGELOG.md's [Unreleased] "Fixed" list, by keeping both entries: this branch's CI Web bullet and main's #165 bullet about withholding unverifiable URL credentials. No duplicate "### Fixed" heading was introduced. main's "### Changed" side won on its own: the branch's "retaining the published npm scope, MCP identity, and existing cache paths" wording is false after #162 changed mcpName to io.github.bytefolk/mem-mcp, and the merged text no longer carries that clause. GOVERNANCE.md arrived from main without conflict because this branch never added one. This commit is the conflict resolution only; the CI evidence fixes follow.
Closes the remaining review blockers on #198. The batch helper was dead code that the description advertised as evidence: nothing executed scripts/win-audit-verify.bat, only scripts/test_win_audit_verify.mjs ran, and that test replays the batch source against a stub npm.cmd. The repo does have a Windows runner (windows-2025 in the npm-wrapper-compatibility matrix), so the helper can be executed for real. Adds a dedicated `windows-audit-evidence` job that runs npm ci in web, executes the helper against the registry from web/ so `npm run` supplies npm_execpath, and uploads win-audit-transcript-<sha> with the same retention and if-no-files-found: error as the Linux transcript. The helper's fixture test moves into this job: it was gated behind `if: runner.os == 'Windows'` on a matrix entry whose removal would have deleted the regression silently. Replaces the "ci.yml keeps the audit transcript pipe fail-closed and uploads it" assertion added by 62d6507, which never passed: its regex required a blank line before `shell: bash`, and the step has comment lines there. It now splits the workflow into steps and asserts the properties directly - every transcript step uses shell: bash (measured: without pipefail a failing audit exits 0, with it exits 1), both transcript uploads use if: always() && !cancelled() plus if-no-files-found: error and retention-days: 14, and ci.yml stays free of continue-on-error and `|| true`. Adds a matching assertion that the batch helper is really executed on a Windows runner.
The job added in d594942 was green but collected nothing. Its step log shows cmd.exe printing its interactive banner and a bare prompt, then exiting 0: under the runner's git-bash, the leading /d and /c were rewritten to D:/ and C:/, so cmd.exe never received its option flags and win-audit-verify.bat never ran. The 267-byte artifact was the banner. Doubles the slashes so MSYS leaves the flags alone, and adds a gate that greps the transcript for the helper's starting line, its finished line, a recorded audit exit code of 0, and the report itself. cmd.exe's exit status is not proof of execution, and that is the difference between evidence and a green check. The step dumps the transcript and fails with ::error:: when a marker is missing. Pins the same property in the workflow assertion, since the previous assertion matched the invocation text and still passed while nothing executed.
waterbro-8
left a comment
There was a problem hiding this comment.
COMMENT — the gate genuinely got stricter; the body's central provenance claim is now false
Two separate things, and only one of them needs work from you.
The code direction is right
I looked specifically for a PR that quietly makes CI easier to pass, and it does the opposite:
- No
continue-on-error, no|| true, no--force, no widened job timeout anywhere in the
diff — everytimeoutline is an addition (timeout-minutes: 20on the new Windows leg,
ATTEMPT_TIMEOUT_MSper attempt,--fetch-timeout=45000). 4e1ea308afix(ci): stop the Windows audit job from passing on an empty transcript fixes a
job that could go green while having done nothing. That is the correct instinct and the
reason I am commenting rather than requesting changes on substance.audit-retry.test.mjs:454-455asserts every--fetch-timeoutis strictly below the spawn
timeout, so npm aborts before SIGKILL instead of the reverse, and :691 pins "terminates a
stalled process and fails closed at the attempt timeout". Ordering invariants asserted rather
than assumed is good to see.
But the tracking record in the body no longer identifies this PR
The body says:
- Original/final source head:
5c3a4a75ab96bed4c046c0822ebc76a87f215cda.- Successor head:
5c3a4a75ab96bed4c046c0822ebc76a87f215cda.- This successor changes no source file relative to #169's exact source head.
Current head is 4e1ea308a6. compare/5c3a4a75...4e1ea308a6 = 12 commits: two
Merge branch 'main', main's already-merged work, and three of this PR's own —
62d650784, d59494240, 4e1ea308a.
Of those, 62d650784 modifies web/audit-retry.mjs (+6/−1). That is shipped source, not a
test and not a doc. So as of this head both sentences are untrue: the successor head is no
longer 5c3a4a75, and the successor does now change a source file relative to #169.
I want to be precise about the nature of the problem, because it is not sloppiness: those
sentences were true when written, and the three commits that broke them are the reviewer
responses this PR was supposed to carry. The claims are load-bearing though — "changes no
source file relative to #169" is exactly the sentence that lets a reviewer skip re-reading
audit-retry.mjs, and Original/final source head == Successor head is what tells them the
evidence in the table transfers unchanged. A reviewer who trusts either will now be trusting
something false.
What I'd ask for
Refresh the tracking-record SHAs, and either reword the no-source-change sentence to name what
62d650784 deliberately changed in audit-retry.mjs, or restate it as scoped to the CI
workflows if that was the intent. The evidence table's commands also need re-running on
4e1ea308a — in particular the Windows leg, since the three commits after the snapshot are the
ones that changed how the Windows audit helper executes.
CI
mergeable_state=blocked; Validate Agent memory fails on this head with
pull access denied for minio/minio, the same Docker Hub anonymous-pull failure as
#199/#203/#205 — it happens at container start, before any project code runs.
Provenance, and what I did not check
Commit attribution is from compare/5c3a4a75...4e1ea308a6 plus per-commit file lists; the
gate-tightening read is from the diff. I did not run any Go or Node test, and I have not
verified the real-Windows behaviour that win-audit-verify.bat exists to prove — which is
also why I would not sign off on the evidence table's Windows rows myself. Note #169 is
closed (merged=False), so all of that work still shows as new relative to main; nothing in
this comment is a criticism of the commit history.
The one red check is external infrastructure, not this PRTracked in #207. Posting so this job's failure is not read as a defect in What is failing, verbatim
The job dies during container startup, i.e. before any script under test is reached. Evidence specific to this PR
What this does not ask of youPlease do not rebase or re-push to chase this red — that spends a CI cycle and returns the What I did not verify — please do not treat the above as complete
One systemic note, because it changes how long this stays containable: the nine other open PRs Forensics: run logs of the four failing jobs, |
The gate genuinely got stricter; the body's central provenance claim is now falseTwo separate things, only one of which needs work from you. The code direction is right, and I looked for the oppositeI specifically went looking for a PR that quietly makes CI easier to pass. It
That is real hardening, and none of it is in question here. But the provenance claim no longer holdsThe body states: "Original/final source head: The actual head is So "Source and successor tree" identity — the sentence that establishes the This matters more than usual here because What would make this reviewable
Separately
|
## Canonical requirement Refs bytefolk/.github#32 - Canonical Issue URL: bytefolk/.github#32 - Consumed revision: R1 - No automatic close keywords: acknowledged Decision reference: the initial R1 Issue body. It explicitly records that local candidates preceded this prospective publication record; no retrospective approval is claimed. ## Requirement trace | REQ/AC IDs | Changed files / domain | Tests or review evidence | |---|---|---| | REQ-001 / AC-001 | 4 exact-pinned version annotations | Exact expected-byte replacement PASS | | REQ-002 / AC-002 | 2 files in bytefolk/mem | Repository inventory PASS; aggregate 7 repositories, 13 files, 21 lines | | REQ-003 / AC-003 | Existing workflow content and modes | Parsed YAML and comment-stripped bytes identical | | REQ-004 / AC-004 | Current-head CI and independent review | Local independent replay recorded in the canonical R1 Issue linked above; hosted CI collected on head `f464f686` (19 of 20 checks succeed, see Validation); independent human review requested and still pending | ## File domains `.github/workflows/bytefolk-scorecard.yml` (47); `.github/workflows/bytefolk-security.yml` (58, 65, 68). Prepared parent / merge base: `2986fe38175f54d99f15dd38a498708c6ecd88cd` PR base at publication: `87db0dfe0507be2190fe2fdcce0e267be8224f4d`. Since that baseline `main` advanced by six commits through `3c13f04e` (#162, #160, #165, #188, #158, #204) — not only `web/package-lock.json` as previously stated here. None of them touched `.github/workflows/`, so the F9 workflow blobs and the PR diff are unchanged. The reviewed commit and original parent are preserved. Head: `f464f68636adc6bb5295c3818aa6654c46a3caad` — `d2a9ec5` plus one non-forced `Merge branch 'main'` commit (`f464f686`) that brought the branch up to `3c13f04e` so it is no longer `BEHIND`. Verified: `git rev-parse d2a9ec5:.github/workflows/bytefolk-scorecard.yml` and `...:bytefolk-security.yml` return the same blobs (`2058126c`, `48a507e0`) as at `f464f686`, and `git diff main...f464f68` is still exactly these 2 files, `+4/-4`. The comment-only payload is therefore byte-identical to the reviewed commit and the equality proof above holds on the current head. ## Scope and non-goals Correct only `# v4.37.4` to `# v4.37.9` on CodeQL uses-lines pinned to `cdf488f595d80d6e07e03d4674febd5ab45fa938`. The [official tag object](https://api.github.com/repos/github/codeql-action/git/tags/a35ac6e6798d72df5475948b28efb89edc2e19ca) resolves to that existing pin. Action SHAs, permissions, triggers, steps, matrices, other pins, and runtime code are unchanged. ## Validation - Exact commands: `ruby evidence/verify.rb --baseline` and `ruby evidence/verify.rb --committed` from the retained review packet; `git diff --check 2986fe3 d2a9ec5` from this repository. - Observed counts/results: PASS 2/2 files and 4/4 replacements here; aggregate PASS 13/13 files and 21/21 replacements. Baseline intentionally exits 1 after detecting all 21 stale annotations; committed verification exits 0. - Check URLs: collected on head `f464f686` — 19 of 20 checks succeed. The single failure is [`HTTP, CLI and MCP lifecycle`](https://github.com/bytefolk/mem/actions/runs/34807101354/job/103861020551), whose log is `pull access denied for minio/minio` at ~13s: a container-image pull failure in an unrelated job. The same workflow was green on `main` at `3c13f04e`, and the identical failure is present on #198 and #199, so it is not caused by this comment-only change. Root-cause tracking is separate and open. The strict verifier checks the changed-file allowlist; exact old blobs and line inventory; complete expected-byte replacement; absence of stale target annotations; parsed YAML equality; comment-stripped byte equality and SHA-256 digests; whitespace and unchanged modes; one commit with the exact parent; and clean worktrees with no untracked files. All passed. The independent replay is recorded in canonical R1. The verifier and inventory are retained outside repository commits. | ID | REQ/AC | Observable acceptance criterion | Command or manual steps | Environment | Expected | Observed | Status | |---|---|---|---|---|---|---|---| | V1 | AC-001, AC-002, AC-003 | Exact annotations with executable YAML unchanged | `ruby evidence/verify.rb --committed` | Ruby 2.6.10, Psych 3.1.0, isolated review packet | Exact scoped replacements and equality | 2/2 files; 4/4 lines; all invariants pass | PASS | | V2 | AC-004 | Hosted checks on this exact head | Inspect this PR's checks at `f464f686` | GitHub Actions | Applicable checks succeed | 19 of 20 succeed; `HTTP, CLI and MCP lifecycle` fails on `pull access denied for minio/minio` (infra, unrelated job, also failing on #198/#199, green on `main`) | PARTIAL | ## Security and compatibility Documentation annotation only. No dependencies, permissions, credentials, data flows, or runtime behavior change. The diff and commit identity were inspected for public-safe content. No CHANGELOG entry or behavior-documentation update is needed because only explanatory comments change. ## Known limitations Runtime suites, build, coverage, and dependency audits were not rerun for this comment-only change; no runtime test result is claimed. Hosted CI is separate from local equality proof. Two limits now apply: (1) the strict verifier's `one commit with the exact parent` invariant describes the reviewed payload commit `d2a9ec5`, not the current branch shape, which carries two additional `Merge branch 'main'` commits; (2) this PR is **not merge-ready yet** — repository `AGENTS.md` step 6 requires passing CI *and* an approval from someone other than the author, and `HTTP, CLI and MCP lifecycle` is red on the unrelated `minio` pull, so the green-CI half is unmet until that infrastructure failure is fixed. ## Risk and rollback Low-risk annotation correction. Roll back through an ordinary revert of this single commit. There is no migration or release action. ## Product review handoff - Implementation/publication owner: @PeterGuy326 - Automated pre-review result: independent local replay recorded in R1; no human approval implied. - Human final review: PENDING; no human review requested by this publication. - Merge ledger owner: @PeterGuy326 - Product reviewer: @PeterGuy326 - Milestone or release packet: N/A: bounded documentation annotation maintenance - Merge, CI, release, and model judgment do not accept or close the Issue: acknowledged ## Maintenance update (2026-09-14, @waterbro-8) Records written by the maintainer account, not by the implementation owner: - `f464f686 Merge branch 'main'` was pushed to this head branch (non-forced, `main` at `3c13f04e` is an ancestor of the head) to clear the `BEHIND` state this PR's own body said blocked merging. No workflow file content changed: both blobs are identical to `d2a9ec5`. - The stale facts above were corrected in place: the recorded head SHA, the "Main advanced only `web/package-lock.json` in PR #192" claim, the `NOT VERIFIED` hosted-CI rows, and the "this is a draft, not merge-ready" note. - This PR was marked ready for review and an independent review was requested. The maintainer account that pushed the merge commit did **not** approve it: `AGENTS.md` step 6 requires an approval from someone other than the author, and a commit author on the head cannot supply that approval for their own push. `@PeterGuy326` remains implementation and merge-ledger owner. Co-authored-by: 勒布朗-詹姆斯 <2986253039@qq.com>
waterbro-8
left a comment
There was a problem hiding this comment.
Code review: approved(条件见第五节)
我是这条 PR 的受邀评审人,不是作者,也不是其 head 的推送者。
一、接线是完整的,不是只加了个脚本
这类改动最容易"看起来很完整但其实没接上",所以我先查了落点:
web/package.json:"audit": "npm audit --omit=dev --audit-level=moderate && npm audit --audit-level=high"→"audit": "node audit-retry.mjs"。接上了,CI 里的npm run audit走的确实是新脚本。web/vite.config.ts:include加进了audit-retry.test.mjs。接上了,否则 CI 新加的npm test根本不会执行这份测试。package.json里"test": "vitest run"本来就存在 → CI 新增的npm test这一步是可执行的,不会因脚本缺失而红。
二、shell: bash 那两处注释是实质,不是仪式
GitHub 的默认 shell 是 bash -e {0},没有 pipefail。所以 cmd | tee 的退出状态取的是 tee 的,一个失败的 audit 会被判绿。两处都显式指定 shell: bash 并写了注释说明,这是对的。
Windows 那条更进一步:cmd.exe //d //c(双斜杠)是 git-bash 的路径重写陷阱——写单斜杠 /d /c 会被 MSYS2 改写成 D:/ C:/,cmd.exe 拿到的就不是选项标志,于是它打个交互式横幅并以 0 退出,helper 从未执行、job 却是绿的。注释把这条写出来,并且后面还有一步专门验 transcript,形成闭环。
三、"证据必须是真的"这条设计,我认为是这条 PR 最好的部分
只断言 cmd.exe 退出 0 什么都证明不了(上面那个陷阱就是这么绿的)。所以加了一步在 transcript 里找四根针,包括 [win-audit-verify] npm run audit exit code: 0 和 found 0 vulnerabilities。
scripts/test_win_audit_verify.mjs 里还有两个反向对照,我特意看了:
- 把
call npm run audit改成npm run audit→ 断言"完成标记消失"。没有CALL的话批处理不会返回,后审计证据根本不会被打印——这是个真实的批处理陷阱。 - 把
endlocal & exit /b %AUDIT_RC%拆成两行 → 断言"日志里有 exit code: 7,但进程退出码是 0"。ENDLOCAL单独一行会让保存的退出码在延迟展开的边界上丢失——这正是"helper 报告失败但 job 绿"的经典形态。
这两个用例断言的是失败形态本身,不是成功路径。这是正确的测试设计。
四、重试策略的失败闭合方向是对的
- 未完成的 audit(
result.error/ 有 signal / status 不在 0–255)不重试直接失败——这点很关键:一次中断的 audit 即使输出里恰好出现了网络字样,也不能当成"瞬时失败"去重试,否则会把截断的输出当成一次有效审计。 isVulnerabilityReport优先于isNetworkError:真实漏洞一律不重试。测试里甚至造了"漏洞报告里含 ETIMEDOUT"的混合输出来验证不会被误判为瞬时。- 被重试的每一次都把输出回显到 stderr(stdout 留给最终报告),所以自愈的失败仍然留痕。
- 两个阈值各有 3 次预算(不是共用),末次不 backoff。测试断言
wait.mock.calls精确等于[[10_000],[10_000]]这种细节,说明是真的在数。 - Windows 上
npm_execpath缺失时直接失败并给出可操作提示——因为 Windows 的 npm 是.cmdshim,无 shell 的spawnSync起不来,必须走node <npm-cli.js>。
五、批准的条件(请务必看这一节)
这个批准是针对当前 head 的代码,它不覆盖两件尚未发生的事:
- 本 PR 与 main 冲突,且冲突只落在
CHANGELOG.md一个文件。 我核过两侧:本 PR 改 8 个文件,main 自 merge-base 起改 7 个,交集只有 CHANGELOG.md。也就是说另外 7 个(ci.yml、两个脚本、两个 web 文件、package.json、vite.config.ts)都不冲突,解冲突只需处理 changelog 里相邻位置的两段条目。 - CI 还没有在解冲突后的 head 上跑过。 目前挂在 #198 上的检查结果来自旧 head,不代表最终状态。按仓库闸门,解冲突后必须重跑。
所以:解完 CHANGELOG 冲突、CI 全绿之后这条就可以进队列。我可以帮你触发重跑。
(本次为独立评审,不构成除代码批准之外的任何承诺。)
…ccessor # Conflicts: # CHANGELOG.md
Bindy-lbb
left a comment
There was a problem hiding this comment.
Mem PR #198 Review: LGTM (Approved) ✅
Key Review Highlights:
-
Web Test Pipeline Integration (
.github/workflows/ci.yml):- The Web CI workflow now explicitly executes unit tests (
npm test), covering 104 tests across 7 files including 37 audit regression tests. - Enforces
shell: bashon piped transcript commands, guaranteeing thatpipefailis respected and preventing silent gate bypasses. - Audit transcripts are uploaded via
actions/upload-artifactwithif: always() && !cancelled()and a 14-day retention window.
- The Web CI workflow now explicitly executes unit tests (
-
Deterministic Audit Retry Mechanism (
web/audit-retry.mjs):- Executes dual-threshold audits (
moderatefor prod,highfor all dependencies). - Retries are strictly limited to recognized transient registry/network blips (e.g. 503 Service Unavailable, ETIMEDOUT).
- Fails closed immediately upon actual vulnerabilities, spawn errors, signals, or non-transient status codes.
- Preserves complete stdout/stderr outputs so lower-severity findings and audit summaries are visible.
- Executes dual-threshold audits (
-
Cross-Platform & Regression Verification:
- Integrates Windows batch evidence helper (
win-audit-verify.bat) with native runner verification and space-tolerant path fixtures. - All 21 GitHub CI checks have passed cleanly.
- Integrates Windows batch evidence helper (
waterbro-8
left a comment
There was a problem hiding this comment.
Re-review of 0a6c5366 — substance is green; the tracking record still doesn't match the branch
(受邀对 09-17 07:39Z 的评审请求做复审。我此前在 4e1ea308 的条件批准已处于 DISMISSED 状态,本条按当前 head 独立成立。)
已核实为真的部分
- CI 在精确 head 上全绿:
0a6c5366上 21/21 个 check 全部 success,包括 Web、Windows audit evidence、CodeQL(4 个语言上下文)、PostgreSQL integration、npm wrapper 三个平台。 - 我此前批准的两个条件均已满足:CHANGELOG 冲突在
dc865b2a解决(净 diff 只保留本 PR 条目,+13/-0,两侧内容无丢失);main 已并入(0a6c5366),mergeable=true。 - ci.yml 净 diff 复读无误:两处
shell: bash(各带 pipefail 缺失的注释)、transcript 经固定 SHA 的 upload-artifact v7.0.1 上传(14 天保留)、Windows legtimeout-minutes: 20+ transcript 四针断言;没有continue-on-error/|| true/ 放宽超时。 - Bindy-lbb 已在当前 head 批准(2026-09-17T07:43:31Z)。
仍然拦住我批准的:tracking record 与分支事实不符(09-15 已提,至今未更新)
body 仍是 09-10 起草时的口径,与当前分支状态冲突:
Successor head: 5c3a4a75…— 实际 head 是0a6c5366。- "This successor changes no source file relative to #169's exact source head" — 已不成立:
62d650784改了web/audit-retry.mjs(+6/−1)、web/audit-retry.test.mjs(+20)、ci.yml(+14/−1),主题是 "keep the audit transcript as a downloadable artifact",加上4e1ea308的空 transcript 修复。这些改动本身是好的(方向正是我 09-15 评论里认可的),但这句 load-bearing 的话必须点名它们,或改为 workflow-only 的限定说法。 - Changed-files 清单里的
web/package-lock.json已不在实际 diff 中(与 main 相同)。 Current canonical main: 2986fe38…— main 现在是904e8e79(#199 已并入)。- 验证台账最后一行 "PENDING at draft creation" 已过时 — CI 现在全绿,该行应改判,台账在
0a6c5366上重新盖章。
合并前的操作提示
mergeStateStatus=BEHIND(main 先进了 #199 的904e8e79):按 base branch policy,必须先 update-branch 才能合并。- 本 PR 的历史显示批准不一定扛得住新提交(我在
4e1ea308上的批准随 06:09Z / 07:23Z 两次 push 进入 DISMISSED)。update-branch 之后请复核reviewDecision;若 Bindy-lbb 的批准被作废,任一非作者 code owner(Bindy-lbb / waterbro-8)重新批准一次即可恢复闸门(作者本人不行)。
结论
代码与 CI 都站得住。唯一剩下的是把 body 的 SHA 与两句话改成与分支一致——机械修改,改完我立即批准。
Tracking record and provenance
Refs #122 — bounded CI/release-readiness follow-up, not completion or publication
of that release. Canonical draft successor to #169, with the original author's
sun-970commits and maintainer follow-ups retained unchanged in ancestry.The original PR stays open; its reviews and discussion remain authoritative
history, not an approval of this successor.
5c3a4a75ab96bed4c046c0822ebc76a87f215cda.5c3a4a75ab96bed4c046c0822ebc76a87f215cda.9d8a127375fd8e945113e06ae88983a1328b9fae.2986fe38175f54d99f15dd38a498708c6ecd88cd, alreadyan ancestor. A normal merge reports
Already up to date; no empty commit,cherry-pick reconstruction, rebasing, or force push was used.
11e02e21ef2c3dbd2dae26e4376872e54e78ecb5(cherry-pick -xin ancestry).Summary and acceptance criteria
The Web CI job must run its unit tests. Recognized transient npm audit failures
may retry, but vulnerabilities, unknown errors, failed spawns, signals and
timeouts must remain failures. Successful audit output must remain visible,
including below-threshold findings. The Windows evidence helper must complete
its report and preserve a nonzero audit exit status.
This successor changes no source file relative to #169's exact source head.
It exists because the canonical security workflow skips the entire CodeQL job
on fork PRs while main requires three language-specific CodeQL contexts. A
same-repository candidate executes the existing supported path; no security
workflow, permission, required check, audit threshold, or fork restriction is
modified or waived.
Changed files against main:
.github/workflows/ci.yml,CHANGELOG.md,scripts/test_win_audit_verify.mjs,scripts/win-audit-verify.bat,web/audit-retry.mjs,web/audit-retry.test.mjs,web/package.json,web/package-lock.json,web/vite.config.ts.Validation ledger
Environment: isolated Linux aarch64, Linux 6.8, GNU find 4.9.0/coreutils 9.4,
Bash 5.2.21, Node 24.13.0/npm 11.6.2; checksum-verified official Node archive.
Fresh Git clone from an exact local bundle, two CPUs, GOMAXPROCS=2 and
GOFLAGS=-p=1. Tests use disposable fixtures, not production data or secrets.
git diff --exit-code 5c3a4a75ab96bed4c046c0822ebc76a87f215cda HEADgit merge-base --is-ancestor 2986fe38175f54d99f15dd38a498708c6ecd88cd HEADbash scripts/test_release_guards.shbash scripts/test_release_helpers_compat.shbash scripts/test_validate_release_action_pins_compat.shbash scripts/validate_release_version.sh 0.1.1web/:npm ci --registry=https://registry.npmjs.org --fetch-timeout=45000npm run audit --registry=https://registry.npmjs.orgnpm testnpm run lint/npm run typecheck/npm run buildgit -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol diff --check 2986fe38175f54d99f15dd38a498708c6ecd88cd HEADTests, coverage and known limits
The original successful-report regression was red before the fix (1 failed /
36 passed). Existing exact-source Web CI
passed 104 tests including 37 audit regressions. Existing real
Windows CI
passed four native batch-helper regressions, including negative controls for
both original defects. These are source-head evidence, not independent review
or substitute results for the new canonical workflow execution.
Coverage percentage was not remeasured. A real-registry Windows audit has not
been requalified; its helper tests use local npm.cmd fixtures. The unchanged
five-second process fixture timeout reproduces on both pre-follow-up and fixed
heads on the managed macOS host; Linux is the validated environment. The
existing large-chunk build warning remains. Full Linux process/database and
browser acceptance, and native Windows execution, are delegated to unchanged
CI; no temporary Go executable runs on macOS.
Risk, rollback and review
Build/CI/dependency maintenance; no application API, CLI/MCP authorization,
storage or migration contract changes.
[Unreleased]already documents thebehavior. The PR-triggered workflows reference no custom repository secrets;
CodeQL retains only its existing security-events upload permission. No release,
npm publication, Scorecard dispatch, tag, merge, or formal approval is performed.
Rollback is to leave this draft unmerged; no deployed behavior changes.
Draft until the exact candidate has required CI plus independent review. The
Owner reports independent review of the fix deltas is already in progress;
this description does not represent that review as completed. Automated
assistance produced validation and the maintainer follow-up; the original
human-authored history remains intact.