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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog target/vCurrent Targets the current version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants