feat(studio): friendlyError catches hub-specific patterns
Some checks failed
Security / Security check (push) Failing after 1s
Some checks failed
Security / Security check (push) Failing after 1s
Generic gRPC-code mapping was right but not specific enough.
A flow failing with an approval-timeout used to land on
'Deadline exceeded — try again later'; now it reads 'Freigabe-
Timeout abgelaufen — entweder timeout_seconds erhöhen oder
den Reviewer informieren.'
New pattern matchers in _matchHubPattern, runs before the
gRPC-code switch. Six FlowExecutionError shapes covered:
- approval rejected ("rejected by")
- approval timeout
- output too large ("exceeding the X MB cap")
- host service not declared
- missing value reference
- MCP endpoint unreachable
- capability not installed (NotFound fallback)
Every match comes with a localised hint pointing at the
concrete fix path (audit log / timeout config / Integrations
panel / Text-tab Fix button).
Five new tests pin the matchers — would catch a silent
regression when the hub renames a variant Display string.
All 11 friendly_error tests + 19 Studio tests green.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
28fafce7dc
commit
971196518c
8 changed files with 370 additions and 4 deletions
|
|
@ -74,11 +74,82 @@ void main() {
|
|||
final r =
|
||||
friendlyError(_FakeGrpcError(14, 'UNAVAILABLE', 'connection refused'), lDe);
|
||||
expect(r.headline, lDe.errUnavailable);
|
||||
// Sanity: the DE headline really is different from the EN
|
||||
// one — guards against the test silently passing if l10n
|
||||
// regen returned EN for both.
|
||||
final lEn = await _loadL10n(const Locale('en'));
|
||||
expect(lDe.errUnavailable, isNot(equals(lEn.errUnavailable)));
|
||||
});
|
||||
|
||||
// --- Hub-pattern-specific detection ---
|
||||
// The mapper inspects the message DETAIL for hub patterns and
|
||||
// returns a more specific FriendlyError than the gRPC code's
|
||||
// default. These guards lock the matchers — a regression here
|
||||
// would silently fall back to the generic gRPC-code copy.
|
||||
|
||||
test("approval rejection maps to specific headline", () async {
|
||||
final l = await _loadL10n(const Locale('en'));
|
||||
final r = friendlyError(
|
||||
_FakeGrpcError(
|
||||
7,
|
||||
'PERMISSION_DENIED',
|
||||
"step 'ap1' rejected by alice: needs more detail",
|
||||
),
|
||||
l,
|
||||
);
|
||||
expect(r.headline, l.errApprovalRejected);
|
||||
expect(r.hint, l.errApprovalRejectedHint);
|
||||
});
|
||||
|
||||
test('approval timeout maps to specific headline', () async {
|
||||
final l = await _loadL10n(const Locale('en'));
|
||||
final r = friendlyError(
|
||||
_FakeGrpcError(
|
||||
4,
|
||||
'DEADLINE_EXCEEDED',
|
||||
"step 'ap1' timed out waiting for approval after 600s",
|
||||
),
|
||||
l,
|
||||
);
|
||||
expect(r.headline, l.errApprovalTimedOut);
|
||||
});
|
||||
|
||||
test('output-too-large maps to specific headline', () async {
|
||||
final l = await _loadL10n(const Locale('en'));
|
||||
final r = friendlyError(
|
||||
_FakeGrpcError(
|
||||
8,
|
||||
'RESOURCE_EXHAUSTED',
|
||||
"step 'extract' produced 52428800 bytes of output, "
|
||||
"exceeding the 10 MB cap",
|
||||
),
|
||||
l,
|
||||
);
|
||||
expect(r.headline, l.errOutputTooLarge);
|
||||
});
|
||||
|
||||
test('host-service-not-declared maps to specific headline', () async {
|
||||
final l = await _loadL10n(const Locale('en'));
|
||||
final r = friendlyError(
|
||||
_FakeGrpcError(
|
||||
14,
|
||||
'UNAVAILABLE',
|
||||
"step 'summarise' requires service 'ollama' which is not declared "
|
||||
"in operator config",
|
||||
),
|
||||
l,
|
||||
);
|
||||
expect(r.headline, l.errServiceUnavailableForStep);
|
||||
});
|
||||
|
||||
test('missing value maps to specific headline', () async {
|
||||
final l = await _loadL10n(const Locale('en'));
|
||||
final r = friendlyError(
|
||||
_FakeGrpcError(
|
||||
3,
|
||||
'INVALID_ARGUMENT',
|
||||
r"step 'classify' references missing value '$inputs.text'",
|
||||
),
|
||||
l,
|
||||
);
|
||||
expect(r.headline, l.errMissingValue);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue