Skip to content

Reduction/visualization endpoints: structured 400 on unparsable input (closes #355)#353

Open
wrigjl wants to merge 4 commits into
ReduxISU:CSharpAPIfrom
wrigjl:submit/reduction-input-exception
Open

Reduction/visualization endpoints: structured 400 on unparsable input (closes #355)#353
wrigjl wants to merge 4 commits into
ReduxISU:CSharpAPIfrom
wrigjl:submit/reduction-input-exception

Conversation

@wrigjl

@wrigjl wrigjl commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

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 structured
HTTP 400, matching the existing instance_parse_error /
certificate_parse_error pattern already used by solve/verify/problemInstance.

Changes

Reduction input exception + /mapSolution (original scope)

  • Add ReductionInputException to Interfaces/ParseExceptions.cs (carries the
    IReduction, the received string, and the expected-format hint chosen at the
    throw site, so one type covers both instance-side and certificate-side parse
    failures).
  • SipserReduceToSAT3 validates its source instance and certificate, throwing
    ReductionInputException with the CLIQUE instanceFormat/certificateFormat
    plus a Sipser-node-format addendum.
  • SipserReduceToCliqueStandard.mapSolutions validates the : separator before
    indexing, throwing ReductionInputException naming 3SAT's certificateFormat.
    This replaces the IndexOutOfRangeException at the original crash site.

Extend to the remaining endpoints (#355)

  • Add 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.
  • reduce, gadgets, visualizeReduction, and visualize each gain a single
    catch (Exception ex) when (IsParseError(ex)) => ParseError(ex) arm. These
    previously let a ProblemParseException/ReductionInputException escape as an
    unhandled 500 (the reduce path was the endpoint in the reported Reduction/visualization endpoints return 500 (with stack trace) instead of 400 on unparsable instances #355 trace).
  • mapSolution is refactored onto the same helper, collapsing its three inline
    catch blocks into one arm — all reduction/visualization endpoints now handle
    parse errors uniformly. verify/solve/problemInstance are 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.slnx687 passed, 0 failed, including new endpoint
tests asserting 400 + instance_parse_error for reduce, gadgets,
visualizeReduction, and visualize, plus the existing mapSolution
parse-error tests.

Live against a running backend (/ProblemProvider/mapSolution):

Input Before After
valid SAT3 solution → SipserReduceToCliqueStandard 200 200
clique-shaped cert → SipserReduceToCliqueStandard 500 IndexOutOfRange 400, 3SAT cert format, missing ':' separator
non-Sipser CLIQUE instance → SipserReduceToSAT3 500 400, CLIQUE instanceFormat + Sipser addendum
bad certificate → SipserReduceToSAT3 500 400, CLIQUE certificateFormat + Sipser addendum

No unhandled exceptions in the server log across all cases.

🤖 Generated with Claude Code

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>
@wrigjl wrigjl marked this pull request as draft July 5, 2026 15:47
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>
@wrigjl wrigjl marked this pull request as ready for review July 5, 2026 21:38
@wrigjl wrigjl marked this pull request as draft July 5, 2026 22:03
wrigjl and others added 2 commits July 5, 2026 16:31
…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>
@wrigjl wrigjl changed the title Wrap /mapSolution: structured 400 with format hint on parse error Reduction/visualization endpoints: structured 400 on unparsable input (closes #355) Jul 5, 2026
@wrigjl wrigjl marked this pull request as ready for review July 5, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduction/visualization endpoints return 500 (with stack trace) instead of 400 on unparsable instances

1 participant