Skip to content

fix(release): restore the MCP Registry marker and make gate failures diagnosable - #264

Merged
harishquantamix merged 1 commit into
masterfrom
cr-mcp-marker-public
Sep 23, 2026
Merged

harishquantamix merged 1 commit into
masterfrom
cr-mcp-marker-public

Conversation

@quantamixsol

Copy link
Copy Markdown
Owner

Two release-path fixes found auditing the v0.84.1 merge

Neither is a regression from #263 — both were already broken and were surfaced by auditing the merge.


1. MCP Registry ownership marker — the wrong README

Publishing to the MCP Registry has failed since 0.84.0 with HTTP 400:

registry validation failed for package 0 (graqle): PyPI package 'graqle' ownership validation failed. The server name 'io.github.quantamixsol/graqle' must appear as 'mcp-name: io.github.quantamixsol/graqle' in the package README

Root cause: the marker lives in README.md, but pyproject.toml:23 sets readme = "README_PYPI.md". The registry reads the PyPI long_description, not the GitHub README, so the published artifact never carried the marker. CR-README-01 repointed pyproject.readme and did not carry the marker across; 0.83.0 published fine, 0.84.0 was the first failure.

The marker was simply in the wrong file. Fixed by adding it to README_PYPI.md — a 2-line diff, CRLF preserved.

Verified in the built artifact, not the source: graqle-0.84.1-py3-none-any.whl METADATA now contains the marker, which is precisely what the registry reads.

Ports tests/test_packaging/test_mcp_name_marker_in_pypi_readme.py from private master. It asserts against the pyproject.readme pointer rather than a hard-coded filename — the defect was a pointer move silently invalidating an assumption about which file ships, so pinning the filename would miss the next repoint. It also cross-checks the marker against server.json and keeps README.md's copy.

Guard proven: removing the marker makes it fail; restoring makes it pass.

This unblocks the registry publish on the next v* tag.


2. Release-gate failures were undiagnosable

Release Gate (PyPI) is red on every PR. Both provider-exception handlers logged only type(exc).__name__ — no message, no traceback — so the cause stayed unknown across multiple releases.

Now logger.exception(... %r, exc): the operator log carries type, message and traceback.

The verdict object is deliberately unchanged. It is user-facing and the module's IP-redaction contract requires it stay free of internal detail. The log and the verdict have opposite requirements; the new test asserts both, so neither can be satisfied by breaking the other.

Guard proven: reverting to the old logging makes the new test fail.

Not included, deliberately

Making the gate fail closed (WARNBLOCK) on internal error. Research asked for it and it is the right end state, but it flips a governance contract pinned by four existing tests and documented as the module's "never-crash" behaviour. Changing what a gate does to a release needs an explicit decision with Research naming the semantics — does a timeout block a release, is there an override path — not a drive-by edit. This PR makes the failures diagnosable, which is the prerequisite for deciding that on evidence.


🔴 Blocked on the private PR (ABSOLUTE RULE #0)

The release-gate fix has a private counterpart: quantamixsol/research-development-graqle PR #354. Private has the identical defect, so the fix must land there first or the repos drift.

Do not merge this PR until #354 is merged. The MCP marker half is already a port of merged private work (c80f4ab7).


Verification

Check Result
ip-content-gate (4 paths) PASS
trade-secret-wheel-gate --check-monetisation PASS
lint-imports (AC-21) 1 kept, 0 broken
sync_manifest_versions.py 0.84.1 --check all 5 at 0.84.1
tests/test_release_gate + tests/test_packaging 92 passed, 1 skipped
ruff 27 on branch vs 27 on base — no new lint debt
marker in built wheel METADATA True

🤖 Generated with Claude Code

…diagnosable

Two independent release-path defects found while auditing the v0.84.1 merge.
Both are ports of work already on private master, or fixes to public-only gaps.

1. MCP REGISTRY OWNERSHIP MARKER (blocks every registry publish)

   Publishing to the MCP Registry has failed since 0.84.0 with HTTP 400:
   "PyPI package 'graqle' ownership validation failed. The server name must
   appear as 'mcp-name: io.github.quantamixsol/graqle' in the package README".

   Root cause: the marker lives in README.md, but pyproject.toml sets
   readme = "README_PYPI.md". The registry reads the PyPI long_description,
   not the GitHub README, so the published artifact never carried it. The
   marker was in the wrong file.

   Fixed by adding it to README_PYPI.md (CRLF preserved; the diff is 2 lines).
   VERIFIED IN THE BUILT ARTIFACT: graqle-0.84.1-py3-none-any.whl METADATA
   now contains the marker, which is what the registry actually reads.

   Ports tests/test_packaging/test_mcp_name_marker_in_pypi_readme.py from
   private. It asserts against the pyproject readme POINTER rather than a
   hard-coded filename, because the defect was a pointer move silently
   invalidating an assumption about which file ships. Proven by removing the
   marker: the guard fails, then passes once restored.

2. RELEASE GATE FAILURES WERE UNDIAGNOSABLE

   Release Gate (PyPI) has been red on every PR. Both provider-exception
   handlers logged only type(exc).__name__ -- no message, no traceback -- so
   every failure read as a bare class name and the cause stayed unknown across
   multiple releases.

   Now logger.exception with %r, so the operator log carries type, message and
   traceback. The verdict object is deliberately NOT changed: it is
   user-facing and the module's IP-redaction contract requires it stay free of
   internal detail. The two surfaces have opposite requirements and the new
   test asserts both -- exception text present in the log, absent from the
   verdict JSON.

   Proven: reverting to the old logging makes the new test fail.

NOT INCLUDED, deliberately: making the gate fail CLOSED (WARN -> BLOCK) on
internal error. Research asked for it, and it is the right end state, but it
flips a governance contract pinned by four existing tests and documented as
the module's "never-crash" behaviour. Changing what a gate does to a release
needs an explicit decision, not a drive-by edit. Raised separately.

Verified: 92 passed / 1 skipped across test_release_gate + test_packaging.
TS scan on the diff: clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🛡️ GraQle PR Guardian

💥 Blast Radius: 4 modules affected

Module Files Changed Risk Level Impact Radius
README_PYPI.md 1 🟡 T2 1
graqle 1 🟡 T2 1
tests 2 🟢 T1 2

Total blast radius: 4


🏛️ Governance Verdict

⚠️ WARN

  • T2: Advisory warnings detected. Review recommended.

🔍 SHACL Violations

No SHACL violations detected.


🔐 Approval Requirements

This PR requires approval from: T2

  • A Senior Engineer or above must approve.

Approval requirement NOT yet satisfied.


Metric Value
Blast Radius 4
Files Analyzed 4
Blocked 0
SHACL Violations 0
Verdict WARN

🔬 Powered by GraQle PR Guardian v0.1.0 · Scan completed 2026-09-23T14:35:50.851832+00:00

@harishquantamix
harishquantamix merged commit 52e6166 into master Sep 23, 2026
19 of 20 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.

2 participants