Move ParameterService onto the BuildContext (FT-4)#452
Draft
ChrisonSimtian wants to merge 3 commits into
Draft
Conversation
…ion leaks) BuildManager.Execute leaked process-global state across invocations, so a second build in the same process (tests, hosted/reentrant scenarios) inherited the first's residue: - Console.CancelKeyPress / ToolOptions.Created handlers were re-subscribed every call and never removed (accumulating); - the CancellationHandler list kept each run's Finish (capturing a stale build); - Logging.InMemorySink.Instance carried log events over; - ValueInjectionUtility's value cache and the NuGet/Npm tool-path resolver config persisted. Fix (non-breaking): the two global handlers are now held in locals and the finally undoes exactly what the run set — unsubscribes both, removes Finish from the cancellation list, and resets the carried-over state (InMemorySink.Clear, ValueInjectionUtility.ClearCache, NuGet/NpmToolPathResolver.Reset). Build creation moved ahead of the subscriptions so a failed `new T()` leaks nothing. Groundwork for the BuildContext foundation (FT-2). Full build + test suite green; reentrancy is verified by FT-9.
Adds BuildContext — an internal, per-run, AsyncLocal-ambient scope activated at the top of BuildManager.Execute (`using var context = BuildContext.Activate()`) and disposed at method exit. It owns the per-run global-state lifecycle: the Console.CancelKeyPress / ToolOptions.Created subscriptions, the cancellation-handler list, and the teardown FT-1 centralised (now run on dispose). BuildManager.CancellationHandler becomes a thin facade over BuildContext.Current — the first "static surface over the context" seam, and the rail subsequent steps ride (FT-4 ParameterService, FT-5 tool-path config, FT-6 logging scope move their state onto the context). Internal-only; not a public contract until the SDK (milestone #7). Disposing on method exit means a failed `new T()` also leaks nothing. Full build + test suite green.
The active ParameterService is now the per-run instance held on BuildContext.Parameters; the static ParameterService.Instance becomes a facade over BuildContext.Current. This is the first service to ride the FT-2 rail: production and tests now exercise the same instance form (killing the test/prod divergence — tests already `new ParameterService(funcs)`), and the per-run instance + its mutated fields (ArgumentsFromFilesService / ArgumentsFromCommitMessageService) no longer leak across runs. A lazy fallback (s_ambient) covers any access outside a build run (no cross-run concern there); it can retire once that path is confirmed dead. Non-breaking — the static API is unchanged. Full build + test suite green.
This was referenced Jun 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
⏳ Stacked on #451 → #450 (FT-2 → FT-1) — until those merge this diff includes their commits; I'll rebase onto
mainas they land so it narrows to just the FT-4 change. Draft until then.Engine de-statification ([Foundation] epic #315) — FT-4 / #309. The first service to ride the
BuildContextrail (FT-2).The active
ParameterServiceis now the per-run instance held onBuildContext.Parameters; the staticParameterService.Instancebecomes a facade overBuildContext.Current(with a lazy fallback for any access outside a run). Result:new ParameterService(funcs)) — the test/prod divergence is gone;ArgumentsFromFilesService/ArgumentsFromCommitMessageServicefields no longer leak across runs.Non-breaking — the static
ParameterServiceAPI is unchanged. Full build + test suite green.🤖 Generated with Claude Code