python-docs-mcp-server 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/CODEOWNERS +5 -3
  2. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/ISSUE_TEMPLATE/autonomous-agent.yml +14 -7
  3. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/PULL_REQUEST_TEMPLATE/agent.md +23 -7
  4. python_docs_mcp_server-0.3.2/.github/RELEASE.md +35 -0
  5. python_docs_mcp_server-0.3.2/.github/scripts/install_publisher.sh +8 -0
  6. python_docs_mcp_server-0.3.2/.github/scripts/release_gate.py +85 -0
  7. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/workflows/ci.yml +19 -8
  8. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/workflows/codeql.yml +5 -3
  9. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/workflows/e2e.yml +29 -5
  10. python_docs_mcp_server-0.3.2/.github/workflows/product-quality.yml +63 -0
  11. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/workflows/release.yml +62 -27
  12. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/workflows/scorecard.yml +3 -3
  13. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/workflows/security.yml +4 -2
  14. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.gitignore +3 -0
  15. python_docs_mcp_server-0.3.2/.mcp.json +9 -0
  16. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/AGENT-EXECUTION-PIPELINE.md +157 -2
  17. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/AGENTS.md +20 -11
  18. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/CHANGELOG.md +41 -0
  19. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/OPENCLAW-FORGE-PROTOCOL.md +72 -51
  20. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/PKG-INFO +54 -3
  21. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/README.md +51 -0
  22. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/STRATEGIC-ROADMAP-2026-05-29.md +38 -0
  23. python_docs_mcp_server-0.3.2/benchmarks/__init__.py +1 -0
  24. python_docs_mcp_server-0.3.2/benchmarks/__main__.py +245 -0
  25. python_docs_mcp_server-0.3.2/benchmarks/adapters/__init__.py +90 -0
  26. python_docs_mcp_server-0.3.2/benchmarks/adapters/base.py +110 -0
  27. python_docs_mcp_server-0.3.2/benchmarks/adapters/claude_tokens.py +277 -0
  28. python_docs_mcp_server-0.3.2/benchmarks/adapters/context7_adapter.py +337 -0
  29. python_docs_mcp_server-0.3.2/benchmarks/adapters/deepwiki_adapter.py +206 -0
  30. python_docs_mcp_server-0.3.2/benchmarks/adapters/eligibility.py +158 -0
  31. python_docs_mcp_server-0.3.2/benchmarks/adapters/gitmcp_adapter.py +273 -0
  32. python_docs_mcp_server-0.3.2/benchmarks/adapters/google_adapter.py +78 -0
  33. python_docs_mcp_server-0.3.2/benchmarks/adapters/guard.py +160 -0
  34. python_docs_mcp_server-0.3.2/benchmarks/adapters/openai_adapter.py +78 -0
  35. python_docs_mcp_server-0.3.2/benchmarks/adapters/python_docs_mcp_adapter.py +259 -0
  36. python_docs_mcp_server-0.3.2/benchmarks/adapters/ref_tools_adapter.py +281 -0
  37. python_docs_mcp_server-0.3.2/benchmarks/corpus.py +336 -0
  38. python_docs_mcp_server-0.3.2/benchmarks/model_matrix.py +240 -0
  39. python_docs_mcp_server-0.3.2/benchmarks/regression.py +141 -0
  40. python_docs_mcp_server-0.3.2/benchmarks/report.py +828 -0
  41. python_docs_mcp_server-0.3.2/benchmarks/runner.py +758 -0
  42. python_docs_mcp_server-0.3.2/benchmarks/scoring.py +599 -0
  43. python_docs_mcp_server-0.3.2/docs/architecture/ADR-007-cache.md +185 -0
  44. python_docs_mcp_server-0.3.2/docs/architecture/ADR-008-transport.md +142 -0
  45. python_docs_mcp_server-0.3.2/docs/architecture/DESIGN.md +526 -0
  46. python_docs_mcp_server-0.3.2/docs/benchmarks/PUBLIC-BENCHMARK-METHODOLOGY.md +220 -0
  47. python_docs_mcp_server-0.3.2/docs/benchmarks/competitor-manifest.template.yml +170 -0
  48. python_docs_mcp_server-0.3.2/docs/benchmarks/corpus.schema.json +119 -0
  49. python_docs_mcp_server-0.3.2/docs/benchmarks/corpus.yml +668 -0
  50. python_docs_mcp_server-0.3.2/docs/benchmarks/model-matrix.yml +103 -0
  51. python_docs_mcp_server-0.3.2/docs/benchmarks/regression-baseline.json +479 -0
  52. python_docs_mcp_server-0.3.2/ops/vision/README.md +247 -0
  53. python_docs_mcp_server-0.3.2/ops/vision/client.py +87 -0
  54. python_docs_mcp_server-0.3.2/ops/vision/configure_apps.py +315 -0
  55. python_docs_mcp_server-0.3.2/ops/vision/control.py +808 -0
  56. python_docs_mcp_server-0.3.2/ops/vision/install.py +364 -0
  57. python_docs_mcp_server-0.3.2/ops/vision/worker_shell.py +85 -0
  58. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/pyproject.toml +2 -2
  59. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/server.json +2 -2
  60. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/sphinx_json.py +26 -1
  61. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/retrieval/ranker.py +56 -6
  62. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/content.py +3 -24
  63. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/search.py +64 -3
  64. python_docs_mcp_server-0.3.2/tests/benchmarks/fixtures/corpus.sample.yml +703 -0
  65. python_docs_mcp_server-0.3.2/tests/benchmarks/test_adapters.py +205 -0
  66. python_docs_mcp_server-0.3.2/tests/benchmarks/test_claude_tokens.py +239 -0
  67. python_docs_mcp_server-0.3.2/tests/benchmarks/test_competitor_adapters.py +1132 -0
  68. python_docs_mcp_server-0.3.2/tests/benchmarks/test_corpus_validation.py +303 -0
  69. python_docs_mcp_server-0.3.2/tests/benchmarks/test_model_matrix.py +271 -0
  70. python_docs_mcp_server-0.3.2/tests/benchmarks/test_python_docs_mcp_adapter.py +310 -0
  71. python_docs_mcp_server-0.3.2/tests/benchmarks/test_regression.py +39 -0
  72. python_docs_mcp_server-0.3.2/tests/benchmarks/test_report.py +669 -0
  73. python_docs_mcp_server-0.3.2/tests/benchmarks/test_runner.py +576 -0
  74. python_docs_mcp_server-0.3.2/tests/benchmarks/test_scoring.py +692 -0
  75. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_ingestion.py +11 -0
  76. python_docs_mcp_server-0.3.2/tests/test_release_gate.py +63 -0
  77. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_retrieval.py +109 -0
  78. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_retrieval_regression.py +3 -0
  79. python_docs_mcp_server-0.3.2/tests/test_search_spare_slot.py +167 -0
  80. python_docs_mcp_server-0.3.2/tests/test_search_symbol_fallback.py +116 -0
  81. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_services.py +2 -2
  82. python_docs_mcp_server-0.3.2/tests/test_vision_control.py +696 -0
  83. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/uv.lock +113 -110
  84. python_docs_mcp_server-0.3.0/.github/RELEASE.md +0 -115
  85. python_docs_mcp_server-0.3.0/.planning/POSITIONING.md +0 -20
  86. python_docs_mcp_server-0.3.0/.planning/ROADMAP.md +0 -23
  87. python_docs_mcp_server-0.3.0/.planning/agent-context/adr-001-source-adapters.md +0 -49
  88. python_docs_mcp_server-0.3.0/.planning/agent-context/adr-006-serialization.md +0 -55
  89. python_docs_mcp_server-0.3.0/.planning/agent-context/cpython-source-sha-pin.md +0 -78
  90. python_docs_mcp_server-0.3.0/.planning/agent-context/pyyaml-safe-loader-audit.md +0 -52
  91. python_docs_mcp_server-0.3.0/.planning/agent-context/readme-glama-six-tool-refresh.md +0 -54
  92. python_docs_mcp_server-0.3.0/.planning/agent-context/zstd-cache-codec.md +0 -71
  93. python_docs_mcp_server-0.3.0/.planning/issues/v0.3.0/00-README.md +0 -63
  94. python_docs_mcp_server-0.3.0/.planning/issues/v0.3.0/01-zstd-cache-codec.md +0 -83
  95. python_docs_mcp_server-0.3.0/.planning/issues/v0.3.0/02-readme-glama-six-tool-refresh.md +0 -59
  96. python_docs_mcp_server-0.3.0/.planning/issues/v0.3.0/03-pyyaml-safe-loader-audit.md +0 -50
  97. python_docs_mcp_server-0.3.0/.planning/issues/v0.3.0/04-adr-006-serialization.md +0 -91
  98. python_docs_mcp_server-0.3.0/.planning/issues/v0.3.0/05-adr-001-source-adapters.md +0 -76
  99. python_docs_mcp_server-0.3.0/.planning/issues/v0.3.0/06-cpython-source-sha-pin.md +0 -61
  100. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-01-data-shape-spike-PLAN.md +0 -205
  101. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-01-data-shape-spike-SUMMARY.md +0 -181
  102. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-02-result-models-PLAN.md +0 -183
  103. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-02-result-models-SUMMARY.md +0 -97
  104. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-03-compare-service-PLAN.md +0 -403
  105. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-03-compare-service-SUMMARY.md +0 -158
  106. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-04-mcp-tool-wiring-PLAN.md +0 -405
  107. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-04-mcp-tool-wiring-SUMMARY.md +0 -157
  108. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-05-user-facing-docs-PLAN.md +0 -254
  109. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-05-user-facing-docs-SUMMARY.md +0 -95
  110. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-CONTEXT.md +0 -40
  111. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-REVIEW.md +0 -240
  112. python_docs_mcp_server-0.3.0/.planning/phases/09-compare-versions/09-VERIFICATION.md +0 -120
  113. python_docs_mcp_server-0.3.0/.planning/phases/10-whatsnew/10-CONTEXT.md +0 -40
  114. python_docs_mcp_server-0.3.0/.planning/phases/11-detect-venv/11-CONTEXT.md +0 -43
  115. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.coderabbit.yaml +0 -0
  116. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.cursorignore +0 -0
  117. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/INTEGRATION-TEST.md +0 -0
  118. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/TEST-STRATEGY.md +0 -0
  119. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/.github/dependabot.yml +0 -0
  120. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/CLAUDE.md +0 -0
  121. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/CONTRIBUTING.md +0 -0
  122. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/LICENSE +0 -0
  123. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/SECURITY.md +0 -0
  124. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/docs/architecture/ADR-001-source-adapters.md +0 -0
  125. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/docs/architecture/ADR-006-serialization.md +0 -0
  126. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/docs/architecture/YAML-TRUST-BOUNDARY.md +0 -0
  127. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/glama.json +0 -0
  128. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/__init__.py +0 -0
  129. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/__main__.py +0 -0
  130. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/app_context.py +0 -0
  131. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/cache/__init__.py +0 -0
  132. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/cache/codec.py +0 -0
  133. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/data/synonyms.yaml +0 -0
  134. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/detection.py +0 -0
  135. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/diagnostics.py +0 -0
  136. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/errors.py +0 -0
  137. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/__init__.py +0 -0
  138. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/cpython_versions.py +0 -0
  139. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/inventory.py +0 -0
  140. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/publish.py +0 -0
  141. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/models.py +0 -0
  142. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/py.typed +0 -0
  143. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/retrieval/__init__.py +0 -0
  144. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/retrieval/budget.py +0 -0
  145. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/retrieval/query.py +0 -0
  146. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/server.py +0 -0
  147. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/__init__.py +0 -0
  148. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/cache.py +0 -0
  149. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/compare.py +0 -0
  150. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/observability.py +0 -0
  151. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/package_docs.py +0 -0
  152. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/persistent_cache.py +0 -0
  153. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/version.py +0 -0
  154. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/version_resolution.py +0 -0
  155. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/storage/__init__.py +0 -0
  156. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/storage/db.py +0 -0
  157. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/storage/schema.sql +0 -0
  158. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/__init__.py +0 -0
  159. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/cache/__init__.py +0 -0
  160. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/cache/test_codec.py +0 -0
  161. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/conftest.py +0 -0
  162. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/fixtures/retrieval_regression_cases.json +0 -0
  163. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/fixtures/sample_broken.fjson +0 -0
  164. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/fixtures/sample_library.fjson +0 -0
  165. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-get_docs-input.json +0 -0
  166. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-get_docs-output.json +0 -0
  167. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-list_versions-output.json +0 -0
  168. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-search_docs-input.json +0 -0
  169. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-search_docs-output.json +0 -0
  170. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_ci_workflows.py +0 -0
  171. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_compare_versions.py +0 -0
  172. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_compare_versions_spike.py +0 -0
  173. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_detection.py +0 -0
  174. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_doctor.py +0 -0
  175. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_mcp_get_docs_cache_smoke.py +0 -0
  176. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_multi_version.py +0 -0
  177. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_package_docs.py +0 -0
  178. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_packaging.py +0 -0
  179. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_persistent_docs_cache.py +0 -0
  180. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_phase1_integration.py +0 -0
  181. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_publish.py +0 -0
  182. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_schema.py +0 -0
  183. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_schema_snapshot.py +0 -0
  184. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_stability.py +0 -0
  185. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_stdio_hygiene.py +0 -0
  186. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_stdio_smoke.py +0 -0
  187. {python_docs_mcp_server-0.3.0 → python_docs_mcp_server-0.3.2}/tests/test_synonyms.py +0 -0
@@ -3,9 +3,11 @@
3
3
  # Source of truth: AGENT-EXECUTION-PIPELINE.md §2 (Forbidden Territory),
4
4
  # required by §10 (Pre-flight Checklist).
5
5
  #
6
- # For these rules to be ENFORCED, branch protection on `main` must enable
7
- # "Require review from Code Owners". CODEOWNERS alone only requests review;
8
- # branch protection only blocks merge when review rules are enabled.
6
+ # These entries retain GitHub account visibility, not a human approval gate.
7
+ # Vision owns project decisions under the 2026-10-01 pipeline amendment.
8
+ # Required PR/CI rules enforce delivery; independent agent verification is
9
+ # recorded against the current head. Do not require a self-approval from this
10
+ # shared GitHub identity or treat CODEOWNERS as an independent verification.
9
11
  #
10
12
  # Autonomous agents may NOT modify these paths without explicit Vision approval
11
13
  # (pipeline §2). Any agent PR touching them must add the `supervisor-review`
@@ -16,9 +16,9 @@ body:
16
16
  id: context
17
17
  attributes:
18
18
  label: Context (self-containment)
19
- description: Link to the per-issue context file, this pipeline doc, the roadmap, any relevant ADR or `.planning/phases/0X-*` directory, and prior related issues.
19
+ description: Include working context here or link an existing context file, the pipeline, roadmap, relevant ADRs, and related issues (2026-10-01 ownership amendment).
20
20
  value: |
