Skip to content

[Bug][CI]: Windows batch leg skips its nested live-lock regression under OCX_TEST_NO_QUEUE=1 #4991

Closed

Description

@Ingwannu

Summary

PR #4876 correctly stops the Windows batch runner from queueing against its own previous batch by setting OCX_TEST_NO_QUEUE=1 on the Test in fresh-process batches step. However, the only Windows-only regression that proves nested Bun processes inherit and enforce the live test-run lock is guarded by the opposite condition:

test.if(process.platform === "win32" && process.env[TEST_RUN_NO_QUEUE_ENV] !== "1")(
  "nested Windows Bun tests inherit the acquired live lock and refuse an incomplete capability",
  // ...
)

On current dev (6304a94c03), that test is therefore skipped in the exact Windows step whose lock behavior it is meant to protect.

Current evidence

  • .github/workflows/ci.yml sets OCX_TEST_NO_QUEUE: "1" for the Windows fresh-process batch step.
  • tests/ci-workflows/test-runner.test.ts skips the nested live-lock test whenever that variable is 1.
  • The same test is Windows-only, so Linux/macOS shards cannot cover it.
  • The ordinary no-queue unit test only proves that resolveWrappedTestRunLockPath() returns undefined; it does not prove the nested-process capability/incomplete-capability behavior exercised by the skipped integration.

Impact

A regression in nested Windows lock inheritance, membership creation, preload/home guard propagation, or incomplete-capability refusal can pass the main Windows suite silently. This is a test-coverage hole, not a claim that production service behavior is currently broken.

Required correction

Keep the outer batch step's no-queue behavior from #4876, but run the nested lock regression in a controlled child environment that explicitly supplies an acquired test lock and removes OCX_TEST_NO_QUEUE only for that fixture. The test should prove:

  1. the child inherits the same lock path, run id, and token;
  2. the child member receipt exists;
  3. preload and the live-home guard are armed;
  4. an incomplete inherited capability is refused; and
  5. the parent owner receipt is unchanged.

The corrected test must execute on hosted Windows CI and must not reintroduce queueing between the outer six-file batches.

Regression origin

Introduced by the interaction between #4851's fresh-process batching and #4876's step-wide no-queue environment. #4876 remains directionally correct; this issue tracks restoring the coverage it unintentionally disabled.

Activity

  1. added
    bugSomething isn't working
    platformOS/service/tray/ACL (Windows-heavy, not Windows-only)
    on Sep 18, 2026
  2. lidge-jun commented on Sep 18, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 72 / 80

    이 이슈는 Windows fresh-process 배치 스텝이 OCX_TEST_NO_QUEUE=1을 켜서 자기 배치끼리 줄 서지 않게 한 #4876과, nested live-lock 회귀가 그 env가 1이 아닐 때만 돌아가게 둔 #4851 계열 가드가 맞부딪혀 커버리지가 빠졌다는 보고서입니다. tip(e80e571f63, package 2.59.0)에서 확인했습니다.

    .github/workflows/ci.yml Windows “Test in fresh-process batches” 스텝은 주석대로 preload의 Windows user lock이 배치 N+1을 스트래글러 뒤에 세우지 않도록 OCX_TEST_NO_QUEUE: "1"을 넣습니다. 같은 tip의 tests/ci-workflows/test-runner.test.ts는 test.if(process.platform === "win32" && process.env[TEST_RUN_NO_QUEUE_ENV] !== "1")로 “nested Windows Bun tests inherit the acquired live lock and refuse an incomplete capability”를 가드합니다. 따라서 호스티드 Windows 배치 잡에서는 이 테스트가 항상 skip입니다. Linux/macOS 샤드는 win32 가드 때문에 대체 커버가 안 됩니다. 같은 파일의 no-queue 단위 테스트는 resolveWrappedTestRunLockPath()가 undefined인지만 보고, nested inherit·member receipt·preload/home guard·incomplete capability 거부는 증명하지 않습니다.

    요구되는 다섯 단언은 tip 테스트 본문에 이미 있습니다. child가 같은 lock path/run id/token을 상속하고, members 영수증이 생기고, preload·live-home guard가 켜지며, token을 뺀 incomplete env는 거부되고, parent owner.json은 변하지 않는 것입니다. 고침은 이 단언을 유지한 채 가드만 “바깥 NO_QUEUE=1이어도 child fixture는 lock을 명시 주입”으로 바꾸는 일입니다. 바깥 여섯 파일 배치가 다시 서로 줄 서게 만들면 #4876 회귀입니다.

    영향은 테스트 구멍이지, 지금 프로덕션 서비스가 깨졌다는 주장은 아닙니다. 다만 nested Windows lock inheritance·membership·guard 전파·incomplete refusal이 깨져도 메인 Windows 스위트가 조용히 초록일 수 있습니다. #4876 방향(배치 간 큐 제거)은 유지해야 하고, 고침은 바깥 스텝 no-queue는 남긴 채 픽스처 child에서만 획득된 lock을 주입하고 OCX_TEST_NO_QUEUE를 제거해 다섯 가지 단언을 다시 돌리는 형태가 맞습니다. types/config 스플릿과 무관합니다.

    점수는 높게 잡습니다. tip에서 상호 배타 조건이 코드로 확인되고, Windows-only라 다른 OS가 못 메꿉니다. 운영 장애 신고는 아니지만 CI 회귀 망원경 손실이라 우선순위가 있습니다.

    .github/workflows/ci.yml (Windows Test in fresh-process batches) - tip L864 근처 OCX_TEST_NO_QUEUE=1. #4876 의도 유지 대상.
    tests/ci-workflows/test-runner.test.ts (~L1038) - win32 && NO_QUEUE!==1 가드로 nested live-lock 회귀. 배치 스텝과 동시에 참이 될 수 없음.
    경로/심볼 TEST_RUN_NO_QUEUE_ENV / resolveWrappedTestRunLockPath - no-queue 단위 테스트는 path undefined만 증명.
    경로/심볼 #4851/#4876 - 배치화와 no-queue의 상호작용. #4876을 되돌리지 말 것.

    메인테이너의 판단이 필요한 지점

    • nested 회귀를 같은 파일의 조건부 child env로 살릴지, Windows 전용 작은 잡/스텝으로 분리할지.
    • skip을 명시적 test.todo/문서화로 남길지(비추천) 바로 픽스처 수정 PR을 받을지.

    너의 추천

    이슈 맞고 tip에서도 재현됩니다. 바깥 배치 no-queue는 유지한 채 nested 픽스처만 통제된 child env로 고치는 PR을 받으세요. 호스티드 Windows에서 실제로 실행되는 것까지 CI로 증명되게 하세요. 라벨은 바꾸지 마세요.

    이 댓글은 grok-bot이 작성했습니다

  3. added a commit that references this issue on Sep 19, 2026
    0429c0a
  4. lidge-jun commented on Sep 19, 2026

    @lidge-jun
    Owner

    Fixed on dev by #5078.

    The outer no-queue setting from #4876 is unchanged. Instead of restoring the lane's lock, the case now brings its own holder: a controller running as a plain bun <file> child under an isolated mkdtemp root, with the no-queue opt-out removed only from the environment copy handed to it. The outer environment, the real home, and any pre-existing owner are never touched, and the controller's cwd sits outside the repository so Bun loads no preload into the holder itself — which would otherwise take the same lock and then wait on itself.

    It resolves the user-scoped lock through resolveWrappedTestRunLockPath and takes it with acquireTestRunLock for its own run id, rather than writing an owner file by hand. The healthy nested child returns booleans only: path match, run match, token match, member receipt, preload executed, home guard armed, with OCX_TEST_PRELOAD_PID and OCX_TEST_HOME_GUARD stripped from every child environment so those two receipts have to come from the child's own preload. Three children are rejected before they execute — no token, a foreign token, a foreign lock path — each checked for a non-zero exit, the matching refusal on stderr, and the absence of a receipt on stdout. A fifth scenario plants a live foreign owner and proves the acquire path waits it out and gives up rather than reclaiming it, with an elapsed floor so an immediate refusal carrying the right message cannot pass.

    The completion bar for this issue was that the case be recorded as executed rather than skipped on a hosted Windows lane with no-queue actually set. On windows-latest shard 6/9 of run 35380618954 at head 499ca44f27:

    (pass) bun test user lock > a nested Windows Bun test inherits the live lock its controller
    holds and refuses an incomplete capability [4035.04ms]
    

    All nine Windows shards are green at that head, and no budget was widened — the controller is handed a deadline below the caller's spawnSync timeout and bounds each child by what is left of it.

    Two limits are recorded rather than hidden. On the no-queue lane the controller creates and ACL-hardens the real per-user lock directory, because that path is what resolveInheritedTestRunLock validates by host digest and basename; a relocated lock would be rejected by the very check under test. And reclaimStaleLock has a pre-existing check-then-rename race between two contenders; this change adds one contender on a lane that has no other, and closing that race means editing the lock implementation, which is outside this fix.

    No local suite was run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions