Skip to content

Add typed OpenAPI schemas for public read APIs#699

Open
xyjk0511 wants to merge 2 commits into
ramimbo:mainfrom
xyjk0511:codex/647-688-openapi-schemas
Open

Add typed OpenAPI schemas for public read APIs#699
xyjk0511 wants to merge 2 commits into
ramimbo:mainfrom
xyjk0511:codex/647-688-openapi-schemas

Conversation

@xyjk0511
Copy link
Copy Markdown
Contributor

@xyjk0511 xyjk0511 commented May 31, 2026

Related bounty or issue

Bounty: #647
Source issue: #688

Summary

This PR adds typed OpenAPI response models for the public MRWK read APIs called out in #688, without changing payout, ledger, wallet, proof, treasury execution, or bounty acceptance behavior.

Covered public read surfaces:

  • GET /api/v1/status
  • GET /api/v1/bounties
  • GET /api/v1/bounties/{bounty_id}
  • GET /api/v1/bounties/summary
  • GET /api/v1/treasury/proposals
  • GET /api/v1/activity
  • GET /api/v1/accounts/{account}
  • GET /api/v1/accounts/{account}/accepted-work
  • GET /api/v1/proofs/{proof_hash}

The models use extra="allow" and the routes use response_model_exclude_unset=True so additive public fields remain possible and list/detail JSON shapes are not padded with default-only fields.

Verification

  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest tests\test_openapi_public_schemas.py -q -> 2 passed
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest -q -> 562 passed
  • python -m ruff format .
  • python -m ruff check .
  • git diff --check
  • Seeded route smoke test exercises the scoped public read routes and validates real response serialization, including a pre-execution treasury proposal path.
  • OpenAPI smoke check confirmed the scoped routes use component refs such as BountyResponse, SystemStatusResponse, TreasuryProposalResponse, ActivityResponse, AccountAcceptedWorkResponse, and ProofResponse.

Not tested

  • python -m mypy app is blocked in this local environment before this change can be isolated: PySide6 stubs report invalid disable_error_code values, and the existing codebase reports FastAPI Request generic type errors across multiple modules.

Summary by CodeRabbit

  • New Features

    • Structured response models applied to public read endpoints for consistent, typed JSON.
    • API responses now omit unset/unused fields for cleaner payloads.
  • Bug Fixes

    • Terminal bounty detail responses retain accepted-awards data; bounty listing entries omit accepted-awards as expected.
  • Tests

    • Added integration tests validating OpenAPI response schemas and endpoint payloads.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5b89894a-0c23-4dff-a723-9d10df38e11f

📥 Commits

Reviewing files that changed from the base of the PR and between 1b4c74b and 4fbf1ee.

📒 Files selected for processing (1)
  • tests/test_bounty_api_routes.py

📝 Walkthrough

Walkthrough

This PR adds Pydantic response models for public API outputs, applies them to multiple FastAPI GET endpoints with response_model_exclude_unset=True, and adds OpenAPI + runtime tests to verify the exposed schemas and runtime responses.

Changes

Public API Response Schema Typing

Layer / File(s) Summary
Response schema definitions and base configuration
app/api_schemas.py
Introduces PublicApiModel base with extra="allow" and defines response models for system status, treasury proposals/challenges, bounties, activity, accepted work, accounts, and proofs.
Apply schemas to route endpoints
app/main.py, app/bounty_api.py, app/treasury_routes.py, app/activity.py, app/accounts.py
Route decorators and imports updated to declare response_model and response_model_exclude_unset=True for endpoints: /api/v1/status, /api/v1/proofs/{proof_hash}, /api/v1/bounties*, /api/v1/treasury/proposals*, /api/v1/activity, and /api/v1/accounts/{account}*.
OpenAPI schema contract validation and test updates
tests/test_openapi_public_schemas.py, tests/test_bounty_api_routes.py
Adds OpenAPI helper utilities and two tests: one resolving /openapi.json response schemas and asserting expected properties, one that seeds DB and asserts runtime responses; updates bounty test to check accepted_awards present in detail but omitted from list responses.

Possibly related issues

Possibly related PRs

  • ramimbo/mergework#388: Related extraction/registration of the account routes that now receive typed response models.
  • ramimbo/mergework#295: Related to accepted-work payload on account endpoints and prior shape changes.
  • ramimbo/mergework#393: Related changes around the bounty API routes that now declare typed response models.
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly and concretely names the main change: adding typed OpenAPI schemas for public read APIs, which aligns with the primary objective of the PR.
Description check ✅ Passed Description covers the summary, scope, verification steps, and known limitations. Uses bounty/issue references and documents test evidence comprehensively.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Mergework Public Artifact Hygiene ✅ Passed PR adds typed OpenAPI schemas for read endpoints with no investment, price, cash-out, payout guarantee, or security disclosure claims; purely technical schema and route type safety changes.
Bounty Pr Focus ✅ Passed PR diff matches scope: 8 files with 15 response models, 9 typed endpoints, tests added. Bounty focus maintained—only public read API serialization, no behavior changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1e3407f4-02f9-4524-9b1d-e5c7ca165b7f

📥 Commits

Reviewing files that changed from the base of the PR and between 6cd957c and a038fe0.

📒 Files selected for processing (7)
  • app/accounts.py
  • app/activity.py
  • app/api_schemas.py
  • app/bounty_api.py
  • app/main.py
  • app/treasury_routes.py
  • tests/test_openapi_public_schemas.py

Comment thread tests/test_openapi_public_schemas.py
Add typed response models for the public MRWK read surfaces called out by accepted proposed-work ramimbo#688, then bind those models to the existing FastAPI routes without changing payout, ledger, proof, wallet, or treasury behavior. Add seeded public-route smoke coverage so the response models are proven against real payload serialization, not only OpenAPI component names.

Constraint: Bounty ramimbo#647 requires a focused PR anchored to accepted proposed-work; ramimbo#688 requested typed OpenAPI response schemas for public read APIs.

Rejected: Manual OpenAPI schema dictionaries | would avoid response validation but would not produce stable component refs.

Rejected: Schema-only test coverage | would not catch response_model validation failures on real seeded payloads.

Confidence: high

Scope-risk: moderate

Directive: Keep these models additive and public-read only; do not use this layer to change runtime payout or ledger semantics.

Tested: PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest tests\\test_openapi_public_schemas.py -q -> 2 passed; PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest -q -> 562 passed; python -m ruff format .; python -m ruff check .; git diff --check.

Not-tested: python -m mypy app is blocked in this environment by PySide6 stub disable_error_code errors and existing FastAPI Request generic errors outside this change.
@xyjk0511 xyjk0511 force-pushed the codex/647-688-openapi-schemas branch from a038fe0 to 91130eb Compare May 31, 2026 16:40
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e722554a-ed00-457c-815a-1d19656d5aa8

📥 Commits

Reviewing files that changed from the base of the PR and between a038fe0 and 91130eb.

📒 Files selected for processing (7)
  • app/accounts.py
  • app/activity.py
  • app/api_schemas.py
  • app/bounty_api.py
  • app/main.py
  • app/treasury_routes.py
  • tests/test_openapi_public_schemas.py

Comment on lines +136 to +138
bounties_response = client.get("/api/v1/bounties")
assert bounties_response.status_code == 200
assert bounties_response.json()[0]["pending_payout_awards"] == 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add an assertion that proves response_model_exclude_unset=True actually omits unset fields.

The runtime test confirms 200s and present fields but never proves the omission behavior, which is the change's whole point. accepted_awards is populated only on the detail route (api_bounty), so the list payload should not carry it. Asserting its absence here locks in exclude_unset and guards against a future regression to response_model_exclude_unset=False.

💚 Proposed assertion
     bounties_response = client.get("/api/v1/bounties")
     assert bounties_response.status_code == 200
