Repository navigation
fix(core/inference): name response validation checks - #588
Conversation
|
Reviewed at No functional defects found: all 27 Remaining findings, most important first: 1. Only one of the 16 labels is pinned by a test. 2. Nothing enforces the naming. Every label depends on a hand-written 3. Label granularity and cross-pipeline asymmetry.
4. Scope against #584. The PR body says "Fixes #584", so merging auto-closes the issue, but proposals (2) (leaf cause on the |
|
Follow-up at The coverage, mechanism, granularity and scope items from the first pass are addressed: the 25-case table plus the real provider-path test close the coverage gap, typed checks remove the hand-typed names, labels now follow the actually-failing check (a Four things remain. 1. Restore the stream scope for terminal validation failures — and don't silently rename labels that already ship.
If this came out of my earlier note that the two pipelines "mean two queries": that note was about vocabulary drift, not about the phase. The pipeline is a real axis — it is where proposal 3's retry-policy distinction will live — and the scope prefix is the only place that axis can be carried; a cross-pipeline consumer can normalize scope in the query layer. Concretely: keep the single naming path, but take the scope from the call site instead of deriving it from
(If you'd rather flatten the three specials into And if dropping the scope was deliberate, it deserves a comment where the prefix is derived, because nothing in the diff says why. 2. 3. The 4. Check precedence for multi-fault payloads changed. Happy to re-review once revised. |
|
Follow-up at The four items from the previous pass are addressed: the scope is taken from the call site again with the three terminal labels preserved ( 1. Multi-fault precedence is order-dependent, and it flips the terminal label in and out of a preserved special. (Both verified at An alert keyed on 2. nit: the normalize failure drops the part position, unlike the loops it preempts. Happy to re-review once revised. |
|
Re-reviewed at Both remaining items are addressed:
Verified locally at this head: Thanks for working through the revision rounds — the result is a better shape than the first pass. I'll take it from here: approving the pending CI run for the fork workflow, then updating the branch against One non-blocking note for later: since a corrupt tool payload outranks the rest, |
Adds `.release/core-v0.5.0.json`: a `minor` changeset for `core`. ``` core: 0.4.11 -> 0.5.0 (minor), tag core/v0.5.0 ``` ## Why minor #603 recorded the decision: its commit message and the review disposition both state that when `core` is tagged, the changeset must be `minor` and must name the `tool_search` ranking change, not just "shared BM25 kernel". This tag carries that change — `tool_search` ranks with prefix expansion, and the model-visible ranking and hit set change — which is the behaviour change the repository reserves a pre-1.0 `minor` for. The delta removes or renames no exported identifier, so nothing else forces the bump either way; `backends/memory` stays untagged. ## What the summary covers, since `core/v0.4.11` - `feat(core)`: the first upstream batch — `backends/secret` keychain store (non-release-managed), `core/tool/middleware` Truncate, the `core/inference/inferencetest` scripted wire provider, `core/utils` fsatomic + pathsafe + httpprobe, `core/workspace` Capped reads, plus the review follow-ups. - `feat(core/sandbox)`: the escalation front end — refusal detection, the rules store, the gate, one prompt, one approved retry through the unconfined chain (fail closed). - `feat(core/media)`: the media payload layer — `filetype` classification, `imageutil` normalization, the `media.attachments` prepare hook, and their budgets. - `feat(core)`: the shared BM25 kernel and the `tool_search` ranking change — `core/utils/bm25`, the golden score table, and the catalog contract tests. - `feat(core/skill)`: the read-only Agent Skills engine — parse, discover, service, rank, render. - `fix(core/inference)`: response validation checks named in `Error.Detail` for unary and terminal streaming (#588). ## Verification - `make ci`, `make lint` (9 modules, 0 issues), `make release-check`, `make release-plan` (`core: 0.4.11 -> 0.5.0 (minor), tag core/v0.5.0`), `make release-preflight` (`core: preflight tidy OK`), `git diff --check`. ## Next The Release workflow aggregates this changeset into `CHANGELOG.md` and opens the release PR; merging that publishes `core/v0.5.0`.
…he leaf cause (#639) Refs #584 ## Scope Implements proposals 2 and 3 from #584 — the follow-ups left open by #588 (proposal 1 shipped there). - **Proposal 2: the failure log learns why.** The `inference route failed` warn line now carries the leaf cause message as its own `error.cause` attribute, when and only when that message is redacted by construction. `inference.CauseMessage` walks the chain beneath the outer `*Error` and returns the first inference-owned cause (response-validation checks, undefined-tool rejections, tool-call conflicts, stream assembly); driver, transport, and context causes stay out, because `Error` documents the chain as diagnostic data rather than redacted output. Provider-supplied tokens that reach these messages are bounded first: tool names and media types render through `quoteToken` — valid UTF-8, quoted, truncated at 64 runes. New error types opt in through the `redactedCause` marker, whose doc names the three sources it allows. - **Proposal 3: unusable completions stop looking like corruption.** A response that completed — a terminal finish event was received, or a unary call returned — but whose artifact violates the request contract now raises `ProviderResponseUnusable`, classified `NotAvailable`: attempt-void at caller granularity, the same contract shape as `ProviderTruncated`. The boundary is completion, not the site that detects the failure: a part that cannot be assembled after the finish event is this kind too, while decode, normalize, and in-flight accumulation failures (including an event whose own payload is malformed) stay `InvalidProviderResponse` (Internal). The transcription session follows its unary sibling on the same rule. Core still never auto-retries the new kind (no route retry, no `fallback_on_retry_exhausted`), so this only exposes the flake-vs-corruption split to caller policies. The triage story for the production sample in #584 becomes: ``` WARN inference route failed inference.operation=generate error.message="provider_response_unusable during generate: stream.finish.validation.empty_content" error.cause="generate response content is required for finish reason \"completed\"" llm.request.id=f601f0d806630f48c523b7d708c89f17 ``` ## Summary - attach the leaf cause to the route failure log, guarded by a redacted-by-construction marker and bounded token rendering - give completed-but-unusable responses their own kind with `NotAvailable` (attempt-void) classification, keyed on completion rather than on the validation surface - align the transcription session's terminal check with its unary sibling - keep core's never-auto-retry contract explicit for the new kind (route predicate + docs) - coverage: marker boundary table, token bounding observed at `CauseMessage`, kind/classification split, terminal assembly vs in-flight classification, the #584 chain through the stream accumulator and its provider-id wrapper, a routed stream whose terminal payload is rejected end to end, the session's terminal net, and no-retry invariants - docs: graph/tool guides name the new generic kind for the `undefined_tool` contrast; the routing section of the inference guide states the failure policy ## New API surface - `inference.ProviderResponseUnusable` (ErrorKind) - `inference.CauseMessage` - `telemetry.AttrErrorCause` (`"error.cause"`) ## Validation - `make ci` - `make lint` - `make release-check` - `go test -count=1 -race ./...` (from `core`) - `git diff --check` Issue: #584
Refs #584
Scope
Implements proposal 1 from #584: preserve a stable, redacted response-validation check in
Error.Detailfor unary and terminal streaming generate responses, with modality-specific labels where applicable.Proposal 2 (logging the leaf cause) and proposal 3 (retry-policy differentiation) are not included. Issue #584 remains open to track those follow-ups.
Summary
UndefinedTool, and preserve tool-call data and the error chain.Validation
make cimake release-checkgo test -count=1 -race ./...(fromcore)CGO_ENABLED=0 GOOS=darwin go vet ./...(fromcore)CGO_ENABLED=0 GOOS=freebsd go vet ./...(fromcore)golangci-lint run --new-from-rev=dd7b5bda(fromcore)Issue: #584