21
- - Per-issue context file: `.planning/agent-context/<issue-slug>.md` (read this first)
21
+ - Working context or existing context-file link:
22
22
  - Pipeline: `AGENT-EXECUTION-PIPELINE.md`
23
23
  - Roadmap: `STRATEGIC-ROADMAP-2026-05-29.md` §<section>
24
24
  - Related issues:
@@ -41,6 +41,13 @@ body:
41
41
  - [ ] `<exact command>` <expected result>
42
42
  validations:
43
43
  required: true
44
+ - type: textarea
45
+ id: product-evidence
46
+ attributes:
47
+ label: Product evidence
48
+ description: For features include dated sources, a relevant alternative, baseline and target, non-goals, review date, and a revisit/removal condition. For repairs provide the reproduction or maintenance rationale.
49
+ validations:
50
+ required: true
44
51
  - type: textarea
45
52
  id: scope
46
53
  attributes:
@@ -68,10 +75,10 @@ body:
68
75
  description: The exact canonical gate, in order, plus any change-type-specific gates. Must pass before any PR is opened.
69
76
  value: |
70
77
  ```bash
71
- uv run ruff check src/ tests/
72
- uv run pyright src/
73
- uv run pytest --tb=short -q
74
- uv run python-docs-mcp-server doctor
78
+ uv run --locked ruff check src/ tests/ benchmarks/ ops/ .github/scripts/
79
+ uv run --locked pyright src/ benchmarks/
80
+ uv run --locked pytest --tb=short -q
81
+ uv run --locked python-docs-mcp-server doctor
75
82
  ```
