Skip to content

fix(FN-166): bypass coordination-only overlap leases#1172

Merged
gsxdsm merged 1 commit into
Runfusion:mainfrom
plarson:fix/fn166-scheduler-starvation
May 30, 2026
Merged

fix(FN-166): bypass coordination-only overlap leases#1172
gsxdsm merged 1 commit into
Runfusion:mainfrom
plarson:fix/fn166-scheduler-starvation

Conversation

@plarson
Copy link
Copy Markdown
Contributor

@plarson plarson commented May 30, 2026

Summary

  • Fix scheduler starvation where coordination/no-commit tasks with read-only bookkeeping scopes can be blocked indefinitely behind active implementation file-scope leases.
  • Keep implementation tasks with real source-code scope overlaps serialized behind active leases.
  • Add focused scheduler helper and live-schedule regression coverage for the FN-158/FN-118 pattern.

Verification

  • COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack pnpm --filter @fusion/engine exec vitest run src/__tests__/scheduler-overlap-starvation.test.ts src/__tests__/scheduler.test.ts src/__tests__/reliability-interactions/scheduler-overlap-priority-inversion.test.ts --reporter=dot
  • COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack pnpm --filter @fusion/engine typecheck
  • COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack pnpm lint
  • COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack pnpm build
  • COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack pnpm --filter @fusion/engine test -- --runInBand

Fusion-Task-Id: FN-166

Summary by CodeRabbit

  • Bug Fixes

    • Coordination-only / no-commit tasks can bypass active file-scope leases when overlaps are limited to safe read‑only paths, preventing unnecessary blocking and clearing stale overlap blockers.
  • Tests

    • Added regression and unit tests covering overlap, priority, and starvation scenarios to validate coordination-only dispatch behavior.
    • Broadened release-workflow test to accept multiple Linux AppImage naming conventions.
  • Chores

    • Patch release bump and release-note update for the scheduler overlap behavior change.

Review Change Stack

Copilot AI review requested due to automatic review settings May 30, 2026 12:51
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds detection for coordination-only/no-commit tasks and bypasses file-scope overlap leases for such tasks: new exported helper isCoordinationOnlyTask(), precomputation and dispatch-time changes to skip/register leases accordingly, clearing of stale overlapBlockedBy for coordination tasks, plus unit and regression tests and a changeset/release-note.

Changes

Coordination-only overlap bypass

Layer / File(s) Summary
Coordination-only classification helper
packages/engine/src/scheduler.ts, packages/engine/src/__tests__/scheduler.test.ts
New exported isCoordinationOnlyTask(task, scope) and supporting test imports; classifies tasks via explicit boolean flags/metadata and exercised by unit tests.
Overlap lease precomputation updates
packages/engine/src/scheduler.ts
Precomputation skips coordination-only tasks when building in-progress and in-review file-scope lease maps and when generating queued overlap candidates.
Queued overlap gating and bypass logic
packages/engine/src/scheduler.ts
Dispatch-time gating computes coordination-only and skips overlap-blocker logic for such tasks; if a coordination-only queued task still has overlapBlockedBy, it is cleared and a dedicated bypass log entry is written.
Record in-progress lease conditionally
packages/engine/src/scheduler.ts
When starting a task, the scheduler only registers its in-progress file-scope lease for overlap tracking if the task is not coordination-only and has a non-empty scope.
Unit and regression tests for helpers and overlap behavior
packages/engine/src/__tests__/scheduler.test.ts, packages/engine/src/__tests__/scheduler-overlap-starvation.test.ts, packages/engine/src/__tests__/reliability-interactions/scheduler-overlap-priority-inversion.test.ts
Adds unit tests for isCoordinationOnlyTask and queued-candidate eligibility, a regression test asserting coordination-backlog-audit tasks can bypass active implementation leases, and a priority-inversion test ensuring implementation-file overlaps still block via overlapBlockedBy.
Release notes and desktop test tweak
.changeset/fn-166-coordination-overlap-bypass.md, packages/desktop/src/__tests__/release-workflow.test.ts
Changeset documents the coordination-only bypass behavior and a desktop test now accepts both x64 and x86_64 AppImage filename variants.

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Runfusion/Fusion#1162: Both PRs modify scheduler overlap/queued dispatch logic and related tests; changes are directly related.

Poem

🐰 I hop through logs and leases fine,
Coordination tasks slip past the line,
Read-only paths get gentle breeze,
While writers wait for lease appease,
A tiny rabbit cheers the queue's design.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title directly and clearly describes the main change: implementing a bypass for coordination-only tasks in the scheduler overlap lease system, which is the core fix for FN-166.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/engine/src/scheduler.ts (1)

129-132: 💤 Low value

Glob pattern in exact-match set may be intentional but is potentially confusing.

