Release v0.25.0

Merged
LC
19d ago
+15468-1096

Release v0.25.0

Bumps version from 0.24.0 to 0.25.0. Promotes dev → main.

Changelog

Added

  • The core error registry, generated: mthds.protocol.problem.registry is generated from the standard's core error registry 8.0.0, vendored byte for byte from the standard's v8.0.0 release in vendor/mthds-error-registry/ with its source tag and commit, and gives a constant per core code (CoreCode), a typed parameters model per code, reading a number strictly as JsonInteger and JsonNumber (mthds.protocol.problem.json_types) do, never from a string or a boolean, each code's entry (CORE_CODE_SPECS) and the readings a client falls back on; CORE_ERROR_REGISTRY_VERSION in mthds.protocol.protocol declares the version, and make check-error-registry fails when the vendored files, the declared version and the generated module disagree.
  • Problem and ProblemItem: mthds.protocol.problem.models reads the protocol's problem document as received, its undeclared members on model_extra, with effective_domain and effective_step_kind reading a value the protocol does not list by the code's family, effective_retry reading an unknown verdict as no, is_retryable true only for a retry of yes, outcome_is_unknown, params_as to read the parameters as the code's model, and each fault of errors and its suggested_fix typed; make_client_problem in mthds.protocol.problem.client_problems states a client's own problem from the registry.

Changed

  • Standard version 8.0.0 and Protocol 2.0.0 (Breaking): MTHDS_STANDARD_VERSION moved from 7.0.0 to 8.0.0 and PROTOCOL_VERSION from 1.0.0 to 2.0.0, the release of the standard in which every error is a problem document, so a manifest's mthds_version is evaluated against 8.0.0, and ^7.0.0, ~7.0.0, 7.* or an exact 7.0.0 no longer pass.
  • Every request error carries a problem (Breaking): PipelineRequestError(message, *, problem) requires the failure as a Problem, read on exc.problem, and every error this package raises carries one under a registered code: an argument refused before any request leaves, by options, method_files or the client, carries client.argument_invalid naming the argument and the reason, and RunStillRunningError, raised on a 202 from execute that names its run, carries client.follow_failed with the run as the problem's pipeline_run_id, while a 202 naming no run raises ApiResponseError carrying client.outcome_unknown, since the run may exist. BlobUploadError, raised when an upload target refuses a blob, carries the target's own problem document, or else the problem its status names, its message never quoting the target's body, which an object store's refusal such as S3's SignatureDoesNotMatch fills with the presigned signature and query that grant the write, while response_body keeps it whole, and an upload that gets no usable answer raises it too, with status, status_text and response_body None, carrying client.unreachable or client.timeout as a request that creates nothing does, since a blob's upload is safe to repeat, or client.response_unreadable when the target is malformed, no URL the client can send to or a header it cannot write, such as a value not in ASCII or holding a line break, its headers never quoted, and a missing_blobs answer naming a blob the request did not list raises ApiResponseError carrying client.response_unreadable, as any success that is not its route's answer does. A subclass built elsewhere passes a problem to the constructor, and every error, the PipelineRequestError that make_argument_invalid_error raises for a refused argument included, ends str(exc) on the problem's next step, on a line of its own.
  • ApiResponseError reads every answer as a problem by its code (Breaking): a failed answer raises ApiResponseError carrying the runtime's problem document, with status and retry_after filled from the answer when the body leaves them out, and an answer that is no problem document reads as client.outcome_unknown when it is a 5xx on execute or start, where a gateway may stand in front of a run that started, as the problem its status names for 503 on a route that creates nothing and for 405 on any route, and else as client.response_unreadable. A success whose body is not the route's answer reads as client.response_unreadable on a route that creates nothing, and on execute or start, where the runtime accepted the request and the run may exist, as client.outcome_unknown, naming the run as its pipeline_run_id when the body gives the run's id as a non-empty string; an execute or start answer whose pipeline_run_id is empty names no run, so it reads as client.outcome_unknown naming none, as a 202 on execute does. Neither raises a pydantic or JSON error, and str(exc) then quotes the start of the body the server sent, except a missing_blobs success's, whose upload URLs carry the permission to write and which only response_body keeps. An error body is decoded refusing NaN, Infinity, a number past the range of a double and nesting deeper than MAX_BODY_NESTING (512 levels, checked before parsing), and reads an integral number such as 2.0 as the integer 2, as a JavaScript client reads it, while a success body is decoded from its bytes as Response.json() decodes it (decode_success_json): strictly as UTF-8, so that a body that is not UTF-8 is unreadable rather than read with its bytes replaced, refusing NaN and Infinity, and otherwise within Python's own limits, so that a run's output nested deeper or holding an integer past a double's range reads whole and its numbers stay as written, a pipe output's 10.0 reaching the caller as a float. The members type_uri, title, instance, server_message, error_type, error_domain, retryable, user_action and validation_errors are gone, read from exc.problem instead, and so are ProblemDocument and UserAction, while request_id stays, the problem's own request_id member or else the X-Request-ID header; mthds.runners.api.problem.read_error_answer reads an answer as an AnswerReading, its problem and whether that problem is the body's own, as mthds.protocol.problem.answers.read_answer does, and the protected _raise_api_response_error receives the problem and problem_from_body.
  • A request that gets no answer raises ApiTransportError (Breaking): httpx's transport and decoding exceptions no longer escape a route; the request raises ApiTransportError, carrying client.unreachable when no request left, client.timeout when none came back in time, and on execute and start client.outcome_unknown once the request has left, since the run may exist. An answer whose body cannot be read, such as one whose content encoding cannot be decoded, is no usable answer either, whatever its status: it raises ApiTransportError carrying client.outcome_unknown on execute and start and client.unreachable on any other route, as the TypeScript client reads it. The client never repeats a request by itself.
  • ClientNotConfiguredError replaces ClientAuthenticationError (Breaking): the client raises it, a PipelineRequestError carrying client.not_configured and the setting, when no API key or base URL resolves at construction, when the API key holds a character an HTTP header cannot carry, such as a line break or a space at its end, which httpx would refuse to write at every request, when the base URL does not make a valid URL or does not start with http:// or https://, or when request_timeout_seconds is set to anything but an int or a float, never a bool, holding a finite number of seconds a float can hold, never negative, each reading as a setting to fix rather than as an unreachable runtime to retry; the key is never quoted, and neither is a user:password@ written in the base URL, which this error's message and client.unreachable name without its userinfo, query and fragment.
  • The validate verdict's items are problem items (Breaking): InvalidValidationReport.errors replaces validation_errors, each fault a ProblemItem with its code, detail, params, location and suggested_fix, both arms carry advisory warnings in the same schema, and the invalid arm's message is optional; the reports are generic over the item type, and ValidationDiagnostic is gone.

šŸ¤– Generated with Claude Code

https://claude.ai/code/session_01MTPBJkbpj7cQMqEfePgfDU


Summary by cubic

Promotes dev to main for the v0.25.0 release: bumps the version to 0.25.0 and implements the MTHDS standard 8.0.0 and Protocol 2.0.0, in which every error is a problem document. This is a breaking release.

Breaking changes

  • PipelineRequestError now requires a problem; every error this package raises carries one under a registered code.
  • ApiResponseError reads any answer as a problem by code; run routes that get a 202 naming no run, or an unreadable success, raise client.outcome_unknown.
  • Requests that get no usable answer raise ApiTransportError (client.unreachable, client.timeout, or client.outcome_unknown) instead of leaking httpx exceptions.
  • ClientAuthenticationError is replaced by ClientNotConfiguredError, carrying client.not_configured.
  • A validate verdict's validation_errors become errors of ProblemItems; ProblemDocument and UserAction are removed.
  • A manifest's mthds_version is now evaluated against 8.0.0, so ^7.0.0, ~7.0.0, 7.*, and 7.0.0 no longer pass.

New

  • Vendors the core error registry 8.0.0 and generates mthds.protocol.problem.registry: a constant (CoreCode) and typed parameters model per code, strict JsonInteger/JsonNumber reading, and a make check-error-registry gate that fails when the vendored files, declared version, and generated module disagree.
  • Problem and ProblemItem read documents as received, keeping undeclared members on model_extra.
  • BlobUploadError now carries problems too: an object store's refusal, an unrequested blob in a missing_blobs answer, or an upload target the client cannot send to.