76
83
  validations:
77
84
  required: true
@@ -100,7 +107,7 @@ body:
100
107
  attributes:
101
108
  label: Agent acknowledgements
102
109
  options:
103
- - label: I will work on a branch, never on `main`, and will not self-merge.
110
+ - label: I will work on a branch; Vision may merge only after separate current-head verification and required checks.
104
111
  required: true
105
112
  - label: I will stop and comment rather than silently expand scope or touch forbidden territory.
106
113
  required: true
@@ -1,6 +1,8 @@
1
1
  <!--
2
2
  Autonomous-agent PR template. Enforces AGENT-EXECUTION-PIPELINE.md §6.
3
- PR title MUST match the issue title verbatim. Never self-merge.
3
+ PR title MUST match the issue title verbatim. Implementers do not self-verify.
4
+ Vision may merge after separate current-head verification and required checks
5
+ under the 2026-10-01 ownership amendment; no human approval is required.
4
6
  -->
5
7
 
6
8
  Closes #<issue-number>
@@ -14,10 +16,10 @@ Closes #<issue-number>
14
16
  ## Validation gate output
15
17
  <!-- Paste the tail of each gate command. All must be green before opening this PR. -->
16
18
  ```text
17
- $ uv run ruff check src/ tests/
18
- $ uv run pyright src/
19
- $ uv run pytest --tb=short -q
20
- $ uv run python-docs-mcp-server doctor
19
+ $ uv run --locked ruff check src/ tests/ benchmarks/ ops/ .github/scripts/
20
+ $ uv run --locked pyright src/ benchmarks/
21
+ $ uv run --locked pytest --tb=short -q
22
+ $ uv run --locked python-docs-mcp-server doctor
21
23
  ```
22
24
  <!-- Plus any change-type-specific gates from pipeline §5 (stdio smoke,
23
25
  validate-corpus, uv lock --check) that applied to this change. -->
@@ -37,6 +39,20 @@ Pending.
37
39
 
38
40
  ## Why this triggered supervisor review
39
41
  <!-- List any pipeline §7 triggers and explain each. If none, write "None."
40
- If any fired: this PR is opened for supervisor review only; do not merge it yourself,
41
- and ensure the `supervisor-review` label is applied. -->
42
+ If any fired: apply `supervisor-review` for Vision to decide. Vision can
43
+ resolve it and merge after separate verification; delegates cannot self-merge. -->
42
44
  None.
