Utilities/New-SignalPointerFork.ps1

function New-SignalPointerFork {
    <#
    .SYNOPSIS
    Creates a Signal with an independent pointer Graph and optionally reuses
    the source Graph's registered Signal instances.

    .DESCRIPTION
    This is a shallow fork. The returned Signal and Graph are new containers,
    but copied Grid members remain the same Signal references. Replacing Grid
    registrations is therefore isolated while mutating a reused Signal is not.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [Signal]$SourceSignal,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$Name,

        [object]$ReversePointer,

        [Graph]$TargetGraph,

        [ValidateSet('PreserveTarget', 'OverwriteTarget', 'Error')]
        [string]$CollisionAction = 'PreserveTarget',

        [string[]]$ExcludeKeys = @(),

        [switch]$CopyJacket,

        [switch]$CopyResult
    )

    $opSignal = [Signal]::Start("New-SignalPointerFork:$Name", $ReversePointer) | Select-Object -Last 1

    try {
        # Read source properties directly so a Signal received from another
        # in-process runspace can be forked without invoking its session-bound
        # PowerShell class methods.
        $sourceGraph = $SourceSignal.Pointer
        if ($sourceGraph -isnot [Graph]) {
            $null = $opSignal.LogCritical("Source signal '$($SourceSignal.Name)' does not have a Graph pointer.")
            return $opSignal
        }

        if ($null -eq $TargetGraph) {
            $graphSignal = [Graph]::Start("Graph:$Name", $opSignal, $false) | Select-Object -Last 1
            if ($opSignal.MergeSignalAndVerifyFailure(@($graphSignal)) -or -not $graphSignal.HasResult()) {
                return $opSignal
            }

            $TargetGraph = $graphSignal.GetResult()
        }

        foreach ($key in @($sourceGraph.Grid.Keys)) {
            if ($ExcludeKeys -contains [string]$key) {
                continue
            }

            if ($TargetGraph.Grid.Contains($key)) {
                switch ($CollisionAction) {
                    'PreserveTarget' { continue }
                    'Error' {
                        $null = $opSignal.LogCritical("Target graph already contains '$key'.")
                        return $opSignal
                    }
                }
            }

            $registerSignal = $TargetGraph.RegisterSignal([string]$key, $sourceGraph.Grid[$key]) | Select-Object -Last 1
            if ($opSignal.MergeSignalAndVerifyFailure(@($registerSignal))) {
                return $opSignal
            }
        }

        $forkedSignal = [Signal]::Start($Name, $ReversePointer) | Select-Object -Last 1
        $null = $forkedSignal.SetPointer($TargetGraph)

        if ($CopyJacket -and $null -ne $SourceSignal.Jacket) {
            $null = $forkedSignal.SetJacket($SourceSignal.Jacket)
        }

        if ($CopyResult -and $null -ne $SourceSignal.Result) {
            $forkedSignal.SetResult($SourceSignal.Result)
        }

        $opSignal.SetResult($forkedSignal)
    }
    catch {
        $null = $opSignal.LogCritical("Failed to fork signal pointer: $($_.Exception.Message)", $null, $_)
    }

    return $opSignal
}