package layoutgraph

import (
	
	
	
	
	
	

	

	
	
)

type GraphState struct {
	// nodeGeometry is also the transaction's deduplicated node set.
	nodeGeometry     map[*Node]graphGeometrySnapshot
	originalNodes    []*Node
	originalNodesRef []*Node
	hasFixedTopLeft  bool

	clusterArrangements map[*Cluster]ClusterArrangement
	clusterDesired      map[*Cluster]ClusterArrangement
	clusterPaddings     map[*Cluster]float64
	edgeGeometry        map[*Edge]edgeSnapshot
	treeOrientations    map[*Tree]geo.Orientation

	// We don't want to be frozen due to some existing overlap, since many can be valid diagrams
	// We just care about not introducing new overlaps
	existingOverlaps      map[*Node]map[*Node]struct{}
	existingExactOverlaps map[*Node]map[*Node]struct{}
	captureTopology       bool
	captureEdgeRoutes     bool

	graph          graphSnapshot
	nodes          map[*Node]nodeSnapshot
	edges          map[*Edge]edgeSnapshot
	clusters       map[*Cluster]clusterSnapshot
	sequences      map[*Sequence]sequenceSnapshot
	trees          map[*Tree]treeSnapshot
	edgeAbductions map[*EdgeAbduction]EdgeAbduction
	herds          map[*HerdAssignment]herdSnapshot
	hierarchies    map[*Hierarchy]hierarchySnapshot
}

// graphGeometrySnapshot keeps geometry in one value for speculative commit
// checks and preserves the original position pointer for rollback.
type graphGeometrySnapshot struct {
	topLeft pointerSnapshot[geo.Point]
	width   float64
	height  float64
}

type transactionPendingDescendant struct {
	node *Node
	emit bool
}

type Transaction struct {
	Ops     []func() error
	Graph   *Graph
	options TransactionOptions
	guard   *limits.WorkGuard

	PriorGraphState *GraphState
	spareGraphState *GraphState
	// placementCostSnapshot is optional stage-owned rollback data. Ordinary
	// speculative Rollback deliberately ignores it.
	placementCostSnapshot *PlacementCostSnapshot

	// Geometry-only transactions usually move a small subset of the graph. Reuse
	// these sets across speculative candidates so validation neither scans every
	// pair nor allocates fresh bookkeeping for every Commit.
	dirtyNodes     map[*Node]struct{}
	dirtyNodeMarks []bool
	fixedOrigins   map[*Node]geo.Point

	// Final-state overlap validation uses one sweep-built candidate graph per
	// commit. The slices and pointer index are retained across speculative
	// candidates, which avoids both O(changed*nodes) closure construction and an
	// O(nodes) scan for every node being validated.
	overlapCandidates     [][]int
	overlapSweepNodes     []transactionSweepNode
	overlapActiveNodes    []transactionSweepNode
	overlapNodeIndices    map[*Node][]int
	overlapNodeIndexReady bool
	// Geometry trial clones can share an immutable rollback point. Their first
	// accepted UpdateState must not recycle that shared state as scratch.
	priorGraphStateShared bool
	overlapInvalidBoxes   []bool
	exceptionMarks        []uint32
	exceptionGeneration   uint32
	descendantStack       []transactionPendingDescendant
	descendantNodes       []*Node
	descendantSeen        map[*Node]uint32
	descendantGeneration  uint32
}

type TransactionOptions struct {
	AffectContainers      bool
	IgnoreContainerEscape bool
	// AffectEdgeRoutes records route slice and point identity for operations
	// that move already-routed edges together with nodes.
	AffectEdgeRoutes bool
}

type transactionWorkGuardKey struct{}

func contextWithTransactionWorkGuard( context.Context,  *limits.WorkGuard) context.Context {
	if  == nil ||  == nil {
		return 
	}
	return context.WithValue(, transactionWorkGuardKey{}, )
}

func existingTransactionWorkGuard( context.Context,  string) (*limits.WorkGuard, bool, error) {
	if  == nil {
		return nil, false, fmt.Errorf("TALA %s requires a context", )
	}
	if ,  := .Value(transactionWorkGuardKey{}).(*limits.WorkGuard);  &&  != nil {
		if  := .Finish();  != nil {
			return nil, false, 
		}
		return , true, nil
	}
	return nil, false, nil
}

func ensureTransactionWorkGuard( context.Context,  string) (context.Context, *limits.WorkGuard, error) {
	, ,  := existingTransactionWorkGuard(, )
	if  != nil {
		return nil, nil, 
	}
	if  {
		return , , nil
	}
	,  = limits.NewWorkGuard(, , maxTransactionWorkUnits)
	if  != nil {
		return nil, nil, 
	}
	return context.WithValue(, transactionWorkGuardKey{}, ), , nil
}

func ( *Graph) ( context.Context,  TransactionOptions) (*Transaction, error) {
	, ,  := ensureTransactionWorkGuard(, "Transaction")
	if  != nil {
		return nil, 
	}
	return .newTransactionWithOptionsContext(, , )
}

func ( *Graph) ( context.Context,  *limits.WorkGuard,  TransactionOptions) (*Transaction, error) {
	if  == nil {
		return nil, fmt.Errorf("TALA transaction requires a shared work guard")
	}
	return .newTransactionWithOptionsContext(, , )
}

func cloneSlice[ any]( []) [] {
	 := make([], len())
	copy(, )
	return 
}

func ( *GraphState) ( *Graph,  *limits.WorkGuard) error {
	if  == nil {
		return fmt.Errorf("TALA transaction graph is nil")
	}
	if  == nil {
		return fmt.Errorf("TALA transaction requires a work guard")
	}
	if len(.Nodes) > maxEngineNodes {
		return fmt.Errorf("TALA transaction node count exceeds limit %d", maxEngineNodes)
	}
	if len(.Edges) > maxEngineEdges {
		return fmt.Errorf("TALA transaction edge count exceeds limit %d", maxEngineEdges)
	}
	for ,  := range []struct {
		  string
		 int
	}{
		{: "container", : len(.Containers)},
		{: "cluster", : len(.Clusters)},
		{: "sequence", : len(.Sequences)},
		{: "tree", : len(.Trees)},
		{: "node-tree", : len(.NodeToTree)},
		{: "hub", : len(.Hubs)},
		{: "direction", : len(.Directions)},
		{: "sibling", : len(.CommonUncleSiblings)},
	} {
		if . > maxEngineNodes+1 {
			return fmt.Errorf("TALA transaction %s map exceeds limit %d", ., maxEngineNodes+1)
		}
	}
	// Cluster, sequence, and container views commonly repeat the same nodes.
	// Size the initial maps only from the graph's primary view and let Go grow
	// them if the deduped traversal discovers additional unique nodes. The
	// traversal itself, rather than an additive membership estimate, enforces
	// the supported unique-node limit.
	 := min(len(.Nodes), maxEngineNodes)

	// Reset or create maps all at once to minimize allocation overhead
	// Using a more efficient approach to allocation
	if .nodeGeometry == nil || len(.nodeGeometry) > 2* {
		// Create new maps when they don't exist or are significantly larger than needed
		.nodeGeometry = make(map[*Node]graphGeometrySnapshot, )
	} else {
		// Clear maps without reallocating
		clear(.nodeGeometry)
	}
	.hasFixedTopLeft = false

	 := len(.Clusters)
	if .clusterArrangements == nil || len(.clusterArrangements) > 2* {
		.clusterArrangements = make(map[*Cluster]ClusterArrangement, )
		.clusterDesired = make(map[*Cluster]ClusterArrangement, )
		.clusterPaddings = make(map[*Cluster]float64, )
	} else {
		clear(.clusterArrangements)
		clear(.clusterDesired)
		clear(.clusterPaddings)
	}

	.originalNodesRef = .Nodes
	if cap(.originalNodes) < len(.Nodes) {
		.originalNodes = make([]*Node, len(.Nodes))
	} else {
		.originalNodes = .originalNodes[:len(.Nodes)]
	}
	copy(.originalNodes, .Nodes)

	 := func( *Node) (bool, error) {
		if  == nil {
			return false, nil
		}
		if ,  := .nodeGeometry[];  {
			return false, nil
		}
		if len(.nodeGeometry) >= maxEngineNodes {
			return false, fmt.Errorf("TALA transaction unique node snapshot exceeds limit %d", maxEngineNodes)
		}
		if  := .Step();  != nil {
			return false, 
		}
		 := snapshotPointer(.TopLeft)
		.nodeGeometry[] = graphGeometrySnapshot{
			topLeft: ,
			width:   .Width,
			height:  .Height,
		}
		.hasFixedTopLeft = .hasFixedTopLeft || .FixedTopLeft != nil
		return true, nil
	}

	 := func( *Node) error {
		 := []*Node{}
		for len() > 0 {
			 := [len()-1]
			 = [:len()-1]
			,  := ()
			if  != nil {
				return 
			}
			if ! {
				continue
			}
			for range .Containers[] {
				if  := .Step();  != nil {
					return 
				}
			}
			 = append(, .Containers[]...)
		}
		return nil
	}
	for ,  := range .Nodes {
		if  := ();  != nil {
			return 
		}
	}
	// Some speculative subgraphs keep descendants outside g.Nodes. Record map
	// roots and values as well so rollback does not depend on slice membership.
	for ,  := range .Containers {
		if  := .Step();  != nil {
			return 
		}
		if  := ();  != nil {
			return 
		}
		for ,  := range  {
			if  := ();  != nil {
				return 
			}
		}
	}

	// Store cluster policy and nodes.
	for ,  := range .Clusters {
		if  := .Step();  != nil {
			return 
		}
		if  == nil {
			continue
		}
		.clusterArrangements[] = .Arrangement
		.clusterDesired[] = .DesiredArrangement
		.clusterPaddings[] = .Padding
		if  := (.Vessel);  != nil {
			return 
		}
		if  := (.Container);  != nil {
			return 
		}
		for ,  := range .Nodes {
			if  := ();  != nil {
				return 
			}
		}
	}

	// Store sequence nodes that may be temporarily removed from g.Nodes.
	for ,  := range .Sequences {
		if  := .Step();  != nil {
			return 
		}
		if  == nil {
			continue
		}
		if  := (.Vessel);  != nil {
			return 
		}
		if  := (.Container);  != nil {
			return 
		}
		for ,  := range .Nodes {
			if  := ();  != nil {
				return 
			}
		}
	}

	if .captureTopology {
		if  := .captureRuntimeStateContext(, );  != nil {
			return 
		}
	} else {
		if  := .captureGeometryStateContext(, );  != nil {
			return 
		}
	}
	return .Finish()
}

// PreservePriorGraphState pins the current rollback point so a later
// UpdateState cannot recycle it as scratch. Callers may retain the returned
// state for a larger atomic operation that spans multiple transaction commits.
func ( *Transaction) () *GraphState {
	if  == nil {
		return nil
	}
	.priorGraphStateShared = true
	return .PriorGraphState
}

// CapturePlacementCosts attaches an optional stage-owned cost rollback point
// to this transaction. Ordinary Transaction.Rollback deliberately ignores it:
// speculative rejections retain memoized costs, while the enclosing stage
// decides whether to restore them.
func ( *Transaction) ( string) error {
	if  == nil || .Graph == nil || .guard == nil {
		return fmt.Errorf("TALA %s placement-cost snapshot requires an initialized transaction", )
	}
	if .placementCostSnapshot != nil {
		return nil
	}
	 := .Graph.EdgeLengthCacheEntries()
	if int64() > maxEngineTopologyReferences {
		return fmt.Errorf("TALA %s edge-length cache entries exceed limit %d", , maxEngineTopologyReferences)
	}
	for range  {
		if  := .guard.Step();  != nil {
			return 
		}
	}
	 := .Graph.SnapshotPlacementCosts()
	if  := .guard.Finish();  != nil {
		return 
	}
	.placementCostSnapshot = 
	return nil
}

// RestorePlacementCosts restores a captured placement-cost rollback point and
// reports whether one was present.
func ( *Transaction) () bool {
	if  == nil || .placementCostSnapshot == nil {
		return false
	}
	 := .placementCostSnapshot
	.placementCostSnapshot = nil
	.Restore()
	return true
}

func transactionSweepPadding( *Graph,  *limits.WorkGuard) (float64, error) {
	 := float64(TableNodeGap)
	 := 0.0
	 := 0.0
	 := make(map[*Edge]struct{}, len(.Edges))
	for ,  := range .Nodes {
		if  := .Step();  != nil {
			return 0, 
		}
		if  == nil {
			return 0, fmt.Errorf("TALA transaction contains a nil node")
		}
		if .TopLeft != nil {
			if !transactionNodeHasFiniteBox() {
				// Empty containers deliberately use NaN/+Inf sentinel geometry until
				// their final fit stage. The legacy all-pairs predicates never treated
				// those sentinels as overlaps, so omit them from the spatial index too.
				if .isContainer && len(.Containers[]) == 0 {
					continue
				}
				return 0, invariant.Errorf(
					"transaction node %d has invalid geometry (x=%v y=%v width=%v height=%v)",
					.ID, .TopLeft.X, .TopLeft.Y, .Width, .Height,
				)
			}
		}
		for ,  := range []float64{.margin.top, .margin.right, .margin.bottom, .margin.left} {
			if !transactionFinite() {
				return 0, invariant.Errorf("transaction node %d has non-finite margin", .ID)
			}
		}
		 = max(, .margin.top, .margin.right, .margin.bottom, .margin.left)
		for ,  := range .LoopOffsets {
			if  := .Step();  != nil {
				return 0, 
			}
			if !transactionFinite() {
				return 0, invariant.Errorf("transaction node %d has a non-finite loop offset", .ID)
			}
			if  >  {
				 = 
			}
		}
		// Direct internal callers can temporarily expose an edge through only one
		// endpoint before graph.Edges is synchronized. Include those references so
		// the broad phase never drops a pair that deltaTo would inspect.
		for ,  := range .Edges {
			if  := .Step();  != nil {
				return 0, 
			}
			if  == nil {
				return 0, fmt.Errorf("TALA transaction node %d contains a nil edge", .ID)
			}
			[] = struct{}{}
		}
	}
	for ,  := range .Edges {
		if  := .Step();  != nil {
			return 0, 
		}
		if  == nil {
			return 0, fmt.Errorf("TALA transaction contains a nil edge")
		}
		[] = struct{}{}
	}
	for  := range  {
		if  := .Step();  != nil {
			return 0, 
		}
		 = max(, float64(.MinWidth), float64(.MinHeight))
	}
	// deltaTo can combine one directional margin or loop offset from each
	// node in the pair. Twice the graph maximum is therefore a proven broad-
	// phase bound for every exact predicate evaluated below.
	 = max(, 2*, float64(NodeGap)+2*)
	if !transactionFinite() {
		return 0, invariant.New("transaction overlap padding is non-finite")
	}
	return , .Finish()
}

func transactionFinite( float64) bool {
	return !math.IsNaN() && !math.IsInf(, 0)
}

func transactionNodeHasFiniteBox( *Node) bool {
	return  != nil && .TopLeft != nil &&
		transactionFinite(.TopLeft.X) && transactionFinite(.TopLeft.Y) &&
		transactionFinite(.Width) && transactionFinite(.Height) &&
		transactionFinite(.TopLeft.X+.Width) && transactionFinite(.TopLeft.Y+.Height) &&
		.Width >= 0 && .Height >= 0
}

type transactionSweepNode struct {
	node  *Node
	index int
}

func buildTransactionOverlaps( *Graph,  *limits.WorkGuard) (map[*Node]map[*Node]struct{}, map[*Node]map[*Node]struct{}, error) {
	return buildTransactionOverlapsWithReferenceLimit(, , maxTransactionOverlapReferences)
}

func buildTransactionOverlapsWithReferenceLimit( *Graph,  *limits.WorkGuard,  int64) (map[*Node]map[*Node]struct{}, map[*Node]map[*Node]struct{}, error) {
	,  := transactionSweepPadding(, )
	if  != nil {
		return nil, nil, 
	}
	 := make([]transactionSweepNode, 0, len(.Nodes))
	for ,  := range .Nodes {
		if  := .Step();  != nil {
			return nil, nil, 
		}
		if .TopLeft != nil && transactionNodeHasFiniteBox() {
			 = append(, transactionSweepNode{node: , index: })
		}
	}
	if  := .Step();  != nil {
		return nil, nil, 
	}
	slices.SortStableFunc(, func(,  transactionSweepNode) int {
		if .node.TopLeft.X != .node.TopLeft.X {
			switch {
			case .node.TopLeft.X < .node.TopLeft.X:
				return -1
			case .node.TopLeft.X < .node.TopLeft.X:
				return 1
			default:
				return 0
			}
		}
		if  := cmp.Compare(.node.ID, .node.ID);  != 0 {
			return 
		}
		return cmp.Compare(.index, .index)
	})

	 := make(map[*Node]map[*Node]struct{})
	 := make(map[*Node]map[*Node]struct{})
	var  int64
	 := func( map[*Node]map[*Node]struct{}, ,  *Node) error {
		if  < 2 ||  > -2 {
			return fmt.Errorf("TALA transaction overlap references exceed limit %d", )
		}
		if [] == nil {
			[] = make(map[*Node]struct{})
		}
		if [] == nil {
			[] = make(map[*Node]struct{})
		}
		[][] = struct{}{}
		[][] = struct{}{}
		 += 2
		return nil
	}

	 := make([]*Node, 0)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, nil, 
		}
		 := [:0]
		for ,  := range  {
			if  := .Step();  != nil {
				return nil, nil, 
			}
			// g.Nodes is a legacy public slice and malformed direct callers can
			// repeat the same pointer. The old all-pairs scan explicitly skipped
			// identity pairs, so the sweep must not retain a self-overlap either.
			if  == .node {
				continue
			}
			if .TopLeft.X+.Width+ <= .node.TopLeft.X {
				continue
			}
			 = append(, )
			if .TopLeft.Y >= .node.TopLeft.Y+.node.Height+ ||
				.node.TopLeft.Y >= .TopLeft.Y+.Height+ {
				continue
			}
			if .node.DoesOverlapExact() {
				if  := (, .node, );  != nil {
					return nil, nil, 
				}
			}
			// Preserve the old ordered-pair semantics even if a malformed direct
			// caller has asymmetric edge references.
			if .node.doesOverlap() || .doesOverlap(.node) {
				if  := (, .node, );  != nil {
					return nil, nil, 
				}
			}
		}
		 = append(, .node)
	}
	if  := .Finish();  != nil {
		return nil, nil, 
	}
	return , , nil
}

// newTransactionWithOptionsContext constructs a transaction using a request-scoped
// work guard so production stages can share one aggregate budget across all
// speculative candidates.
func ( *Graph) ( context.Context,  TransactionOptions,  *limits.WorkGuard) (*Transaction, error) {
	if  == nil {
		var  error
		_, ,  = ensureTransactionWorkGuard(, "Transaction")
		if  != nil {
			return nil, 
		}
	} else if  == nil {
		return nil, fmt.Errorf("TALA transaction requires a context")
	}
	if  := .Finish();  != nil {
		return nil, 
	}
	 := &GraphState{captureEdgeRoutes: .AffectEdgeRoutes}
	if  := .updateContext(, );  != nil {
		return nil, 
	}

	, ,  := buildTransactionOverlaps(, )
	if  != nil {
		return nil, 
	}

	.existingOverlaps = 
	.existingExactOverlaps = 
	 := &Transaction{
		Ops:     make([]func() error, 0),
		Graph:   ,
		options: ,
		guard:   ,

		PriorGraphState: ,
	}

	return , .Finish()
}

func ( *Transaction) () error {
	// Existing-overlap exceptions intentionally remain anchored to transaction
	// construction. Reusing a transaction updates the rollback point, not which
	// preexisting collisions are allowed. Snapshot refresh remains cancellable
	// and budgeted.
	 := .PriorGraphState
	 := .spareGraphState
	if  == nil {
		 = &GraphState{}
	}
	.captureTopology = .captureTopology
	.captureEdgeRoutes = .captureEdgeRoutes
	if  := .updateContext(.Graph, .guard);  != nil {
		// updateContext only mutates the spare snapshot. The prior rollback point
		// remains exact, so a failed refresh can reject the accepted candidate.
		.Rollback()
		return 
	}
	.existingOverlaps = .existingOverlaps
	.existingExactOverlaps = .existingExactOverlaps
	.PriorGraphState = 
	if .priorGraphStateShared {
		.spareGraphState = nil
		.priorGraphStateShared = false
	} else {
		.spareGraphState = 
	}
	return nil
}

func ( *Transaction) ( func() error) {
	.Ops = append(.Ops, )
}

func ( *Transaction) ( context.Context) error {
	 := make([]*Node, 0, len(.Graph.Containers))
	for  := range .Graph.Containers {
		if  := .guard.Step();  != nil {
			return 
		}
		if  == nil || .TopLeft == nil {
			continue
		}
		 = append(, )
	}
	sort.Slice(, func(,  int) bool {
		if [].area() == [].area() {
			return [].ID < [].ID
		}
		return [].area() < [].area()
	})

	for ,  := range  {
		if  := .Err();  != nil {
			return 
		}
		.wrapChildren()
		if  := .guard.Step();  != nil {
			return 
		}
	}
	return .guard.Finish()
}

func ( *GraphState) ( *Graph) bool {
	if  == nil ||  == nil || len(.originalNodes) != len(.Nodes) {
		return false
	}
	for ,  := range .Nodes {
		if .originalNodes[] !=  {
			return false
		}
	}
	return true
}

func ( *GraphState) ( *Node) bool {
	if  == nil ||  == nil {
		return true
	}
	,  := .nodeGeometry[]
	if ! {
		return true
	}
	if .TopLeft == nil {
		return .topLeft.pointer != nil ||
			.Width != .width || .Height != .height
	}
	return .topLeft.pointer == nil ||
		.TopLeft.X != .topLeft.value.X || .TopLeft.Y != .topLeft.value.Y ||
		.Width != .width || .Height != .height
}

func transactionBoxesMayInteract(,  *Node) bool {
	if  == nil ||  == nil ||  ==  || .TopLeft == nil || .TopLeft == nil {
		return false
	}
	// This is the same symmetric broad phase used by
	// doesOverlapWithDimensionsContext. NaN values deliberately survive the
	// comparisons and are sent to the normal bad-state path.
	const  = 500.0
	return !(.TopLeft.X > .TopLeft.X+.Width+ ||
		.TopLeft.X+.Width+ < .TopLeft.X ||
		.TopLeft.Y > .TopLeft.Y+.Height+ ||
		.TopLeft.Y+.Height+ < .TopLeft.Y)
}

func ( *Transaction) ( context.Context) error {
	if .fixedOrigins == nil {
		.fixedOrigins = make(map[*Node]geo.Point)
	} else {
		clear(.fixedOrigins)
	}
	if !.PriorGraphState.hasFixedTopLeft {
		return .guard.Finish()
	}
	for ,  := range .Graph.Nodes {
		if  := .guard.Step();  != nil {
			return 
		}
		if  := .Err();  != nil {
			return 
		}
		if  == nil || .TopLeft == nil || .FixedTopLeft == nil {
			continue
		}
		 := .container()
		if ,  := .fixedOrigins[];  {
			continue
		}
		.fixedOrigins[] = geo.Point{
			X: .TopLeft.X - .FixedTopLeft.X,
			Y: .TopLeft.Y - .FixedTopLeft.Y,
		}
	}
	return .guard.Finish()
}

// collectOverlapValidationNodes records geometry changes for the legacy
// non-exact-to-exact regression check. Ordered overlap validation itself uses a
// complete post-state sweep, so it no longer needs a changed-node closure.
func ( *Transaction) ( context.Context) ( bool,  error) {
	if !.PriorGraphState.hasOriginalNodeOrder(.Graph) {
		return false, nil
	}
	if .dirtyNodes == nil {
		.dirtyNodes = make(map[*Node]struct{})
	} else {
		clear(.dirtyNodes)
	}
	if cap(.dirtyNodeMarks) < len(.Graph.Nodes) {
		.dirtyNodeMarks = make([]bool, len(.Graph.Nodes))
	} else {
		.dirtyNodeMarks = .dirtyNodeMarks[:len(.Graph.Nodes)]
		clear(.dirtyNodeMarks)
	}

	for ,  := range .Graph.Nodes {
		if  := .guard.Step();  != nil {
			return false, 
		}
		if  := .Err();  != nil {
			return false, 
		}
		if .PriorGraphState.geometryChanged() {
			.dirtyNodes[] = struct{}{}
			.dirtyNodeMarks[] = true
		}
	}
	return true, .guard.Finish()
}

