Skip to content

refactor(di): remove process-global singletons to enable t.Parallel() [IDE-2036]#1319

Open
bastiandoetsch wants to merge 42 commits into
mainfrom
chore/IDE-2036
Open

refactor(di): remove process-global singletons to enable t.Parallel() [IDE-2036]#1319
bastiandoetsch wants to merge 42 commits into
mainfrom
chore/IDE-2036

Conversation

@bastiandoetsch

@bastiandoetsch bastiandoetsch commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

  • di.TestInit no longer writes package globalsbuildTestDependencies builds all services as local variables and returns a self-contained Dependencies struct, so concurrent TestInit calls are race-free.
  • Per-server progressStopChan — replaced the global 1000-capacity channel with a per-initHandlers channel (capacity 1, non-blocking send in shutdownHandler), eliminating cross-test stop-signal interference.
  • Installer added to di.Dependencies — test code uses deps.Installer rather than the global accessor.
  • All test files migrated from di.Xxx() to deps.*di.ScanStateAggregator(), di.HoverService(), di.Notifier(), di.AuthenticationService(), etc. replaced throughout application/server/.
  • t.Parallel() added to all smoke tests and their subtests — except Test_SmokeRealScanMonorepoFixture (uses pprof.StartCPUProfile, which is process-global). t.Setenv-after-t.Parallel() panics fixed with os.Setenv + t.Cleanup restore pattern throughout.
  • browser_noop_test.go guards in application/di, application/server, domain/ide/codelens, and infrastructure/oss — prevent real browser opens in test binaries after DefaultOpenBrowserFunc was moved out of TestInit.

Depends on: #1318 (IDE-2103 — fflags data race fix)

What's deferred (not in this PR)

  • progress.ToServerProgressChannel is still a shared global buffer (documented in cleanupChannels) — full isolation requires threading a per-server channel through NewTracker.
  • command.SetService writes a global singleton — documented in TestInit godoc. Tests exercising workspace/executeCommand must not be marked t.Parallel() until migrated to context injection.
  • The globals annotation sweep (CP 2.6a/2.6b) and remaining R-* removals (progress.Bus, cacheCheckCancel, globalExpandState, etc.) are deferred to follow-up PRs.

Test plan

  • make test — all unit tests pass
  • make lint — 0 issues
  • go test -race ./application/di/...TestTestInit_ReturnedDepsAreIndependent confirms independent instances
  • Smoke tests (SMOKE_TESTS=1) — t.Parallel() now added to all shards

PR Type

Enhancement, Bug fix


Description

  • Remove process-global singletons for testability.

  • Inject per-server dependencies for concurrency safety.

  • Integrate server-lifetime contexts for graceful shutdown.

  • Use per-server progress channels for isolation.


Diagram Walkthrough

flowchart LR
  A[Old: Process Globals] --> B(New: Per-Server Dependencies)
  B --> C{Enable t.Parallel()}
  B --> D{Scoped Contexts (ScanCtx)}
  B --> E{Per-Server Progress Tracker}
  F[Tests Pass]
Loading

File Walkthrough

