Skip to content

Introduce the per-run BuildContext foundation (FT-2)#451

Open
ChrisonSimtian wants to merge 2 commits into
Fallout-build:mainfrom
ChrisonSimtian:engine/ft2-build-context
Open

Introduce the per-run BuildContext foundation (FT-2)#451
ChrisonSimtian wants to merge 2 commits into
Fallout-build:mainfrom
ChrisonSimtian:engine/ft2-build-context

Conversation

@ChrisonSimtian

@ChrisonSimtian ChrisonSimtian commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Engine de-statification ([Foundation] epic #315) — FT-2 / #307. The foundation the rest of the de-static work rides. Rebased onto main now that FT-1 (#450) has landed, so the diff is just the FT-2 change.

Adds BuildContext — an internal, per-run, AsyncLocal-ambient scope:

  • activated at the top of BuildManager.Execute (using var context = BuildContext.Activate()), disposed at method exit;
  • owns the per-run global-state lifecycle — the Console.CancelKeyPress / ToolOptions.Created subscriptions, the cancellation-handler list (moved off BuildManager), and the FT-1 teardown (now run on dispose);
  • BuildManager.CancellationHandler becomes a thin facade over BuildContext.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's ExecuteAssuredTargets subscription — 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 failed new T() also leaks nothing.

TestsBuildContextSpecs covers the new surface: Current lifecycle, the identity guard that stops a superseded context from clobbering a newer Current, the facade no-op outside a run, and that dispose runs the per-run teardown. Full build + test suite green.

🤖 Generated with Claude Code

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator Author

@dennisdoomen this one here, start of the de-static work

@ChrisonSimtian
ChrisonSimtian marked this pull request as ready for review July 4, 2026 22:39
@ChrisonSimtian
ChrisonSimtian requested a review from a team as a code owner July 4, 2026 22:39
Comment thread src/Fallout.Build/Execution/BuildContext.cs Outdated
@ChrisonSimtian ChrisonSimtian self-assigned this Jul 4, 2026
@ChrisonSimtian
ChrisonSimtian force-pushed the engine/ft2-build-context branch from 9884d44 to 1783254 Compare July 12, 2026 09:43
ChrisonSimtian and others added 2 commits July 12, 2026 21:50
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>

Copilot AI 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.

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 BuildContext as an internal per-run scope that installs itself as ambient Current and performs teardown on dispose.
  • Activate BuildContext at the start of BuildManager.Execute, moving cancellation handler ownership and FT-1 cleanup responsibility into the context.
  • Add BuildContextSpecs validating Current lifecycle, 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>
@ChrisonSimtian ChrisonSimtian added target/vNext Targets the next calendar-version and removed target/vCurrent Targets the current version labels Jul 18, 2026

@dennisdoomen dennisdoomen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nothing to add to the points Copilot already found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog target/vNext Targets the next calendar-version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants