Introduce the per-run BuildContext foundation (FT-2)#451
Open
ChrisonSimtian wants to merge 2 commits into
Open
Introduce the per-run BuildContext foundation (FT-2)#451ChrisonSimtian wants to merge 2 commits into
ChrisonSimtian wants to merge 2 commits into
Conversation
This was referenced Jun 30, 2026
Collaborator
Author
|
@dennisdoomen this one here, start of the de-static work |
ChrisonSimtian
commented
Jul 4, 2026
9884d44 to
1783254
Compare
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.
Exercises the FT-2 ambient scope: Current lifecycle (null → activate → dispose), the identity guard that keeps a superseded context from clobbering a newer Current, the cancellation-handler facade no-op outside a run, and that Dispose runs the per-run teardown. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1783254 to
646d233
Compare
3 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
Introduces an internal, per-run BuildContext ambient scope (via AsyncLocal) to own and centralize build-run global-state subscriptions and teardown, forming the foundation for the broader engine de-statification effort (FT-2 / #307).
Changes:
- Add
BuildContextas an internal per-run scope that installs itself as ambientCurrentand performs teardown on dispose. - Activate
BuildContextat the start ofBuildManager.Execute, moving cancellation handler ownership and FT-1 cleanup responsibility into the context. - Add
BuildContextSpecsvalidatingCurrentlifecycle, facade no-op behavior, and teardown execution.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tests/Fallout.Build.Specs/BuildContextSpecs.cs | Adds specs for BuildContext lifecycle and teardown behavior. |
| src/Fallout.Build/Execution/BuildManager.cs | Activates the per-run context and turns CancellationHandler into a context-backed facade. |
| src/Fallout.Build/Execution/BuildContext.cs | Implements the new per-run ambient context and centralizes teardown previously in FT-1. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+48
to
+61
| public void Dispose() | ||
| { | ||
| // Undo this run's process-global state (the FT-1 cleanup, now owned by the scope). | ||
| Console.CancelKeyPress -= onCancelKeyPress; | ||
| ToolOptions.Created -= onToolOptionsCreated; | ||
| Logging.InMemorySink.Instance.Clear(); | ||
| ValueInjectionUtility.ClearCache(); | ||
| NuGetToolPathResolver.Reset(); | ||
| NpmToolPathResolver.Reset(); | ||
|
|
||
| if (ReferenceEquals(current.Value, this)) | ||
| current.Value = null; | ||
| } | ||
| } |
Comment on lines
+14
to
+16
| /// The static surface (e.g. <see cref="BuildManager.CancellationHandler"/>) reads through | ||
| /// <see cref="Current"/>; <c>AsyncLocal</c> keeps concurrent runs on separate flows isolated. | ||
| /// </summary> |
Comment on lines
+11
to
+14
| /// Covers <see cref="BuildContext"/> (FT-2 / #307) — the per-run ambient scope that owns the | ||
| /// process-global state a build touches. <see cref="BuildContext.Current"/> is <c>AsyncLocal</c>, so | ||
| /// these cases stay isolated from any build running on another flow. | ||
| /// </summary> |
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.
Engine de-statification ([Foundation] epic #315) — FT-2 / #307. The foundation the rest of the de-static work rides. Rebased onto
mainnow that FT-1 (#450) has landed, so the diff is just the FT-2 change.Adds
BuildContext— an internal, per-run,AsyncLocal-ambient scope:BuildManager.Execute(using var context = BuildContext.Activate()), disposed at method exit;Console.CancelKeyPress/ToolOptions.Createdsubscriptions, the cancellation-handler list (moved offBuildManager), and the FT-1 teardown (now run on dispose);BuildManager.CancellationHandlerbecomes a thin facade overBuildContext.Current— the first "static surface over the context" seam.Because the handler list is now owned by the context and discarded wholesale on dispose,
BuildExecutor'sExecuteAssuredTargetssubscription — which was never explicitly unsubscribed — no longer persists across in-process invocations. FT-2 tightens that leak in passing.Subsequent steps move the per-run services onto the context: FT-4
ParameterService, FT-5 tool-path config, FT-6 logging scope. Internal-only — not a public contract until the SDK (milestone #7). Disposing on method exit means a failednew T()also leaks nothing.Tests —
BuildContextSpecscovers the new surface:Currentlifecycle, the identity guard that stops a superseded context from clobbering a newerCurrent, the facade no-op outside a run, and that dispose runs the per-run teardown. Full build + test suite green.🤖 Generated with Claude Code