Relevant files
Miscellaneous
28 files
config.go
Add nolint:gochecknoglobals to package variables                 
+7/-7     
expand_state.go
Add nolint:gochecknoglobals to globalExpandState                 
+1/-1     
git_persistence_provider.go
Add nolint:gochecknoglobals to ExpirationInSeconds             
+1/-1     
analytics.go
Add nolint:gochecknoglobals to analyticsMu                             
+1/-1     
environment.go
Add nolint:gochecknoglobals to environment variable constants
+9/-9     
code_html.go
Add nolint:gochecknoglobals to codeRenderer                           
+1/-1     
snyk_code_http_client.go
Add nolint:gochecknoglobals to issueSeverities                     
+1/-1     
formatter.go
Add nolint:gochecknoglobals to style constants                     
+5/-5     
featureflag.go
Add nolint:gochecknoglobals to Flags                                         
+1/-1     
errors.go
Add nolint:gochecknoglobals to ignorableIacErrorCodes       
+1/-1     
issue.go
Add nolint:gochecknoglobals to packageIssueCacheMutex       
+1/-1     
ostest_scan.go
Add nolint:gochecknoglobals to map constants                         
+3/-3     
url_parse_cache.go
Add nolint:gochecknoglobals to parsedURLStringCache           
+1/-1     
errors.go
Add nolint:gochecknoglobals to ignorableSecretsErrorCodes
+1/-1     
init.go
Add nolint:gochecknoglobals to initialized flag                   
+1/-1     
error_messages.go
Add nolint:gochecknoglobals to ErrorConfig and nonFailingScanErrors
+2/-2     
context.go
Add nolint:gochecknoglobals for context keys and remove Clone function
+8/-26   
fuzzy_matcher.go
Add nolint:gochecknoglobals to weights                                     
+1/-1     
features.go
Add nolint:gochecknoglobals to Flags                                         
+2/-2     
pm.go
Add nolint:gochecknoglobals to packageManagerSVGs               
+1/-1     
command.go
Add nolint:gochecknoglobals to DefaultOpenBrowserFunc       
+1/-1     
config_resolver.go
Add nolint:gochecknoglobals to map constants                         
+2/-2     
issues.go
Add nolint:gochecknoglobals to IssuesSeverity                       
+1/-1     
ldx_sync_adapter.go
Add nolint:gochecknoglobals to ldxSyncSettingKeyMap           
+1/-1     
uri_util.go
Add nolint:gochecknoglobals to global variables                   
+3/-3     
git_utils.go
Add nolint:gochecknoglobals to InvalidBranchNameRegex       
+1/-1     
directory_check_workflow.go
Add nolint:gochecknoglobals to WORKFLOWID_IDE_DIRECTORY_CHECK
+1/-1     
language_server_workflow.go
Add nolint:gochecknoglobals to WORKFLOWID_LS                         
+2/-2     
Tests
45 files
browser_noop_test.go
Add test-only init for browser no-op                                         
+27/-0   
init_test.go
Update tests for independent dependencies and parallel safety
+46/-4   
test_init.go
Refactor TestInit for race-free, independent dependency creation
+116/-44
authentication_flows_e2e_test.go
Use deps.CommandService and deps.ScanCtx in server setup 
+7/-4     
browser_noop_test.go
Add test-only init for browser no-op                                         
+28/-0   
configuration_oauth_endpoint_test.go
Use deps.Notifier instead of global di.Notifier                   
+2/-2     
configuration_test.go
Use local dependency instances instead of globals               
+12/-14 
env_once_helpers_test.go
Isolate API endpoint setting per-engine config                     
+84/-0   
env_race_test.go
Test parallel server setup without os.Setenv races             
+55/-0   
execute_command_test.go
Update tests to inject dependencies into context                 
+94/-33 
ldx_sync_smoke_test.go
Use per-test config isolation and deps for DI access         
+13/-12 
lsp_init_perf_test.go
Replace global FeatureFlagService with local instance       
+5/-7     
notification_test.go
Update tests to use per-test dependency instances               
+30/-26 
parallelization_test.go
Test concurrent CLI runs using real DI deps                           
+3/-4     
precedence_smoke_test.go
Add test config isolation and use DI deps                               
+91/-49 
progress_channel_test.go
Test per-server ProgressTracker isolation                               
+99/-0   
progress_tracker_test.go
Test ProgressTracker injection and cancel isolation           
+104/-0 
scan_context_command_test.go
Verify commands use server-lifetime scanCtx                           
+346/-0 
scan_context_test.go
Test scanCtx cancellation on server shutdown                         
+476/-0 
secrets_smoke_test.go
Update tests to use deps for DI access and ProgressTracker
+9/-6     
server_smoke_test.go
Update smoke tests to use WithRealDI and pass deps             
+129/-62
server_smoke_treeview_test.go
Use deps for DI access in treeview tests                                 
+7/-5     
server_test.go
Refactor setupServer to return DI dependencies and use WithAPIEndpoint
+89/-60 
trust_test.go
Update tests to use deps for DI accessors                               
+12/-13 
browser_noop_test.go
Add test-only init for browser no-op                                         
browser_noop_test.go
Add test-only init for browser no-op                                         
+27/-0   
codelens_test.go
Update tests to use deps for DI access and progress listeners
+12/-11 
code_fix_diffs_test.go
Update New call for Scanner to include progress channel   
+1/-1     
command_service_test.go
Update NewService call to pass context.Background()           
+2/-1     
folder_handler_test.go
Ensure HandleFolders forwards context to HandleUntrustedFolders
+42/-0   
scanner_test.go
Add tests for progress channel isolation and context propagation
+68/-0   
cli_test.go
Verify process-global semaphore sharing across executors 
+21/-0   
downloader_owner_test.go
Test NewDownloader routes progress to injected owner channel
+46/-0   
downloader_test.go
Update tests to use per-test progress tracker                       
+7/-18   
code_integration_test.go
Add test progress tracker channel to New call                       
+1/-0     
code_test.go
Update Scanner constructor calls with progress channel     
+26/-18 
code_tracker_test.go
Test progress channel isolation and task self-cancellation
+38/-4   
iac_test.go
Add test progress tracker channel to New calls                     
+43/-15 
browser_noop_test.go
Add test-only init for browser no-op                                         
+27/-0   
cli_scanner_test.go
Test NewCLIScanner routes progress to injected owner channel
+35/-0   
vulnerability_count_test.go
Update NewCLIScanner calls with progress tracker channel 
+2/-2     
context_test.go
Remove Clone function due to redundancy                                   
+0/-58   
owner_test.go
Test Tracker cancel and channel isolation                               
+205/-0 
progress_test.go
Update tests for progress channel isolation and new task type
+24/-4   
test_setup.go
Remove global progress channel cleanup and add per-test tracker
+19/-14 
Enhancement
17 files
init.go
Refactor DI to use local dependencies and per-server contexts
+178/-121
execute_command.go
Use context-injected CommandService instead of global       
+1/-2     
notification.go
Remove global progressStopChan and use per-server channel
+6/-22   
server.go
Refactor DI to use local dependencies and per-server contexts
+126/-56
clear_cache.go
Use server-lifetime scanCtx for background scans                 
+4/-1     
command_factory.go
Inject server-lifetime scanCtx into command factory           
+8/-4     
command_service.go
Inject server-lifetime scanCtx into CommandService             
+12/-3   
workspace_scan.go
Use server-lifetime scanCtx for background scan goroutines
+7/-5     
scanner.go
Inject progress channel into Scanner constructor                 
+5/-1     
cli.go
Share process-global semaphore for CLI concurrency             
+5/-3     
downloader.go
Refactor Downloader to accept per-server progress owner   
+58/-25 
code.go
Inject progress channel into Scanner constructor and use per-task
progress
+8/-8     
code_tracker.go
Refactor progress tracking to per-server owner and task   
+5/-4     
iac.go
Introduce progress channel to IAC scanner and add nolint 
+7/-5     
cli_scanner.go
Introduce progress channel to CLI scanner and add nolint 
+9/-7     
progress.go
Refactor progress tracking to per-server owner and task   
+20/-282
task.go
Introduce Task as the per-operation progress handle           
+279/-0 
Formatting
1 files
values.go
Fix linting error for reflect.Interface                                   
+1/-1     
Configuration changes
1 files
.golangci.yaml
Add gochecknoglobals linter configuration                               
+10/-0   
Dependencies
1 files
Makefile
Update golanci-lint version to v2.12.2                                     
+1/-1     
Documentation
1 files
architecture.md
Document progress channel replacement and context injection
+143/-0 
Additional files
7 files
update_folder_config.go +2/-2     
workspace_folder_scan.go +6/-2     
service.go +1/-1     
oss_integration_test.go +1/-1     
oss_test.go +25/-24 
types.go +2/-2     
tracker.go +136/-0 

@snyk-io

snyk-io Bot commented Jun 3, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@snyk-pr-review-bot

This comment has been minimized.

@bastiandoetsch bastiandoetsch force-pushed the chore/IDE-2103 branch 2 times, most recently from e936705 to 186a478 Compare June 3, 2026 15:11
Base automatically changed from chore/IDE-2103 to main June 3, 2026 15:46
@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (c9fa4cd)

@snyk-pr-review-bot

This comment has been minimized.

@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (c9fa4cd)

@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (4aadc51)

@snyk-pr-review-bot

This comment has been minimized.

@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (d2db8ed)

…el + complete scanCtx threading [IDE-2036]

Replaces the process-global progress.ToServerProgressChannel and global tracker
registry with a per-server progress.Tracker (owner: channel + token->Task registry,
Cancel/IsCanceled) and progress.Task (per-operation handle, implements ui.ProgressBar);
token cancellation resolves per-server via the context-injected Tracker. Migrates the
downloader and the GAF extension entrypoint off the global ctor and all scanner/test
callsites onto per-server (drained) Trackers. Threads the server-lifetime scanCtx into
HandleFolders (initialized) and the workspace/folder/clear-cache scan commands so every
background scan respects shutdown cancellation. Also: thread scanCtx into the didSave +
didChangeWorkspaceFolders handlers; share one process-global CLI concurrency semaphore
across executors; replace the order-dependent sync.Once SNYK_API env with a per-server
WithAPIEndpoint config option.
@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (d2db8ed)

@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

1 similar comment
@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (3e13561)

2 similar comments
@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (3e13561)

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (3e13561)

@snyk-pr-review-bot

This comment has been minimized.

