fix: make the MCP error tools answer the no-unknown-errors policy - #763
Merged
Conversation
…res as Maple errors `severity: "ERROR"` compiled to `SeverityText = 'ERROR'`, but Effect services write Title Case (`Error`), so the MCP log search, dashboard filters and alert rules on Maple's own services matched nothing. The scalar level now expands to every spelling as an `IN` list, which keeps the sorting-key prefix on `logs_aggregates_hourly`. Facet arrays stay exact. The raw-SQL catalog and dashboard example, which told agents the opposite, now point at `SeverityNumber` ranges. The model-call span closed with the upstream package's `AI.Error` tag because the mapping to `LlmCallError` ran outside `Stream.withSpan`. Both the chat turn and the compaction call now map before the span records the failure.
…was it expected" Triage through the MCP tools needed several round-trips for facts the warehouse already had: - `find_errors` prints one sample message per fingerprint, so a tag that owns a dozen fingerprints no longer needs an `error_detail` call each. `identity="unexpected"` narrows to identities that break a no-unknown-errors policy: labels outside `namespace_prefix` (default `@maple/`) plus the 5xx and unexpected-envelope markers. - `error_detail` reports the failing span (name, service, status message, and the model/route/tool/query attributes it carries) instead of an arbitrary span's status, and points at `inspect_span` for it. `any(StatusMessage)` used to pick a healthy span. - `list_error_issues` takes `last_seen_after`, prints the fingerprint so an issue can go straight to `error_detail`, and `compact=true` trims the table and payload to identity, state and volume. - `inspect_trace` takes `errors_only` (error spans, their ancestors and roots) and `max_spans`, so a 400-span trace's failure fits in one response.
…QL baseline `ErrorDetailTrace` gained `errorSpan`; the CLI's remote mode builds that shape from the v2 trace, so it now picks the first `Error` span and the same attribute allowlist the warehouse query projects. The SQL baseline records the new error-span columns and the severity spellings, and the catalog sweeps the `identity="unexpected"` shape so the `NOT LIKE ... OR IN` predicate is DESCRIBE-checked against real ClickHouse.
`scripts/bench-queries.ts` loads `scripts/bench-suites/*.ts` by path through a dynamic import off its `--suite` argument, an edge knip cannot follow, so the unified-catalog commit left `bench-suites/services.ts` reported as unused and turned main red.
🍁 Maple PR previewWarning Preview cleanup could not be confirmed. The Alchemy teardown outcome was Final commit |
Makisuo
added a commit
that referenced
this pull request
Sep 5, 2026
One conflict, and it is the good kind: main's #763 landed the same knip fix this branch carried a commit earlier, so both sides added `scripts/bench-suites/*.ts` to the apps/api entry list. The entry arrays are byte-identical; only the explanatory comment differed. Took main's comment because it is more accurate, and checked before adopting it. Mine said nothing ever imports a bench suite; main's says they are loaded by path from `scripts/bench-queries.ts` via a dynamic import off the CLI's `--suite` argument, which is why knip cannot see the edge. That import is real — `bench-queries.ts:659`, `import(pathToFileURL(resolve(path)).href)` — so main's version describes the actual mechanism and mine described its symptom. This branch's own knip commit (c6dd7d9) is now redundant with main and does nothing on top of it; it stays in history as part of the merge rather than being rewritten out. Verified: `bun knip` exits 0, the full test-packages lane is 16/16, `bun typecheck` 40/40, `bun run lint` clean, ClickHouse schema / local-manifest (v17) / Tinybird manifest gates up to date, apps/api 2586, apps/web 2370, apps/cli 538. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Triaging
maple-apierrors against the "no unknown or unexpected error" policy took a dozen MCP calls, and two of the tools returned wrong or empty answers along the way. This PR fixes the two product bugs found and closes the tooling gaps that made the triage slow.Bugs fixed
severity: "ERROR"compiled toSeverityText = 'ERROR', but Effect's logger writes Title Case (Error), OTel SDKs upper-case, and pino-style shims lower-case.search_logs, dashboard severity filters and alert rules onmaple-api/alertingsilently matched nothing. The scalar level now expands to every spelling as anINlist (keeps the sorting-key prefix onlogs_aggregates_hourly); facet arrays stay exact. The raw-SQL catalog text and dashboard example that told agents the opposite now point atSeverityNumberranges.AI.Error. The upstream package's tag leaked onto thechat <model>span because the mapping to@maple/llm/LlmCallErrorran outsideStream.withSpan. Both the chat turn and the compaction call now map inside the span.MCP tooling
find_errors: one sample message per fingerprint;identity="unexpected"(+namespace_prefix) narrows to labels outside the namespace plus the 5xx / unexpected-envelope markers — a one-call answer to the policy question.error_detail: reports the failing span (name, service, status, model/route/tool/query attributes) rather than an arbitrary span's status message, which was empty for most traces. Next step points atinspect_spanfor that span.list_error_issues:last_seen_after, aFingerprintcolumn, andcompact=truefor a narrow table and payload. The 50-row default used to exceed client output caps.inspect_trace:errors_onlyandmax_spans.Not in this PR
Fingerprinting transport failures by tag + reason instead of message (so a retried
LlmCallErrorlands on the existing issue) needs a change to theerror_events_mvmaterialization and a partial hash rotation; it is worth its own change.Verification
packages/query-engine:errors,logs,pipe-dispatch,error-detail,search-logstests — 171 passed.apps/api:span-tree,render-trace,turn,registry,tool-outputtests — 83 passed.tsc --noEmitclean forapps/api,packages/query-engine,packages/domain.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.