45
+
46
+
47
+ ## Product decision and independent evidence
48
+
49
+ - Kind: feature / bugfix / maintenance / policy
50
+ - User problem or reproducible failure:
51
+ - Dated research and alternative/market comparison (features):
52
+ - Baseline → target; acceptance evidence:
53
+ - Non-goals; compatibility/security impact:
54
+ - Outcome review date and revisit/removal condition (features):
55
+ - Exact head/base SHA; independent verifier check; unresolved limitations:
56
+
57
+ <!-- Keep the corresponding pdctl decision JSON with this evidence. A label or
58
+ another agent's summary does not replace the independent check. -->
@@ -0,0 +1,35 @@
1
+ # Release process
2
+
3
+ Vision releases through the project broker after the scoped GitHub Apps are
4
+ activated (`ops/vision/README.md`). While setup is pending, release eligibility
5
+ fails closed. Do not substitute personal tokens or bypass checks.
6
+
7
+ 1. Merge the version/changelog PR after independent current-head verification
8
+ and all required CI. `pyproject.toml`, `uv.lock`, `server.json` and its package
9
+ entry must agree. CI covers Python 3.12–3.14 on Ubuntu and macOS, the real
10
+ benchmark corpus, offline full-index regression, and installed-wheel stdio.
11
+ 2. Wait for the required checks on the resulting **main commit** to pass.
12
+ 3. Run `pdctl release EXACT_MAIN_COMMIT vX.Y.Z`. The broker confirms main
13
+ ancestry, the merged PR's verifier App check, main CI and manifest versions
14
+ before creating the tag. Release tags cannot be moved or deleted.
15
+ 4. The release workflow runs eligibility → build/test/manifest validation →
16
+ installed-wheel integration on Python 3.13 and 3.14 → PyPI → MCP Registry →
17
+ GitHub release. Integration builds documentation 3.10–3.14 before publishing.
18
+ PyPI receives the same wheel that passed integration, with provenance.
19
+ 5. Confirm every job succeeded, the exact version is visible on PyPI and in the
20
+ MCP Registry, the GitHub release has both artifacts, and a clean
21
+ `uvx --refresh python-docs-mcp-server@X.Y.Z --version` reports that version.
22
+ Confirm a representative real MCP client query before claiming client
23
+ compatibility; automated stdio tests are a distinct proof.
24
+
25
+ The Linux publisher helper `.github/scripts/install_publisher.sh` pins the
26
+ release URL and verifies its SHA-256 before extracting the executable. The
27
+ manifest is validated **before** PyPI publication. Do not use an unverified
28
+ `curl | tar` download or a moving `latest` URL.
29
+
30
+ PyPI Trusted Publishing remains bound to this repository, `release.yml` and the
31
+ `pypi` environment. Activation restricts that environment to `v*` tags and tag
32
+ creation to the owner App; the separate immutable-tag rule has no bypass actors.
33
+ No routine human reviewer is required. If publication partially fails, record
34
+ which registries succeeded and diagnose the failure; never overwrite a published
35
+ version, move a tag, or claim a release complete from a partial result.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ # Linux amd64 release runners only. Deliberate version/digest update required.
4
+ curl --fail --location --proto '=https' --tlsv1.2 \
5
+ https://github.com/modelcontextprotocol/registry/releases/download/v1.8.1/mcp-publisher_linux_amd64.tar.gz \
6
+ --output "${RUNNER_TEMP}/mcp-publisher.tar.gz"
7
+ echo "a06c9096dcb9727c13555b6be26c7effa707b01f06a4c561ba7a3635443cf2cc ${RUNNER_TEMP}/mcp-publisher.tar.gz" | sha256sum --check
8
+ tar -xzf "${RUNNER_TEMP}/mcp-publisher.tar.gz" -C "${RUNNER_TEMP}" mcp-publisher
@@ -0,0 +1,85 @@
1
+ """Fail closed unless this tag names an independently verified main commit."""
2
+
3
+ import json
4
+ import os
5
+ import re
6
+ import urllib.request
7
+
8
+ REQUIRED = {
9
+ "Test (Python 3.12, ubuntu-latest)",
10
+ "Test (Python 3.13, ubuntu-latest)",
11
+ "Test (Python 3.14, ubuntu-latest)",
12
+ "Test (Python 3.12, macos-latest)",
13
+ "Test (Python 3.13, macos-latest)",
14
+ "Test (Python 3.14, macos-latest)",
15
+ "Dependency audit",
16
+ "Analyze",
17
+ "Installed package smoke",
18
+ "Product regression",
19
+ }
20
+
21
+
22
+ def require_eligible(api, sha: str, verifier_app_id: int) -> None:
23
+ if not re.fullmatch(r"[0-9a-f]{40}", sha) or verifier_app_id <= 0:
24
+ raise ValueError("Exact commit and configured verifier App ID are required")
25
+ if api(f"compare/{sha}...main")["status"] not in {"ahead", "identical"}:
26
+ raise ValueError("Release commit is not on main")
27
+ prs = [
28
+ p
29
+ for p in api(f"commits/{sha}/pulls?per_page=100")
30
+ if p["merged_at"] and p["merge_commit_sha"] == sha and p["base"]["ref"] == "main"
31
+ ]
32
+ if len(prs) != 1:
33
+ raise ValueError("Release must be a uniquely identified merged PR")
34
+ head = prs[0]["head"]["sha"]
35
+ head_checks = api(f"commits/{head}/check-runs?per_page=100")["check_runs"]
36
+ codeql = [c for c in head_checks if c["name"] == "CodeQL" and c["app"]["id"] == 57789]
37
+ if not codeql or max(codeql, key=lambda c: c["id"])["conclusion"] != "success":
38
+ raise ValueError("Missing or failing CodeQL findings check on merged PR head")
39
+ reviews = [
40
+ c
41
+ for c in head_checks
42
+ if c["name"] == "Independent verification" and c["app"]["id"] == verifier_app_id
43
+ ]
44
+ parents = api(f"git/commits/{sha}")["parents"]
45
+ latest = max(reviews, key=lambda c: c["id"], default={})
46
+ if (
47
+ len(parents) != 1
48
+ or latest.get("conclusion") != "success"
49
+ or latest.get("external_id") != f"{parents[0]['sha']}:{head}"
50
+ ):
51
+ raise ValueError("Missing successful independent verification for merged PR head")
52
+ checks = api(f"commits/{sha}/check-runs?per_page=100")["check_runs"]
53
+ latest = {}
54
+ for check in sorted(checks, key=lambda c: c["id"]):
55
+ if check["app"]["id"] == 15368:
56
+ latest[check["name"]] = check
57
+ failed = sorted(
58
+ name for name in REQUIRED if latest.get(name, {}).get("conclusion") != "success"
59
+ )
60
+ if failed:
61
+ raise ValueError(f"Missing or failing main checks: {', '.join(failed)}")
62
+
63
+
64
+ def main() -> None:
65
+ repo = os.environ["GITHUB_REPOSITORY"]
66
+ token = os.environ["GH_TOKEN"]
67
+
68
+ def api(path):
69
+ request = urllib.request.Request(
70
+ f"https://api.github.com/repos/{repo}/{path}",
71
+ headers={
72
+ "Authorization": f"Bearer {token}",
73
+ "Accept": "application/vnd.github+json",
74
+ "User-Agent": "release-eligibility",
75
+ },
76
+ )
77
+ with urllib.request.urlopen(request, timeout=30) as response:
78
+ return json.load(response)
79
+
80
+ require_eligible(api, os.environ["GITHUB_SHA"], int(os.environ.get("VERIFIER_APP_ID") or "0"))
81
+ print("Verified main commit, independent review and required main checks.")
82
+
83
+
84
+ if __name__ == "__main__":
85
+ main()
@@ -6,22 +6,30 @@ on:
6
6
  pull_request:
