From cdbd06dc72dbf0b023d5f47f84bb651ded5ec28a Mon Sep 17 00:00:00 2001 From: Mike Odnis Date: Sat, 9 May 2026 15:04:24 -0400 Subject: [PATCH 1/2] ci: add docstring coverage gate via interrogate Surface missing docstrings on the public API surface as a failing PR check rather than letting them leak into the auto-generated docs as empty headings. Initial thresholds anchor today's measured coverage with a small buffer so new code can't regress, and the floor can be raised incrementally as gaps fill in: resq-mcp: fail-under = 75 (current 81%; concentration in core/telemetry.py) resq-dsa: fail-under = 90 (current 100% with private/init/magic exclusions) Configuration lives in `[tool.interrogate]` per-package so contributors can run `uvx interrogate --config pyproject.toml src/` locally and get the same result. --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++++++ packages/resq-dsa/pyproject.toml | 15 +++++++++++++++ packages/resq-mcp/pyproject.toml | 18 ++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c91ffc..414e376 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,6 +56,32 @@ jobs: - run: uv run mypy src/ working-directory: ${{ matrix.dir }} + docstrings: + # Public API surface in src/ must carry docstrings. interrogate + # threshold is configured per-package in [tool.interrogate] + # in each pyproject.toml; raise the floor over time as gaps + # are filled. + name: Docstring Coverage (${{ matrix.name }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - name: resq-mcp + dir: packages/resq-mcp + - name: resq-dsa + dir: packages/resq-dsa + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + python-version: "3.13" + enable-cache: true + - run: uvx interrogate --config pyproject.toml src/ + working-directory: ${{ matrix.dir }} + test: name: Test (${{ matrix.name }} / ${{ matrix.python-version }}) needs: [lint, typecheck] diff --git a/packages/resq-dsa/pyproject.toml b/packages/resq-dsa/pyproject.toml index 6e8df18..7f7c6d7 100644 --- a/packages/resq-dsa/pyproject.toml +++ b/packages/resq-dsa/pyproject.toml @@ -45,6 +45,21 @@ select = ["E", "W", "F", "I", "B", "C4", "UP", "SIM", "RUF"] strict = true python_version = "3.11" +[tool.interrogate] +# Current coverage is 95% (only 2 missing in trie.py). Threshold set +# at 90% to lock in today's level with a small buffer for refactors. +fail-under = 90 +ignore-init-module = true +ignore-init-method = true +ignore-magic = true +ignore-private = true +ignore-property-decorators = true +ignore-nested-functions = true +exclude = ["tests", "build", "dist"] +verbose = 1 +quiet = false +color = true + [tool.semantic_release] version_toml = ["pyproject.toml:project.version"] branch = "main" diff --git a/packages/resq-mcp/pyproject.toml b/packages/resq-mcp/pyproject.toml index ac1ec9c..ba1300d 100644 --- a/packages/resq-mcp/pyproject.toml +++ b/packages/resq-mcp/pyproject.toml @@ -123,6 +123,24 @@ exclude_lines = [ "if __name__ == .__main__.:", ] +[tool.interrogate] +# Initial fail threshold set just below current measured coverage +# (76.6%) so the gate locks in today's level and forces ratcheting up +# as docstrings are added. Concentration of misses is in +# core/telemetry.py (OpenTelemetry helpers); document those next and +# raise this number. +fail-under = 75 +ignore-init-module = true +ignore-init-method = true +ignore-magic = true +ignore-private = true +ignore-property-decorators = true +ignore-nested-functions = true +exclude = ["tests", "build", "dist"] +verbose = 1 +quiet = false +color = true + [tool.semantic_release] version_toml = ["pyproject.toml:project.version"] branch = "main" From e25661c4dedecbc97ddde652284e10e52c70e13b Mon Sep 17 00:00:00 2001 From: Mike Odnis Date: Sat, 9 May 2026 15:08:18 -0400 Subject: [PATCH 2/2] fix: align comments with post-exclusion coverage numbers Per gemini-code-assist review on PR #42, the original comments cited raw interrogate output (95%, 76.6%) but [tool.interrogate] enables ignore-init/ignore-magic/ignore-private which raise the measured coverage to 100% / 81%. Update comments to match what the gate actually evaluates. --- packages/resq-dsa/pyproject.toml | 6 ++++-- packages/resq-mcp/pyproject.toml | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/resq-dsa/pyproject.toml b/packages/resq-dsa/pyproject.toml index 7f7c6d7..521810c 100644 --- a/packages/resq-dsa/pyproject.toml +++ b/packages/resq-dsa/pyproject.toml @@ -46,8 +46,10 @@ strict = true python_version = "3.11" [tool.interrogate] -# Current coverage is 95% (only 2 missing in trie.py). Threshold set -# at 90% to lock in today's level with a small buffer for refactors. +# Current coverage is 100% under the exclusions below (the 2 +# missing in trie.py are private helpers ignored by ignore-private). +# Threshold set at 90% to leave headroom for refactors that +# temporarily expose a new symbol before its docstring lands. fail-under = 90 ignore-init-module = true ignore-init-method = true diff --git a/packages/resq-mcp/pyproject.toml b/packages/resq-mcp/pyproject.toml index ba1300d..e43856c 100644 --- a/packages/resq-mcp/pyproject.toml +++ b/packages/resq-mcp/pyproject.toml @@ -125,10 +125,10 @@ exclude_lines = [ [tool.interrogate] # Initial fail threshold set just below current measured coverage -# (76.6%) so the gate locks in today's level and forces ratcheting up -# as docstrings are added. Concentration of misses is in -# core/telemetry.py (OpenTelemetry helpers); document those next and -# raise this number. +# under the exclusions below (81%) so the gate locks in today's level +# and forces ratcheting up as docstrings are added. Concentration of +# misses is in core/telemetry.py (OpenTelemetry helpers); document +# those next and raise this number. fail-under = 75 ignore-init-module = true ignore-init-method = true