Skip to content

test(ci): 让 test725/test745 覆盖 tests/ 目录(两个门自称 complete 却漏了 25 个文件) - #800

Open
vansin wants to merge 4 commits into
mainfrom
test/pkg-tests-dir-gate
Open

test(ci): 让 test725/test745 覆盖 tests/ 目录(两个门自称 complete 却漏了 25 个文件)#800
vansin wants to merge 4 commits into
mainfrom
test/pkg-tests-dir-gate

Conversation

@vansin

@vansin vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

test(ci): 让 test725/test745 覆盖 tests/ 目录,兑现"complete unit domain"

两个门的抬头都写着 "complete agent-node/agent-network unit domain",
但只跑 src/,把 tests/ 下 25 个文件排除在外 —— 其中不乏安全相关的:
feishu-markdown-image-ssrf、secret-mask ×3、vendor-error-sanitize、feishu-tool-deny。
这些正是静默失效代价最高的那类。

这个目录里混着两种测试,任何单一命令都跑不全:

  • 脚本式(16+6 个):自己打 "N/N passed",失败 process.exit(1),必须 bun ;
    用 bun test 跑会因为 top-level 的 process.exit 把整个 run 打断在第一个文件
    (实测:bun test tests/ 只跑完第一个就结束)。
  • bun:test 式(3 个):describe/it,必须 bun test ;用 bun 跑会报
    "Cannot use describe outside of the test runner"。
    所以按文件内容分派,并把两条判据都写进注释。

退出码可用已先验:这些脚本失败时确实 process.exit(1),不是 fail-open。

落地前实测:
agent-node/tests 6/6 直接过
agent-network/tests 单命令 14/19 → 按内容分派 17/19 → 补两处环境契约 19/19
两处契约都在 Dockerfile 内解决,并写明原因:

  • feishu-envelope-compat 跨包 import agent-node/src/runtime/feishu-envelope
  • feishu-bridge-ipc 硬编码绝对路径 /work/feishu-attachments,容器里 node 建不了

分母承重:tests_dir_executed 必须等于 find 出来的数,且 >0。

实测:test725 tests_dir 6/6/0 + MUTATION_RED + PASS;
test745 tests_dir 19/19/0 + MUTATION_RED + PASS。