# Conflicts:
#	application/server/configuration_test.go
@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (0df9634)

@snyk-pr-review-bot

This comment has been minimized.

…i 2.12.2 [IDE-2036]

- scan_context_test.go: build the didSave intercept path via filepath.Join and
  store interceptPath as uri.PathFromUri(uri.PathToUri(fakePath)) so it matches
  the handler's computed path on Windows (was a forward-slash literal + exact
  string match, failing integration/smoke on windows-latest).
- internal/util/values.go: reflect.Ptr -> reflect.Pointer (deprecated since Go 1.18).
- .golangci.yaml: targeted exclusion for the govet 'inline' analyzer false-positive
  on generic stdlib calls (slices.Contains/ContainsFunc) — "type parameter inference
  is not yet supported", no fix available; real inline findings stay enforced.
- Makefile: bump pinned golangci-lint v2.10.1 -> v2.12.2 so CI's make lint matches
  the analyzer set; make lint reports 0 issues whole-repo.
@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (44966cf)

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Reviewer Guide 🔍

🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Systemic Starvation Risk 🟠 [major]

The move to sharedSemaphore means the CLI concurrency limit is now enforced process-wide across all server instances. In the smoke test environment, where multiple servers run in parallel within the same process, this creates a bottleneck. A single slow scan in one test instance can now starve CLI slots for other parallel tests, leading to non-deterministic timeouts (as noted in the server_smoke_test.go added comment for shard-3). This violates the isolation goal of t.Parallel() by introducing a shared global resource dependency.

var sharedSemaphore = semaphore.NewWeighted(int64(concurrencyLimit)) //nolint:gochecknoglobals // process-global CLI concurrency limiter shared across all SnykCli executors
Inconsistent Shutdown Ordering 🟡 [minor]

In shutdownHandler, scanCancel() is called to terminate background scans, but mustNotifierFromContext(ctx).DisposeListener() is called immediately after. If a background scan goroutine is still cleaning up and attempts to send a terminal progress or notification via that listener, it may encounter a race or dropped notification. While scanCancel is idempotent, ensuring all background workers have exited before disposing the notification infrastructure would be safer for Windows file-handle release telemetry.

	scanCancel()
}
mustNotifierFromContext(ctx).DisposeListener()
📚 Repository Context Analyzed

This review considered 130 relevant code sections from 12 files (average relevance: 0.96)

@bastiandoetsch

Copy link
Copy Markdown
Contributor Author

/describe

@snyk-pr-review-bot

Copy link
Copy Markdown

PR Description updated to latest commit (44966cf)

@rrama rrama left a comment

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.

I haven't finished reviewing, but I am going to leave the comments I have so far. I haven't prioritised them or anything, but I'm sure you can use AI to figure out what you want to do or not.
Also, given the time I am leaving some of the AI comments without first checking them myself and some without me even reading them 🙈

Comment thread application/di/init.go
// Access them via di.Installer() / di.Initializer() until those global
// accessors are retired.
// Note: Initializer is intentionally absent — it is a process-lifecycle
// dependency used during startup only.

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.

Will it not be added in the future?

Comment thread application/di/init.go
// token→task registry [IDE-2036]. Each server instance has its own Tracker so
// progress events from one server cannot leak to another server's listener.
ProgressTracker *progress.Tracker
// ScanCtx is a server-lifetime context for workspace scan goroutines.

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.

I was planning to do this as part of #1173 after we merge this, can we close that PR and Jira ticket?

Comment thread application/di/init.go
// are safe to run concurrently without a data race.
func RealDependencies(engine workflow.Engine, tokenService types.TokenService) Dependencies {
owner := progress.NewTracker(engine.GetLogger())
deps, _, _ := buildDependencies(engine, tokenService, owner)

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.

Should this func move to a test util package and call t.Cleanup(treeEmitter.Dispose)? It does only seem to be one channel left open per tree emitter, so not the worst test-to-test leak.
Or return the treeEmitter and let the caller do it.

}

// Resolve the per-test progress tracker.
// Priority: overrideDeps.ProgressTracker > default fresh tracker.

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.

