Skip to content

🤖 tests: reset the process-global workflow archive guard in WorkflowService context tests - #4530

Merged
ThomasK33 merged 1 commit into
mainfrom
test-audit/ws2-workflow-guard-isolation
Sep 25, 2026
Merged

ThomasK33 merged 1 commit into
mainfrom
test-audit/ws2-workflow-guard-isolation

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

Makes WorkflowService.context.test.ts independent of test order by resetting the process-global workflow archive admission guard before each test. Test-only.

Background

WorkspaceService's constructor installs a module-level guard with setWorkflowArchiveAdmissionGuard that calls this.config.loadConfigOrDefault(). Since #4475 split workspaceService.test.ts, the split files can land in the same bun unit shard as WorkflowService.context.test.ts. When one runs first with a partial config double, the leftover guard throws this.config.loadConfigOrDefault is not a function inside every workflow start/resume, and 9 context tests fail.

Reproduced on current main (7c133d0) with one process:

bun test ./src/node/services/workspaceService.archive.test.ts ./src/node/services/workspaceService.bashAndFiles.test.ts ./src/node/services/workflows/WorkflowService.context.test.ts

Main's own CI passes only because shard balancing currently keeps those files apart. The WS2 test-audit stack (#4483–#4487) removes test files, which reshuffles the shards, and its merge groups failed Test / Unit (4/6) on exactly these tests.

Implementation

beforeEach resets the guard to admit everything, the same reset WorkflowService.test.ts already uses. The underlying leak (every WorkspaceService instance overwrites a process-global guard and never unregisters it) belongs to the WorkspaceService owner and is reported to that workstream rather than redesigned here.

Validation

The reproduction command above: 9 failures before, 102 pass after. bun test src/node/services/workflows/ passes.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $4.45

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-25T10:16:01.260082Z 78d02a1 PR opened
🔒 Security Review ✅ Completed 2026-09-25T10:17:30.688007Z 78d02a1 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThomasK33
ThomasK33 added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 1bce83b Sep 25, 2026
30 of 31 checks passed
@ThomasK33
ThomasK33 deleted the test-audit/ws2-workflow-guard-isolation branch September 25, 2026 10:39
yermakoffivan pushed a commit to yermakoffivan/mux that referenced this pull request Sep 25, 2026
…sts (coder#4536)

## Summary

`evaluateScreening.test.ts` resets the process-global workflow archive
admission guard before each test, the same one-line fix coder#4530 applied to
`WorkflowService.context.test.ts`.

## Background

Every `WorkspaceService` constructor installs a process-global archive
admission guard bound to its own config. WorkspaceService suites built
on partial config doubles (`workspaceService.aiSettings`,
`workspaceService.bashAndFiles`, `terminalService`) leave that guard
behind; when CI's size-balanced shard split puts one of them before this
file, all 7 screening tests fail with `this.config.loadConfigOrDefault
is not a function`. This hit the WS7 stack's merge group and PR CI (Test
/ Unit 2/6) after an unrelated reshuffle.

## Validation

- `bun test src/node/services/workspaceService.aiSettings.test.ts
src/node/services/workflows/evaluateScreening.test.ts`: 7 fail before,
38 pass after.

