Skip to content

docs(demo): answer errors as problems, invite as "invited", read without changing - #72

Merged
alukach merged 1 commit into
mainfrom
fix/demo-stub
Nov 6, 2026
Merged

alukach merged 1 commit into
mainfrom
fix/demo-stub

Conversation

@alukach

@alukach alukach commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

The stub fixes from the code review of demo/ (#59, #60, #69): three places where demo/stub.py answered in ways the real API doesn't, so a demo would show behaviour real users never see. The recorder fixes are in #71.

What changes

  • Errors are RFC 9457 problems. The stub answered refusals with the legacy {"error": {code, message, field_errors}} body, so demos went through ApiError::from_response's legacy branch, which real users don't hit. error() now returns a problem (type, title, status, detail, code, and errors as JSON Pointers) with Content-Type: application/problem+json. Both 409s (a taken product ID, a taken service-account ID) use it. AGENTS.md's stub section now says the same.
  • Invitations start as "invited". POST /memberships created memberships already in state "member", so a demo of member invite showed the invitee as a member straight away, and member accept couldn't be demoed. Memberships created along with a service account stay "member", which they are.
  • Reading a membership no longer changes it. /memberships/{id} ran update() for every method, so a GET bumped state_changed, and a DELETE answered 200 as if it had worked. Now only PATCH changes it, GET reads, and anything else gets the stub's usual 404 (The demo stub has no METHOD PATH).

Testing

Against the stub on a spare port:

  • POST /products/demo-org with a taken ID returns 409, application/problem+json, errors: [{"pointer": "#/product_id", "detail": "is taken"}].
  • The CLI reads that as a problem: product create demo-org/climate-grid --json (prompts off, a throwaway HOME and its own environment) prints {"error":{"code":"conflict","field_errors":{"product_id":["is taken"]},…,"type":"https://source.coop/api/problems/conflict"}} and exits 3.
  • Two GETs of a membership leave state_changed the same, and a DELETE answers 404.
  • POST /memberships answers "state": "invited".
  • The demos from chore(demo): attach demo SVGs to PRs with gh instead of hosting them #69 still record. cargo test: 165 pass. No Rust changes.

🤖 Generated with Claude Code

…ut changing

- The stub answers errors as RFC 9457 problems (application/problem+json,
  field errors as JSON Pointers), as the API does, so demos of a refusal
  go through the CLI's problem parsing rather than the legacy branch.
- POST /memberships creates an invitation in state "invited".
- /memberships/{id} changes the record only on PATCH; other methods than
  GET get the stub's 404.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Claude finished @alukach's task in 10s —— View job


✅ No blocking issues — safe to merge.

I read the diff and checked demo/stub.py for any remaining legacy {"error": …} bodies. There are none. Every refusal now goes through error(), and Handler sends application/problem+json for any status of 400 or above. I did not run the stub or the tests.

Non-blocking notes:

  • demo/stub.py:171-176: a PATCH or GET on a missing membership returns the problem 404, which is fine. A DELETE on an existing one gets the "no DELETE" 404, matching the PR description. This stub has no DELETE /memberships/{id} branch, so member revoke can't be demoed against it yet. Add the branch when a demo needs it.
  • TITLES only covers 400, 404 and 409. Any other status gets the title "Error", which is harmless for a stub.

Simplify (ponytail)

  • demo/stub.py:34: the TITLES dict could be dropped by using http.HTTPStatus(status).phrase (stdlib). That would give "Not Found", "Conflict" and so on. It changes the title casing only slightly and removes the table.

💰 Estimated review cost: $0.11 · 0m09s · 5 turns

@alukach alukach changed the title fix(demo): answer errors as problems, invite as "invited", read without changing docs(demo): answer errors as problems, invite as "invited", read without changing Nov 6, 2026
@alukach
alukach added this pull request to stack #74 November 6, 2026 22:44
@alukach
alukach merged commit 7d95e1d into main Nov 6, 2026
10 checks passed
@alukach
alukach deleted the fix/demo-stub branch November 6, 2026 22:44
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.

1 participant