The entry ".changeset/*.md" in COORDINATION_SAFE_SCOPE_EXACT will only match if a scope entry is literally the string ".changeset/*.md" (e.g., from a PROMPT.md scope declaration), not actual files like .changeset/fn-166.md. Since COORDINATION_SAFE_SCOPE_PREFIXES includes ".changeset/" which covers all changeset files, this works correctly.

If the intent is to match literal glob scope entries, consider adding a clarifying comment. Otherwise, this entry is redundant given the prefix coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine/src/scheduler.ts` around lines 129 - 132,
COORDINATION_SAFE_SCOPE_EXACT contains the string ".changeset/*.md" which only
matches a literal scope equal to that string and is redundant because
COORDINATION_SAFE_SCOPE_PREFIXES already includes ".changeset/"; either remove
the ".changeset/*.md" entry from COORDINATION_SAFE_SCOPE_EXACT or add a brief
clarifying comment next to COORDINATION_SAFE_SCOPE_EXACT explaining that the
entry is intentional only for literal-scope matches (and that prefix coverage is
handled by COORDINATION_SAFE_SCOPE_PREFIXES) so future readers understand the
difference; reference COORDINATION_SAFE_SCOPE_EXACT,
COORDINATION_SAFE_SCOPE_PREFIXES, and the ".changeset/*.md" entry when making
the change.
packages/engine/src/__tests__/scheduler.test.ts (2)

236-283: 💤 Low value

Consider adding edge case coverage for isCoordinationOnlyTask.

The test suite covers core scenarios well, but a few edge cases could strengthen coverage:

  • Empty scope array (should return false per upstream contract)
  • decisionOnly: true in sourceMetadata (alternative coordination signal per context snippet 1)
  • Tasks with only direct noCommitsExpected property vs only sourceMetadata
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine/src/__tests__/scheduler.test.ts` around lines 236 - 283, Add
unit tests for isCoordinationOnlyTask using createMockTask to cover missing edge
cases: (1) assert false when scope array is empty; (2) assert true when
sourceMetadata contains decisionOnly: true (treat as coordination signal); and
(3) add explicit comparisons for tasks that set noCommitsExpected directly vs
tasks that set sourceMetadata.noCommitsExpected to ensure both code paths behave
identically. Place these new it blocks alongside the existing
describe("isCoordinationOnlyTask") tests and use the same scope arrays and
helper to mirror current test patterns.

285-320: ⚡ Quick win

Consider testing empty/undefined activeScopes edge case.

The function explicitly handles !activeScopes || activeScopes.size === 0 by returning true (per context snippet 2), but this branch is not explicitly covered. Adding a test case would document this behavior and prevent regression.

