Release v0.5.0#10
Conversation
Minor bump for the structured error responses landed in #9. Version is minor rather than patch because the error wire format is a client-visible behavior change: tool failures now raise ToolError with a JSON envelope (code, message, retryable, suggestion, help_url) and isError=true at the MCP protocol level, rather than returning human-readable strings. Clients keying off isError get proper failure signaling for the first time; clients pattern-matching the old text format ("[!] ... failed:") will need to update. Files touched: - pyproject.toml: 0.4.1 → 0.5.0 - server.json: both version fields bumped (top-level + pypi package) - uv.lock: re-resolved via ``uv lock`` - CHANGELOG.md: 0.5.0 entry documenting the change, the new ErrorCode enum / HELP_URLS registry / docs/error-codes.md drift test, the errno.ENOSPC fix, the unavailable retryable consistency fix, and the new system-module test coverage Local verification on release/v0.5.0: - uv run pytest -q: 312 passed, 94 deselected - uv run ruff check src/ tests/: clean - uv run ruff format --check src/ tests/: clean - uv run mypy src/: no issues found in 27 source files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Adding QA Active — beginning release verification. Will check version consistency across pyproject.toml/server.json/uv.lock, CHANGELOG.md categories, and re-run pytest/ruff/mypy fresh in this session before signoff. |
cmeans
left a comment
There was a problem hiding this comment.
QA Review — Release v0.5.0
Verdict: QA Failed — single substantive finding on a non-standard CHANGELOG category (### Dev). Otherwise the release is well-formed and ready to ship.
Verification (fresh in this session, commit 9722e0e)
- pytest:
312 passed, 94 deselected, 7 warnings in 16.12s(matches PR #9 final state) - ruff check: All checks passed!
- ruff format --check: 62 files already formatted
- mypy src/: Success: no issues found in 27 source files
Version consistency (verified across all 4 files)
| File | Field | Value |
|---|---|---|
pyproject.toml |
[project] version |
0.5.0 ✓ |
server.json |
top-level version |
0.5.0 ✓ |
server.json |
packages[0].version |
0.5.0 ✓ |
uv.lock |
name = "mcp-synology" → version |
0.5.0 ✓ (line 729) |
Minor bump from 0.4.1 → 0.5.0 is correctly justified — the wire format for tool failures is a client-visible behavior change, which is exactly what a minor (rather than patch) bump signals under SemVer.
Findings
1. [substantive] Non-standard ### Dev CHANGELOG category
CHANGELOG.md:39 introduces a ### Dev heading under the 0.5.0 entry. Per the repo convention I have on file, CHANGELOG entries must use only standard Keep a Changelog categories: Added, Changed, Deprecated, Removed, Fixed, Security. Dev is custom and was flagged as such in a prior review (Improved was the previous offender).
The content under the heading is internal metadata that doesn't really belong in a user-facing changelog at all:
### Dev
- Tests: 270 → 312 (+42, including a new tests/modules/system/ package …)
- Patch coverage: 100% on the structured-errors diff per codecov
- mypy --strict clean across all 27 source files
- ruff check / ruff format --check cleanSuggested fix (any of these works):
- (a) Delete the section. Test counts, coverage stats, and tooling status are CI/PR-description concerns, not changelog entries that operators upgrading from 0.4.1 → 0.5.0 need to read.
- (b) Fold the genuinely user-relevant bit (test count growth) into the existing Added section as a one-line note about the new system-module test coverage — that part is real Added work.
I'd recommend (a) — keep the changelog focused on what changes for consumers of mcp-synology, not internal metrics.
Pre-existing observation (not blocking, not in this PR's diff)
The 0.4.1 entry at CHANGELOG.md:48 uses ### Fixes rather than the standard ### Fixed. That's pre-existing — not introduced by this PR — so I'm not flagging it as a Round 1 finding, but worth bundling into a future cleanup PR if you want full Keep-a-Changelog conformance throughout the file.
CI status
All required checks green:
lint— SUCCESStypecheck— SUCCESStest (3.11)— SUCCESStest (3.12)— SUCCESStest (3.13)— SUCCESSqa-approved(QA Gate) — SUCCESSon-push— SUCCESS
Test plan checkboxes
Most of the test plan's items I can verify here, but two are post-merge actions (PyPI publish, manual smoke test with Claude Desktop) that are out of scope for QA:
- CI green — verified above
-
uv run pytest: 312 passed, 94 deselected — re-verified locally in this session -
uv run ruff check: clean — re-verified -
uv run ruff format --check: clean — re-verified -
uv run mypy src/: 27 files clean — re-verified - PyPI publish post-merge — out of QA scope, owner-verified after tag
- Manual smoke test post-publish — out of QA scope, owner-verified after PyPI propagates
Summary
Once ### Dev is removed (or its content is folded into ### Added), this is a clean release. PR #9's full test suite passes locally, version numbers are consistent across all four files, and the migration note for clients is well-written.
|
QA audit — Round 1 complete Release verification done. One substantive finding (non-standard Test results (fresh in this session, commit 9722e0e):
Version consistency verified across pyproject.toml, server.json (both fields), and uv.lock — all 0.5.0. Applying QA Failed as the final act. One CHANGELOG.md edit and we're clear. |
QA finding: ``### Dev`` is not a Keep a Changelog category. Standard categories are Added, Changed, Deprecated, Removed, Fixed, Security. Took option (a) from the QA suggestion — delete the section rather than fold its content into Added. Internal metrics (test count deltas, patch coverage percentages, mypy/ruff status) are CI and PR-description concerns, not consumer-facing changelog entries. Operators upgrading from 0.4.1 → 0.5.0 don't need to read them; they care about behavior changes and the migration note, which are already covered under Changed/Added/Fixed. Also fixed the pre-existing ``### Fixes`` → ``### Fixed`` typo in the 0.4.1 entry. QA noted it as a non-blocking pre-existing observation; folding it into this release PR per the project's "any nits should be addressed" convention rather than leaving it for a future cleanup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Round 1 response — both items addressedFinding #1 (substantive) — Non-standard `### Dev` CHANGELOG categoryRemoved. Took option (a) from the QA suggestion — delete the section rather than fold it into `### Added`. Internal metrics (test count deltas, patch coverage percentages, mypy/ruff status) are CI and PR-description concerns, not consumer-facing changelog entries. Operators upgrading 0.4.1 → 0.5.0 don't need to read them; they care about the behavior change and migration note, which are already covered under `Changed`/`Added`/`Fixed`. Pre-existing observation — `### Fixes` vs `### Fixed` in 0.4.1Also fixed. QA flagged this as non-blocking and pre-existing, but per the project's "any nits should be addressed" convention I folded it into this release PR rather than leaving it for a future cleanup. One-character change to the 0.4.1 entry. Verified locally on the new commit
CHANGELOG.md now uses only Keep a Changelog standard categories throughout (for 0.5.0 and the newly-corrected 0.4.1). Ready for QA Round 2 / Signoff. |
cmeans
left a comment
There was a problem hiding this comment.
QA Review — Round 2 (Release v0.5.0)
Verdict: Ready for QA Signoff. Single Round 1 finding resolved cleanly, plus a thoughtful bonus fix.
Round 1 finding — resolved
Non-standard ### Dev CHANGELOG category: Fixed. The 0.5.0 entry now uses only standard Keep a Changelog categories — Changed, Added, Fixed. The internal-metadata bullets (test counts, coverage stats, mypy/ruff status) were removed entirely, which is the cleaner of the two options I suggested.
Bonus fix (beyond the ask)
I flagged the pre-existing ### Fixes heading on the 0.4.1 entry as a non-blocking observation in Round 1, noting it was outside this PR's diff. Dev fixed it anyway: CHANGELOG.md:41 now reads ### Fixed. The whole file is now Keep-a-Changelog conformant, not just the new entry.
Verification (fresh in this session, commit 170356)
- pytest:
312 passed, 94 deselected, 7 warnings in 16.73s - ruff check: All checks passed!
- ruff format --check: 62 files already formatted
- mypy src/: Success: no issues found in 27 source files
- All CI checks SUCCESS (lint, typecheck, test 3.11/3.12/3.13, qa-approved, on-push)
Version consistency (re-verified)
Unchanged since Round 1 — 0.5.0 consistent across pyproject.toml, server.json (top-level + packages[0]), and uv.lock line 729.
Summary
Two-round release. Findable substantive issues: 1. Resolved: 1. Bonus cleanup: 1. CHANGELOG is now fully Keep-a-Changelog conformant front to back.
Applying Ready for QA Signoff as the final act. Awaiting maintainer for QA Approved + tag/merge.
|
QA audit — Round 2 complete (clean) Round 1 Test results (fresh in this session, commit 170356):
Applying Ready for QA Signoff as the final act. Awaiting maintainer for QA Approved + tag/merge. |
Summary
Minor version bump (0.4.1 → 0.5.0) to ship the structured error envelope work merged in #9. Minor rather than patch because the wire format for tool failures is a client-visible behavior change.
What's in 0.5.0
The headline change is #9 — structured error responses with JSON envelopes:
ToolErrorwith a JSON envelope (code,message,retryable,suggestion,help_url) andisError=trueat the MCP protocol level.ErrorCode(StrEnum);error_response(code: ErrorCode)is typed so call-site typos are mypy errors.docs/error-codes.md— a new 12-section reference with root causes, fix steps, and explicit retryability statements.tests/core/test_help_urls.py) enforcesErrorCode↔HELP_URLS↔ docs consistency in both directions.Plus fixes landed alongside #9:
unavailablecode now usesretryable=Trueconsistently acrosssystem/info.pyandsystem/utilization.py(previously disagreed).download_fileOSError fallback useserrno.ENOSPCinstead of locale-dependent substring matching, and now emitsdisk_full/retryable=True consistently with the pre-flight branch.json.dumps(default=str)safety on the error path so a non-serializablevalueargument can't crash the error handler itself.New test coverage:
tests/modules/system/test_info.pyandtest_utilization.py— those modules previously had no unit tests (13% coverage), now at 99–100%.modules/filestation/module (metadata, operations, search, listing, transfer).See CHANGELOG.md for the full entry.
Behavior change — migration note for clients
The wire format for tool failures has changed. Before: tool returned text like
[!] List files failed: No such file or directory. After: tool raises withisError=true, body is a JSON envelope.isErrornow get correct failure signaling for the first time (previously every failure looked like a success with error text).error.messagefor a cleaner presentation.[!] ... failed:string format will need to update.Every code has a
help_urlpointing atdocs/error-codes.md#<code>, so the envelope is self-describing for both humans and automated tools.Files touched
pyproject.toml— version 0.4.1 → 0.5.0server.json— both version fields (top-level + PyPI package)uv.lock— re-resolvedCHANGELOG.md— 0.5.0 entryTest plan
uv run pytest: 312 passed, 94 deselected — verified locallyuv run ruff check: clean — verified locallyuv run ruff format --check: clean — verified locallyuv run mypy src/: 27 files clean — verified locally🤖 Generated with Claude Code