// buildPostStateOverlapCandidates builds the exact 500-unit broad phase used
// by doesOverlapWithDimensionsContext. Sparse geometry transactions retain only
// pairs incident to a changed box; full geometry scans retain every pair.
// Candidate lists are sorted by g.Nodes index so directional deltaTo and
// first-rejection order remain unchanged.
func ( *Transaction) ( context.Context,  bool) error {
	 := len(.Graph.Nodes)
	if  > maxEngineNodes {
		return fmt.Errorf("TALA transaction node count exceeds limit %d", maxEngineNodes)
	}
	if cap(.overlapCandidates) <  {
		.overlapCandidates = make([][]int, )
	} else {
		.overlapCandidates = .overlapCandidates[:]
	}
	for  := range .overlapCandidates {
		.overlapCandidates[] = .overlapCandidates[][:0]
	}
	if cap(.overlapInvalidBoxes) <  {
		.overlapInvalidBoxes = make([]bool, )
	} else {
		.overlapInvalidBoxes = .overlapInvalidBoxes[:]
		clear(.overlapInvalidBoxes)
	}
	if cap(.exceptionMarks) <  {
		.exceptionMarks = make([]uint32, )
	} else {
		.exceptionMarks = .exceptionMarks[:]
	}

	 := ! || !.overlapNodeIndexReady
	if .overlapNodeIndices == nil {
		.overlapNodeIndices = make(map[*Node][]int, )
		 = true
	} else if  {
		for ,  := range .overlapNodeIndices {
			.overlapNodeIndices[] = [:0]
		}
	}
	.overlapSweepNodes = .overlapSweepNodes[:0]
	 := false
	 := 0
	for ,  := range .Graph.Nodes {
		if  := .guard.Step();  != nil {
			return 
		}
		if  := .Err();  != nil {
			return 
		}
		if  == nil {
			return invariant.New("transaction overlap check encountered a nil graph node")
		}
		if  {
			.overlapNodeIndices[] = append(.overlapNodeIndices[], )
		}
		if  && .dirtyNodeMarks[] {
			++
		}
		if .TopLeft == nil {
			continue
		}
		if !transactionNodeHasFiniteBox() {
			.overlapInvalidBoxes[] = true
			 = true
			continue
		}
		.overlapSweepNodes = append(.overlapSweepNodes, transactionSweepNode{node: , index: })
	}
	.overlapNodeIndexReady = 

	 := int64(0)
	 := func(,  int) error {
		if  > maxTransactionOverlapReferences-2 {
			return fmt.Errorf("TALA transaction overlap references exceed limit %d", maxTransactionOverlapReferences)
		}
		.overlapCandidates[] = append(.overlapCandidates[], )
		.overlapCandidates[] = append(.overlapCandidates[], )
		 += 2
		return nil
	}

	// A sparse geometry trial is cheapest as changed-nodes x graph. When many
	// boxes move, the sweep avoids scanning pairs that are far apart.
	 :=  && *4 < 
	if  {
		for ,  := range .Graph.Nodes {
			if !.dirtyNodeMarks[] || .TopLeft == nil {
				continue
			}
			for ,  := range .Graph.Nodes {
				if  := .guard.Step();  != nil {
					return 
				}
				if  ==  ||  ==  || .TopLeft == nil {
					continue
				}
				if .dirtyNodeMarks[] &&  <  {
					continue
				}
				if !transactionBoxesMayInteract(, ) {
					continue
				}
				if  := (, );  != nil {
					return 
				}
			}
		}
	} else {
		slices.SortStableFunc(.overlapSweepNodes, func(,  transactionSweepNode) int {
			if .node.TopLeft.X != .node.TopLeft.X {
				switch {
				case .node.TopLeft.X < .node.TopLeft.X:
					return -1
				case .node.TopLeft.X < .node.TopLeft.X:
					return 1
				default:
					return 0
				}
			}
			if  := cmp.Compare(.node.ID, .node.ID);  != 0 {
				return 
			}
			return cmp.Compare(.index, .index)
		})
		.overlapActiveNodes = .overlapActiveNodes[:0]
		for ,  := range .overlapSweepNodes {
			if  := .guard.Step();  != nil {
				return 
			}
			 := .overlapActiveNodes[:0]
			for ,  := range .overlapActiveNodes {
				if  := .guard.Step();  != nil {
					return 
				}
				// Equality remains active because the legacy broad phase only rejects
				// a pair when there is a strict gap greater than 500.
				if .node.TopLeft.X+.node.Width+500 < .node.TopLeft.X {
					continue
				}
				 = append(, )
				if .node == .node || !transactionBoxesMayInteract(.node, .node) {
					continue
				}
				if  {
					if !.dirtyNodeMarks[.index] && !.dirtyNodeMarks[.index] {
						continue
					}
				}
				if  := (.index, .index);  != nil {
					return 
				}
			}
			.overlapActiveNodes = append(, )
		}

		// Non-finite or negative boxes deliberately follow legacy comparisons,
		// whose NaN behavior cannot be represented by a numeric sweep ordering.
		if  {
			for  := 0;  < ; ++ {
				for  :=  + 1;  < ; ++ {
					if !.overlapInvalidBoxes[] && !.overlapInvalidBoxes[] {
						continue
					}
					if  {
						if !.dirtyNodeMarks[] && !.dirtyNodeMarks[] {
							continue
						}
					}
					if  := .guard.Step();  != nil {
						return 
					}
					,  := .Graph.Nodes[], .Graph.Nodes[]
					if  ==  || .TopLeft == nil || .TopLeft == nil ||
						!transactionBoxesMayInteract(, ) {
						continue
					}
					if  := (, );  != nil {
						return 
					}
				}
			}
		}
	}

	for ,  := range .overlapCandidates {
		if  := .guard.Step();  != nil {
			return 
		}
		sort.Ints()
	}
	return .guard.Finish()
}

func ( *Transaction) ( *Node,  uint32) {
	for ,  := range .overlapNodeIndices[] {
		.exceptionMarks[] = 
	}
}

