feature/Python-problem-by-code · L-261015-339eba

Merged
LC
19d ago
+15466-1094

mthds-python vendors the MTHDS core error registry's snapshot, generates its codes, parameters models and constants from it, and reads every runtime answer as a problem document by code, so MthdsAPIClient raises one coded problem for every failure, including the answers that are no problem document and the transport failures. It agrees with the TypeScript twin on a shared case file of answers and their readings, and records the breaking changes in the changelog.

Closes L-261015-339eba

🤖 Generated with Claude Code


Summary by cubic

mthds now implements MTHDS standard 8.0.0 and protocol 2.0.0, vendors the core error registry from the v8.0.0 release, and reads every request failure as a problem document by code, so MthdsAPIClient raises PipelineRequestError subclasses that always carry a problem.

New Features

  • Vendors the core error registry 8.0.0 byte for byte from the standard's v8.0.0 tag and generates mthds.protocol.problem.registry: a constant per core code, a typed parameters model per code, each code's entry with its fallback family and status readings, the strict JsonInteger and JsonNumber types, and a make check-error-registry gate that fails when the vendored files, the declared version, and the generated module disagree.
  • read_answer reads any answer as a problem: a problem document as received, and HTML pages, empty or non-JSON bodies, and mistyped members under client.response_unreadable or the status readings. Success bodies decode from bytes as Response.json() does, keeping numbers as written (10.0 stays a float) and refusing only NaN and Infinity, so a deeply nested or huge-integer output succeeds and non-UTF-8 bytes read as client.outcome_unknown on run routes.
  • Client-state failures (client.argument_invalid, client.unreachable, client.timeout, client.outcome_unknown, client.not_configured) are built from the registry with their parameters filled in; a base URL or API key HTTP cannot carry, or a time limit that is no finite number of seconds, is refused as client.not_configured at construction, and an answer whose body cannot be decoded reads as client.outcome_unknown on run routes, client.unreachable on the others.
  • The client's answers are pinned against a shared case file that the TypeScript twin also reads, which the merge from dev extended to the blob and files routes.

Breaking changes

  • ClientAuthenticationError becomes ClientNotConfiguredError; a 202 or unreadable success on execute or start, including one with an empty run id, now raises client.outcome_unknown, naming the run when the body gives one.
  • A /validate verdict's validation_errors become errors of ProblemItems; ProblemDocument and its lenient member reading are removed in favor of Problem, which reads a document as received and keeps undeclared members on model_extra.
  • BlobUploadError and the errors of the blob routes now carry a problem too: a runner's refusal reads as request.invalid, an object store's page, an unrequested blob named by a missing_blobs answer, or an upload target the client cannot send to, by URL or by its headers, as client.response_unreadable, and a refused files or data argument as client.argument_invalid; an upload that got no usable answer raises BlobUploadError with client.unreachable or client.timeout. An upload error's message names the blob and target only, never quoting a missing_blobs success or an object store's refusal, since their bodies and URLs can carry the permission to write.
  • Base URLs are written into problems and messages without their userinfo, query, or fragment.
  • Only the API runner raises these problem-carrying errors; the local PipelexRunner keeps its own PipelexRunnerError.