Suggested test case
+  it("accepts queued overlap candidates when no active scopes exist", () => {
+    const candidate = createMockTask({ id: "FN-050", status: "queued" });
+    
+    expect(isRunnableQueuedOverlapCandidate(candidate, [candidate], now, undefined, ["src/app.ts"])).toBe(true);
+    expect(isRunnableQueuedOverlapCandidate(candidate, [candidate], now, new Map(), ["src/app.ts"])).toBe(true);
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine/src/__tests__/scheduler.test.ts` around lines 285 - 320, Add
a test to cover the empty/undefined activeScopes edge case for
isRunnableQueuedOverlapCandidate: create a queued runnable task (e.g., via
createMockTask with status "queued") and assert that
isRunnableQueuedOverlapCandidate(runnable, [runnable], now, undefined,
someFileList) returns true, and also assert the same when passing an empty Map
(new Map()) as activeScopes; place these assertions alongside the existing
"rejects queued overlap candidates blocked by active file-scope leases" tests so
the branch where !activeScopes || activeScopes.size === 0 is explicitly
exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/engine/src/__tests__/scheduler-overlap-starvation.test.ts`:
- Around line 206-232: The test setup doesn't trigger the coordination-only
bypass because FN-158 has no overlapBlockedBy and the store scopes don't
actually overlap with FN-118; update the test so overlap is detected or pre-seed
the blocked field: either (A) change the scope entries passed to createStore so
FN-118's scope includes a path that will overlap with one of FN-158's entries
(for example make FN-118 include a `.changeset/*` or the
`.fusion/tasks/FN-158/...` pattern) so pathsOverlap between the active lease in
Scheduler and FN-158 is true, or (B) set FN-158's initial task object (via
makeTask) to include overlapBlockedBy: "FN-118" to exercise the
coordination-only clearing branch in Scheduler when you mark (scheduler as
any).running = true and call scheduler.schedule(); ensure references to
makeTask, createStore and Scheduler are updated accordingly.

---

Nitpick comments:
In `@packages/engine/src/__tests__/scheduler.test.ts`:
- Around line 236-283: Add unit tests for isCoordinationOnlyTask using
createMockTask to cover missing edge cases: (1) assert false when scope array is
empty; (2) assert true when sourceMetadata contains decisionOnly: true (treat as
coordination signal); and (3) add explicit comparisons for tasks that set
noCommitsExpected directly vs tasks that set sourceMetadata.noCommitsExpected to
ensure both code paths behave identically. Place these new it blocks alongside
the existing describe("isCoordinationOnlyTask") tests and use the same scope
arrays and helper to mirror current test patterns.
- Around line 285-320: Add a test to cover the empty/undefined activeScopes edge
case for isRunnableQueuedOverlapCandidate: create a queued runnable task (e.g.,
via createMockTask with status "queued") and assert that
isRunnableQueuedOverlapCandidate(runnable, [runnable], now, undefined,
someFileList) returns true, and also assert the same when passing an empty Map
(new Map()) as activeScopes; place these assertions alongside the existing
"rejects queued overlap candidates blocked by active file-scope leases" tests so
the branch where !activeScopes || activeScopes.size === 0 is explicitly
exercised.

In `@packages/engine/src/scheduler.ts`:
- Around line 129-132: COORDINATION_SAFE_SCOPE_EXACT contains the string
".changeset/*.md" which only matches a literal scope equal to that string and is
redundant because COORDINATION_SAFE_SCOPE_PREFIXES already includes
".changeset/"; either remove the ".changeset/*.md" entry from
COORDINATION_SAFE_SCOPE_EXACT or add a brief clarifying comment next to
COORDINATION_SAFE_SCOPE_EXACT explaining that the entry is intentional only for
literal-scope matches (and that prefix coverage is handled by
COORDINATION_SAFE_SCOPE_PREFIXES) so future readers understand the difference;
reference COORDINATION_SAFE_SCOPE_EXACT, COORDINATION_SAFE_SCOPE_PREFIXES, and
the ".changeset/*.md" entry when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f28a7c81-89e4-4143-81d1-00a7bb55d3be

📥 Commits

Reviewing files that changed from the base of the PR and between b5178fd and b7c7ab6.

📒 Files selected for processing (5)
  • .changeset/fn-166-coordination-overlap-bypass.md
  • packages/engine/src/__tests__/reliability-interactions/scheduler-overlap-priority-inversion.test.ts
  • packages/engine/src/__tests__/scheduler-overlap-starvation.test.ts
  • packages/engine/src/__tests__/scheduler.test.ts
  • packages/engine/src/scheduler.ts

Comment thread packages/engine/src/__tests__/scheduler-overlap-starvation.test.ts
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 30, 2026

Greptile Summary

This PR fixes a scheduler starvation bug (FN-166) where coordination/no-commit tasks (e.g. backlog audits, doc-only tasks) could be indefinitely blocked behind active implementation file-scope leases, even when their scopes only touch safe read-only paths like docs/, .changeset/, or .fusion/tasks/.

  • Introduces isCoordinationOnlyTask which requires an explicit noCommitsExpected: true or sourceMetadata.decisionOnly: true signal combined with a fully coordination-safe scope; without an explicit signal, tasks are never inferred as coordination-only, closing the regression noted in a prior review of over-broad prefix heuristics.
  • Coordination-only tasks are excluded from active scope lease registration and from the overlap-check block; stale overlapBlockedBy values on such tasks are cleared and logged at dispatch time.
  • Adds focused unit tests for isCoordinationOnlyTask and isRunnableQueuedOverlapCandidate, plus a live-schedule regression test for the FN-158/FN-118 starvation pattern.

Confidence Score: 5/5

Safe to merge. The bypass is gated on an explicit opt-in flag and a scope allow-list, so it cannot fire on tasks that haven't declared themselves coordination-only.

The coordination bypass requires both an explicit noCommitsExpected: true (or equivalent sourceMetadata signal) AND a scope composed entirely of safe prefixes. Neither condition alone is sufficient. The change is well-covered by unit tests and a live-schedule regression test, the previous over-broad tests/ prefix heuristic was removed before this PR landed, and the post-dispatch lease path is also patched consistently.

No files require special attention. packages/engine/src/scheduler.ts is the critical path but all changed call sites are consistent with each other.

Important Files Changed

Filename Overview
packages/engine/src/scheduler.ts Core fix: adds isCoordinationOnlyTask, skips scope lease registration and overlap checks for qualifying tasks, clears stale overlapBlockedBy at dispatch. Logic is sound and gated on an explicit opt-in flag.
packages/engine/src/tests/scheduler-overlap-starvation.test.ts Adds FN-158/FN-118 regression test; the scopes do share .fusion/tasks/FN-158/task.json which ensures the bypass path is exercised for the shared-path case. Coverage is adequate for the intended regression.
packages/engine/src/tests/scheduler.test.ts Comprehensive unit tests for both isCoordinationOnlyTask and isRunnableQueuedOverlapCandidate, covering explicit signals, empty scopes, mixed scopes, and the sourceMetadata fallback chain.
packages/engine/src/tests/reliability-interactions/scheduler-overlap-priority-inversion.test.ts New test verifies that an implementation task sharing a source file with an in-progress task is still correctly blocked via overlapBlockedBy, confirming the bypass does not weaken implementation serialization.
packages/desktop/src/tests/release-workflow.test.ts Broadens AppImage filename assertion to accept both x64 and x86_64 naming conventions; straightforward compatibility fix.
.changeset/fn-166-coordination-overlap-bypass.md Patch-level changeset entry describing the coordination bypass fix; accurate and complete.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Schedule pass: build activeScopes] --> B{groupOverlappingFiles?}
    B -- No --> Z[Skip overlap logic]
    B -- Yes --> C[For each in-progress / in-review task]
    C --> D{isCoordinationOnlyTask?}
    D -- Yes --> E[Skip: no scope lease registered]
    D -- No --> F[setActiveScopeLease]
    F --> G[Build queuedHigherPriorityScopes from todo tasks]
    G --> H{isCoordinationOnlyTask todo?}
    H -- Yes --> I[Skip: not added to queued scopes]
    H -- No --> J[Add to queuedHigherPriorityScopes if runnable]
    J --> K[Process each todo task for dispatch]
    I --> K
    K --> L{taskScope.length > 0 AND NOT coordinationOnly?}
    L -- Yes --> M[Run overlap check against activeScopes]
    M --> N{Overlap found?}
    N -- Yes --> O[Set overlapBlockedBy, continue]
    N -- No --> P[Clear stale overlapBlockedBy if present]
    P --> Q[Check concurrency → dispatch]
    L -- No --> R{coordinationOnly AND overlapBlockedBy set?}
    R -- Yes --> S[Clear overlapBlockedBy, log bypass]
    S --> Q
    R -- No --> Q
    Q --> T{Dispatched?}
    T -- Yes --> U{isCoordinationOnlyTask?}
    U -- Yes --> V[Do NOT register post-dispatch scope lease]
    U -- No --> W[setActiveScopeLease in-progress]