Refs the test-audit campaign (WS7 landing blocker; the root cause,
partial WorkspaceService doubles installing a real global guard, belongs
to the WorkspaceService harness work).

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking:
`high` • Cost: `$13.67`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high
costs=13.67 -->
yermakoffivan pushed a commit to yermakoffivan/mux that referenced this pull request Sep 25, 2026
…ions instead of a process-global guard (coder#4562)

## Summary

Removes the process-wide workflow archive guard. Workflow
start/resume/retry admissions now ask the owning `WorkspaceService`
directly (`getWorkflowArchiveRefusal`), passed in through
`WorkflowServiceContext` and a required `WorkflowService` constructor
option. With nothing registered at module scope, a `WorkspaceService`
built in one test file can no longer decide admissions in another. The
three per-file guard resets, including coder#4530's, are deleted.

## Background

Every `WorkspaceService` constructor called
`setWorkflowArchiveAdmissionGuard(...)` with a closure over its own
config and never cleared it. After coder#4475 split the WorkspaceService
tests, a split file sharing a unit shard with
`WorkflowService.context.test.ts` left a guard over a partial config
double behind, and 9 context tests failed. coder#4530 reset the guard in that
one file; `evaluateScreening.test.ts` and `WorkflowService.test.ts`
carried the same reset. The leak itself stayed open.

A compare-and-clear release on dispose would not have closed it: about
170 test fixtures build a `WorkspaceService` without disposing it, so
the last guard would still outlive its file.

## Implementation

- `workflowArchiveAdmission.ts`:
  - `admissionGuard` and `setWorkflowArchiveAdmissionGuard` are gone.
- `acquireWorkflowArchiveAdmission(guard, workspaceId)` takes a
`WorkflowArchiveAdmissionGuard`.
- The in-process admission/runner counters stay process-wide:
WorkflowService instances are per-request, and the archive sink must see
admissions from any of them.
- `WorkspaceService`: the constructor closure became the public
`getWorkflowArchiveRefusal(workspaceId)`, with the same body. The class
declares `implements WorkflowArchiveAdmissionGuard`.
- `WorkflowService`: new required `archiveAdmission` option, so tsgo
finds every construction site. It is wired at all three production
sites:
  - `resolveWorkflowContext` passes `context.workspaceService`.
- `cli/workflow.ts` passes the CLI's own `services.workspaceService`,
which is the instance whose guard was installed before.
- Tool-started runs in `TurnRequestBuilder` get a new
`workflowArchiveAdmission` binding. It is set in `di/layers/core.ts`
next to the other WorkspaceService bindings, and the builder asserts it
when `taskService` is bound.
- The top-level
`startWorkflowRun`/`resumeWorkflowRun`/`retryWorkflowRunFromCheckpoint`
pass `context.workspaceService`.

Tests:
- The refusing-guard test in `WorkflowService.test.ts` injects its gate
instead of setting and resetting a global.
- New owner test: `WorkspaceService` refuses archived and archiving
workspaces, and admits active, unarchived and unknown ones. The logic
previously had no owner-side coverage.
- New wiring test: `startWorkflowRun` refuses through the context's
WorkspaceService before creating a run. Replacing both the top-level and
the class-level gate with an admit-all stub makes it fail.

## Validation

- The coder#4530 reproduction order passes with the resets removed: 131 pass.
The command was `bun test workspaceService.archive
workspaceService.bashAndFiles workflows/WorkflowService.context
workflows/evaluateScreening workflows/WorkflowService`.
- `bun test src/node/services/workflows`: 347 pass. `bun test
src/node/services/{workspaceService,taskService,turnRequestBuilder}*
src/node/services/serviceContainer.test.ts`: 1701 pass.
`src/node/services/{agentSession*,tools}` and `src/node/orpc` also pass.
- `src/cli` passes after `make build-main`. One run under host load 66
timed out "CLI run closes the AppFiberScope first…" at 5 s;
`workflow.test.ts` then passed 3 of 3 runs on its own.
- `make static-check` passes.

## Risks

Low. Admission semantics are unchanged in production, which has one
WorkspaceService per process; the refusal is now looked up explicitly
instead of through a module variable. A future `WorkflowService`
construction must supply the gate, and the type system enforces that.

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking:
`high`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
yermakoffivan pushed a commit to yermakoffivan/mux that referenced this pull request Sep 26, 2026
…aluation (coder#4642)

## Summary

`GeneralSection` computed `isBrowserMode` (no `window.api`) once, when
its module was evaluated. It now reads it where it is used. Same result
in the app (`window.api` never changes at runtime), but the answer no
longer depends on which environment first imported the module.

## Background

In one bun process, `SettingsPage.test.tsx` imports `GeneralSection`
before a DOM exists, which caches `isBrowserMode = false`. A later
`GeneralSection.test.tsx` then fails "loads the SSH host setting in
browser mode". Reproduced on current `main`:

```
bun test ./src/browser/features/Settings/SettingsPage.test.tsx ./src/browser/features/Settings/Sections/GeneralSection.test.tsx
```

CI passes today only because shard balancing keeps the two files in
different unit processes. The WS2 test-audit stack (coder#4632–coder#4634) changes
other test files, which reshuffles shard 4 so both land in one process,
and `Test / Unit (4/6)` fails there. This is the same latent-order class
as coder#4530.

## Validation

The pair above goes from 1 fail to 47 pass. Typecheck and the React
Compiler coverage check pass.

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking:
`high` • Cost: `$46.10`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high
costs=46.10 -->
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