// markDescendantOverlapExceptions performs the same stable descendant walk as
// allDescendantNodesGuarded, but retains its stack, result slice, and seen
// set across the thousands of speculative transaction checks in a layout.
func ( *Transaction) ( *Node,  bool,  uint32) error {
	.descendantGeneration++
	if .descendantGeneration == 0 {
		clear(.descendantSeen)
		.descendantGeneration = 1
	}
	 := .descendantGeneration
	if .descendantSeen == nil {
		.descendantSeen = make(map[*Node]uint32)
	}
	.descendantStack = .descendantStack[:0]
	.descendantNodes = .descendantNodes[:0]
	if  != nil {
		.descendantSeen[] = 
	}

	 := func( *Node) error {
		if  := .Graph.Sequences[];  != nil {
			for  := len(.Nodes) - 1;  >= 0; -- {
				if  := .guard.Step();  != nil {
					return 
				}
				.descendantStack = append(.descendantStack, transactionPendingDescendant{
					node: .Nodes[], emit: ,
				})
			}
		}
		if  != nil && .isClusterVessel {
			if  := .Graph.Clusters[];  != nil {
				for  := len(.Nodes) - 1;  >= 0; -- {
					if  := .guard.Step();  != nil {
						return 
					}
					.descendantStack = append(.descendantStack, transactionPendingDescendant{
						node: .Nodes[], emit: ,
					})
				}
			}
		}
		if  == nil || .isContainer {
			 := .Graph.Containers[]
			for  := len() - 1;  >= 0; -- {
				if  := .guard.Step();  != nil {
					return 
				}
				.descendantStack = append(.descendantStack, transactionPendingDescendant{
					node: [], emit: true,
				})
			}
		}
		return nil
	}
	if  := ();  != nil {
		return 
	}
	for len(.descendantStack) > 0 {
		if  := .guard.Step();  != nil {
			return 
		}
		 := len(.descendantStack) - 1
		 := .descendantStack[]
		.descendantStack = .descendantStack[:]
		if .node == nil || .descendantSeen[.node] ==  {
			continue
		}
		.descendantSeen[.node] = 
		if .emit {
			.descendantNodes = append(.descendantNodes, .node)
		}
		if  := (.node);  != nil {
			return 
		}
	}
	for ,  := range .descendantNodes {
		if  := .guard.Step();  != nil {
			return 
		}
		.markOverlapException(, )
	}
	return .guard.Finish()
}

func ( *Transaction) ( int) (bool, error) {
	 := .Graph.Nodes[]
	if  == nil || .TopLeft == nil {
		return  == nil, nil
	}
	if .Cluster != nil {
		return false, nil
	}

	.exceptionGeneration++
	if .exceptionGeneration == 0 {
		clear(.exceptionMarks)
		.exceptionGeneration = 1
	}
	 := .exceptionGeneration
	if .isContainer || .isClusterVessel || .Graph.Sequences[] != nil {
		if  := .markDescendantOverlapExceptions(, true, );  != nil {
			return false, 
		}
	}
	if .Container != nil || .Cluster != nil || .Sequence != nil {
		,  := .Graph.ancestorsOfGuarded(, .guard)
		if  != nil {
			return false, 
		}
		for ,  := range  {
			if  := .guard.Step();  != nil {
				return false, 
			}
			.markOverlapException(, )
		}
	}

	 := .PriorGraphState.existingOverlaps[]
	 := .TopLeft.X + .Width
	 := .TopLeft.Y + .Height
	for ,  := range .overlapCandidates[] {
		if  := .guard.Step();  != nil {
			return false, 
		}
		 := .Graph.Nodes[]
		if  == nil {
			return false, invariant.New("transaction overlap check encountered a nil graph node")
		}
		if ,  := [];  || .exceptionMarks[] ==  {
			continue
		}
		if .TopLeft == nil || !transactionBoxesMayInteract(, ) {
			continue
		}
		,  := .deltaToGuarded(, .TopLeft, .guard)
		if  != nil {
			return false, 
		}
		 := float64()
		if .TopLeft.X < .TopLeft.X+.Width+ && + > .TopLeft.X &&
			.TopLeft.Y < .TopLeft.Y+.Height+ && + > .TopLeft.Y {
			return true, nil
		}
	}
	return false, .guard.Finish()
}

func ( *Transaction) ( context.Context) ( error) {
	// A rejected trial is atomic: callers never observe a half-applied graph.
	// Keep Rollback idempotent because existing call sites also invoke it after
	// an error and after successful candidate evaluation.
	defer func() {
		if  := recover();  != nil {
			.Rollback()
			panic()
		}
		if  != nil {
			.Rollback()
		}
	}()

	if  == nil {
		return fmt.Errorf("TALA transaction commit requires a context")
	}
	if .guard == nil {
		return fmt.Errorf("TALA transaction commit requires a work guard")
	}
	if  := .guard.Finish();  != nil {
		return 
	}
	if  := .Err();  != nil {
		return 
	}
	for ,  := range .Ops {
		if  := .guard.Step();  != nil {
			return 
		}
		if  := .Err();  != nil {
			return 
		}
		if  := ();  != nil {
			return 
		}
		if  := .Err();  != nil {
			return 
		}
		// Syncing clusters will reposition cluster nodes, which may shrink containers
		// But repositioning containers can also expand clusters, since cluster nodes can be containers
		// TODO by this logic I think we need to run reposition containers again after syncCluster, but can't find a scenario where it matter
		if .options.AffectContainers {
			if  := .repositionContainers();  != nil {
				return 
			}
			for  := range .Graph.Containers {
				if  := .guard.Step();  != nil {
					return 
				}
				if  := .Err();  != nil {
					return 
				}
				if  == nil || .TopLeft == nil {
					continue
				}
				,  := .Graph.isBadStateContext(, .PriorGraphState, .options.IgnoreContainerEscape, .guard)
				if  != nil {
					return 
				}
				if  {
					return ErrInvalidCandidate
				}
			}
		}
		.Graph.SyncClusters()
		.Graph.SyncSequences()
		if  := .Err();  != nil {
			return 
		}
	}

	,  := .collectOverlapValidationNodes()
	if  != nil {
		return 
	}
	if  := .collectFixedOrigins();  != nil {
		return 
	}
	// Containment and fixed-position invariants remain graph-wide. Pairwise
	// overlap is validated afterward from one stable post-state sweep.
	for ,  := range .Graph.Nodes {
		if  := .guard.Step();  != nil {
			return 
		}
		if  := .Err();  != nil {
			return 
		}
		if  == nil {
			return invariant.New("transaction bad-state check received a nil node")
		}
		if .TopLeft == nil {
			continue
		}
		,  := .fixedOrigins[.container()]
		var  *geo.Point
		if  {
			 = &
		}
		, ,  := .Graph.isStructurallyBadStateWithFixedOriginContext(
			,
			.PriorGraphState,
			.options.IgnoreContainerEscape,
			,
			true,
			.guard,
		)
		if  != nil {
			return 
		}
		if  {
			return ErrInvalidCandidate
		}
	}
	if  := .buildPostStateOverlapCandidates(, );  != nil {
		return 
	}
	for ,  := range .Graph.Nodes {
		if len(.overlapCandidates[]) == 0 {
			continue
		}
		if  := .guard.Step();  != nil {
			return 
		}
		if  := .Err();  != nil {
			return 
		}
		if .TopLeft == nil {
			continue
		}
		,  := .hasBadPostStateOverlap()
		if  != nil {
			return 
		}
		if  {
			return ErrInvalidCandidate
		}
	}

	// If a non-exact overlap became an exact overlap, that's bad
	for ,  := range .PriorGraphState.existingOverlaps {
		if  := .guard.Step();  != nil {
			return 
		}
		if  := .Err();  != nil {
			return 
		}
		for  := range  {
			if  {
				,  := .dirtyNodes[]
				,  := .dirtyNodes[]
				if ! && ! {
					continue
				}
			}
			if  := .guard.Step();  != nil {
				return 
			}
			if  := .Err();  != nil {
				return 
			}
			 := false
			if ,  := .PriorGraphState.existingExactOverlaps[];  {
				if ,  := .PriorGraphState.existingExactOverlaps[][];  {
					 = true
				}
			}
			if ! {
				if .DoesOverlapExact() {
					return ErrInvalidCandidate
				}
			}
		}
	}

	if  := .Err();  != nil {
		return 
	}
	return .guard.Finish()
}

// Clear only needs to be called if transaction will be reused
func ( *Transaction) () {
	.Ops = make([]func() error, 0)
}

func ( *Transaction) () {
	 := .PriorGraphState
	if .captureTopology {
		.graph.restore(.Graph)

		for ,  := range .clusters {
			* = .value
			.Nodes = .nodes.restore()
			.EdgeAbductions = .edgeAbductions.restore()
		}
		for ,  := range .sequences {
			* = .value
			.Nodes = .nodes.restore()
			.EdgeAbductions = .edgeAbductions.restore()
		}
		for ,  := range .trees {
			* = .value
			.Children = .children.restore()
		}
		for ,  := range .edgeAbductions {
			* = 
		}
		for ,  := range .herds {
			* = .value
			.oppositeSidePaired = restoreMap(.value.oppositeSidePaired, .oppositeSidePaired)
			.sameSidePaired = restoreMap(.value.sameSidePaired, .sameSidePaired)
		}
		for ,  := range .hierarchies {
			* = .value
			.level = restoreMap(.value.level, .level)
		}
		for ,  := range .edges {
			.restore()
		}
		for ,  := range .nodes {
			.restore()
		}
		return
	}

	 := func( *Node) {
		 := .nodeGeometry[]
		.TopLeft = .topLeft.restore()
		.Width = .width
		.Height = .height
	}
	for  := range .nodeGeometry {
		()
	}
	for ,  := range .clusterArrangements {
		.Arrangement = 
		.DesiredArrangement = .clusterDesired[]
		.Padding = .clusterPaddings[]
	}
	for ,  := range .edgeGeometry {
		.restore()
	}
	for ,  := range .treeOrientations {
		.Orientation = 
	}
	copy(.originalNodesRef, .originalNodes)
	.Graph.Nodes = .originalNodesRef
}

// CloneGeometryContext creates a nested speculative transaction that may only
// move geometry. GraphState snapshots are immutable for such trials, so sharing
// the rollback point avoids cloning every node map and overlap-exception set.
// UpdateState detaches on the first accepted candidate before recycling state.
func ( *Transaction) () (*Transaction, error) {
	if  == nil || .PriorGraphState == nil || .guard == nil {
		return nil, fmt.Errorf("TALA geometry transaction clone requires an initialized transaction")
	}
	if .PriorGraphState.captureTopology {
		return nil, fmt.Errorf("TALA topology transaction requires an independent clone")
	}
	if  := .guard.Finish();  != nil {
		return nil, 
	}
	// The source and clone now have equal read-only ownership of this rollback
	// point. Force either side's next UpdateState to allocate its own scratch
	// state instead of recycling and mutating the shared snapshot.
	.priorGraphStateShared = true
	return &Transaction{
		Ops:                   cloneSlice(.Ops),
		Graph:                 .Graph,
		options:               .options,
		guard:                 .guard,
		PriorGraphState:       .PriorGraphState,
		priorGraphStateShared: true,
	}, nil
}