正文最初没写、后来才加的两处(补记)

  1. test725 的 mutation 命名断言锚到 (fail)(与 #798 同类)。
    原来 grep 的 the inbox choke point feeds the augmented text into processTask测试名,
    该用例通过时也会命中。收紧后重跑仍绿。
    这道门不是我写的;我在本 PR 里本就要改它的 run.sh(加 tests/ 分派),所以顺手收紧,
    改动只让门更严。若 owner 认为不该由本 PR 动它,可以拆出去。
  2. tests/ 分派的绝对下限(AGENT_NETWORK_TESTS_FLOOR=15 / AGENT_NODE_TESTS_FLOOR=5)。
    #798 那个洞:executed == discovered 抓不到「文件消失」。
    双向验过:19 个 → PASS;删到 4 个 → rc=1 FAIL: only 4 file(s) under agent-network/tests, floor is 15
    范围:只给本 PR 新加的 tests/ 分派加下限,没动这两个门原有的 src/ 分母判定 ——
    那属既有代码,同类缺失另报(见 #817)。

合并顺序:本 PR 单独合入兑现「整棵 tests/ 永久 complete」——
find … -maxdepth 1 只覆盖顶层,嵌套目录要靠 #801 的深度感知才闭。顺序:#798/#800#801

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

独立对抗窄审 · PR #800 (Draft)

Verdict: CLEAN — no BLOCKER, no MAJOR. One MINOR observation (structural gap, does not fire on this PR) documented at ⑦. Not a merge blocker.

Reviewer: 通信IM马 (independent, read-only). First reviewer's vendor 300s timeout not consulted. Extracted PR tree via git archive origin/pr-800 → temp dir; author worktree untouched. No merge, no deploy.

Scope framing: this PR extends the two "complete unit domain" gates (test725/test745) to actually cover the previously-excluded 25 files under agent-node/tests/ and agent-network/tests/. It adds a script-vs-bun:test dispatch loop, two new mutation gates (one per package), plus two environmental fixes (cross-package agent-node/src COPY + hard-coded /work/feishu-attachments dir). Product source and workflow YAML both 0-changed.


Provenance

value check
HEAD (single commit) 2b2a7c2bcd801c6b01a7c285f96b12c67e0bc00d ✓ matches brief
original base d4283a229dbdcd85d0e4ceb9f715c84607a521b4 ✓ matches brief
current main tip 034f00647d42d38d5086d7fc057eb7824a441791 ✓ matches brief (advanced past base by #802)
files (base..HEAD) 4: 1 report + 2 run.sh + 1 Dockerfile matches diff
commits 1: 2b2a7c2b test(ci): 让 test725/test745 覆盖 tests/ 目录... source == HEAD (no split)
report size 2091 lines (all +, no -) matches brief

Item-by-item

① base→HEAD 4 files / product 0 changed / source-report topology honest — CONFIRMED

git diff --numstat base..HEAD:

2091  0  docs/tests/report-pkg-tests-dir-gate.txt
  37  0  tests/test725-agent-node-unit-ci/run.sh
   6  1  tests/test745-agent-network-unit-ci/Dockerfile
  37  0  tests/test745-agent-network-unit-ci/run.sh
  • 0 product source: no agent-network/src, no agent-network/bin, no agent-node/src, no agent-node/bin, no server/, no deploy/
  • 0 workflow YAML: .github/workflows/qa.yml unchanged (test725/test745 jobs already existed with timeout-minutes: 12 each and pull_request+push paths covering tests/test725-... and tests/test745-...); no new job, no new path, no timeout bump
  • Single-commit PR: source == HEAD → no source-vs-report topology split possible. The 2091-line report matches this single commit's output.

② agent-node/tests 6 + agent-network/tests 19 denominator — CONFIRMED (independently enumerated)

Independent git ls-tree -r $HEAD + filter *.test.ts + -maxdepth 1:

agent-node/tests/*.test.ts (maxdepth 1)6 files:

feishu-tool-deny.test.ts, outbound-secret-mask.test.ts, quota-error-passthrough.test.ts,
secret-mask-spawn.test.ts, secret-mask.test.ts, vendor-error-sanitize.test.ts

agent-network/tests/*.test.ts (maxdepth 1)19 files:

environ-alias.test.ts, feishu-bridge-{ackplaceholder,dispatch,ipc}.test.ts,
feishu-envelope-compat.test.ts, feishu-hub-upload.test.ts,
feishu-image-{download,upload-fallback}.test.ts, feishu-inbound-file-download.test.ts,
feishu-markdown-{image,image-ssrf,render}.test.ts,
feishu-outbound-{marker,paths,render-config,render-mode}.test.ts,
feishu-post-parse.test.ts, goal-wake-log-render.test.ts, project-key.test.ts

Brief's 6 + 19 = 25 denominator matches ✓

Denominator load-bearing: find "$ROOT/agent-*/tests" -maxdepth 1 -type f -name '*.test.ts' | wc -ltdir_total; loop increments tdir_ran on both success and failure; hard assertion [[ "$tdir_ran" -eq "$tdir_total" && "$tdir_total" -gt 0 ]] → if the find comes back 0 or the loop skips a file, the runner reds. Silent-skip via count is caught.

Kind discrimination (grep 'bun:test' heuristic) verified per-file on all 25 files:

File count bun:test grep Correct dispatch
agent-node × 6 0 hits each all → bun <file> ✓ (all have process.exit, no describe/it)
agent-network × 3 (environ-alias, goal-wake-log-render, project-key) 1 hit each all → bun test <file> ✓ (all use bun:test API, have describe/it)
agent-network × 16 (feishu-* + others) 0 hits each all → bun <file> ✓ (all have process.exit, no describe/it)

On the CURRENT 25 files, the heuristic dispatches correctly — I verified each file's import, bun:test count, describe/it/test line count, and process.exit count. No file misdispatches today.

③ Dockerfile 跨包源码 + /work/feishu-attachments 权限最小且不掩盖测试 — CONFIRMED

Cross-package COPY (Dockerfile L26):

COPY agent-node/src ./agent-node/src
  • Only src/ is copied (not full agent-node, not bin/, not node_modules, not package.json other than the already-present agent-node/package.json)
  • Reason (Dockerfile comment): tests/feishu-envelope-compat.test.ts 跨包 import agent-node 的 runtime 源码 — a real cross-package import contract by the test file. Without this, bun would fail at import resolution. The COPY is the minimal enabler, not masking any product behavior.
  • No secrets (agent-node/src is code, not creds); no dev artifacts (no build output, no .env)

/work directory creation (Dockerfile L34):

RUN install -d -o node -g node -m 0755 /work \
 && chmod 0755 ./tests/...
  • Owner: node / group: node / mode: 0755 — node has full rwx on /work; others read+execute (needed for ls-style traversal if any test does it)
  • Reason (Dockerfile comment): tests/feishu-bridge-ipc.test.ts 把附件落在硬编码的 /work/feishu-attachments 下
  • Minimal: only /work is created; /work/feishu-attachments itself is created by the test's own mkdir call inside its setup. The Dockerfile provides only the parent dir writable-by-node — it does NOT pre-create feishu-attachments/.
  • Doesn't mask test bugs: the test's writes still exercise the real production code path (agent-network/src/feishu-bridge); making /work writable only removes the environment-EACCES noise that would otherwise be misdiagnosed as a product bug. The report explicitly says: 否则它红在 EACCES 上、看着像产品坏 — exactly the "environmental precondition vs product invariant" distinction.
  • Potential concern (informational, not blocker): /work/feishu-attachments as an absolute hard-coded path is questionable design in feishu-bridge-ipc.test.ts itself. A workspace-relative path would be more portable. But that's the test file's authorship debt, not this PR's scope; this PR only enables the existing test's environment.

④ Two mutations — baseline first / target unique / byte-change / named-red — CONFIRMED

test725 mutation (readable-attachment runtime wiring):

  • Order: L0 aggregate bun test src/ first (must produce [1-9]* pass + 0 fail), then L0b per-file dispatch (all 6 files must exit 0), then L1 mutation. Baseline pre-green ✓
  • Target: deliverToRuntime: () => processTask(\n runtimeContent, in /workspace/agent-node/src/cli.ts
  • Independent verification: python3 count(target) on HEAD's agent-node/src/cli.ts1 occurrence
  • Mutation replaces runtimeContent with content (severs the augmented-text wiring)
  • Byte-change guard: [ "$before" != "$after" ] — fails if no bytes change
  • Named-red: grep -Fq 'the inbox choke point feeds the augmented text into processTask'
  • Independent verification: the string exists as a test(...) name in agent-node/src/runtime/readable-attachment-prompt.test.ts on HEAD. When mutation causes the test to fail, bun test prints the test name in the failure output. Named-behavior gate is load-bearing.

test745 mutation (top-level config help contract):

  • Order: L0 aggregate + L0b tests/ dispatch (all 19 must exit 0) both first. Baseline pre-green ✓
  • Target: anet config [path|json] Show config summary, path, or raw JSON in /workspace/agent-network/bin/cli.ts
  • Independent verification: python3 count(target) on HEAD's agent-network/bin/cli.ts1 occurrence
  • Mutation replaces with anet config get|set Inspect or edit config
  • Byte-change guard: [[ "$before" != "$after" ]]
  • Named-red: grep -Fq 'Expected to contain: "anet config [path|json]"'
  • Independent verification: agent-network/src/top-level-help-contract.test.ts on HEAD contains expect(result.stdout).toContain("anet config [path|json]"); — when mutation removes the target, this exact bun-test failure message fires. Named-behavior gate is load-bearing.

Not obscured by pre-front self-red or environment failure:

  • Both mutations run only AFTER their baseline aggregate + per-file dispatch passes; if the baseline reds, exit happens before the mutation phase.
  • Both mutations run on real production source (agent-node/src/cli.ts, agent-network/bin/cli.ts), not on fixtures.
  • Both use set +e + rc capture; the assertion is on rc != 0 AND the named string. A generic environment failure would produce a different named string (or none), so it can't accidentally satisfy the named-red gate.

Report evidence (report lines 1535, 1537-1538 for test725; 2084, 2086, 2089-2090 for test745):

test725: tests_dir_executed=6 tests_dir_discovered=6 tests_dir_failed=0
         MUTATION_RED readable-attachment-runtime-disconnected rc=1
         RESULT: PASS
test745: executed_files=46 discovered_files=46
         tests_dir_executed=19 tests_dir_discovered=19 tests_dir_failed=0
         MUTATION_RED stale-config-help rc=1
         RESULT: PASS

⑤ Secret / CI budget / current-main compat — CONFIRMED clean

  • Secret sweep across 4 files (patterns ntok_/utok_/atok_/BEGIN PRIVATE KEY/password=/api-key/AKIA/AIza/ghp_/gho_/xoxb-/sk-live): 0 hits on every file.
  • Current-main drift: 0 commits on any of the 4 touched files (base..main). Current main advanced only via ci: pin Bun in the always-on rename-ghost gate #802 which touched tests/qa-180-rename-ghost/Dockerfile + docs/tests/report-test728-...txtzero file overlap with this PR.
  • Virtual merge-tree git merge-tree base main pr-800 = 0 conflict markers. Rebase-clean over current main.
  • CI budget: existing qa.yml jobs agent-node-unit + agent-network-unit both have timeout-minutes: 12. New per-file loops add ~25 subprocess invocations; each is bounded by bun test's own timeout. No config change to timeout, path triggers, or new job. Budget headroom preserved.

⑥ "Complete unit domain" claim + implicit NOT COVERED honesty — CONFIRMED (with informational note at ⑧)

The report's title and motivation explicitly acknowledge the gap the PR fixes:

两个门的抬头都写着 complete X unit domain,却把 tests/ 下 25 个文件排除在外。

After this PR, the complete unit domain claim covers:

  • agent-network/src/**/*.test.ts (46 files, 438 tests) — pre-existing
  • agent-network/tests/*.test.ts maxdepth 1 (19 files) — NEW
  • agent-node/src/**/*.test.ts — pre-existing
  • agent-node/tests/*.test.ts maxdepth 1 (6 files) — NEW

Implicit NOT COVERED (structurally excluded by -maxdepth 1 -name '*.test.ts', all legitimately non-unit):

  • agent-node/tests/rfc-030-*.ts (6 files: NOT .test.ts extension) — RFC-030 E2E / integration scripts
  • agent-node/tests/archive/ (deprecated)
  • agent-network/tests/archive/ (deprecated)
  • agent-network/tests/docker-e2e/ (E2E, not unit)
  • agent-network/tests/test-grok-build-capability/ (integration, own Dockerfile)
  • agent-network/tests/fixtures/ (helpers, not tests)

These exclusions are appropriate for "unit domain" (E2E and integration are separate concerns). The report describes the scope but does NOT enumerate the exclusions as explicit "NOT COVERED" items — see ⑧ for informational note.


⑦ MINOR: per-file "at least N tests ran" assertion missing — not fired on this PR, but structural gap

The finding: the tests/ dispatch loop asserts only exit code:

if runuser -u node -- ... $cmd" >"/tmp/...log" 2>&1; then
  tdir_ran=$((tdir_ran+1))
else
  tdir_ran=$((tdir_ran+1)); tdir_failed=$((tdir_failed+1))
  ...
fi

There is no per-file assertion of the form grep -Eq '[1-9][0-9]* pass' /tmp/...log. Structurally, a future contribution that:

  • adds a .test.ts file containing a top-level // bun:test comment but no import { describe } from 'bun:test' (comment-decoy) — the heuristic misdispatches to bun test <file>. If bun test on a file with no describe/it returns rc=0 with "0 tests ran" (the typical behavior in recent bun versions), the tdir_failed counter does not increment → false-green;
  • adds an all-describe.skip bun:test file — bun test returns rc=0 with "0 tests ran" (or 0 pass with 0 fail) → false-green;
  • adds a script file whose primary success path is process.exit(0) with no assertions — rc=0 → false-green.

On the CURRENT 25 files, this never fires — I verified each file has real work:

  • 6 agent-node files: all script-style with process.exit and real assertions (no comment decoys)
  • 3 agent-network bun:test files: all have real describe/it with assertions (no .skip)
  • 16 agent-network script files: all have real process.exit(1) on failure paths

Therefore the CURRENT PR's success does not rely on silent exit. But the gate would not catch the drift class if a future contributor introduces one of the three patterns above.

Why MINOR (not MAJOR):

  • The failure mode requires FUTURE adversarial-shaped contributions; no CURRENT file triggers it
  • The PR strictly improves coverage (0 → 25 files under tests/)
  • The feedback_finding_confirmation_is_not_verdict gate wording is 执行成功不能靠...静默 exit — the CURRENT execution success does not; the STRUCTURAL gate could be fooled by future contributions. Reading strictly: the current claim is honest; the follow-up hardening is a distinct concern.
  • Reasonable follow-up: add per-file grep -Eq '(bun|test).*[1-9][0-9]* (pass|passed)' "/tmp/.../<file>.log" after each dispatch, so a "0 tests" outcome reds.

Recommend as follow-up hardening PR, not a merge blocker for this one.


Additional observations (informational, not blocking)

⑧ Report could enumerate NOT COVERED explicitly

The report's motivation section (## 为什么) says the "complete" claim was previously wrong because tests/ was excluded. After this PR, the claim is closer to true — but a future reader would benefit from an explicit table of what IS and IS NOT in scope (subdirs, .ts non-.test.ts scripts, E2E, playwright, fixtures). Not a merge blocker; would strengthen the feedback_docs_true_now_wrong_at_release_need_a_ship_checklist discipline.

/work/feishu-attachments hard-coded path is a test-file authoring concern

The reason the Dockerfile needs the install -d /work line is that feishu-bridge-ipc.test.ts uses an absolute path instead of a workspace-relative one. This PR does not fix the test's hard-coded path (out of scope — that's a product/test-quality PR). The Dockerfile fix is the minimal appropriate enabler. Worth tracking as a separate cleanup ticket.

⑩ Cross-package agent-node/src COPY introduces a coupling

tests/feishu-envelope-compat.test.ts in agent-network/tests/ imports from agent-node/src/runtime/feishu-envelope. This means the test image now bundles two packages' src. That's not wrong (the test is a legitimate cross-package contract test), but it does mean agent-node/src changes will invalidate the test745 build cache. Acceptable trade-off for the test contract; noted.

⑪ Trivially rebase-clean, no drift

git log --oneline base..main -- <4 files> = 0 per file. git merge-tree produces 0 conflict markers. Land-safe.


Reviewer discipline (self)

Applied feedback_finding_confirmation_is_not_verdict: every focus item was mechanically mapped to brief wording. The MINOR finding on per-file min-tests assertion is real but does not fire on the current 25 files, so it stays MINOR (not MAJOR). Verdict remains CLEAN.

Independent verifications on this host:

  1. git rev-parse origin/pr-800 = 2b2a7c2b... ✓ matches brief HEAD
  2. git merge-base origin/pr-800 origin/main = d4283a22... ✓ matches brief original base
  3. git rev-parse origin/main = 034f0064... ✓ matches brief current main
  4. git diff --numstat base..HEAD = 4 files as listed in brief
  5. 0 product-source files touched (confirmed by path prefix filter)
  6. 0 workflow YAML files touched
  7. Enumerated agent-node/tests + agent-network/tests → 6+19=25 .test.ts files at maxdepth 1
  8. Characterized each of the 25 files: 3 with bun:test, 22 without; every file's dispatch is correctly heuristic-selected
  9. python3 count(target) on HEAD agent-node/src/cli.ts for test725 mutation target = 1
  10. python3 count(target) on HEAD agent-network/bin/cli.ts for test745 mutation target = 1
  11. Named-red strings both exist as test(...) names / expect(...).toContain(...) sites in the referenced test files
  12. Report lines 1535/1537–1538 and 2084/2086/2089–2090 show MUTATION_RED ... rc=1 + RESULT: PASS for both packages
  13. Secret sweep across 4 files (broad-net + case-sensitive) = 0 hits
  14. git log --oneline base..main -- <4 files> = 0 per file — no drift
  15. git merge-tree base main pr-800 | grep -cE '^<<<<<<<' = 0 conflict markers
  16. ci: pin Bun in the always-on rename-ghost gate #802 file set (tests/qa-180-rename-ghost/Dockerfile + docs/tests/report-test728-...txt) has zero overlap with this PR's 4 files
  17. Dockerfile L26 (COPY agent-node/src) is minimal (only src, not full package); L34 (install -d /work 0755 owned by node) is minimal (only parent dir, not the child feishu-attachments)
  18. qa.yml jobs agent-node-unit/agent-network-unit unchanged, timeout-minutes: 12 preserved

No approve, no merge, no deploy.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Gate correction — DO-NOT-MERGE current HEAD pending provenance repair, despite the otherwise positive independent review.

The committed report is not anchored to this PR source. It states source_commit=92d9612949a4207eae4facab2b337c1f23de65e0 at lines 2, 23, and 1543. That SHA predates PR base d4283a22 and does not contain this PR’s four-file delta. Frozen PR HEAD is 2b2a7c2b. There is no committed image/file hash bridge proving the dirty worktree used for the report was byte-identical to 2b2a7c2b. Therefore “single commit → source==HEAD” is not a valid provenance inference, and the committed 2091-line log cannot be presented as exact-source evidence.

Positive counter-evidence, carefully scoped: GitHub Actions did execute the two changed gates on PR virtual-merge commit f0dd16e7f19d112799054890998f271679977f84 and recorded:

  • agent-node: tests_dir_executed=6 ... failed=0, named mutation red, RESULT PASS;
  • agent-network: tests_dir_executed=19 ... failed=0, named mutation red, RESULT PASS.
    This supports the code behavior, but ephemeral Actions retention does not repair a false source coordinate in the repo’s durable report.

Required closeout: freeze 2b2a7c2b as source, rerun the exact Docker gates from that committed tree, and append a report-only child commit with truthful source/image/log coordinates (or explicitly supersede the old report rather than rewriting its observed source). Then re-review only the provenance/report delta plus current-main drift. Do not merely replace the string 92d96129 with 2b2a7c2b; that would relabel an old run rather than reproduce it.

No product defect claimed, no code or production change made by reviewer.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

SUPERSEDE · PR #800 — provenance gap 更正

Reviewer: 通信IM马 (independent, read-only). This comment supersedes the earlier CLEAN verdict at #issuecomment-5274674239. The prior comment is preserved unchanged for traceability. The CLEAN verdict is hereby withdrawn.

Revised Verdict: DO-NOT-MERGE — pending exact HEAD 2b2a7c2b rerun + report-only child commit

Category: MAJOR — evidence provenance gap (Git-internal false anchor). Not a code correctness finding; a provenance-of-evidence finding. The prior audit correctly identified 4 files and correctly enumerated the 25 denominator, but did NOT interrogate the report's declared source_commit — which is the gate-critical anchor for whether the reported PASS actually pertains to the code being merged.


The provenance contradiction (independently verified)

The 2091-line report docs/tests/report-pkg-tests-dir-gate.txt at HEAD 2b2a7c2b declares:

L2:    source_commit=92d9612949a4207eae4facab2b337c1f23de65e0
L23:   source_commit=92d9612949a4207eae4facab2b337c1f23de65e0
L1543: source_commit=92d9612949a4207eae4facab2b337c1f23de65e0

But the PR's freeze coordinates are:

  • HEAD: 2b2a7c2bcd801c6b01a7c285f96b12c67e0bc00d
  • base: d4283a229dbdcd85d0e4ceb9f715c84607a521b4

92d9612949... is a commit two commits behind base, and it does not contain the PR's delta:

file 92d... state HEAD 2b2a... state contains PR delta?
tests/test725-agent-node-unit-ci/run.sh 66 lines (blob 40a64ad6) 103 lines (blob 5f26509d) NO on 92d — the +37 tests/ dispatch loop is missing
tests/test745-agent-network-unit-ci/Dockerfile 35 lines (blob ca29fd9c) 40 lines (blob 067a6f39) NO on 92d — the COPY agent-node/src + install -d /work additions are missing
tests/test745-agent-network-unit-ci/run.sh 91 lines (blob ae46f0fc) 128 lines (blob be889fd3) NO on 92d — the +37 tests/ dispatch loop is missing
docs/tests/report-pkg-tests-dir-gate.txt absent 2091 lines (blob 5f21938e) NO on 92d — file doesn't exist

Since the tests/ dispatch code that emits the tests_dir_executed=... output line only exists on 2b2a:

grep -c 'tests_dir_executed' in 92d's run.sh files: 0 / 0
grep -c 'tests_dir_executed' in HEAD's run.sh files: 1 / 1

...the report's contents (which include tests_dir_executed=6 at L1535 and tests_dir_executed=19 at L2086) provably could NOT have been produced by running the 92d-shaped runners. The source_commit=92d field is therefore a false anchor — the runner-that-emitted-the-report was not on 92d.


What the audit needed and what CANNOT bridge the gap

Per brief: "GitHub Actions 虚拟 merge f0dd 的 6/6、19/19、双 mutation red 可作为代码行为正证,但不能修复 Git 内报告假锚"

GitHub Actions runs on head_sha=2b2a7c2b (informational, all conclusion: success):

These prove the CODE BEHAVIOR on HEAD 2b2a (the runners actually work, the mutations actually red, the denominators actually match) — but they do not repair the Git-internal false anchor in the committed report. A future reader picking up this report will read source_commit=92d and follow a broken pointer, unable to reproduce or forensically verify.

The bridging evidence that would repair this (and is NOT present):

  • Runtime workspace / built-image four-file byte-hash listing showing all 4 files' contents == the exact blob hashes at HEAD 2b2a (blobs 5f26509d, 067a6f39, be889fd3, 5f21938e), OR
  • A rerun of the exact test725/test745 containers with SOURCE_COMMIT=2b2a7c2b... producing a fresh report whose source_commit line matches HEAD, committed as a report-only child on top of the current source (5f21938e-replacement, 2b2a7c2b-parent).

Neither is present. Without one, the committed evidence claims to describe 92d while the surrounding PR files change 2b2a — this is the exact class described by feedback_committed_gate_artifact_source_commit_can_lag_code and feedback_verify_current_fact_not_the_action_i_took.


What I got wrong in the earlier comment

The prior comment stated:

"Single-commit PR: source == HEAD → no source-vs-report topology split possible. The 2091-line report matches this single commit's output."

This was incorrect. Single-commit topology does not by itself guarantee the report was generated FROM the code IN the same commit. In this PR, the 2091-line report contains a source_commit field pointing at a commit whose files do not contain the tests/ dispatch loop that produced the report's output. That's a topology mismatch that a single-commit PR does not preclude.

The Focus ① check should have grepped the report body for source_commit= and cross-referenced against git rev-parse HEAD before waving-off topology. I did not do that. Corrected here.

The FOCUS 4 mutation evidence (target counts on HEAD, named-red strings existing) still stands as CODE behavior evidence. But that stands independently of the report anchor; it does not repair the anchor.


What's required to move this back to CLEAN

Any one of:

  1. Rerun on HEAD 2b2a7c2b and commit a report-only child whose source_commit line is 2b2a7c2b... (or a subsequent report-anchor commit if the source is bumped). The child would preserve the current source commit's parent while replacing the report blob with fresh evidence. This is the cleanest path.

  2. Prove byte-identity between the runtime workspace and HEAD 2b2a7c2b via a signed manifest (blob-hash listing of the 4 files inside the image or workspace that produced the report) attached to the PR as fresh evidence.

  3. A witnessed rerun log with the 4 file hashes emitted as part of the runner's provenance section (e.g., sha256 <path> for each of the 4 files at start), matching the blob hashes above.

Absent any of the above, the report's source_commit=92d field is a broken Git-internal anchor and the PASS evidence cannot be attributed to the exact code being asked to merge.


Discipline citations

  • feedback_committed_gate_artifact_source_commit_can_lag_code — the exact pattern that fired here
  • feedback_verify_current_fact_not_the_action_i_took — "verify the current fact, not the action you took"
  • feedback_finding_confirmation_is_not_verdict — a MAJOR provenance finding, confirmed by direct git-tree diff, must translate to DO-NOT-MERGE (no follow-up space)
  • feedback_fetch_evidence_at_report_head_not_source_ref — report evidence must anchor to the report-head, not a stale source ref

Original CLEAN verdict retracted. Revised Verdict: DO-NOT-MERGE pending exact 2b2a7c2 rerun + report-only child commit.

Not editing / not deleting the prior comment — supersede by append only, per audit protocol.

vansin pushed a commit that referenced this pull request Aug 13, 2026
#800 被独审抓到的那条:上一份报告声称的 source commit 是
92d9612,而那不是本 PR 的 head。
根因是我跑门时 --build-arg SOURCE_COMMIT 传的是当时的 origin/main,
不是分支自己的 head。这次是主动自查修复,不等独审再点一次。

本提交 report-only,不动被测代码。重跑结果(锚点 = 源码提交 ecf4679):

  test_files=69  executed_files=69  discovered_files=69  failed_files=0
  MUTATION_RED registration-password-floor-weakened rc=1
  RESULT: PASS

正文提到旧锚点时刻意不写成 key=value,避免本文件出现第二个可被 grep 误认的锚点。
vansin pushed a commit that referenced this pull request Aug 13, 2026
#798/#800 的同一根因:上一份报告的锚点是 034f006…,不是本 PR 的 head,
因为跑门时 --build-arg 传的是当时的 origin/main。本提交 report-only,不动被测代码。

三个套件按独立 job 里逐字相同的命令重跑,全部 PASS。
两个门的抬头都写着 "complete agent-node/agent-network unit domain",
但只跑 src/,把 tests/ 下 25 个文件排除在外 —— 其中不乏安全相关的:
feishu-markdown-image-ssrf、secret-mask ×3、vendor-error-sanitize、feishu-tool-deny。
这些正是静默失效代价最高的那类。

这个目录里混着两种测试,任何单一命令都跑不全:
- 脚本式(16+6 个):自己打 "N/N passed",失败 process.exit(1),必须 bun <file>;
  用 bun test 跑会因为 top-level 的 process.exit 把整个 run 打断在第一个文件
  (实测:bun test tests/ 只跑完第一个就结束)。
- bun:test 式(3 个):describe/it,必须 bun test <file>;用 bun <file> 跑会报
  "Cannot use describe outside of the test runner"。
所以按文件内容分派,并把两条判据都写进注释。

退出码可用已先验:这些脚本失败时确实 process.exit(1),不是 fail-open。

落地前实测:
  agent-node/tests   6/6 直接过
  agent-network/tests 单命令 14/19 → 按内容分派 17/19 → 补两处环境契约 19/19
两处契约都在 Dockerfile 内解决,并写明原因:
  - feishu-envelope-compat 跨包 import agent-node/src/runtime/feishu-envelope
  - feishu-bridge-ipc 硬编码绝对路径 /work/feishu-attachments,容器里 node 建不了

分母承重:tests_dir_executed 必须等于 find 出来的数,且 >0。

实测:test725 tests_dir 6/6/0 + MUTATION_RED + PASS;
     test745 tests_dir 19/19/0 + MUTATION_RED + PASS。
@vansin
vansin force-pushed the test/pkg-tests-dir-gate branch from 7a04706 to bdfd432 Compare August 13, 2026 02:14
vansin pushed a commit that referenced this pull request Aug 13, 2026
#798/#800 的同一根因修复:早先的锚点是跑门时的 origin/main,不是分支 head。
本提交 report-only,不动被测代码。三个套件按独立 job 里逐字相同的命令重跑,全部 PASS。
vansin pushed a commit that referenced this pull request Aug 13, 2026
自查清单(#815)第 ⑤ 条「断言要精确到不合规会被拒绝」在自己门上的应用。

原来写的是 `grep -Fq 'rejects 7-char password'`。bun test 对每个用例都打
`(pass) <名字>` 或 `(fail) <名字>` —— 只 grep 名字的话,那条用例**通过**时
也会命中。于是这条断言只证明了「这条用例存在」,而不是「红落在它身上」。

A/B(把断言指向一条在该 mutation 下**不会红**的用例
`accepts 8-char strong password`,其余完全不动):

  松版 grep -Fq '<名字>'                → rc=0  RESULT: PASS   ← 收下了不合规
  严版 grep -Eq '^\(fail\).*<名字>'      → rc=1  FAIL: mutation red did not reach the named…

改成锚定形式后正常绿:MUTATION_RED registration-password-floor-weakened rc=1,RESULT: PASS。

同类问题在 tests/test725-agent-node-unit-ci/run.sh 也有(它 grep 的
'the inbox choke point feeds the augmented text into processTask' 同样是测试名);
在 #800 里一并收紧,那边有单独说明。
tests/test745 那条不受影响 —— 它 grep 的是断言失败信息
`Expected to contain: "anet config [path|json]"`,只在失败时出现。
#798 同一类:原来 grep 的
'the inbox choke point feeds the augmented text into processTask'
是**测试名**,而 bun test 对每个用例都打 `(pass) <名字>` / `(fail) <名字>` ——
那条用例通过时也会命中,断言只证明了「它存在」,不证明「红落在它身上」。

A/B 在 #798 上做过(把断言指向一条该 mutation 下不会红的用例):
  松版 → rc=0 RESULT: PASS(收下了不合规);严版 → rc=1 点名失败。

这道门不是我写的,我在本 PR 里本来就在改它的 run.sh(加 tests/ 分派),
所以顺手收紧;改动只让门更严,并在下面重跑验证仍绿。
若 owner 认为不该由本 PR 动它,我可以拆出去。
@vansin
vansin force-pushed the test/pkg-tests-dir-gate branch from bdfd432 to 4d56276 Compare August 13, 2026 03:02
#798 实测:只比「executed == discovered」的门,在删掉 85% 测试文件后
照样 RESULT: PASS —— 分母跟着现实自动缩水。

我在本 PR 里加的 tests/ 分派用的是同一形状,所以有同一个洞。
补 AGENT_NETWORK_TESTS_FLOOR=15(现 19 个)、AGENT_NODE_TESTS_FLOOR=5(现 6 个),
并写明「真删了测试就故意改这个数」。

范围说明:只给**我在本 PR 新加的 tests/ 分派**加下限,没有动这两个门原有的
src/ 分母判定(那是 #791/#725 的既有代码,同类下限缺失我另报,不夹进本 PR)。
@vansin
vansin force-pushed the test/pkg-tests-dir-gate branch from 4d56276 to 539a7e7 Compare August 13, 2026 03:16
vansin pushed a commit that referenced this pull request Aug 13, 2026
自查发现本报告里有两个不同的 source_commit:抬头是 2617987(正确,==源码提交),
但嵌入的运行输出里是 187a6ff。

根因是我上一轮的操作顺序错了:**先 `git rev-parse HEAD` 打戳、后提交下限改动**。
于是镜像里跑的是含下限的代码,戳进日志的却是提交前的 SHA ——
证据本身有效,但它自称的锚点指向一个不含该改动的提交。

这与 #798/#800/#803 早先被独审抓到的假锚点是**同一个根因的第二次发作**
(那次是把 --build-arg 传成了 origin/main,这次是传成了未提交前的 HEAD)。

已在真源码提交 2617987 上重跑并重出报告,全文 source_commit 只指向一个值:
  test_files=69 executed_files=69 failed_files=0
  MUTATION_RED registration-password-floor-weakened rc=1
  RESULT: PASS
@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

状态更新:上面那条 SUPERSEDE 提出的要求已经照做

上一条评论(SUPERSEDE · PR #800 — provenance gap 更正)撤回了原 CLEAN,并要求:
在 frozen source 2b2a7c2b 上 exact rerun + truthful report-only child,禁止直接改字符串冒充。

那个指控是对的,根因也是我的:跑门时把 --build-arg SOURCE_COMMIT 传成了当时的 origin/main,
于是报告声称的锚点(92d96129…)是一个provably 不可能产出该报告的提交 —— 那一版的 run.sh
根本没有 tests_dir_executed 那段代码。

已按要求完成,且没有改字符串冒充:重跑是在真提交上做的,报告整份重出。
后续因为 rebase 到 current main、又补了下限与断言收紧,坐标再次前移。

当前坐标(冻结中,我不再改动)

source     1e9e75da…   (代码提交)
report     539a7e72…   (report-only 子提交)
base       034f0064    (current main,已 append)

自检:grep -oE 'source_commit=[0-9a-f]{40}' docs/tests/report-pkg-tests-dir-gate.txt | sort -u
只有 1 个值,等于上面的 source。

实测:test725 tests_dir 6/6/0 + MUTATION_RED readable-attachment-runtime-disconnected rc=1;
test745 tests_dir 19/19/0 + MUTATION_RED stale-config-help rc=1;两者 RESULT: PASS

近期审查发现(经 commhub 收到;我的转录,非终审)

提出的点 结论
find tests -maxdepth 1 只覆盖顶层;将来出现 tests/<sub>/*.test.tsexecuted==discovered 仍会静默绿 成立。当前两个目录都没有嵌套测试,所以不是当前漏跑;但本 PR 单独不能兑现「整棵 tests/ 永久 complete」
grep -q bun:test 是粗分类器,未来注释/字符串可能误分 成立;当前枚举为 agent-node 6/6 脚本式、agent-network 16 脚本式 + 3 bun:test,与 CI 全绿吻合,当前无误分
floor 5 / 15 只挡大幅删测 是已披露的设计取舍,不是精确全集锁
set -e + if runuser + process substitution 会不会提前退出 不会;失败累计,最后统一 fail

第一条正是 #801 元门要闭的角:我在 #801 里让判定从「路径前缀」改成从门里推导扫描深度
(scan_depth()find … -maxdepth N,再用 rest.count("/") >= d 判定)。
当时的双向验证:把测试放进 agent-network/tests/sub/ → 元门 rc=1 并点名该文件;直属文件仍 rc=0。

所以合并顺序是硬要求:#798 / #800#801 本 PR 单独合入不构成「tests/ 永久闭环」。

待决清单

本 PR 目前零待改点。若你们认为正文该补一句「完整闭环依赖 #801」的交叉引用,我可以加 —— 但我在冻结中,等点头

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

自查结论:新增块没有让既有断言变假;但 -maxdepth 1 是个会静默的盲区(非当前缺陷)

#809 那条 MAJOR 的形态(往已存在文件里只加不删,新增内容全对但让页面上某句老话变假)自查本 PR。

第一问:新增块有没有破坏既有断言?没有。
新增的 :62-91 是自带计数器(tdir_total / tdir_ran / tdir_failed)、自带下限、自带三条断言的独立块;既有的 src/:15-47 逐字节未改。两段互不干涉。


第二问:-maxdepth 1 漏不漏?今天不漏,一个都不漏。

src/ 的发现是递归的,新增的 tests/ 发现用了 -maxdepth 1,两边不对称,所以量了一下(按 origin/main 的 tree,非工作树):

目录 深度1 递归
agent-network/tests 19 19 0
agent-node/tests 6 6 0

下限也都成立:AGENT_NETWORK_TESTS_FLOOR=15 vs 实际 19;AGENT_NODE_TESTS_FLOOR=5 vs 实际 6。

所以这不是当前缺陷,不需要在本 PR 改。


但它失效的方式值得记:分母和判据用了同一个受限的发现

如果将来有人加了 agent-network/tests/foo/bar.test.ts:

  1. tdir_total(分母)用 -maxdepth 1 数 → 看不见它;
  2. 执行循环用同一个 find也不跑它;
  3. 于是 tdir_ran == tdir_total 仍然成立 → 门照常绿。

没有任何东西会变红。 这道门对"新增了嵌套测试文件"这件事是完全瞎的,而且瞎得不留痕迹 —— 因为发现范围和验证范围是同一个,两者的不一致永远暴露不出来。

同族于本仓已记过的那类:一道门只要把"该做什么"和"做了什么"用同一个来源算,它就只能证明自洽,不能证明完整。

若要消除(不建议在本 PR 做,会扩大范围):分母用递归 find、执行仍可限深,让两者故意不同源,这样一旦出现嵌套文件,tdir_ran == tdir_total 立刻红。


附:我这次的扫描先是空的

第一次我在当前工作树上跑 find agent-network/tests -name '*.test.ts',得到 0,差点报出"这两个目录根本没有测试文件"。实际是这个 checkout 在别的分支、目录没铺开,而我还把 stderr 吞了(2>/dev/null)。

origin/main 的 tree 重查才拿到真实的 19 / 6。记一笔:枚举要打 origin/main,不要打当前 checkout;以及吞掉 stderr 的 find 返回 0 时,0 可能是"没找到",也可能是"根本没跑成"。

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

自审(本 PR 至今零审查):查了派发逻辑里最可疑的一处,结论是没问题 —— 但这个"没问题"是验出来的

本 PR 是三条从没被任何审查器碰过的之一(另两条 #810 / #823,#823 已自审出一条 fail-open 并修)。

被查的形态

:66  if grep -q 'bun:test' "$f"; then cmd="bun test $rel"; else cmd="bun $rel"; fi

19 个被发现的文件里,16 个不含 bun:test,走裸 bun <file> —— 也就是当普通脚本执行,不经过测试 runner。

这个形状有两个真实风险:

  1. 失败信号丢失 —— 脚本跑完退 0,失败只打印在 stdout,那 tdir_ran == tdir_total 会把它算成「已执行且通过」,门对这 16 个文件是瞎的;
  2. 真实网络出口 —— agent-network/tests/ 下是飞书桥的测试,若其中有真连外网/真打飞书的,那就是拿门去碰线上通道。

逐条核完:两个风险都不成立

风险 1 —— 16 个文件全部能把失败传出去。

  • 15 个:收集结果后 if (failed.length > 0) { … process.exit(1) };
  • 1 个(feishu-bridge-ipc.test.ts):用 node:assert 严格模式,断言失败抛异常;它的 try { … } finally { … } 没有 catch,不吞异常 → 未捕获异常本身就是非零退出。

我第一版的扫描判据是「有没有 process.exit(1)」,于是把这个文件标成了可疑。判据太窄 —— assert 抛异常是等价(甚至更好)的失败信号。

风险 2 —— 没有真实出口。

扫出两个「非占位 URL」命中,逐个看完都是误报:

  • feishu-markdown-image-ssrf.test.ts169.254.169.254metadata.google.internalkubernetes.default.svcattack.com。这些是 SSRF 测试向量,是代码必须拒绝的输入,不是它要访问的地址。一个 SSRF 测试里出现这些字符串,恰恰说明它在做该做的事;
  • feishu-hub-upload.test.tshttp://hubhttp://x,是 hub.example.com 一类占位串被我的正则切碎的片段。

其余全部是 example.com / localhost / 127.0.0.1

结论

派发逻辑是健全的:走裸 bun 的 16 个文件都能让门变红,且不接触任何真实端点。本轮无需改动。

记两条判据(两次都是我的扫描器太窄)

  1. 失败信号不止一种写法。 找「有没有 process.exit(1)」会漏掉 throw / assert;
  2. 命中一个危险字符串不等于存在危险行为。 安全测试的语料里必然出现攻击向量 —— 判断要看它是被当作输入还是被当作目标。

这与我在 #815 补的那条同源:任何以「找到 N 个可疑项」为结论的扫描,报出去之前要先确认这 N 个里有没有一整类是按设计就该长这样的。

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

本 PR 至今零审查记录(自动审查器只在开 PR / 草稿转就绪 / 显式 @ 时触发,push 不触发)。这是第二次请求。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 539a7e7251

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -0,0 +1,2080 @@
# test725/test745 扩到 tests/ 目录

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Store the evidence under the report-testN naming scheme

The new test evidence is saved as report-pkg-tests-dir-gate.txt, while the repository requires test results under docs/tests/report-testN.txt. Rename or split this combined artifact into test-numbered reports (for example, test725 and test745) so the evidence remains discoverable through the mandated convention.

AGENTS.md reference: AGENTS.md:L8-L8

Useful? React with 👍 / 👎.

# 🔴 绝对下限:`executed == discovered` 只能抓「runner 跳过了文件」,
# 抓不到「文件消失了」—— 分母会跟着现实自动缩水。见 #798 的实测:
# 删掉 85% 的测试后,只比数量的门照样 PASS。真删了测试就故意改这个数。
AGENT_NETWORK_TESTS_FLOOR=15

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Raise the floors to match the current test inventories

When up to four agent-network/tests files are deleted or renamed away from *.test.ts, discovery and execution shrink together and this 15-file floor still passes even though the current inventory is 19; the analogous 5 floor in test725 also permits one of its six tests to disappear. This preserves exactly the silent-loss gap these checks claim to close, including the possibility of dropping security tests while CI stays green, so initialize the floors to 19 and 6 and require an intentional update whenever a test is actually removed.

Useful? React with 👍 / 👎.

@vansin vansin left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

结论:前提我独立核过,属实;修法扎实,建议合并。一条 MINOR(不挡合并)

前提:我没看 PR 自述,自己对 origin/main 数了一遍

「两个门自称 complete」 —— 属实:

tests/test725-agent-node-unit-ci/run.sh:11    echo "# test725 — complete agent-node unit domain"
tests/test745-agent-network-unit-ci/run.sh:11 echo "# test745 — complete agent-network unit domain"

「只跑 src/」 —— 属实:两个门实际执行的都是 bun test src/
(test725:18、test745:24)。

「漏了 25 个文件」 —— 属实,而且数字精确。按 *.test.ts 数:

agent-node/tests/     6   (feishu-tool-deny / outbound-secret-mask / quota-error-passthrough
                           / secret-mask-spawn / secret-mask / vendor-error-sanitize)
agent-network/tests/ 19   (environ-alias / feishu-* ×16 / goal-wake-log-render / project-key)
                     ──
                     25

点名的那几个安全相关文件确实都在里面:feishu-markdown-image-ssrf
secret-mask 三件(secret-mask / secret-mask-spawn / outbound-secret-mask)、
vendor-error-sanitizefeishu-tool-deny

顺带一个更难看见的点:test745 原本在 :47 有一道分母检查
(bun executed N file(s) but $test_files exist under src/),但它的范围本身就限定在 src/
所以「漏掉整个 tests/ 目录」这件事,连既有的那道分母门都照不到 —— 门是绿的,因为它按自己划的范围数,数对了。

修法

按文件内容分派(bun:testbun test <f>,否则 bun <f>)、逐个跑、失败打名字和尾部日志,
再加一条绝对下限 AGENT_NETWORK_TESTS_FLOOR=15,注释里引了 #798 的实测
(删掉 85% 测试后,只比数量的门照样 PASS)。这条下限是对的,而且是这份改动里最值钱的一行。

两处环境契约在 Dockerfile 里解决、并写明了原因(feishu-bridge-ipc 硬编码 /work/...;
feishu-envelope-compat 跨包 import),没有去改产品代码迁就测试 —— 方向对。

我另外核了两个边界,当下都干净:

  • -maxdepth 1 之下目前没有更深层的 .test.ts,所以没有漏网;
  • 分派判据 grep -q 'bun:test':25 个文件里凡提到 bun:test 的都确实 import ... from "bun:test",
    不存在「注释里提了一嘴就被误分派」的情况。

🔴 MINOR:executed == discovered 这条断言是恒真的,和它注释说的不是一回事

test745:87 和 test725:66 都有:

[[ "$tdir_ran" -eq "$tdir_total" && "$tdir_total" -gt 0 ]] || { echo "FAIL: ran ... of ..."; exit 1; }

但循环里两个分支都在给同一个计数器加一(test745:69 / :71,test725:48 / :50):

if runuser ... ; then
  tdir_ran=$((tdir_ran+1))
else
  tdir_ran=$((tdir_ran+1)); tdir_failed=$((tdir_failed+1))
fi

所以 tdir_ran 数的是循环跑了几圈,不是执行成功了几个。我按同样结构做了最小复现,
把命令换成必然失败:

模拟「每个文件都执行失败」:executed=3 discovered=3 failed=3
→ executed == discovered 仍然成立(该断言不会 fire)

也就是说,它唯一可能 fire 的情形,是 :62 和 :77 那两次 find 之间文件被增删的竞态。
而注释写的是「只能抓『runner 跳过了文件』」—— 在这个循环结构里,没有任何东西能「跳过」。

这不是覆盖漏洞:真正兜底的是 tdir_failed -eq 0 和那条 floor,这两条都工作正常,
所以不挡合并。要改的是别让注释承诺超过它实际执行的范围 —— 要么把注释收窄成
「防两次 find 之间的竞态」,要么让计数器真的只在成功分支加(那样它就和 failed 冗余了,
删掉反而更诚实)。

对照一下就更清楚:被替换掉的 src/ 那道检查是去解析 bun 自己输出的执行数,
那个数和枚举数是两个独立来源,所以它真能抓到 runner 跳文件。新加的这条没有第二个来源。

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

补一条:这个 PR 不会关掉 #817,合并时别顺手关。

#817 复现的洞在 src/,而这个 PR 加的两条 floor 守的是 tests/:

src/ tests/(本 PR 新增)
test745 有分母 test_files(:15),断言 executed >= test_files(:46) —— 但没有 floor AGENT_NETWORK_TESTS_FLOOR=15(:82) ✅
test725 连分母都没有:只有一行 bun test src/(:18) AGENT_NODE_TESTS_FLOOR=5(:61) ✅

executed >= test_files 挡不住删测试:删掉 40 个文件后,test_files 跟着变成 6、
executed 也是 6,两边一起缩水,断言照样成立 —— 这正是 #817 实测出来的结果
(test_files=6 / executed_files=6 / RESULT: PASS rc=0)。
本 PR 自己的注释也写了这个道理(:58「executed == discovered 只能抓『runner 跳过了文件』」),
并据此给 tests/ 加了 floor —— 但 src/ 那边没有跟着加。

所以合并之后:

  • agent-network/tests/agent-node/tests/ 有了下限保护 ✅
  • agent-network/src/ 仍可被大量删除而不红 ❌
  • agent-node/src/ 连数都不数 ❌

补法和这个 PR 里已有的一样,两行的事:src/ 也各加一条 floor,
test725 还要先把分母加上。要不要在本 PR 里补,看你们的偏好 ——
本 PR 的范围写的是「让两个门覆盖 tests/ 目录」,src/ 的下限属于 #817,分开也合理。
只要别在合并本 PR 时关掉 #817 就行。

(核的是本 PR head 539a7e72,行号按该提交。)

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

独立深审结论:CLEAN(exact head 539a7e7251a67ca2cfcc2f182208bff613188362,source 1e9e75dab635dc03d12636232ebc2ac117c2dee6,且 head^ == source)。

我从 source archive 独立重建并真跑两个 Docker 门:

  • agent-node src:1281 pass / 0 fail / 4365 expects / 91 files;tests/:6/6/0
  • agent-network src:438/0/1333/46;tests/:19/19/0
  • 两条 mutation 均在命名断言上转红;
  • 独立 find 分母与门输出一致:91 / 46 / 6 / 19。

因此 #800 门本体可独立放行。顺序边界:#854 会与 test725 同一插入区发生 content conflict;必须先落 #800,再把 #854 rebase/人工 union,不能顺手选任一侧。未 approve、未 merge、未 deploy。

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.

2 participants