Skip to content

Add OpenAPI specification for public API endpoints (closes #944)#1175

Open
yanyishuai wants to merge 1 commit into
ramimbo:mainfrom
yanyishuai:fix/issue-944-openapi-client
Open

Add OpenAPI specification for public API endpoints (closes #944)#1175
yanyishuai wants to merge 1 commit into
ramimbo:mainfrom
yanyishuai:fix/issue-944-openapi-client

Conversation

@yanyishuai

@yanyishuai yanyishuai commented Jun 28, 2026

Copy link
Copy Markdown

Summary

This PR adds an OpenAPI 3.0.3 specification for MergeWork public API endpoints, addressing #944 (MRWK bounty: 200 MRWK - public API and OpenAPI client contract completion).

Changes

  • Add docs/openapi.yaml with OpenAPI 3.0.3 specification
  • Document key public POST endpoints: /api/accounts, /api/claims, /api/transfers, /api/bounty-attempts, /api/proposals
  • Add request/response schemas with validation rules (e.g., amount_mrwk with minimum: 1)
  • Add error response schemas
  • Add security scheme (Bearer JWT)

Why This Helps

  • Clients: Can generate SDKs using OpenAPI generators (e.g., @openapitools/openapi-generator)
  • Agents: Can call MergeWork API safely without source-code inspection
  • Maintainers: Have a contract to validate against

Next Steps

This is an initial specification. Feedback welcome on:

  1. Additional endpoints to document
  2. Schema improvements
  3. Response examples

Bounty Claim

  • Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE
  • GitHub: @yanyishuai

Summary by CodeRabbit

  • Documentation
    • Added a comprehensive OpenAPI 3.1 specification for the MergeWork service, including API and UI routes plus contract schemas.
  • Chores
    • Added a command-line tool to export the live API specification to a YAML file.
  • Tests
    • Added a test to verify all documented OpenAPI paths match the application’s /openapi.json, including required contract anchors.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yanyishuai, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 44c03516-cab7-4be7-abba-12d3f5ecb81d

📥 Commits

Reviewing files that changed from the base of the PR and between 70883fb and 000c6ec.

📒 Files selected for processing (3)
  • docs/openapi.yaml
  • scripts/export_openapi.py
  • tests/test_docs_openapi_yaml.py
📝 Walkthrough

Walkthrough

Adds a generated OpenAPI 3.1.0 specification for the MergeWork service, an executable exporter that writes the specification, and tests that compare documented paths with the live FastAPI schema.

Changes

MergeWork OpenAPI documentation

Layer / File(s) Summary
OpenAPI export script
scripts/export_openapi.py
Generates the FastAPI OpenAPI document, injects production, legacy-compatible, and local servers, and writes YAML to the selected output path.
Generated API specification
docs/openapi.yaml
Documents authentication, health, bounty, treasury, account, wallet, transfer, ledger, proof, activity, MCP, UI, webhook, and admin routes, along with request, response, and validation schemas.
Specification synchronization checks
tests/test_docs_openapi_yaml.py
Compares documented paths with the application’s live OpenAPI paths and verifies required contract paths are present.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description has a summary and change list, but it misses the template's Evidence, Test Evidence, and MRWK sections. Add the missing Evidence, Test Evidence checklist, and MRWK/related issue section, and fill in the required bullets.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding an OpenAPI specification for public API endpoints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 35977757-ef81-4eda-8b86-bb22a2ae2d33

📥 Commits

Reviewing files that changed from the base of the PR and between 3bc87d2 and ebf1972.

📒 Files selected for processing (1)
  • docs/openapi.yaml

Comment thread docs/openapi.yaml Outdated
Comment thread docs/openapi.yaml Outdated
Comment thread docs/openapi.yaml Outdated

@prettyboyvic prettyboyvic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Findings:

  • [P1] docs/openapi.yaml documents /api/accounts, /api/claims, /api/transfers, /api/bounty-attempts, and /api/proposals, but the app's generated OpenAPI does not expose those routes. On this PR head, the relevant public routes are /api/v1/wallets/register, /api/v1/wallets/link-github, /api/v1/github/claim, /api/v1/transfers, /api/v1/bounties/{bounty_id}/attempts, and /api/v1/treasury/proposals. Since docs/api-examples.md already points users to $API_HOST/openapi.json and /api/docs, adding a divergent static spec here will send generated clients to 404s instead of the implemented API.

  • [P1] The transfer operation does not match the implemented /api/v1/transfers contract. app/wallet_api.py requires from_address, to_address, amount_mrwk, nonce, and signature_hex before calling submit_wallet_transfer, while this schema only accepts recipient and numeric amount_mrwk. Existing coverage in tests/test_openapi_request_bodies.py also asserts the signed-transfer fields. A client generated from this spec would be unable to submit a valid wallet transfer.

  • [P1] The treasury proposal schema is not the server contract. The implemented route is POST /api/v1/treasury/proposals and its OpenAPI request body requires action and payload; this new spec publishes /api/proposals with title, description, and requested_mrwk. SDKs generated from this file would serialize proposal requests that the FastAPI handler rejects.

Validation: checked current PR head ebf1972b3f7b1e8045f1539be25be7aab4d59bed; ran .\.venv\Scripts\python.exe -m pytest tests/test_openapi_request_bodies.py -q (9 passed, 1 warning).

@qingfeng312 qingfeng312 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed current head ebf1972b3f7b1e8045f1539be25be7aab4d59bed.

This is not merge-ready. The new docs/openapi.yaml appears to describe placeholder routes rather than the current MergeWork public API: it uses paths such as POST /api/accounts, POST /api/claims, POST /api/transfers, POST /api/bounty-attempts, and POST /api/proposals, plus a production server of https://mergework.example.com. The live app routes and existing OpenAPI helpers use the /api/v1/... surface and concrete route contracts, so generated clients from this file would call endpoints that do not match the application.

Please regenerate this spec from the actual FastAPI app or align every documented path, server URL, request schema, response schema, and auth requirement with the current route definitions, and add a regression check that parses the YAML and verifies the documented paths exist in the app OpenAPI output.

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 Follow-up on #944 — OpenAPI public API contract PR remains open on ebf1972b3f7b (mergeable=clean).

Ready for maintainer review/merge when bandwidth allows.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

@yanyishuai
yanyishuai force-pushed the fix/issue-944-openapi-client branch from ebf1972 to 70883fb Compare July 16, 2026 13:52
@yanyishuai

Copy link
Copy Markdown
Author

Addressed review feedback on 70883fb0

@prettyboyvic @qingfeng312 ? thanks for the P1 findings. The placeholder docs/openapi.yaml is replaced with a regeneration from create_app().openapi() so documented paths match the live FastAPI surface.

Changes on current head:

  • Regenerated docs/openapi.yaml from the app OpenAPI document (52 paths), including /api/v1/wallets/register, /api/v1/wallets/link-github, /api/v1/github/claim, /api/v1/transfers (signed transfer fields), /api/v1/bounties/{bounty_id}/attempts, and /api/v1/treasury/proposals
  • Production servers now point at https://api.mrwk.online / https://api.mrwk.ltclab.site (not mergework.example.com)
  • Added scripts/export_openapi.py so maintainers can re-export after route changes
  • Added tests/test_docs_openapi_yaml.py regression: every YAML path must exist in /openapi.json, plus anchors for the previously drifted contracts

Local: pytest tests/test_docs_openapi_yaml.py -q ? passed.

Please re-review when convenient.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE
Bounty #944

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/openapi.yaml`:
- Line 1: Align the OpenAPI dialect declared by the `openapi` version with the
schema nullability syntax throughout `docs/openapi.yaml`: either replace every
`nullable: true` usage with the equivalent JSON Schema null union for OpenAPI
3.1.0, or change the declaration to OpenAPI 3.0.x and regenerate the
specification consistently.

In `@scripts/export_openapi.py`:
- Line 1: Normalize the exporter and generated specification: in
scripts/export_openapi.py, remove the leading UTF-8 BOM, apply Ruff formatting,
and update its output-writing logic to use open(..., newline="\n"); in
tests/test_docs_openapi_yaml.py, remove the leading BOM and apply Ruff
formatting; regenerate or normalize docs/openapi.yaml to LF line endings
throughout.
- Around line 27-29: Update the OpenAPI export flow around create_app() so
documentation generation cannot connect to or mutate the configured application
database. Instantiate the app with an isolated temporary database configuration,
or use a side-effect-free OpenAPI app factory if one exists, while preserving
the existing spec = app.openapi() behavior.
- Line 9: Add ROOT to sys.path in scripts/export_openapi.py before the from
app.main import create_app import, using the existing ROOT symbol so direct
execution from a checkout can resolve the app package.

In `@tests/test_docs_openapi_yaml.py`:
- Around line 48-58: Extend the regression coverage in the OpenAPI documentation
test to assert the exact generated server URLs for both production and legacy
server contracts. Use the exporter’s existing server URL symbols or expected
values, and keep the current endpoint path assertions unchanged.
- Around line 43-46: Update the OpenAPI synchronization test around the existing
missing-path assertion to also detect application paths absent from the
documented YAML. Compare both app_paths and documented in the test, preserving
the current sorted, descriptive failure behavior so additions and deletions both
fail.
- Around line 34-41: Update test_docs_openapi_yaml_paths_exist_in_app_openapi to
pass the sqlite_url argument as database_url when calling create_app(), ensuring
the TestClient uses the temporary test database instead of the environment or
default database.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1ae205f9-92eb-4b24-b404-d5bd0d4d6f30

📥 Commits

Reviewing files that changed from the base of the PR and between ebf1972 and 70883fb.

📒 Files selected for processing (3)
  • docs/openapi.yaml
  • scripts/export_openapi.py
  • tests/test_docs_openapi_yaml.py

Comment thread docs/openapi.yaml Outdated
@@ -0,0 +1,2201 @@
openapi: 3.1.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

rg -n '^\s*nullable:\s*true\s*$' docs/openapi.yaml
rg -n -C3 '\bnullable\b' app scripts tests 2>/dev/null || true

Repository: ramimbo/mergework

Length of output: 6734


🏁 Script executed:

#!/bin/bash
set -eu

printf '\n## file stats\n'
wc -l docs/openapi.yaml
file docs/openapi.yaml || true

printf '\n## nullable/security/status samples\n'
sed -n '500,650p' docs/openapi.yaml | cat -n
printf '\n## security entries\n'
rg -n '^\s*security:\s*$|^\s*security:\s*\[' docs/openapi.yaml
printf '\n## response status codes near bounty-attempt\n'
rg -n -C 4 'bounty-attempt|responses:|^\s*[0-9]{3}:' docs/openapi.yaml | sed -n '1,120p'

Repository: ramimbo/mergework

Length of output: 6795


🏁 Script executed:

#!/bin/bash
set -eu

printf '\n## file stats\n'
wc -l docs/openapi.yaml
file docs/openapi.yaml || true

printf '\n## nullable/security/status samples\n'
sed -n '500,650p' docs/openapi.yaml | cat -n

printf '\n## security entries\n'
rg -n '^\s*security:\s*$|^\s*security:\s*\[' docs/openapi.yaml

printf '\n## response status codes near bounty-attempt\n'
rg -n -C 4 'bounty-attempt|responses:|^\s*[0-9]{3}:' docs/openapi.yaml | sed -n '1,120p'

Repository: ramimbo/mergework

Length of output: 6795


🏁 Script executed:

#!/bin/bash
set -eu

printf '\n## security scheme declarations\n'
rg -n -C 2 'securitySchemes|^\s*security:\s*$|^\s*security:\s*\[' docs/openapi.yaml || true

printf '\n## endpoints around lines 480-580\n'
sed -n '480,580p' docs/openapi.yaml | cat -n

printf '\n## endpoint around line 630\n'
sed -n '620,650p' docs/openapi.yaml | cat -n

printf '\n## 201/409 occurrences near bounty-attempt\n'
rg -n -C 2 "'201'|'409'|bounty-attempts" docs/openapi.yaml | sed -n '1,120p'

Repository: ramimbo/mergework

Length of output: 6367


Use a single OpenAPI dialect here. docs/openapi.yaml is declared as OpenAPI 3.1.0, but it still uses nullable: true in multiple schemas. Switch those fields to JSON Schema null unions, or keep the spec on 3.0.x before regenerating it.

🧰 Tools
🪛 Checkov (3.3.8)

[high] 1-2203: Ensure that the global security field has rules defined

(CKV_OPENAPI_4)


[high] 1-2203: Ensure that security operations is not empty.

(CKV_OPENAPI_5)

🪛 YAMLlint (1.37.1)

[error] 1-1: wrong new line character: expected \n

(new-lines)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/openapi.yaml` at line 1, Align the OpenAPI dialect declared by the
`openapi` version with the schema nullability syntax throughout
`docs/openapi.yaml`: either replace every `nullable: true` usage with the
equivalent JSON Schema null union for OpenAPI 3.1.0, or change the declaration
to OpenAPI 3.0.x and regenerate the specification consistently.

Comment thread scripts/export_openapi.py Outdated
@@ -0,0 +1,45 @@
#!/usr/bin/env python3

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Normalize encoding and line endings so required quality checks pass.

CI reports Ruff failures for both Python files and YAMLlint reports CRLF throughout the generated specification. The exporter’s leading BOM also precedes its shebang, breaking reliable direct execution.

  • scripts/export_openapi.py#L1-L1: remove the UTF-8 BOM and run Ruff formatting.
  • scripts/export_openapi.py#L35-L39: write through open(..., newline="\n") so Windows regeneration still emits LF.
  • tests/test_docs_openapi_yaml.py#L1-L1: remove the UTF-8 BOM and run Ruff formatting.
  • docs/openapi.yaml#L1-L2201: regenerate or normalize the document to LF line endings.

As per coding guidelines, “Format code using ruff format --check . to ensure consistent code formatting.”

🧰 Tools
🪛 GitHub Actions: CI / 0_Quality, readiness, docs, and image checks.txt

[error] 1-1: ruff format --check failed. File would be reformatted by Ruff.

🪛 GitHub Actions: CI / Quality, readiness, docs, and image checks

[error] 1-1: ruff format --check failed. File would be reformatted by Ruff 'format' (run 'ruff format scripts/export_openapi.py' to fix).

📍 Affects 3 files
  • scripts/export_openapi.py#L1-L1 (this comment)
  • scripts/export_openapi.py#L35-L39
  • tests/test_docs_openapi_yaml.py#L1-L1
  • docs/openapi.yaml#L1-L2201
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/export_openapi.py` at line 1, Normalize the exporter and generated
specification: in scripts/export_openapi.py, remove the leading UTF-8 BOM, apply
Ruff formatting, and update its output-writing logic to use open(...,
newline="\n"); in tests/test_docs_openapi_yaml.py, remove the leading BOM and
apply Ruff formatting; regenerate or normalize docs/openapi.yaml to LF line
endings throughout.

Sources: Coding guidelines, Linters/SAST tools, Pipeline failures

Comment thread scripts/export_openapi.py
import argparse
from pathlib import Path

ROOT = Path(__file__).resolve().parents[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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

fd -HI '^(pyproject\.toml|setup\.py|setup\.cfg)$' \
  -x sh -c 'echo "== $1 =="; sed -n "1,220p" "$1"' sh {}

rg -n -C3 \
  'export_openapi|scripts/export_openapi\.py|console_scripts|project\.scripts' \
  README.md docs scripts 2>/dev/null || true

Repository: ramimbo/mergework

Length of output: 1082


🏁 Script executed:

#!/bin/bash
set -eu

printf '== scripts/export_openapi.py ==\n'
sed -n '1,220p' scripts/export_openapi.py

printf '\n== package tree ==\n'
git ls-files 'app/**' 'scripts/**' 'README.md' | sed -n '1,200p'

printf '\n== import references ==\n'
rg -n 'import app\.main|from app\.main|export_openapi|openapi' app scripts README.md docs tests 2>/dev/null || true

Repository: ramimbo/mergework

Length of output: 13419


🏁 Script executed:

#!/bin/bash
set -eu

nl -ba scripts/export_openapi.py | sed -n '1,220p'

Repository: ramimbo/mergework

Length of output: 191


🏁 Script executed:

#!/bin/bash
set -eu

if [ -f scripts/export_openapi.py ]; then
  nl -ba scripts/export_openapi.py | sed -n '1,120p'
else
  echo "missing scripts/export_openapi.py"
fi

Repository: ramimbo/mergework

Length of output: 191


🏁 Script executed:

#!/bin/bash
set -eu

printf '== project entry points ==\n'
python3 - <<'PY'
from pathlib import Path
text = Path("pyproject.toml").read_text(encoding="utf-8")
for needle in ["[project.scripts]", "[project.gui-scripts]", "console_scripts", "export_openapi"]:
    print(f"{needle}: {needle in text}")
PY

printf '\n== script path/import path probe ==\n'
python3 - <<'PY'
import os, sys
from pathlib import Path

repo = Path.cwd()
script = repo / "scripts" / "export_openapi.py"

# Simulate direct execution from checkout by a filename: sys.path[0] becomes script dir.
simulated_sys_path0 = str(script.parent)
print("repo_root:", repo)
print("script_dir:", script.parent)
print("repo_root_has_app:", (repo / "app" / "main.py").is_file())
print("script_dir_has_app:", (script.parent / "app" / "main.py").is_file())
print("would_import_app_from_script_dir:", (script.parent / "app").exists())
print("sys.path[0]_when_running_by_filename:", simulated_sys_path0)
PY

printf '\n== launcher references ==\n'
rg -n -C2 'export_openapi|openapi.yaml|project\.scripts|console_scripts|scripts/export_openapi\.py' README.md docs pyproject.toml scripts tests 2>/dev/null || true

Repository: ramimbo/mergework

Length of output: 2966


Make scripts/export_openapi.py work from a checkout
Add the repo root to sys.path before from app.main import create_app; pyproject.toml doesn’t define a console script, so running this file directly will fail to import app.main.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/export_openapi.py` at line 9, Add ROOT to sys.path in
scripts/export_openapi.py before the from app.main import create_app import,
using the existing ROOT symbol so direct execution from a checkout can resolve
the app package.

Comment thread scripts/export_openapi.py
Comment on lines +27 to +29
from app.main import create_app

spec = create_app().openapi()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not generate documentation against the configured application database.

create_app() runs create_schema() and ensure_genesis() against the settings database. Running this exporter can therefore mutate a production-configured database. Pass an isolated temporary database or expose a side-effect-free OpenAPI app factory.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/export_openapi.py` around lines 27 - 29, Update the OpenAPI export
flow around create_app() so documentation generation cannot connect to or mutate
the configured application database. Instantiate the app with an isolated
temporary database configuration, or use a side-effect-free OpenAPI app factory
if one exists, while preserving the existing spec = app.openapi() behavior.

Comment on lines +34 to +41
def test_docs_openapi_yaml_paths_exist_in_app_openapi(sqlite_url: str) -> None:
del sqlite_url
assert OPENAPI_YAML.is_file(), "docs/openapi.yaml must exist"
documented = _paths_from_openapi_yaml(OPENAPI_YAML.read_text(encoding="utf-8"))
assert documented, "docs/openapi.yaml must document at least one path"

client = TestClient(create_app())
app_paths = set(client.get("/openapi.json").json().get("paths", {}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

fd -HI '^conftest\.py$' \
  -x rg -n -C8 '\bsqlite_url\b' {}

rg -n -C5 '\bcreate_app\s*\(' tests

Repository: ramimbo/mergework

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -eu

printf '\n== tests/test_docs_openapi_yaml.py ==\n'
sed -n '1,120p' tests/test_docs_openapi_yaml.py

printf '\n== tests/conftest.py ==\n'
sed -n '1,80p' tests/conftest.py

printf '\n== app/main.py create_app slice ==\n'
rg -n -C6 'def create_app|database_url|webhook_secret' app/main.py

Repository: ramimbo/mergework

Length of output: 3477


🏁 Script executed:

#!/bin/bash
set -eu

printf '\n== app/main.py outline ==\n'
ast-grep outline app/main.py --view expanded | sed -n '1,220p'

printf '\n== app/main.py create_app body ==\n'
sed -n '1,260p' app/main.py

printf '\n== settings/search ==\n'
rg -n -C4 'MERGEWORK|database_url|webhook_secret|sqlite:///|create_schema|ensure_genesis' app

Repository: ramimbo/mergework

Length of output: 47762


🏁 Script executed:

#!/bin/bash
set -eu

echo '== app/main.py create_app symbol locations =='
rg -n '^(def create_app|class Settings|`@lru_cache`|def get_settings|database_url|webhook_secret)' app/main.py app/*.py app/**/*.py tests/conftest.py

echo '== app/main.py relevant slice =='
sed -n '1,220p' app/main.py

Repository: ramimbo/mergework

Length of output: 8267


🏁 Script executed:

#!/bin/bash
set -eu

echo '== autouse fixtures in tests =='
rg -n -C3 '`@pytest`\.fixture\(.*autouse=True|autouse=True' tests

echo '== database/url env handling in tests =='
rg -n -C3 'MERGEWORK_DATABASE_URL|DATABASE_URL|database_url|setenv\(' tests/conftest.py tests

Repository: ramimbo/mergework

Length of output: 187


Pass database_url=sqlite_url into create_app() here. create_app() otherwise uses MERGEWORK_DATABASE_URL or the default app database, so this test can write schema/genesis data outside the temp test database.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_docs_openapi_yaml.py` around lines 34 - 41, Update
test_docs_openapi_yaml_paths_exist_in_app_openapi to pass the sqlite_url
argument as database_url when calling create_app(), ensuring the TestClient uses
the temporary test database instead of the environment or default database.

Comment on lines +43 to +46
missing = sorted(documented - app_paths)
assert not missing, (
"docs/openapi.yaml documents paths missing from app OpenAPI: " + ", ".join(missing)
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Check for undocumented application paths as well.

This only validates documented ⊆ app_paths; deleting a route from the YAML still passes. Compare both directions so the test enforces the claimed synchronization.

Proposed fix
     missing = sorted(documented - app_paths)
     assert not missing, (
         "docs/openapi.yaml documents paths missing from app OpenAPI: " + ", ".join(missing)
     )
+
+    undocumented = sorted(app_paths - documented)
+    assert not undocumented, (
+        "App OpenAPI paths missing from docs/openapi.yaml: " + ", ".join(undocumented)
+    )
📝 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
missing = sorted(documented - app_paths)
assert not missing, (
"docs/openapi.yaml documents paths missing from app OpenAPI: " + ", ".join(missing)
)
missing = sorted(documented - app_paths)
assert not missing, (
"docs/openapi.yaml documents paths missing from app OpenAPI: " + ", ".join(missing)
)
undocumented = sorted(app_paths - documented)
assert not undocumented, (
"App OpenAPI paths missing from docs/openapi.yaml: " + ", ".join(undocumented)
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_docs_openapi_yaml.py` around lines 43 - 46, Update the OpenAPI
synchronization test around the existing missing-path assertion to also detect
application paths absent from the documented YAML. Compare both app_paths and
documented in the test, preserving the current sorted, descriptive failure
behavior so additions and deletions both fail.

Comment thread tests/test_docs_openapi_yaml.py Outdated
Comment on lines +48 to +58
# Contract anchors that previously drifted in placeholder specs
for required in (
"/api/v1/wallets/register",
"/api/v1/wallets/link-github",
"/api/v1/github/claim",
"/api/v1/transfers",
"/api/v1/bounties/{bounty_id}/attempts",
"/api/v1/treasury/proposals",
):
assert required in documented
assert required in app_paths

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Add regression coverage for the injected server URLs.

The exporter’s production and legacy server contract can change or disappear while this test remains green. Assert the exact generated server URLs.

As per coding guidelines, “Add or update tests for changed behavior.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_docs_openapi_yaml.py` around lines 48 - 58, Extend the regression
coverage in the OpenAPI documentation test to assert the exact generated server
URLs for both production and legacy server contracts. Use the exporter’s
existing server URL symbols or expected values, and keep the current endpoint
path assertions unchanged.

Source: Coding guidelines

@yanyishuai
yanyishuai force-pushed the fix/issue-944-openapi-client branch from 70883fb to 85c44b8 Compare July 18, 2026 08:41
@yanyishuai

Copy link
Copy Markdown
Author

Follow-up: ruff-format fix on 85c44b8e

@prettyboyvic @qingfeng312 — CI previously failed only on ruff format --check for the new export helper/test. Both files are now ruff-formatted on head 85c44b8e.

The regenerated docs/openapi.yaml still mirrors create_app().openapi() (/api/v1/... contracts, real API hosts). Please recheck when convenient.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE
Bounty #944

Reformat the assert message wrapping to satisfy ruff format --check
under the repo pyproject line-length=100 setting.
@yanyishuai
yanyishuai force-pushed the fix/issue-944-openapi-client branch from 85c44b8 to 000c6ec Compare July 18, 2026 08:45
@yanyishuai

Copy link
Copy Markdown
Author

Format fix follow-up (000c6ec6)

@qingfeng312 @prettyboyvic ? previous CI fail was ruff wrapping under line-length=100. Head 000c6ec6 reformats the assert to the expected style.

Please recheck when the quality job goes green.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE
Bounty #944

@yanyishuai

Copy link
Copy Markdown
Author

CI green re-review (000c6ec6)

@prettyboyvic @qingfeng312 — previous CHANGES_REQUESTED were on old head ebf1972b3f (placeholder OpenAPI paths).

Current head 000c6ec6:

  • docs/openapi.yaml regenerated from create_app().openapi() (/api/v1/... contracts)
  • real API hosts (api.mrwk.online / api.mrwk.ltclab.site)
  • regression test + export helper
  • Quality CI: success, mergeable=clean

Please re-approve when convenient.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE
Bounty #944

@yanyishuai

Copy link
Copy Markdown
Author

@prettyboyvic @qingfeng312 Please re-approve current head 000c6ec66d — prior CR was on placeholder-spec SHA ebf1972b3f.

Current head regenerates docs/openapi.yaml from FastAPI, CI success, mergeable=clean.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE
Bounty #944

@yanyishuai

Copy link
Copy Markdown
Author

@prettyboyvic @qingfeng312 Please re-approve current head 000c6ec66d — prior CR was on placeholder-spec SHA ebf1972b3f.

Current head regenerates docs/openapi.yaml from FastAPI, CI success, mergeable=clean.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE
Bounty #944

@yanyishuai

Copy link
Copy Markdown
Author

Re-review request on 000c6ec.

OpenAPI regenerated from FastAPI; path regression test added; CI green on current SHA. Previous CHANGES_REQUESTED targeted an older placeholder commit — please re-review latest.

Ready for re-approval when convenient.

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.

3 participants