python-docs-mcp-server 0.3.1__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.
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/CODEOWNERS +5 -3
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/ISSUE_TEMPLATE/autonomous-agent.yml +14 -7
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/PULL_REQUEST_TEMPLATE/agent.md +23 -7
- python_docs_mcp_server-0.3.2/.github/RELEASE.md +35 -0
- python_docs_mcp_server-0.3.2/.github/scripts/install_publisher.sh +8 -0
- python_docs_mcp_server-0.3.2/.github/scripts/release_gate.py +85 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/workflows/ci.yml +19 -8
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/workflows/codeql.yml +5 -3
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/workflows/e2e.yml +29 -5
- python_docs_mcp_server-0.3.2/.github/workflows/product-quality.yml +63 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/workflows/release.yml +62 -27
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/workflows/scorecard.yml +3 -3
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/workflows/security.yml +4 -2
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/AGENT-EXECUTION-PIPELINE.md +157 -2
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/AGENTS.md +20 -11
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/CHANGELOG.md +29 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/OPENCLAW-FORGE-PROTOCOL.md +72 -51
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/PKG-INFO +27 -3
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/README.md +24 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/STRATEGIC-ROADMAP-2026-05-29.md +15 -0
- python_docs_mcp_server-0.3.2/benchmarks/__init__.py +1 -0
- python_docs_mcp_server-0.3.2/benchmarks/__main__.py +245 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/__init__.py +90 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/base.py +110 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/claude_tokens.py +277 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/context7_adapter.py +337 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/deepwiki_adapter.py +206 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/eligibility.py +158 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/gitmcp_adapter.py +273 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/google_adapter.py +78 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/guard.py +160 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/openai_adapter.py +78 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/python_docs_mcp_adapter.py +259 -0
- python_docs_mcp_server-0.3.2/benchmarks/adapters/ref_tools_adapter.py +281 -0
- python_docs_mcp_server-0.3.2/benchmarks/corpus.py +336 -0
- python_docs_mcp_server-0.3.2/benchmarks/model_matrix.py +240 -0
- python_docs_mcp_server-0.3.2/benchmarks/regression.py +141 -0
- python_docs_mcp_server-0.3.2/benchmarks/report.py +828 -0
- python_docs_mcp_server-0.3.2/benchmarks/runner.py +758 -0
- python_docs_mcp_server-0.3.2/benchmarks/scoring.py +599 -0
- python_docs_mcp_server-0.3.2/docs/architecture/ADR-007-cache.md +185 -0
- python_docs_mcp_server-0.3.2/docs/architecture/ADR-008-transport.md +142 -0
- python_docs_mcp_server-0.3.2/docs/architecture/DESIGN.md +526 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/docs/benchmarks/PUBLIC-BENCHMARK-METHODOLOGY.md +1 -2
- python_docs_mcp_server-0.3.2/docs/benchmarks/competitor-manifest.template.yml +170 -0
- python_docs_mcp_server-0.3.2/docs/benchmarks/corpus.schema.json +119 -0
- python_docs_mcp_server-0.3.2/docs/benchmarks/corpus.yml +668 -0
- python_docs_mcp_server-0.3.2/docs/benchmarks/model-matrix.yml +103 -0
- python_docs_mcp_server-0.3.2/docs/benchmarks/regression-baseline.json +479 -0
- python_docs_mcp_server-0.3.2/ops/vision/README.md +247 -0
- python_docs_mcp_server-0.3.2/ops/vision/client.py +87 -0
- python_docs_mcp_server-0.3.2/ops/vision/configure_apps.py +315 -0
- python_docs_mcp_server-0.3.2/ops/vision/control.py +808 -0
- python_docs_mcp_server-0.3.2/ops/vision/install.py +364 -0
- python_docs_mcp_server-0.3.2/ops/vision/worker_shell.py +85 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/pyproject.toml +2 -2
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/server.json +2 -2
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/sphinx_json.py +26 -1
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/retrieval/ranker.py +56 -6
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/content.py +3 -24
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/search.py +64 -3
- python_docs_mcp_server-0.3.2/tests/benchmarks/fixtures/corpus.sample.yml +703 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_adapters.py +205 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_claude_tokens.py +239 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_competitor_adapters.py +1132 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_corpus_validation.py +303 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_model_matrix.py +271 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_python_docs_mcp_adapter.py +310 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_regression.py +39 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_report.py +669 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_runner.py +576 -0
- python_docs_mcp_server-0.3.2/tests/benchmarks/test_scoring.py +692 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_ingestion.py +11 -0
- python_docs_mcp_server-0.3.2/tests/test_release_gate.py +63 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_retrieval.py +109 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_retrieval_regression.py +3 -0
- python_docs_mcp_server-0.3.2/tests/test_search_spare_slot.py +167 -0
- python_docs_mcp_server-0.3.2/tests/test_search_symbol_fallback.py +116 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_services.py +2 -2
- python_docs_mcp_server-0.3.2/tests/test_vision_control.py +696 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/uv.lock +101 -95
- python_docs_mcp_server-0.3.1/.github/RELEASE.md +0 -115
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.coderabbit.yaml +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.cursorignore +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/INTEGRATION-TEST.md +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/TEST-STRATEGY.md +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/dependabot.yml +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.gitignore +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.mcp.json +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/CLAUDE.md +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/CONTRIBUTING.md +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/LICENSE +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/SECURITY.md +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/docs/architecture/ADR-001-source-adapters.md +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/docs/architecture/ADR-006-serialization.md +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/docs/architecture/YAML-TRUST-BOUNDARY.md +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/glama.json +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/__init__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/__main__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/app_context.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/cache/__init__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/cache/codec.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/data/synonyms.yaml +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/detection.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/diagnostics.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/errors.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/__init__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/cpython_versions.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/inventory.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/ingestion/publish.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/models.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/py.typed +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/retrieval/__init__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/retrieval/budget.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/retrieval/query.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/server.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/__init__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/cache.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/compare.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/observability.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/package_docs.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/persistent_cache.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/version.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/services/version_resolution.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/storage/__init__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/storage/db.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/src/mcp_server_python_docs/storage/schema.sql +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/__init__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/cache/__init__.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/cache/test_codec.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/conftest.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/fixtures/retrieval_regression_cases.json +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/fixtures/sample_broken.fjson +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/fixtures/sample_library.fjson +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-get_docs-input.json +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-get_docs-output.json +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-list_versions-output.json +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-search_docs-input.json +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/fixtures/schema-search_docs-output.json +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_ci_workflows.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_compare_versions.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_compare_versions_spike.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_detection.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_doctor.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_mcp_get_docs_cache_smoke.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_multi_version.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_package_docs.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_packaging.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_persistent_docs_cache.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_phase1_integration.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_publish.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_schema.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_schema_snapshot.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_stability.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_stdio_hygiene.py +0 -0
- {python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/tests/test_stdio_smoke.py +0 -0
- {python_docs_mcp_server-0.3.1 → 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
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
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:
|
|
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
|
-
-
|
|
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
|
|
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
|
{python_docs_mcp_server-0.3.1 → python_docs_mcp_server-0.3.2}/.github/PULL_REQUEST_TEMPLATE/agent.md
RENAMED
|
@@ -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.
|
|
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:
|
|
41
|
-
and
|
|
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@v7
|
|
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@
|
|
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@v7
|
|
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@v7
|
|
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@
|
|
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@v7
|
|
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@
|
|
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
|
-
|
|
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@v7
|
|
121
|
-
|
|
122
|
-
|
|
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:
|
|
128
|
-
run:
|
|
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:
|
|
166
|
+
run: '"${RUNNER_TEMP}/mcp-publisher" login github-oidc'
|
|
132
167
|
|
|
133
168
|
- name: Publish to MCP Registry
|
|
134
|
-
run:
|
|
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
|