fix(flow-debugger): final-review remediation — 2000-row trace pull, shared ExceptionHeader parser, surrogate-safe clip, wording, alarm source, register renumber (I1/I2/M1-M8)
This commit is contained in:
@@ -272,37 +272,18 @@ public partial class FlowGraphView : ComponentBase
|
||||
|
||||
/// <summary>
|
||||
/// The subtitle a failed or timed-out step shows instead of its own: <c>{Type}: {message}</c>, where
|
||||
/// the type is the exception's name without its namespace, parsed from the first line of the captured
|
||||
/// <see cref="FlowStep.ErrorDetail"/> (a .NET <c>ToString()</c> opens with <c>Namespace.Type: message</c>).
|
||||
/// A wrapper's first line chains its inner exceptions with <c>" ---> "</c>; the LAST segment is taken,
|
||||
/// since the innermost exception is the one the script author has to act on. The namespace is stripped
|
||||
/// only from the head of the type name — any generic arity/argument suffix (<c>`1[System.String]</c>)
|
||||
/// is kept verbatim. Falls back to the line itself when it carries no <c>": "</c>, and to
|
||||
/// <see cref="FlowStep.ErrorMessage"/> when there is no detail. Null for every non-failed step.
|
||||
/// the type is the exception's name without its namespace. Parsing is
|
||||
/// <see cref="ExceptionHeader.Parse"/> (final review M1 — the same parser the step detail panel
|
||||
/// uses), which takes the first line of the captured <see cref="FlowStep.ErrorDetail"/> and follows
|
||||
/// its <c>" ---> "</c> chain to the innermost exception. Falls back to the line itself when it
|
||||
/// carries no <c>": "</c>, and to <see cref="FlowStep.ErrorMessage"/> when there is no usable detail.
|
||||
/// Null for every non-failed step.
|
||||
/// </summary>
|
||||
internal static string? ExceptionSubtitle(FlowStep s)
|
||||
{
|
||||
if (s.Outcome is not (FlowStepOutcome.Failed or FlowStepOutcome.TimedOut)) return null;
|
||||
if (string.IsNullOrWhiteSpace(s.ErrorDetail)) return s.ErrorMessage;
|
||||
|
||||
var first = s.ErrorDetail.Split('\n', 2)[0].TrimEnd('\r').Trim();
|
||||
// A wrapper (AggregateException, a rethrow) chains inner exceptions on the same line — the last is innermost.
|
||||
var inner = first.LastIndexOf(" ---> ", StringComparison.Ordinal);
|
||||
if (inner >= 0) first = first[(inner + " ---> ".Length)..].Trim();
|
||||
if (first.Length == 0) return s.ErrorMessage;
|
||||
|
||||
var split = first.IndexOf(": ", StringComparison.Ordinal);
|
||||
if (split < 0) return first;
|
||||
|
||||
var type = first[..split];
|
||||
var message = first[(split + 2)..];
|
||||
// Shorten only the leading namespace: everything from a generic marker on is part of the name.
|
||||
var generic = type.IndexOfAny(['`', '[']);
|
||||
var head = generic < 0 ? type : type[..generic];
|
||||
var dot = head.LastIndexOf('.');
|
||||
if (dot >= 0 && dot < head.Length - 1)
|
||||
type = head[(dot + 1)..] + (generic < 0 ? string.Empty : type[generic..]);
|
||||
return type + ": " + message;
|
||||
if (ExceptionHeader.Parse(s.ErrorDetail, shortenType: true) is not { } head) return s.ErrorMessage;
|
||||
return head.Message.Length == 0 ? head.Type : head.Type + ": " + head.Message;
|
||||
}
|
||||
|
||||
private static string Eyebrow(FlowLayoutNode n) => n.Kind switch
|
||||
|
||||
Reference in New Issue
Block a user