7
7
  branches: [main]
8
8
 
9
+ permissions:
10
+ contents: read
11
+
9
12
  jobs:
10
13
  test:
11
14
  strategy:
12
15
  fail-fast: false
13
16
  matrix:
14
17
  os: [ubuntu-latest, macos-latest]
15
- python-version: ["3.12", "3.13"]
18
+ python-version: ["3.12", "3.13", "3.14"]
16
19
 
20
+ timeout-minutes: 20
21
+ env:
22
+ UV_PYTHON: ${{ matrix.python-version }}
17
23
  runs-on: ${{ matrix.os }}
18
24
  name: Test (Python ${{ matrix.python-version }}, ${{ matrix.os }})
19
25
 
20
26
  steps:
21
- - uses: actions/checkout@v6
27
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
28
+ with:
29
+ persist-credentials: false
22
30
 
23
31
  - name: Install uv
24
- uses: astral-sh/setup-uv@v8.1.0
32
+ uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
25
33
  with:
26
34
  cache-suffix: py${{ matrix.python-version }}
27
35
 
@@ -29,21 +37,24 @@ jobs:
29
37
  run: uv python install ${{ matrix.python-version }}
30
38
 
31
39
  - name: Install dependencies
32
- run: uv sync --dev
40
+ run: uv sync --locked --dev
33
41
 
34
42
  - name: Run linter
35
- run: uv run ruff check src/ tests/
43
+ run: uv run --locked ruff check src/ tests/ benchmarks/ ops/ .github/scripts/
36
44
 
37
45
  - name: Run type checker
38
- run: uv run pyright src/
46
+ run: uv run --locked pyright src/ benchmarks/
47
+
48
+ - name: Validate frozen benchmark corpus
49
+ run: uv run --locked python -m benchmarks validate-corpus --corpus docs/benchmarks/corpus.yml --schema docs/benchmarks/corpus.schema.json
39
50
 
40
51
  - name: Run tests
41
- run: uv run pytest --tb=short -q
52
+ run: uv run --locked pytest --tb=short -q
42
53
 
43
54
  - name: Verify wheel contents
44
55
  run: |
45
56
  uv build
46
- uv run python -c "
57
+ uv run --locked python -c "
47
58
  import zipfile, glob, sys
48
59
  wheels = glob.glob('dist/*.whl')
49
60
  if not wheels:
@@ -22,13 +22,15 @@ jobs:
22
22
 
23
23
  steps:
24
24
  - name: Checkout repository
25
- uses: actions/checkout@v6
25
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
26
+ with:
27
+ persist-credentials: false
26
28
 
27
29
  - name: Initialize CodeQL
28
- uses: github/codeql-action/init@v4
30
+ uses: github/codeql-action/init@7999b86c43a865dc79d8923397f35af22de63401 # v4
29
31
  with:
30
32
  languages: python
31
33
  queries: security-extended,security-and-quality
32
34
 
33
35
  - name: Perform CodeQL Analysis
34
- uses: github/codeql-action/analyze@v4
36
+ uses: github/codeql-action/analyze@7999b86c43a865dc79d8923397f35af22de63401 # v4
@@ -2,9 +2,18 @@ name: Slow E2E
2
2
 
3
3
  on:
4
4
  workflow_dispatch:
5
+ workflow_call:
6
+ inputs:
7
+ artifact-name:
8
+ type: string
9
+ required: false
10
+ default: ''
5
11
  schedule:
6
12
  - cron: "17 4 * * 1"
7
13
 
14
+ permissions:
15
+ contents: read
16
+
8
17
  jobs:
9
18
  installed-build-index:
10
19
  name: Installed build-index (Python ${{ matrix.python-version }})
@@ -17,29 +26,44 @@ jobs:
17
26
  python-version: ["3.13", "3.14"]
18
27
 
19
28
  steps:
20
- - uses: actions/checkout@v6
29
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
30
+ with:
31
+ persist-credentials: false
21
32
 
22
33
  - name: Install uv
23
- uses: astral-sh/setup-uv@v8.1.0
34
+ uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
24
35
  with:
25
36
  cache-suffix: py${{ matrix.python-version }}
26
37
 
27
38
  - name: Set up Python ${{ matrix.python-version }}
28
39
  run: uv python install ${{ matrix.python-version }}
29
40
 
41
+ - name: Download release artifact
42
+ if: inputs.artifact-name != ''
43
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
44
+ with:
45
+ name: ${{ inputs.artifact-name }}
46
+ path: dist
47
+
30
48
  - name: Build package
49
+ if: inputs.artifact-name == ''
31
50
  run: uv build
32
51
 
33
52
  - name: Install wheel in clean virtual environment
34
53
  run: |