Nitpick: AI comment adding no value.

} else {
featureFlagService = featureflag.New(gafConfiguration, logger, engine, configResolver)
// Default: create a fresh per-test tracker. The process-global
// progress channel has been removed [IDE-2036].

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.

Nitpick: Not needed to be mentioned in the code.

t.Setenv("SNYK_LOG_LEVEL", "debug")
prevLogLevel := os.Getenv("SNYK_LOG_LEVEL")
os.Setenv("SNYK_LOG_LEVEL", "debug") //nolint:usetesting // t.Setenv panics after t.Parallel()
t.Cleanup(func() { _ = os.Setenv("SNYK_LOG_LEVEL", prevLogLevel) }) //nolint:usetesting // t.Setenv panics after t.Parallel()

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.

Why not just not make it t.Parallel() (since it isn't if you are messing with env vars) or stop using the env var...

Msg("Code scanner: files to be scanned")

t := progress.NewTracker(true, sc.engine.GetLogger())
t := progress.NewTaskWithChannel(sc.progressChannel, true, sc.engine.GetLogger())

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.

AI comment (unread by me):

Scanner progress Tasks created via NewTaskWithChannel are not registered with the per-server Tracker, breaking client-initiated cancel

All three product scanners (Code, OSS, IaC) and the code-client-go tracker factory create progress Tasks via NewTaskWithChannel() which sets owner: nil and does not register the task in any Tracker.tasks registry. When the IDE user clicks "Cancel" on a progress bar, windowWorkDoneProgressCancelHandler (application/server/server.go:1249) calls owner.Cancel(params.Token) which looks up the token in owner.tasks. Since scanner Tasks were never registered, the lookup fails silently and the cancel signal is never delivered to the task's cancelChannel.

Before this PR, progress.NewTracker(true, logger) registered every task in the global trackers map, and the old progress.Cancel(token) could find and cancel it. After this PR the global map was removed, but the replacement per-server registry is only populated by Tracker.New() — never by NewTaskWithChannel(). The same issue affects:

  • infrastructure/iac/iac.go:159
  • infrastructure/oss/cli_scanner.go:253
  • infrastructure/code/code_tracker.go:41 (code-client-go upload progress)

// Tracker. Use it when you already hold a channel reference (e.g. from
// Tracker.Channel()) and need a Task with a specific cancellable setting but
// no owner-managed registry entry.
func NewTaskWithChannel(channel chan types.ProgressParams, cancellable bool, logger *zerolog.Logger) *Task {

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.

AI says:

NewTaskWithChannel creates ownerless tasks where IsCanceled() is always false

Tasks created via NewTaskWithChannel (internal/progress/progress.go:53) have owner == nil, so Task.IsCanceled() (task.go:72-77) always returns false. This means cancellation via the owner registry is not possible for these tasks. However, every callsite that previously relied on t.IsCanceled() has been changed: code.go:289-290 now checks ctx.Err() != nil instead, and the scanners use CancelOrDone which listens on the cancel channel directly. So the behavioral change is intentional and correct — but it is a subtle semantic difference from the old code where all tasks were globally registered. Future callers of NewTaskWithChannel should be aware that IsCanceled() is a no-op for these tasks.

Probably worth updating this func's Go doc to call this out.


// decouple scheduled scan from session but keep context values
newCtx := ctx2.Clone(ctx, context.Background())
newCtx := context.WithoutCancel(ctx)

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.

AI comment:

OSS scheduleRefreshScan: newCtx.Err() check is always nil

At infrastructure/oss/cli_scanner.go:614, the code checks newCtx.Err() != nil where newCtx is created via context.WithoutCancel(ctx) at line 603. Since WithoutCancel produces a context that is never canceled, this check will always return nil. This is a pre-existing logic issue — the old ctx2.Clone(ctx, context.Background()) had the exact same behavior (background context is never canceled). The actual cancellation logic correctly uses the original ctx.Done() channel on line 627. The dead Err() check is harmless but misleading.

Not your code smell and doesn't really matter, so up to you if you do anything about it.

engine.SetUserInterface(user_interface.NewLsUserInterface(
user_interface.WithLogger(engine.GetLogger()),
user_interface.WithProgressBar(progress.NewTracker(true, engine.GetLogger()))))
user_interface.WithProgressBar(progress.NewTracker(engine.GetLogger()).New(true))))

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.

AI comment (unchecked by me):

ls_extension GAF UI progress bar also routes to orphaned channel

The same orphaned-channel pattern as the downloader bug exists at ls_extension/language_server_workflow.go:110. progress.NewTracker(engine.GetLogger()).New(true) creates a standalone Tracker whose channel is never read. The GAF framework calls UpdateProgress/SetTitle on the returned Task, which sends to this channel. In the old code, these events went to the global ToServerProgressChannel which the server's listener drained. This is less impactful than the installer path because (a) it only affects the GAF extension entry point and (b) the number of events is likely small (one progress bar for the initial flow). Still, it's worth wiring the per-server owner through to this call site as part of the planned migration documented in docs/requirements/architecture.md:147-148.

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.

3 participants