Skip to content

[Testing][Backend] ArtefactExtractionGateTests saturation entry latch is thread-pool-injection sensitive on windows-latest #2993

Description

@Chris0Jeky

Observed

Taskdeck.Application.Tests.Services.ArtefactExtractionGateTests.Saturated_RejectsExcess_NeverQueues_AndNeverExceedsCap failed once on Backend Unit / Backend Unit (windows-latest) for the documentation-only PR #2947 at head 5eb4d7b9561f1d528524eb6827c778b50634b16f (run 34624770817, job 103347294234, 2026-09-11T16:58Z). The Ubuntu leg and every other Application test passed (4342/4343). The diff touches only docs/STATUS.md and docs/releases/V0_3_0_READINESS.md, so the change cannot have caused it.

The failing assertion is the entry latch at backend/tests/Taskdeck.Application.Tests/Services/ArtefactExtractionGateTests.cs:128:

allEntered.Wait(TimeSpan.FromSeconds(10)).Should().BeTrue("exactly the cap should enter the extractor");

Why it is timing-sensitive

The test submits 8 ExtractAsync calls and expects exactly cap = 2 workers to enter a LatchedCountingExtractor that blocks synchronously on a ManualResetEventSlim. Entry depends on the thread pool scheduling the two admitted continuations within 10 s while the other 6 submissions are also being processed. On a starved hosted Windows runner (thread-pool injection is roughly one thread per 500 ms once the minimum is exhausted, and the admitted workers block pool threads), the latch can miss the 10 s window without any product defect. The assertion is a liveness bound on the test harness, not on the gate.

Acceptance

  • Make the entry wait independent of thread-pool injection rate: for example, make LatchedCountingExtractor await an async signal (TaskCompletionSource) instead of blocking a pool thread, or raise ThreadPool.SetMinThreads for the test, or widen the entry budget with a rationale comment.
  • Keep the assertions that matter (max concurrency equals the cap, no queueing, every permit returned).
  • Do not weaken the gate semantics under test.

Disposition

Non-blocking for #2947 (docs-only). The failed job is being re-run once as the single permitted re-measure; the outcome will be recorded on the PR thread. Filed under global law 2c as a tracked finding rather than a fix-commit on an unrelated PR.

Activity

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

    Priority IVLater maturity/deepening; revisited at horizon planning.backendPrimary implementation impact in .NET API/domain/application/infrastructure.tech-debtDebt cleanup or deferred engineering quality work with limited product-surface change.testingTest coverage, harnesses, regression prevention, and verification pipeline work.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions