Reduction/visualization endpoints: structured 400 on unparsable input (closes #355)#353
Open
wrigjl wants to merge 4 commits into
Open
Reduction/visualization endpoints: structured 400 on unparsable input (closes #355)#353wrigjl wants to merge 4 commits into
wrigjl wants to merge 4 commits into
Conversation
Adds ReductionInputException (carries IReduction, received string,
and the expected-format hint chosen at the throw site so the same
exception type covers both instance-side and certificate-side parse
failures).
SipserReduceToSAT3 wraps its constructor and mapSolutions: catches
ArgumentException from ParseSipserNode and rethrows as
ReductionInputException with reductionFrom.instanceFormat or
reductionFrom.certificateFormat appended with a note about the
Sipser-format addendum.
SipserReduceToCliqueStandard.mapSolutions validates that each
assignment item contains a ':' separator before indexing; throws
ReductionInputException naming SAT3's certificateFormat in the hint.
This replaces the IndexOutOfRangeException at the original gut-check
crash site.
ProblemProvider.mapSolution returns IActionResult; catches
ProblemParseException (from the reduction's instance constructor,
unwrapped from TargetInvocationException) and ReductionInputException,
returning HTTP 400 with {error, reduction, problem, expected, received,
detail}.
Live-verified four cases: valid round-trip clique→SAT3 → 200;
"totally not a clique" → 400 with CLIQUE certificate format; clique
fed into forward mapper (the original gut-check) → 400 with SAT3
certificate format; malformed instance → 400 with CLIQUE instance
format.
Builds on Interfaces/ParseExceptions.cs from submit/problem-format-fields.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Four endpoint tests on /ProblemProvider/mapSolution: valid solution → 200; CLIQUE-shaped certificate to the SAT3→CLIQUE mapper → 400 (the original gut-check); non-Sipser CLIQUE instance and non-Sipser certificate to SipserReduceToSAT3 → 400. Each asserts the reduction_input_parse_error body. One unit test pinning the bug at its source: SipserReduceToCliqueStandard .mapSolutions on a malformed certificate now throws ReductionInputException, not IndexOutOfRangeException. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ualize(Reduction) Extends the /mapSolution parse-error handling to the remaining reduction and visualization endpoints (issue ReduxISU#355). Previously reduce, gadgets, visualizeReduction, and visualize let a ProblemParseException / ReductionInputException escape to Kestrel as an unhandled 500 with a stack trace instead of a structured 400. Adds three shared helpers on ProblemProvider: - Unwrap: normalizes TargetInvocationException (from reflective Activator.CreateInstance) vs bare parse exceptions (direct calls). - IsParseError: predicate used in the catch filter. - ParseError: maps a parse exception to the matching 400 body (instance_parse_error / reduction_input_parse_error / certificate_parse_error), reusing the existing body builders. Each endpoint now has a single `catch (Exception ex) when (IsParseError(ex))` arm. verify/solve/problemInstance/mapSolution are intentionally left as-is to keep the diff scoped to the endpoints from ReduxISU#355. Adds endpoint tests asserting 400 + instance_parse_error for all four. Note: this closes the endpoint layer of ReduxISU#355. Inputs whose underlying problem/reduction throws a non-typed (raw) exception still 500; converting those constructors to throw typed parse exceptions is tracked separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Folds mapSolution's three inline catch blocks into the same `catch (Exception ex) when (IsParseError(ex)) => ParseError(ex)` arm now used by reduce/gadgets/visualizeReduction/visualize, so all reduction and visualization endpoints handle parse errors uniformly. Behavior is unchanged (existing mapSolution parse-error tests still pass). Co-Authored-By: Claude Opus 4.8 <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.
Closes #355.
Summary
Mis-shaped input on the reduction and visualization endpoints currently throws
into an HTTP 500 with a stack trace — any client (the GUI, curl, an LLM/MCP
client) gets opaque output with no actionable signal, and every bad request
writes a full stack trace to the server log.
This makes all five affected endpoints —
mapSolution,reduce,gadgets,visualizeReduction,visualize— surface parse failures as a structuredHTTP 400, matching the existing
instance_parse_error/certificate_parse_errorpattern already used bysolve/verify/problemInstance.Changes
Reduction input exception +
/mapSolution(original scope)ReductionInputExceptiontoInterfaces/ParseExceptions.cs(carries theIReduction, the received string, and the expected-format hint chosen at thethrow site, so one type covers both instance-side and certificate-side parse
failures).
SipserReduceToSAT3validates its source instance and certificate, throwingReductionInputExceptionwith the CLIQUEinstanceFormat/certificateFormatplus a Sipser-node-format addendum.
SipserReduceToCliqueStandard.mapSolutionsvalidates the:separator beforeindexing, throwing
ReductionInputExceptionnaming 3SAT'scertificateFormat.This replaces the
IndexOutOfRangeExceptionat the original crash site.Extend to the remaining endpoints (#355)
ProblemProvider:Unwrap— normalizesTargetInvocationException(from reflectiveActivator.CreateInstance) vs. bare parse exceptions (direct calls).IsParseError— predicate used in the catch filter.ParseError— maps a parse exception to the matching 400 body(
instance_parse_error/reduction_input_parse_error/certificate_parse_error), reusing the existing body builders.reduce,gadgets,visualizeReduction, andvisualizeeach gain a singlecatch (Exception ex) when (IsParseError(ex)) => ParseError(ex)arm. Thesepreviously let a
ProblemParseException/ReductionInputExceptionescape as anunhandled 500 (the
reducepath was the endpoint in the reported Reduction/visualization endpoints return 500 (with stack trace) instead of 400 on unparsable instances #355 trace).mapSolutionis refactored onto the same helper, collapsing its three inlinecatch blocks into one arm — all reduction/visualization endpoints now handle
parse errors uniformly.
verify/solve/problemInstanceare left as-is.Scope note
This closes the endpoint layer of #355: all five endpoints now translate a
typed parse exception into a 400. Inputs whose underlying problem/reduction
still throws a raw (non-typed) exception will continue to 500 through these
endpoints; converting those constructors to throw typed parse exceptions is a
per-problem effort tracked separately.
Verification
dotnet build Redux.slnx— 0 warnings, 0 errors.dotnet test Redux.slnx— 687 passed, 0 failed, including new endpointtests asserting
400+instance_parse_errorforreduce,gadgets,visualizeReduction, andvisualize, plus the existingmapSolutionparse-error tests.
Live against a running backend (
/ProblemProvider/mapSolution):SipserReduceToCliqueStandardSipserReduceToCliqueStandardIndexOutOfRangemissing ':' separatorSipserReduceToSAT3instanceFormat+ Sipser addendumSipserReduceToSAT3certificateFormat+ Sipser addendumNo unhandled exceptions in the server log across all cases.
🤖 Generated with Claude Code