-    assert bounties_response.json()[0]["pending_payout_awards"] == 1
+    assert bounties_response.json()[0]["pending_payout_awards"] == 1
+    # exclude_unset: detail-only fields must stay out of the list payload
+    assert "accepted_awards" not in bounties_response.json()[0]

As per coding guidelines for tests/**: focus on whether tests prove the changed behavior and include regression cases where relevant.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bounties_response = client.get("/api/v1/bounties")
assert bounties_response.status_code == 200
assert bounties_response.json()[0]["pending_payout_awards"] == 1
bounties_response = client.get("/api/v1/bounties")
assert bounties_response.status_code == 200
assert bounties_response.json()[0]["pending_payout_awards"] == 1
# exclude_unset: detail-only fields must stay out of the list payload
assert "accepted_awards" not in bounties_response.json()[0]

xyjk0511 pushed a commit to xyjk0511/mergework that referenced this pull request May 31, 2026
Constraint: PR ramimbo#699 had a CodeRabbit bounty-focus warning asking for explicit response_model_exclude_unset coverage.\nRejected: Changing API serialization code | existing behavior was correct and only lacked a regression assertion.\nConfidence: high\nScope-risk: narrow\nDirective: Keep accepted_awards detail-only unless the public list contract intentionally changes.\nTested: PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest tests\\test_bounty_api_routes.py -q; python -m ruff check tests\\test_bounty_api_routes.py; python -m ruff format --check tests\\test_bounty_api_routes.py\nNot-tested: Full repository test suite not rerun for this test-only assertion update.
@xyjk0511
Copy link
Copy Markdown
Contributor Author

xyjk0511 commented May 31, 2026

Follow-up pushed in 4fbf1ee to address the CodeRabbit bounty-focus note.

What changed:

  • detail responses now have explicit assertions for accepted_awards
  • list responses now assert accepted_awards is omitted for both paid and closed bounty rows

Verified locally:

  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest tests\test_bounty_api_routes.py -q -> 9 passed
  • python -m ruff check tests\test_bounty_api_routes.py -> passed
  • python -m ruff format --check tests\test_bounty_api_routes.py -> passed

Constraint: PR ramimbo#699 had a CodeRabbit bounty-focus warning asking for explicit response_model_exclude_unset coverage.
Rejected: Changing API serialization code | existing behavior was correct and only lacked a regression assertion.
Confidence: high
Scope-risk: narrow
Directive: Keep accepted_awards detail-only unless the public list contract intentionally changes.
Tested: PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest tests\\test_bounty_api_routes.py -q; python -m ruff check tests\\test_bounty_api_routes.py; python -m ruff format --check tests\\test_bounty_api_routes.py
Not-tested: Full repository test suite not rerun for this test-only assertion update.
@xyjk0511 xyjk0511 force-pushed the codex/647-688-openapi-schemas branch from 1b4c74b to 4fbf1ee Compare May 31, 2026 17:25
Copy link
Copy Markdown
Contributor

@Gwani-28 Gwani-28 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed PR #699 at current head 4fbf1eea1ec47108bb1e0098d2f01ee69e1ba9d3.

No blocker found in this review.

Scope checked:

  • Inspected the new app/api_schemas.py response models and the route registrations in app/main.py, app/bounty_api.py, app/treasury_routes.py, app/activity.py, and app/accounts.py.
  • Confirmed the response models are additive/documentation-oriented, use extra="allow", and keep the existing serializer payload shape intact for current public API consumers.
  • Checked that list/detail bounty schema behavior is intentional: list responses omit detail-only accepted_awards, while detail responses still expose accepted award proof rows.
  • Confirmed account, accepted-work, activity, proof, treasury proposal, bounty summary, and status endpoints are all covered by OpenAPI schema assertions plus seeded runtime response checks.
  • Rechecked the follow-up test updates that prove response_model_exclude_unset=True keeps detail-only fields out of list bounty rows.

Validation run locally:

  • .venv/bin/python -m pytest tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py tests/test_api_mcp.py tests/test_bounty_api.py tests/test_public_routes.py tests/test_bounty_pages.py tests/test_account_routes.py tests/test_activity_routes.py tests/test_activity.py tests/test_treasury_proposals.py -q -> 176 passed, 1 warning.
  • .venv/bin/ruff check app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -> passed.
  • .venv/bin/ruff format --check app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -> passed, 8 files already formatted.
  • .venv/bin/python scripts/docs_smoke.py -> docs smoke ok.
  • git diff --check origin/main...HEAD -> clean.
  • git merge-tree --write-tree origin/main HEAD -> clean tree fbc9548bbab88940f654b79a9588b3dc225c2405.
  • Hosted quality/readiness check was green at review time.

The PR looks merge-ready from the public API schema and backwards-compatibility angle.

Copy link
Copy Markdown
Contributor

@JONASXZB JONASXZB left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 4fbf1eea1ec47108bb1e0098d2f01ee69e1ba9d3.

No blockers found; approving from the public read OpenAPI schema and runtime-compatibility angle.

Evidence checked:

  • inspected app/api_schemas.py plus route wiring in app/main.py, app/bounty_api.py, app/treasury_routes.py, app/activity.py, and app/accounts.py;
  • confirmed the new response models cover the #688 public read surfaces without changing runtime serializers, and use extra="allow" plus response_model_exclude_unset=True so additive public fields can still pass through;
  • confirmed bounty list/detail behavior keeps list rows lean while detail rows can expose accepted_awards;
  • confirmed the seeded response-model test exercises status, bounty list/detail/summary, treasury proposals, activity, account accepted-work, and proof responses;
  • checked current remote status: CodeRabbit succeeded and the hosted Quality/readiness/docs/image check succeeded.

Validation run locally:

  • /Users/jonas/Downloads/microfix-leads/mergework/.venv/bin/python -m pytest tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -q -> 11 passed, 1 existing Starlette/httpx warning
  • /Users/jonas/Downloads/microfix-leads/mergework/.venv/bin/ruff check app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -> passed
  • /Users/jonas/Downloads/microfix-leads/mergework/.venv/bin/ruff format --check app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -> 8 files already formatted
  • /Users/jonas/Downloads/microfix-leads/mergework/.venv/bin/python scripts/docs_smoke.py -> docs smoke ok
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean tree 23edfd538b3586dbd0391c4603d6242b4bc967fa

Copy link
Copy Markdown
Contributor

@attaboy11 attaboy11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 4fbf1eea1ec47108bb1e0098d2f01ee69e1ba9d3 against current origin/main 05faf1f89932d59f2935e83b71fc42ffef363c7f as a non-author.

Blocker: this PR is currently dirty against main and needs a rebase/merge conflict pass before it can be merged safely. The OpenAPI schema work still passes in isolation, but current-base integration is blocked.

Evidence checked:

  • GitHub reports mergeStateStatus: DIRTY; hosted Quality/readiness/docs/image check is successful.
  • Merge-base is 6cd957c0f0a9dd29da03a03ec75eac46fc402b2e.
  • git merge-tree origin/main origin/pr-699 exits 1 and reports content conflicts in app/bounty_api.py and app/treasury_routes.py.
  • Focused PR-head verification passes: /Users/mycomputo/Documents/Codex/2026-05-31/goal-goal-find-and-execute-legitimate/work/repos/mergework/.venv/bin/python -m pytest tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -q -> 11 passed, 1 warning in 0.71s.
  • Targeted Ruff check and format check pass for app/api_schemas.py, app/main.py, app/bounty_api.py, app/treasury_routes.py, app/activity.py, app/accounts.py, tests/test_openapi_public_schemas.py, and tests/test_bounty_api_routes.py.
  • git diff --check origin/main...origin/pr-699 passes.

Please rebase or merge current main, resolve app/bounty_api.py and app/treasury_routes.py, then rerun the focused OpenAPI/bounty API tests above. I did not find an isolated test/lint blocker in the PR head; this request is specifically for the current dirty merge state.

Copy link
Copy Markdown
Contributor

@keilogic keilogic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 4fbf1eea1ec47108bb1e0098d2f01ee69e1ba9d3 against current origin/main at 6d324f048319a84cf4b9972d31e6cb81cd4ba036.

Requesting changes because the branch is now materially stale against the current base. git merge-tree origin/main HEAD exits non-zero with content conflicts in:

  • app/accounts.py
  • app/activity.py
  • app/bounty_api.py
  • app/treasury_routes.py

Branch-local validation still passes:

  • pytest tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -q -> 11 passed, 1 warning
  • ruff check app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py
  • ruff format --check app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py
  • mypy app
  • python scripts/docs_smoke.py
  • git diff --check origin/main...HEAD

Hosted Quality/readiness/docs/image and CodeRabbit checks are green for this head. I did not find an isolated PR-head test/lint blocker; the remaining issue is rebasing and resolving the expanded current-main conflicts before merge.

@ramimbo
Copy link
Copy Markdown
Owner

ramimbo commented Jun 2, 2026

Maintainer queue pass 2026-06-02: holding only as a possible future #777 candidate if the branch is refreshed and the scope is still useful. #647 is exhausted, this branch is dirty against current main, and current reviews request changes for mergeability/stale base. If #777 opens, rebase or reopen a focused PR, retarget to Bounty #777, and get fresh current-head review evidence before maintainer acceptance. No accepted/paid labels now.

@ramimbo ramimbo added the mrwk:needs-info More information needed label Jun 2, 2026
Copy link
Copy Markdown
Contributor

@alan747271363-art alan747271363-art left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 4fbf1eea1ec47108bb1e0098d2f01ee69e1ba9d3 against current origin/main d7e9b530fffe as a non-author review for #838.

Requesting changes because the public-read OpenAPI schema work still validates on the branch head, but the PR remains blocked by current-main content conflicts in app/accounts.py, app/activity.py, app/bounty_api.py, and app/treasury_routes.py.

Evidence checked:

  • inspected app/api_schemas.py and route wiring in app/main.py, app/bounty_api.py, app/treasury_routes.py, app/activity.py, and app/accounts.py;
  • confirmed the schema tests still cover public read surfaces and bounty list/detail behavior while leaving runtime serializer output compatibility intact;
  • checked GitHub state: mergeStateStatus=DIRTY, mergeable=CONFLICTING; hosted Quality/readiness/docs/image and CodeRabbit checks are successful on this head.

Validation on this exact head:

  • .\.venv\Scripts\python.exe -m pytest tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -q -> 11 passed, 1 existing Starlette/httpx warning.
  • .\.venv\Scripts\python.exe -m ruff check app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -> passed.
  • .\.venv\Scripts\python.exe -m ruff format --check app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py tests/test_openapi_public_schemas.py tests/test_bounty_api_routes.py -> 8 files already formatted.
  • .\.venv\Scripts\python.exe -m mypy app/accounts.py app/activity.py app/api_schemas.py app/bounty_api.py app/main.py app/treasury_routes.py -> success.
  • .\.venv\Scripts\python.exe scripts/docs_smoke.py -> docs smoke ok.
  • git diff --check origin/main...HEAD -> clean.
  • git merge-tree --write-tree $(git rev-parse origin/main) HEAD -> failed with content conflicts in app/accounts.py, app/activity.py, app/bounty_api.py, and app/treasury_routes.py.

Suggested next step: rebase or merge current main, resolve the public-route/OpenAPI response-model conflicts while preserving response-model compatibility, then rerun the OpenAPI schema and bounty route tests plus static checks before merge.

Scope reviewed: public read API schema annotations and focused tests only. No private data, wallet material, ledger mutation, treasury/proposal execution, payout execution, admin-token operation, bridge/exchange/cash-out behavior, or MRWK price behavior was used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mrwk:needs-info More information needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants