297ae56b85
GetTraceEventsAsync re-implemented GetExecutionTreeAsync's execution-chain walk as a second copy: the upward ParentExecutionId climb, the root MIN(OccurredAtUtc) window, and the recursive Edges/Chain CTE with its DISTINCT-edges trick and MAXRECURSION cap. Two walkers that had to stay in step on window slack, depth and the edge distillation. Extracted into three shared members: - ChainAnchor (root execution id + root's first event timestamp, with the Edges window predicate derived from it) - ResolveChainAnchorAsync — phase 1 up-walk plus the root window read - ChainCtePrefix / AddChainParameters — the Edges/Chain CTE prefix and its @root/@winStart/@winEnd binding Each walker appends its own projection to the prefix: GetExecutionTreeAsync the ChainIds CTE plus the per-execution aggregate, GetTraceEventsAsync the bare id union. Both keep OPTION (MAXRECURSION 32). Pure refactor. The tree walker's generated SQL is byte-identical (verified by diffing the composed command text against the pre-change literal); the trace walker's differs only by the SQL comment lines it now inherits from the shared prefix. Behaviour is pinned by the existing MSSQL-backed tests (GetExecutionTree_MultiLevelChain / _StubParentNode / _RespectsMaxRecursion, ExecutionTree_Bounds_EdgeScan_To_Root_Window, and both AuditLogRepositoryTraceEventsTests) — 410 passed / 0 skipped before and after. Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29