Skip to content

fix: make failed-post retry work — enum status mismatch - #33

Merged
Ooscaar merged 1 commit into
developfrom
fix/failed-post-retry-enum-mismatch
Jul 31, 2026
Merged

fix: make failed-post retry work — enum status mismatch#33
Ooscaar merged 1 commit into
developfrom
fix/failed-post-retry-enum-mismatch

Conversation

@Ooscaar

@Ooscaar Ooscaar commented Jul 31, 2026

Copy link
Copy Markdown
Member

Summary

Fixes zernio-dev/zernio-claude-plugin#1: the MCP retry path never recognized a failed post, so there was no working way to retry one — users had to delete and recreate.

Two bugs conspired:

  1. posts_retry guard never matched. The post's status deserializes into a codegen'd plain Enum with an unstable positional name (Status10 in the released build, renumbered on every spec regen), while the guard compared against the handwritten PostStatus str-enum. Two different enum classes never compare equal in Python, so every failed post was rejected with is not in failed status (current: Status10.FAILED).
  2. posts_retry_all_failed / posts_list_failed queried with a mangled filter. PostStatus.FAILED was passed through to httpx, which serializes params via str() — sending status=PostStatus.FAILED instead of status=failed. The API matched nothing, so the tools reported "No failed posts to retry".

Changes

Single commit on top of develop (branch was rebuilt and squashed; the OAuth discovery work previously on this branch is already in develop as d88b72c):

  • codegen: add --use-subclass-enum to generate_models.py — generated enums are now (str, Enum), so members compare equal to their plain value and to the PostStatus twin (models regenerated; mixin-only diff, no renames).
  • resources: unwrap Enum members to .value in _build_params / _build_payload — in the generator template (each generated resource carries its own shadowing copy) and in the handwritten BaseResource. Fixes every enum filter SDK-wide, e.g. the documented client.posts.list(status=PostStatus.FAILED).
  • mcp: posts_retry compares plain status values and reports the clean value (current: scheduled) in the warning — robust even if codegen flags change.
  • tests: unit tests pin enum unwrapping + value-compatibility; test_mcp_retry_regression.py drives the real MCP tools against a strict in-memory fake API (httpx.MockTransport, no network) that only matches the literal status=failed.

Testing

  • Full suite: 184 passed, 14 skipped
  • The regression tests, run against the unfixed code, fail with the exact error messages from the issue (is not in failed status (current: Status7.FAILED) / No failed posts to retry.) and pass with the fix; one test asserts status=failed is literally on the wire. ✅
  • No public API changes: all 45 curated model re-exports verified by the generation script; wire values are byte-for-byte what the API always expected.

Consumer impact

No breaking changes. Enum-filtered list calls that silently returned wrong results now return correct ones, post.status == "failed" now behaves intuitively, and .value access is unchanged.

Follow-up (out of scope)

Root-cause cleanup in the API repo: name the post status as components/schemas/PostStatus in the OpenAPI spec so codegen stops emitting unstable StatusN names and the handwritten twin enum can be retired.

🤖 Generated with Claude Code

@Ooscaar
Ooscaar force-pushed the fix/failed-post-retry-enum-mismatch branch from 9300612 to 2d99db3 Compare July 31, 2026 09:05
@Ooscaar Ooscaar changed the title fix(mcp): retry failed posts by comparing status by value, not enum identity fix: make failed-post retry work — enum status mismatch Jul 31, 2026
@Ooscaar
Ooscaar force-pushed the fix/failed-post-retry-enum-mismatch branch 3 times, most recently from d8cf278 to 84d680d Compare July 31, 2026 14:18
…e-plugin#1)

The MCP retry path never recognized a failed post. Two bugs conspired:

1. posts_retry compared the post's status — a generated plain Enum with an
   unstable positional name (Status10 in the released build, renumbered on
   every spec regen) — against the handwritten PostStatus str-enum. Two
   different enum classes never compare equal, so every failed post was
   rejected with 'is not in failed status (current: Status10.FAILED)'.

2. posts_retry_all_failed / posts_list_failed passed PostStatus.FAILED into
   the query string, where httpx serialized it via str() as
   'status=PostStatus.FAILED' instead of 'status=failed', so the API
   matched nothing and the tools reported no failed posts.

Fixes:
- codegen: add --use-subclass-enum so generated enums are (str, Enum) and
  compare equal to their plain value and to the PostStatus twin
  (models regenerated).
- resources: unwrap Enum members to .value in _build_params/_build_payload —
  in the generator template (each generated resource carries its own copy
  that shadows BaseResource) and in the handwritten BaseResource
  (resources regenerated).
- mcp: posts_retry guard compares plain status values and reports the clean
  value ('current: scheduled') in the warning.
- tests: unit tests pin enum unwrapping and value-compatibility;
  test_mcp_retry_regression.py drives the real MCP tools against a strict
  in-memory fake API (httpx.MockTransport, no network) that only matches
  the literal status=failed — both bugs reproduce exactly against the
  unfixed code with the same error messages as the issue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Ooscaar
Ooscaar force-pushed the fix/failed-post-retry-enum-mismatch branch from 84d680d to 33632d9 Compare July 31, 2026 14:28
@Ooscaar
Ooscaar merged commit 752fa0f into develop Jul 31, 2026
4 checks passed
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.

posts_retry / posts_retry_all_failed never recognize failed posts (Status10.FAILED enum mismatch)

1 participant