35
- uv run --python ${{ matrix.python-version }} python -m venv .e2e-venv
54
+ uv run --locked --python ${{ matrix.python-version }} python -m venv .e2e-venv
36
55
  .e2e-venv/bin/python -m pip install --upgrade pip
37
56
  .e2e-venv/bin/python -m pip install dist/*.whl
38
57
  .e2e-venv/bin/python-docs-mcp-server --version
39
58
 
59
+ - name: Smoke test the installed wheel
60
+ run: |
61
+ .e2e-venv/bin/python -m pip install pytest
62
+ cp tests/test_stdio_smoke.py "${RUNNER_TEMP}/test_stdio_smoke.py"
63
+ "${GITHUB_WORKSPACE}/.e2e-venv/bin/python" -m pytest --import-mode=importlib "${RUNNER_TEMP}/test_stdio_smoke.py" -q
64
+
40
65
  - name: Build and validate full docs index
41
66
  env:
42
- HOME: ${{ runner.temp }}/mcp-python-docs-home
43
67
  XDG_CACHE_HOME: ${{ runner.temp }}/mcp-python-docs-cache
44
68
  run: |
45
69
  set -o pipefail
@@ -50,7 +74,7 @@ jobs:
50
74
 
51
75
  - name: Upload E2E logs and cache artifacts
52
76
  if: always()
53
- uses: actions/upload-artifact@v7
77
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
54
78
  with:
55
79
  name: e2e-python-${{ matrix.python-version }}
56
80
  path: |
@@ -0,0 +1,63 @@
1
+ name: Product quality
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ installed-smoke:
15
+ name: Installed package smoke
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 15
18
+ steps:
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
20
+ with:
21
+ persist-credentials: false
22
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
23
+ with:
24
+ python-version: '3.14'
25
+ - name: Build and install wheel without editable source
26
+ run: |
27
+ uv sync --locked --dev
28
+ uv build
29
+ uv venv "${RUNNER_TEMP}/installed"
30
+ uv pip install --python "${RUNNER_TEMP}/installed/bin/python" dist/*.whl pytest
31
+ cp tests/test_stdio_smoke.py "${RUNNER_TEMP}/test_stdio_smoke.py"
32
+ cd "${RUNNER_TEMP}"
33
+ installed/bin/python -m pytest --import-mode=importlib test_stdio_smoke.py -q
34
+
35
+ regression:
36
+ name: Product regression
37
+ runs-on: ubuntu-latest
38
+ timeout-minutes: 60
39
+ env:
40
+ UV_PYTHON: '3.13'
41
+ steps:
42
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
43
+ with:
44
+ persist-credentials: false
45
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
46
+ - run: echo "XDG_CACHE_HOME=${RUNNER_TEMP}/docs-cache" >> "$GITHUB_ENV"
47
+ - run: uv sync --locked --dev
48
+ - uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5
49
+ id: index
50
+ with:
51
+ path: ${{ runner.temp }}/docs-cache/mcp-python-docs/index.db
52
+ key: docs-regression-v1-${{ runner.os }}-${{ hashFiles('src/mcp_server_python_docs/ingestion/**', 'src/mcp_server_python_docs/storage/**', 'src/mcp_server_python_docs/__main__.py', 'uv.lock') }}
53
+ - name: Build full reference index
54
+ if: steps.index.outputs.cache-hit != 'true'
55
+ run: uv run --locked python-docs-mcp-server build-index --versions 3.11,3.12,3.13
56
+ - name: Enforce offline retrieval baseline
57
+ run: uv run --locked python -m benchmarks.regression --output regression-results.json
58
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
59
+ if: always()
60
+ with:
61
+ name: product-regression-results
62
+ path: regression-results.json
63
+ if-no-files-found: error
@@ -9,34 +9,58 @@ concurrency:
9
9
  group: release-${{ github.ref_name }}
10
10
  cancel-in-progress: true
11
11
 
12
+ permissions:
13
+ contents: read
14
+
12
15
  jobs:
16
+ eligibility:
17
+ name: Release eligibility
18
+ runs-on: ubuntu-latest
19
+ timeout-minutes: 5
20
+ permissions:
21
+ contents: read
22
+ checks: read
23
+ pull-requests: read
24
+ steps:
25
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
26
+ with:
27
+ persist-credentials: false
28
+ - name: Require verified main commit
29
+ env:
30
+ GH_TOKEN: ${{ github.token }}
31
+ VERIFIER_APP_ID: ${{ vars.VISION_VERIFIER_APP_ID }}
32
+ run: python .github/scripts/release_gate.py
33
+
13
34
  build:
35
+ needs: eligibility
14
36
  runs-on: ubuntu-latest
15
37
  name: Build & Test
16
38
  timeout-minutes: 15
17
39
 
18
40
  steps:
19
- - uses: actions/checkout@v6
41
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
42
+ with:
43
+ persist-credentials: false
20
44
 
21
45
  - name: Install uv
22
- uses: astral-sh/setup-uv@v8.1.0
46
+ uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
23
47
 
24
48
  - name: Set up Python 3.13
25
49
  run: uv python install 3.13
26
50
 
27
51
  - name: Install dependencies
28
- run: uv sync --dev
52
+ run: uv sync --locked --dev
29
53
 
30
54
  - name: Verify tag matches package version
31
55
  run: |
32
56
  TAG_VERSION="${GITHUB_REF_NAME#v}"
33
- PKG_VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
57
+ PKG_VERSION=$(uv run --locked python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
34
58
  if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
35
59
  echo "::error::Tag ${GITHUB_REF_NAME} does not match pyproject.toml version ${PKG_VERSION}"
36
60
  exit 1
37
61
  fi
38
- SERVER_VERSION=$(uv run python -c "import json; print(json.load(open('server.json'))['version'])")
39
- PACKAGE_VERSION=$(uv run python -c "import json; print(json.load(open('server.json'))['packages'][0]['version'])")
62
+ SERVER_VERSION=$(uv run --locked python -c "import json; print(json.load(open('server.json'))['version'])")
63
+ PACKAGE_VERSION=$(uv run --locked python -c "import json; print(json.load(open('server.json'))['packages'][0]['version'])")
40
64
  if [ "$TAG_VERSION" != "$SERVER_VERSION" ]; then
41
65
  echo "::error::Tag ${GITHUB_REF_NAME} does not match server.json version ${SERVER_VERSION}"
42
66
  exit 1
@@ -48,20 +72,28 @@ jobs:
48
72
  echo "Version check passed: ${PKG_VERSION}"
49
73
 
50
74
  - name: Run linter
51
- run: uv run ruff check src/ tests/
75
+ run: uv run --locked ruff check src/ tests/ benchmarks/ ops/ .github/scripts/
52
76
 
53
77
  - name: Run type checker
54
- run: uv run pyright src/
78
+ run: uv run --locked pyright src/ benchmarks/
55
79
 
56
80
  - name: Run tests
57
- run: uv run pytest --tb=short -q
81
+ run: uv run --locked pytest --tb=short -q
82
+
83
+ - name: Validate frozen benchmark corpus
84
+ run: uv run --locked python -m benchmarks validate-corpus --corpus docs/benchmarks/corpus.yml --schema docs/benchmarks/corpus.schema.json
85
+
86
+ - name: Validate MCP manifest before publication
87
+ run: |
88
+ bash .github/scripts/install_publisher.sh
89
+ "${RUNNER_TEMP}/mcp-publisher" validate server.json
58
90
 
59
91
  - name: Build package
60
92
  run: uv build
61
93
 
62
94
  - name: Verify wheel contents
63
95
  run: |
64
- uv run python -c "
96
+ uv run --locked python -c "
65
97
  import zipfile, glob, sys
66
98
  wheels = glob.glob('dist/*.whl')
67
99
  if not wheels:
@@ -76,13 +108,19 @@ jobs:
76
108
  "
77
109
 
78
110
  - name: Upload dist artifacts
79
- uses: actions/upload-artifact@v7
111
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
80
112
  with:
81
113
  name: dist
82
114
  path: dist/
83
115
 
84
- publish:
116
+ integration:
85
117
  needs: build
118
+ uses: ./.github/workflows/e2e.yml
119
+ with:
120
+ artifact-name: dist
121
+
122
+ publish:
123
+ needs: [build, integration]
86
124
  runs-on: ubuntu-latest
87
125
  name: Publish to PyPI
88
126
  timeout-minutes: 10
@@ -94,18 +132,18 @@ jobs:
94
132
 
95
133
  steps:
96
134
  - name: Download dist artifacts
97
- uses: actions/download-artifact@v8
135
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
98
136
  with:
99
137
  name: dist
100
138
  path: dist/
101
139
 
102
140
  - name: Generate artifact attestation
103
- uses: actions/attest-build-provenance@v4
141
+ uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4
104
142
  with:
105
143
  subject-path: 'dist/*'
106
144
 
107
145
  - name: Publish to PyPI
108
- uses: pypa/gh-action-pypi-publish@release/v1
146
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
109
147
 
110
148
  publish-mcp-registry:
111
149
  needs: publish
@@ -117,21 +155,18 @@ jobs:
117
155
  contents: read
118
156
 
119
157
  steps:
120
- - uses: actions/checkout@v6
121
-
122
- - name: Install mcp-publisher
123
- run: |
124
- curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" \
125
- | tar xz mcp-publisher
158
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
159
+ with:
160
+ persist-credentials: false
126
161
 
127
- - name: Validate server.json
128
- run: ./mcp-publisher validate server.json
162
+ - name: Install verified MCP publisher
163
+ run: bash .github/scripts/install_publisher.sh
129
164
 
130
165
  - name: Authenticate to MCP Registry
131
- run: ./mcp-publisher login github-oidc
166
+ run: '"${RUNNER_TEMP}/mcp-publisher" login github-oidc'
132
167
 
133
168
  - name: Publish to MCP Registry
134
- run: ./mcp-publisher publish
169
+ run: '"${RUNNER_TEMP}/mcp-publisher" publish'
135
170
 
136
171
  github-release:
137
172
  needs:
@@ -145,13 +180,13 @@ jobs:
145
180
 
146
181
  steps:
147
182
  - name: Download dist artifacts
148
- uses: actions/download-artifact@v8
183
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
149
184
  with:
150
185
  name: dist
151
186
  path: dist/
152
187
 
153
188
  - name: Create GitHub Release
154
- uses: softprops/action-gh-release@v3
189
+ uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3
155
190
  with:
156
191
  files: dist/*
157
192
  generate_release_notes: true