Loading

Reviews (5): Last reviewed commit: "fix(FN-166): bypass coordination-only ov..." | Re-trigger Greptile

Comment thread packages/engine/src/scheduler.ts
Comment thread packages/engine/src/scheduler.ts
Comment thread packages/engine/src/__tests__/scheduler-overlap-starvation.test.ts
@plarson plarson force-pushed the fix/fn166-scheduler-starvation branch 3 times, most recently from fc70545 to 60a724b Compare May 30, 2026 13:16
Comment thread packages/engine/src/scheduler.ts
@plarson plarson force-pushed the fix/fn166-scheduler-starvation branch from 60a724b to eb8ad24 Compare May 30, 2026 13:30
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/engine/src/scheduler.ts`:
- Around line 135-143: isCoordinationOnlyTask currently ignores the scope and
returns true based solely on metadata, allowing tasks with real implementation
files to bypass overlap leases; change the function to use the scope parameter
(rename _scope to scope) and only return true when the explicitNoCommitSignal is
true AND the scope is verified coordination-safe—e.g., call or add a helper like
isScopeCoordinationSafe(scope) (or iterate scope entries and ensure none are
implementation/source files) before allowing the bypass so metadata alone cannot
override unsafe scopes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21ea07d9-b090-49ff-b873-8e85ef902b28

📥 Commits

Reviewing files that changed from the base of the PR and between 60a724b and eb8ad24.

📒 Files selected for processing (6)
  • .changeset/fn-166-coordination-overlap-bypass.md
  • packages/desktop/src/__tests__/release-workflow.test.ts
  • packages/engine/src/__tests__/reliability-interactions/scheduler-overlap-priority-inversion.test.ts
  • packages/engine/src/__tests__/scheduler-overlap-starvation.test.ts
  • packages/engine/src/__tests__/scheduler.test.ts
  • packages/engine/src/scheduler.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/desktop/src/tests/release-workflow.test.ts
  • .changeset/fn-166-coordination-overlap-bypass.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/engine/src/tests/scheduler-overlap-starvation.test.ts
  • packages/engine/src/tests/reliability-interactions/scheduler-overlap-priority-inversion.test.ts

Comment thread packages/engine/src/scheduler.ts Outdated
@plarson plarson force-pushed the fix/fn166-scheduler-starvation branch from eb8ad24 to f8bda56 Compare May 30, 2026 13:47
@gsxdsm gsxdsm merged commit 7cd4f3a into Runfusion:main May 30, 2026
8 checks passed
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