Skip to content

fix(FN-6035): align workflow dispatch and broad suite#1539

Merged
gsxdsm merged 2 commits into
mainfrom
feature/workflow-mapping
Jun 9, 2026
Merged

fix(FN-6035): align workflow dispatch and broad suite#1539
gsxdsm merged 2 commits into
mainfrom
feature/workflow-mapping

Conversation

@gsxdsm

@gsxdsm gsxdsm commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fix scheduler admission so default in-progress dispatch respects the global semaphore limit as well as project WIP capacity.
  • Update broad-suite test harnesses for Vitest 4 constructable mocks and file URL imports.
  • Refresh workflow cutover test expectations for the workflow-graph review handoff path.

Validation

  • pnpm test
  • pnpm --filter @fusion/engine test
  • pnpm --filter @fusion/engine test:core
  • pnpm typecheck
  • pnpm lint
  • pnpm build

Notes

The concurrency fix covers the case where rows are already in in-progress but executors have not acquired semaphore slots yet; scheduler now treats those rows as consuming global dispatch capacity before admitting more work.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed task scheduler concurrency calculation to properly enforce global semaphore limits when dispatching concurrent tasks, preventing exceeding available capacity.
  • Tests

    • Enhanced test reliability with improved mock cleanup and reset between test cases to prevent test interference.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b9010df1-5b0b-4b44-8057-cba9560f035d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/workflow-mapping

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gsxdsm
gsxdsm marked this pull request as ready for review June 9, 2026 05:59
@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR addresses a race condition in the scheduler's global semaphore accounting and modernizes the broad test suite for Vitest 4 compatibility. The concurrency fix ensures tasks already in in-progress but whose executors have not yet acquired a semaphore slot are counted against global dispatch capacity before new todo tasks are admitted.

  • Scheduler fix (scheduler.ts): semaphoreAvailable is now Math.min(availableCount, limit - agentSlots), capping available slots by both the semaphore's own acquired-count view and the number of currently in-progress rows — preventing over-admission when executors lag behind in slot acquisition.
  • Vitest 4 constructable mock migration: All vi.fn().mockImplementation(() => ({...})) arrow-function factories replaced with function() { return {...}; } across 28 test files, required for proper new-call semantics in Vitest 4.
  • Test expectation updates: interpreter-merge-seam corrected to assert onMerge receives a second {} options argument (matching production code); executor-task-done-invariant updated to workflow-graph-review reason for the graph review handoff path.

Confidence Score: 4/5

The scheduler change is a targeted, well-reasoned fix with a direct regression test; the remaining 29 files are test-only Vitest 4 compatibility updates.

The concurrency fix in scheduler.ts is logically sound: taking the minimum of the semaphore's own available-slot view and the remaining capacity computed from in-progress row count correctly prevents over-admission. The new test covers the precise race scenario described in the PR. The broad test migration is mechanical and low-risk. One assertion in heartbeat-monitor-per-agent-config.test.ts was weakened without explanation, which slightly reduces test fidelity on the warning-emit path.

packages/engine/src/tests/heartbeat-monitor-per-agent-config.test.ts (weakened warn-call assertion) and packages/engine/src/tests/executor-task-done-invariant.test.ts (reason string change to workflow-graph-review — the corresponding production-side change is not visible in this diff).

Important Files Changed

Filename Overview
packages/engine/src/scheduler.ts Core concurrency fix: semaphoreAvailable now takes the minimum of the semaphore's own available count and (limit - agentSlots), correctly accounting for in-progress tasks that haven't acquired semaphore slots yet.
packages/engine/src/tests/scheduler.test.ts New test validates the semaphore cap: 3 in-progress tasks with a limit-3 semaphore and no acquired slots correctly blocks further dispatch from todo.
packages/engine/src/tests/interpreter-merge-seam.test.ts Test corrected to assert onMerge is called with the second options argument ({}) matching the production implementation.
packages/engine/src/tests/executor-task-done-invariant.test.ts Handoff audit reason updated from fn_task_done to workflow-graph-review to match the new workflow-graph review path; no production source change visible in this diff.
packages/engine/src/tests/heartbeat-monitor-per-agent-config.test.ts Assertion relaxed from toHaveBeenCalledTimes(1) to toHaveBeenCalled(), which weakens the warning-count guard.
packages/engine/src/tests/project-engine.test.ts All constructor mocks converted to function() { return {...}; } form for Vitest 4 constructable mock compatibility.
packages/engine/src/tests/reliability-interactions/node-settings-sync-auth.test.ts Cross-package imports switched to file URL form (new URL(..., import.meta.url).href) for reliable ESM resolution in Vitest 4.
packages/engine/src/tests/reliability-interactions/branch-recovery-live-zero-commits.test.ts Added afterEach(() => vi.restoreAllMocks()) for proper spy teardown between tests.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["schedule() called"] --> B["agentSlots = inProgress.length"]
    B --> C{"Semaphore provided?"}
    C -- No --> D["semaphoreAvailable = Infinity"]
    C -- Yes --> E["availableCount = limit minus active"]
    E --> F["capacityByRows = limit minus agentSlots"]
    F --> G["semaphoreAvailable = min of both"]
    G --> H["available = min of maxConcurrent gap, worktree gap, semaphoreAvailable"]
    D --> H
    H --> I{"available <= 0?"}
    I -- Yes --> J["Return early - no dispatch"]
    I -- No --> K["Admit tasks from todo to in-progress"]
Loading

Reviews (1): Last reviewed commit: "fix(FN-6035): cap scheduler dispatch by ..." | Re-trigger Greptile

expect(config.pollIntervalMs).toBe(60_000);
expect(config.heartbeatTimeoutMs).toBe(30_000);
expect(warnSpy).toHaveBeenCalledTimes(1);
expect(warnSpy).toHaveBeenCalled();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 The assertion was relaxed from toHaveBeenCalledTimes(1) to toHaveBeenCalled(), which no longer guards against the warning being emitted multiple times. If a refactor introduces duplicate warn calls on the fallback path this test would still pass silently. The exact-count assertion was the tighter, more useful signal here unless there's a known reason it fires more than once in this scenario.

Suggested change
expect(warnSpy).toHaveBeenCalled();
expect(warnSpy).toHaveBeenCalledTimes(1);

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@gsxdsm
gsxdsm merged commit 9c43e3f into main Jun 9, 2026
6 checks passed
@gsxdsm
gsxdsm deleted the feature/workflow-mapping branch June 9, 2026 06:07
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