Skip to content

ci: gate docstring quality and coverage in CI (#616)#689

Merged
planetf1 merged 18 commits intogenerative-computing:mainfrom
planetf1:ci/doc-quality-gate-616
Mar 20, 2026
Merged

ci: gate docstring quality and coverage in CI (#616)#689
planetf1 merged 18 commits intogenerative-computing:mainfrom
planetf1:ci/doc-quality-gate-616

Conversation

@planetf1
Copy link
Contributor

@planetf1 planetf1 commented Mar 18, 2026

Misc PR

Type of PR

  • Bug Fix
  • New Feature
  • Documentation
  • Other

Description

Adds a hard-fail docstring quality gate to the docs-publish workflow (--quality --fail-on-quality --threshold 100). Both checks currently pass in CI (100% coverage, 0 quality issues).

Also adds a typeddict_mismatch scanner to audit_coverage.py — flags Attributes: sections on TypedDict classes that document phantom fields or omit declared ones (mirrors the existing param_mismatch logic for functions).

Pre-commit hook updated to use --fail-on-quality; stays stages: [manual] since it requires pre-built docs. CI is the hard gate.

Contribution docs updated with TypedDict docstring requirements and the two new check kinds.

Docstring fixes (to reach 0 quality gate issues)

To pass the new gate, 36 docstring issues across 17 files were fixed. Changes are classified below by risk level.

Docstring text only (zero risk): cli/decompose/decompose.py, cli/eval/runner.py, mellea/core/sampling.py, mellea/core/utils.py, mellea/stdlib/functional.py, mellea/stdlib/sampling/base.py, mellea/formatters/granite/intrinsics/input.py, cli/alora/intrinsic_uploader.py. Pure text changes — missing Returns: sections, corrected return types in docstrings, reST-to-Google-style conversion, and Literal['a', 'b'] single-quote normalisation (Python's AST normalises string literals, so docstrings must use single quotes to match).

Type annotation additions (low risk): cli/alora/train.py, mellea/backends/tools.py, mellea/core/utils.py, mellea/helpers/openai_compatible_helpers.py, mellea/stdlib/components/mify.py, mellea/stdlib/session.py, mellea/stdlib/sampling/base.py. Adding type annotations to previously untyped parameters and return values. No runtime behaviour change — Python ignores annotations at runtime.

Requires justification:

granite32/input.py, granite33/input.pysanitize() override: Added from ...granite3.types import Granite3ChatCompletion import and updated the sanitize() signature to use it. Required because the parent class declares sanitize(cls, chat_completion: Granite3ChatCompletion, ...) and mypy flagged an incompatible override. Granite3ChatCompletion is already loaded transitively through the parent import chain; 7 other files use the same import. Method body is unchanged.

mellea/formatters/granite/base/util.py — HuggingFace optional-dependency types: Added from __future__ import annotations, a TYPE_CHECKING guard importing PreTrainedModel and PreTrainedTokenizerBase, and typed 4 previously untyped params. TYPE_CHECKING is dead code at runtime — the HF types are never imported when the module loads. The | None on tokenizer/model is truthful (they have =None defaults).

Adding real types caused mypy to check function bodies it previously skipped (untyped params = implicit Any = no body checking). This exposed pre-existing issues, suppressed with targeted type: ignore comments:

  • # type: ignore[union-attr] — pre-existing None-unsafe attribute access on tokenizer/model (e.g. calling .apply_chat_template() without a None guard). Real gaps, out of scope for a docs PR.
  • # type: ignore[operator] in generate_with_transformers — HuggingFace stub quality issue: stubs mark PreTrainedModel.generate in a way mypy reads as non-callable, but it is callable at runtime.

mellea/stdlib/components/mobject.py:# type: ignore[arg-type] added. Same root cause — our annotations changed mypy's import graph enough to trigger checking of this function. The underlying issue is a dict-invariance warning: dict[str, MelleaTool] passed where dict[str, AbstractMelleaTool] | None is expected. MelleaTool is a subtype of AbstractMelleaTool and the dict is not mutated through the parameter, so this is safe at runtime. Pre-existing issue, not introduced by this PR.

All type: ignore suppressions are narrow (error-code qualified) and document pre-existing issues that should be addressed in a dedicated type-cleanup issue.

Testing

  • Tests added to the respective file if code was changed
  • New code has 100% coverage if code as added
  • Ensure existing tests and github automation passes (a maintainer will kick off the github automation when the rest of the PR is populated)

@github-actions
Copy link
Contributor

The PR description has been updated. Please fill out the template for your PR to be reviewed.

@planetf1
Copy link
Contributor Author

@psschwei @HendrikStrobelt @jakelorocco We are finally at a state where the docs build is clean, and reporting no issues. I recommend we now make this a hard-fail.

We're had at least one PR merged which regressed some docstrings (albeit minor), and another pr in the queue with quite a few changes needed. By ensuring we validate as part of CI we'll maintain the docs in a clean state

Note this does also add a slightly looser pre-commit. That is optional if we think too annoying

@planetf1 planetf1 marked this pull request as ready for review March 18, 2026 14:33
@planetf1 planetf1 requested a review from a team as a code owner March 18, 2026 14:33
Copy link
Member

@psschwei psschwei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favor of adding, but one question: is the output of our docstring checker the kind of thing that could be easily fed into an agent to produce the appropriate docstrings / make the check pass? (thinking of (a) keeping contribution process easy for new folks, and (b) how we can use agents at some point to do this for us)

@mergify
Copy link

mergify bot commented Mar 18, 2026

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 Enforce conventional commit

Wonderful, this rule succeeded.

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert|release)(?:\(.+\))?:

@planetf1
Copy link
Contributor Author

Yes, much of the docs have been written and restructured by AI - long term the ability to generate too is on the cards. I think there will be some incremental improvements to make scan results easier...

@planetf1 planetf1 force-pushed the ci/doc-quality-gate-616 branch from 364fb81 to 71b4bde Compare March 18, 2026 15:38
Copy link
Member

@psschwei psschwei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in favor, but would be good for @jakelorocco to weigh in too

@planetf1
Copy link
Contributor Author

A good time to consider forcing

Screenshot 2026-03-18 at 16 25 06

@planetf1 planetf1 force-pushed the ci/doc-quality-gate-616 branch 2 times, most recently from 58a7f44 to dfb95c4 Compare March 18, 2026 22:37
@planetf1
Copy link
Contributor Author

An intrinsics updated has introduced some documentation errors - not fatal: missing args, and missing returns (10 omissions) -- but having seen 2 other PRs potentially doing this too, this is why we MUST start enforcement, not just the checks, which were the facilitator of improving the docs.

@jakelorocco @HendrikStrobelt What do you think? Are you ok with this in principle?

If so I will add the fix-ups into this PR tomorrow and get it approved/merged ASAP.

Any concerns?

@planetf1
Copy link
Contributor Author

planetf1 commented Mar 18, 2026

vv This was the regression

Screenshot 2026-03-18 at 22 43 25 Screenshot 2026-03-18 at 22 43 35

Copy link
Contributor

@jakelorocco jakelorocco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is my bad for not understanding this earlier, but it looks like we are checking the docstring quality only in terms of our generated docs. I wonder if this is over-complicating things and we should instead be checking docstring quality by looking at our code. Is there an advantage to only checking the quality of things in our generated docs? If we switched to ensuring quality at the code level, could we rely on third party tools / packages to do the checks?

| `missing_param_type` | `Args:` section exists but one or more parameters have no Python type annotation — the type column is absent from the generated API docs | Add a type annotation to each listed parameter in the function signature (e.g. `def f(x: int)`). Only fires when `no_args` is already satisfied; `*args`/`**kwargs` are excluded. |
| `missing_return_type` | `Returns:` section is documented but the function has no return type annotation — the return type is absent from the generated API docs | Add a return annotation to the function signature (e.g. `-> str`). Only fires when `no_returns` is already satisfied. |

#### Class docstrings (Option C)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Option C should be removed here? It looks like this was originally a list of fix options but we now accept all of them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that section has gone - just a single reference to the documentation

@planetf1
Copy link
Contributor Author

Improved checks - clarification

Screenshot 2026-03-19 at 14 15 08

Looking at other comments:

@planetf1
Copy link
Contributor Author

planetf1 commented Mar 19, 2026

I think this is my bad for not understanding this earlier, but it looks like we are checking the docstring quality only in terms of our generated docs. I wonder if this is over-complicating things and we should instead be checking docstring quality by looking at our code. Is there an advantage to only checking the quality of things in our generated docs? If we switched to ensuring quality at the code level, could we rely on third party tools / packages to do the checks?

It's a journey.. the deliverable was docs so my original plan was to minimize code changes -- at least for the first pass - hence the validation focusses on code

But.. as a strategy, yes I agree, it is more of a code-based check (the current tool builds the AST). There may be options to use other tools/plugins to achieve similar checks in a more structured way -- but this first version was a pragmatic way to get started and improve quality. Ideal to then reflect/review on how we can do it better in future.

Also related - #456 : our current mypy configuration isn't checking for missing types -- yet that is confusing for external classes. ruff checks some things, but not everything.

Ruff can do the following -

Our check Ruff equivalent Notes
missing / short D1xx stable
no_returns DOC201 preview
no_yields DOC402 preview
no_raises DOC501 preview
no_args not in ruff DOC
param_mismatch not in ruff DOC
param_type_mismatch not in ruff DOC
return_type_mismatch not in ruff DOC
TypedDict checks not in any tool
Coverage % / public API filter not in any tool

but what it doesn't easily do is address Public vs Private (the current parser looks at what is exported) - so we'd need to move to cleanup all code including internal, or we'd have to restructure and/or be very careful in creating an exclusion list. I think this would best be tracked in a new issue? What we have focusses on external

@jakelorocco
Copy link
Contributor

I think this is my bad for not understanding this earlier, but it looks like we are checking the docstring quality only in terms of our generated docs. I wonder if this is over-complicating things and we should instead be checking docstring quality by looking at our code. Is there an advantage to only checking the quality of things in our generated docs? If we switched to ensuring quality at the code level, could we rely on third party tools / packages to do the checks?

It's a journey.. the deliverable was docs so my original plan was to minimize code changes -- at least for the first pass - hence the validation focusses on code

But.. as a strategy, yes I agree, it is more of a code-based check (the current tool builds the AST). There may be options to use other tools/plugins to achieve similar checks in a more structured way -- but this first version was a pragmatic way to get started and improve quality. Ideal to then reflect/review on how we can do it better in future.

Also related - #456 : our current mypy configuration isn't checking for missing types -- yet that is confusing for external classes. ruff checks some things, but not everything.

I think that's fair. I am all for getting these checks merged and then evaluating if there's versions of this that can work directly on the code. After running the doc generation pipeline locally though, I'm not too concerned about the fact that it runs on the docs since that code is quick enough. Thank you.

Add a hard-fail docstring quality gate to the docs-publish workflow:
- New 'Docstring quality gate' step runs --quality --fail-on-quality
  --threshold 100; fails if any quality issue is found or coverage
  drops below 100% (both currently pass in CI)
- Existing audit_coverage step (soft-fail, threshold 80) retained for
  the summary coverage metric

Add typeddict_mismatch checks to audit_coverage.py:
- typeddict_phantom: Attributes: documents a field not declared in the TypedDict
- typeddict_undocumented: declared field absent from Attributes: section
- Mirrors the existing param_mismatch logic for functions

Pre-commit: enable --fail-on-quality on the manual-stage hook (CI is
the hard gate; hook remains stages: [manual] as docs must be pre-built).

Update CONTRIBUTING.md and docs/docs/guide/CONTRIBUTING.md with TypedDict
docstring requirements and the two new audit check kinds.
… and fix hints

audit_coverage.py:
- Add file/line fields to every issue dict (repo-relative path + def line)
- _print_quality_report now shows [file:line] per issue, per-kind Fix:/Ref:
  hints linking to CONTRIBUTING.md anchors, and emits ::error file=...,line=...
  GHA annotations so issues appear inline in PR diffs
- Cap GHA annotations at 10 per check kind with "N more in job log" notice
- Add _KIND_FIX_HINTS and _gha_file_annotation helpers; _CONTRIB_DOCS_URL constant

validate.py:
- Convert all check functions from list[str] to list[dict] errors (file/line/message)
- Add line-number tracking to validate_source_links, validate_internal_links,
  validate_anchor_collisions, and validate_doc_imports
- Emit per-error GHA annotations with file/line; shared 20-annotation budget
  across all checks so every category gets representation in PR diff
- Fix icon bug: summary rows now use correct pass/fail icon
- Group detailed errors by check type with section headers

docs-publish.yml:
- Add --orphans and --output /tmp/quality_report.json to quality gate step
- Upload quality_report.json as docstring-quality-report artifact (30-day retention)

pyproject.toml:
- cli/**/*.py: suppress only D2/D3/D4xx style rules; enable D1xx (missing
  docstrings) as a ruff-level complement to the audit_coverage quality gate

docs/docs/guide/CONTRIBUTING.md:
- Add CI docstring checks reference section with per-kind tables (fix instructions
  + anchors) for all 11 check kinds across 4 categories
- Add callout explaining GHA annotation cap (10 per kind) and where to find
  the full list (job log + JSON artifact)
…y links

audit_coverage.py (audit_nav_orphans):
- Probe docs/docs/docs.json before docs/mint.json so both Mintlify v1
  and v2 nav configs are supported
- Extend _extract to handle plain string page entries used by docs.json
  (v2 uses "pages": ["api/..."] strings; v1 used {"page": "api/..."} dicts)
- Previously mint.json was never found, nav_refs stayed empty, and every
  MDX file was reported as an orphan

docs-publish.yml (Write job summary):
- When the quality gate fails, render a prominent markdown callout with a
  direct link to the CI docstring checks reference section in CONTRIBUTING.md
- Add a per-kind fix reference table with clickable anchor links to each
  category section (missing/short, args/returns, class Option C, TypedDict)
- Per-kind Ref: URLs in the raw log are inside a text block and do
  not render as links in the step summary; this table surfaces them rendered
planetf1 added 11 commits March 20, 2026 14:55
…ped notice

docs-publish.yml:
- Parse per-kind counts from _print_quality_report section headers in the
  quality gate log (e.g. "Missing docstrings (12)") and show them as a
  comma-separated breakdown in the Docstring Quality table cell instead of
  just the total — gives developers an immediate view of which categories
  are failing without expanding the log

audit_coverage.py:
- Remove the "skipped (pass --quality to enable)" GHA notice emitted by
  the coverage-only step; there is always a dedicated quality gate step
  immediately after so the notice was misleading and redundant
audit_coverage.py:
- Coverage miss section now shows a structured Fix:/Ref: block with the
  exact generate-ast.py command and a link to CONTRIBUTING.md#validating-docstrings
- Missing symbols listed one per line (symbol indented under module) for
  scannability instead of comma-joined on one long line
- Emit a ::error or ::warning GHA annotation with symbol/module counts
  when coverage symbols are undocumented

validate.py:
- Add _CHECK_FIX_HINTS dict mapping each check label to a (fix text, ref URL)
  pair, covering all 8 check types with specific fix instructions and links
  into CONTRIBUTING.md (root or guide as appropriate)
- _print_check_errors now prints Fix:/Ref: under each section header,
  matching the pattern established by _print_quality_report
audit_coverage.py:
- Add missing_param_type check: fires when Args: section exists but one
  or more concrete params lack Python type annotations; naturally
  non-overlapping with no_args (which fires when section is absent)
- Add missing_return_type check: fires when Returns: section is
  documented but the function has no return annotation; naturally
  non-overlapping with no_returns (annotation exists but section absent)
- Add fix hints and CONTRIBUTING.md anchors for both new check kinds
- Update kind_labels and iteration order in _print_quality_report

generate-ast.py:
- Add remove_internal_modules() post-generation filter step
- Uses AST-based import analysis: a submodule is internal when the
  parent __init__.py imports from at least one sibling submodule but
  not from this one (import-based visibility, not __all__ name-matching)
- Conservative: keeps module when parent imports nothing (indeterminate)
  or __init__.py cannot be parsed
- _CONFIRMED_INTERNAL_MODULES hardcoded set for known internals where
  parent imports nothing (json_util, backend_instrumentation); these
  should eventually be renamed with _ prefix per Python convention
- Package index files (stem == parent dir) are never filtered

docs.json: nav regenerated by build; internal modules removed from nav
CONTRIBUTING.md: add missing_param_type / missing_return_type to CI
  docstring checks reference table
docs-publish.yml: add both new kinds to summary kind_short and
  kind_anchors fix-reference table
audit_coverage.py was walking all non-_-prefixed source modules via
Griffe, including internal modules (json_util, backend_instrumentation,
etc.) whose MDX files were removed by remove_internal_modules() in
generate-ast.py.  This caused coverage to drop because those symbols
were no longer 'documented' but were still counted in the denominator.

Apply the same import-based public-API filter in discover_public_symbols():
skip submodules that the parent __init__.py does not import from, mirroring
the generate-ast.py logic.  _CONFIRMED_INTERNAL_MODULES kept in sync.

Also drop the per-kind anchor table from the GHA job summary.  Anchors
in GitHub Actions summaries only navigate to the top of the referenced
document, so the table added noise without working links.
Adds two new quality check kinds that fire when the type explicitly
stated in an Args:/Returns: docstring entry disagrees with the Python
type annotation in the function signature:

  param_type_mismatch — 'param (OldType): ...' vs annotation 'NewType'
  return_type_mismatch — 'Returns: OldType: ...' vs annotation '-> NewType'

Both checks fire only when BOTH sides have an explicit type; one-sided
absence is already handled by missing_param_type / missing_return_type.

Type comparison uses _types_match() / _normalize_type() which handles:
  - typing aliases: List→list, Dict→dict, Optional→X|None, Union→A|B
  - typing. prefix stripping
  - pipe-union component ordering (str|None == None|str)
  - incidental whitespace

Known conservative suppressions (prefer false negatives over false positives,
since there is no per-site suppression mechanism):
  - Nested generics not fully expandable by regex (e.g. Optional[list[str]])
    are silently skipped — both sides must fully normalise to be compared
  - Union with bracket-containing members
  - Callable argument ordering
…ubmodule

For a module file mellea/pkg/submodule.py, Griffe gives filepath ending in
.py (not __init__.py). The parent __init__.py is fp.parent/__init__.py.
The previous code used fp.parent.parent which is correct for packages
(whose filepath IS the __init__.py) but goes one level too far for plain
module files — it was checking the grandparent init instead of the parent.

Effect: genslot, react, unit_test_eval and similar non-exported modules
in stdlib/components were incorrectly counted as public symbols, inflating
the denominator and lowering the reported coverage percentage.
@planetf1 planetf1 force-pushed the ci/doc-quality-gate-616 branch from 48b32b4 to 4bfcd0a Compare March 20, 2026 14:56
@planetf1
Copy link
Contributor Author

Ok I think we're good to push on closing out this

To fix

2 missing, 1 no_args, 1 no_returns, 11 missing_param_type, 15 missing_return_type, 1 param_type_mismatch, 5 return_type_mismatch

I'll do the docstring updates & add to this PR so we can merge - quickly. I'll take first approval

- Fix missing_param_type, missing_return_type, param_type_mismatch,
  return_type_mismatch, no_args, no_returns, and missing docstring issues
- Add TYPE_CHECKING imports for HuggingFace types in util.py with
  type: ignore[union-attr] for pre-existing None-safety gaps
- Add Granite3ChatCompletion import to granite32/33 input.py for
  correct sanitize() parent signature match
- Convert reST-style docstrings to Google style in intrinsics/input.py
- Document AST single-quote normalization for Literal types in
  CONTRIBUTING.md
@planetf1 planetf1 requested review from a team and nrfulton as code owners March 20, 2026 16:23
@planetf1
Copy link
Contributor Author

Fixed the outstanding omissions/corrections. Analysis:

Docstring Quality Gate Fixes — Change Classification

Tier 1: Docstring-Only (Zero Risk)

Pure docstring text changes — no code, no imports, no annotations touched.

File Issues Fixed Change
cli/decompose/decompose.py missing Added Google-style docstrings to reorder_subtasks, verify_user_variables
cli/eval/runner.py missing_return_type Added Returns: sections to to_dict, parse_judge_output docstrings
mellea/core/sampling.py return_type_mismatch Docstring SamplingResult:SamplingResult[S]:
mellea/core/utils.py no_returns Added Returns: section to format() docstring
mellea/stdlib/functional.py return_type_mismatch Docstring return types updated to match tuple[ModelOutputThunk, Context] etc.
mellea/stdlib/sampling/base.py return_type_mismatch Docstring SamplingResult:SamplingResult[S]:
mellea/formatters/granite/intrinsics/input.py no_args + 1× no_returns Converted reST :param/:returns: to Google Args:/Returns:
cli/alora/intrinsic_uploader.py param_type_mismatch Docstring Literal["lora", "alora"]Literal['lora', 'alora'] (AST quote normalization)
docs/docs/guide/CONTRIBUTING.md Added note explaining AST single-quote normalization for Literal types

Tier 2: Type Annotation Additions (Low Risk)

Adding type annotations to previously untyped parameters/returns. No runtime behavior change — Python ignores annotations at runtime.

File Issues Fixed Change
cli/alora/train.py missing_param_type + 1× missing_return_type Added param types to load_dataset_from_json, formatting_prompts_func, on_evaluate
mellea/backends/tools.py missing_return_type + 1× missing_param_type Added return types to from_langchain, from_smolagents, from_callable; param type to find_func
mellea/core/utils.py missing_param_type + 1× missing_return_type Added record: logging.LogRecord and -> dict to format()
mellea/helpers/openai_compatible_helpers.py missing_return_type Added -> dict to message_to_openai_message
mellea/stdlib/components/mify.py missing_return_type Added -> object to mify
mellea/stdlib/session.py missing_return_type Added -> MelleaSession to clone (file already uses from __future__ import annotations)
mellea/stdlib/sampling/base.py missing_return_type Added -> int to MultiTurnStrategy.select_from_failure

Tier 3: Requires Justification (Medium Risk)

Changes involving imports or type annotations that interact with inheritance or optional dependencies.

3a. Granite 3.2/3.3 sanitize() override — granite32/input.py, granite33/input.py

What changed: Added from ...granite3.types import Granite3ChatCompletion import. Changed sanitize() docstring parts (str)parts (list[str] | str) to match annotation. Used Granite3ChatCompletion in sanitize() signature.

Why needed: The sanitize() classmethod overrides a parent method that accepts Granite3ChatCompletion. Without the correct type, mypy flagged an incompatible override (the parent expects Granite3ChatCompletion, the child was using ChatCompletion).

Solution rationale: The lowest-risk fix that produces correct docstrings. Granite3ChatCompletion is already loaded transitively through the parent class import chain, 7 other files use the identical import, and there is no circular dependency risk. The method body is completely unchanged — only the type annotation and docstring were updated to match what the parent already declares.

3b. HuggingFace optional-dependency types — util.py

What changed: Added from __future__ import annotations, TYPE_CHECKING guard with from transformers import PreTrainedModel, PreTrainedTokenizerBase, typed 4 previously untyped params across 2 functions, added 5× # type: ignore[union-attr].

Why needed: load_transformers_lora, chat_completion_request_to_transformers_inputs, and generate_with_transformers had completely untyped params, causing missing_param_type and missing_return_type quality gate failures. The HF types are optional dependencies — using Any would have been no improvement over the original untyped params (which mypy already treats as implicit Any).

Solution rationale: Three approaches were evaluated:

  1. Any annotations — rejected because it adds import noise for zero docstring improvement; Any is semantically identical to the original untyped params.
  2. Proper HF types without suppressions — rejected because adding real types caused mypy to check function bodies it previously skipped (untyped functions get implicit Any and no body checking). This exposed 5 pre-existing None-safety bugs where tokenizer and model (which default to None) are used without guards. Fixing those bugs would be a runtime code change inappropriate for a docs PR.
  3. Proper HF types + type: ignore[union-attr] — chosen as the lowest-risk path to correct docstrings. The TYPE_CHECKING guard ensures HF is never imported at runtime. The | None on params is truthful (they have =None defaults). The type: ignore comments are surgical suppressions of pre-existing issues, not new ones.

Follow-up needed: The 5 suppressed union-attr errors represent genuine None-safety gaps — these functions accept None via default params but unconditionally access .apply_chat_template(), .device, .pad_token_id, and .eos_token_id without guards. Additionally, mypy across the full repo currently reports 12 errors (cpex optional-dependency stubs, dict variance in mobject.py, Tensor not callable in util.py). A separate issue should track a broader mypy/type-verification pass across the mellea/formatters/granite/ module and the repo-wide pre-existing failures.

Adding TYPE_CHECKING annotations to util.py made mypy check function
bodies it previously skipped (untyped params = implicit Any = no body
checking). This exposed a pre-existing Tensor-not-callable issue and
a dict-variance issue in mobject.py. Suppress with targeted type:
ignore comments — these are not new bugs, just newly visible ones.
@planetf1 planetf1 added this pull request to the merge queue Mar 20, 2026
Merged via the queue into generative-computing:main with commit a4b0a71 Mar 20, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: gate doc quality in CI and pre-commit to prevent future degradation

3 participants