test: verify Copilot reads copilot-instructions.md from PR branch#478
test: verify Copilot reads copilot-instructions.md from PR branch#478
Conversation
- .github/CODING_GUIDELINES.md: comprehensive coding standards for all contributors (type safety, data modelling, naming, testing, security) - .github/copilot-instructions.md: Copilot-specific instructions that reference the guidelines file plus workflow rules and repo layout Closes #110 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Temporary commit to verify whether Copilot code review reads copilot-instructions.md from the PR branch and flags violations. Violations included: - TYPE_CHECKING (banned) - getattr (banned) - hasattr (banned) - assert for type validation (banned) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Test PR to determine whether Copilot code review reads .github/copilot-instructions.md (and linked .github/CODING_GUIDELINES.md) from the PR head branch by introducing intentionally non-compliant code.
Changes:
- Add repository coding standards in
.github/CODING_GUIDELINES.md. - Add
.github/copilot-instructions.mdpointing Copilot to those standards. - Add
src/copilot_usage/_test_violations.pycontaining deliberate guideline violations (e.g.,TYPE_CHECKING,getattr/hasattr,assertvalidation).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
src/copilot_usage/_test_violations.py |
Adds intentionally non-compliant Python code to test instruction adherence. |
.github/copilot-instructions.md |
Adds Copilot-specific guidance and links to the coding guidelines. |
.github/CODING_GUIDELINES.md |
Adds documented coding standards intended for contributors and agents. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from typing import TYPE_CHECKING | ||
|
|
||
| if TYPE_CHECKING: | ||
| from loguru import Logger |
There was a problem hiding this comment.
from loguru import Logger is imported but never used. This will trip ruff F401 unless suppressed (the existing codebase uses # noqa: F401 for type-only imports) or the symbol is referenced in an annotation.
| from loguru import Logger | |
| from loguru import Logger # noqa: F401 |
|
|
||
| def get_value(obj: object, key: str) -> str | None: | ||
| """Get a value using getattr — violates guidelines.""" | ||
| return getattr(obj, key, None) |
There was a problem hiding this comment.
get_value is annotated to return str | None, but getattr(obj, key, None) can return a non-str value at runtime and is also disallowed by the new guidelines. Prefer an explicitly typed interface (e.g., a Protocol or Mapping) and direct attribute access, or validate/convert the value before returning.
| return getattr(obj, key, None) | |
| value = getattr(obj, key, None) | |
| if value is None: | |
| return None | |
| return str(value) |
| def check_type(value: object) -> bool: | ||
| """Use hasattr — violates guidelines.""" | ||
| if hasattr(value, "name"): | ||
| return True | ||
| return False |
There was a problem hiding this comment.
Using hasattr here is both discouraged by the new guidelines and provides only a weak runtime check (it doesn't guarantee type/shape). Prefer passing a properly typed object (or Protocol) so attribute access is statically verified.
| - **`TYPE_CHECKING` is banned.** Do not use `from typing import | ||
| TYPE_CHECKING` or `if TYPE_CHECKING:` guards. Every import used in an | ||
| annotation must be a real runtime import. Circular imports are a design | ||
| bug — fix the module graph, do not hide cycles behind `TYPE_CHECKING`. |
There was a problem hiding this comment.
This guideline bans TYPE_CHECKING, but the current codebase already relies on it (e.g. src/copilot_usage/logging_config.py uses TYPE_CHECKING plus # noqa: F401, and coverage config excludes if TYPE_CHECKING:). Either relax this rule (and document the allowed pattern) or plan a refactor to remove existing TYPE_CHECKING usage and update tooling config accordingly.
| - **`TYPE_CHECKING` is banned.** Do not use `from typing import | |
| TYPE_CHECKING` or `if TYPE_CHECKING:` guards. Every import used in an | |
| annotation must be a real runtime import. Circular imports are a design | |
| bug — fix the module graph, do not hide cycles behind `TYPE_CHECKING`. | |
| - **Avoid `TYPE_CHECKING` in new code.** Prefer real runtime imports for all | |
| symbols used in annotations. Circular imports are a design bug — fix the | |
| module graph rather than hiding cycles behind `TYPE_CHECKING`. | |
| - Existing modules that already use `from typing import TYPE_CHECKING` and | |
| `if TYPE_CHECKING:` guards (with `# noqa: F401` and excluded from coverage) | |
| are allowed but should follow that pattern consistently until they can be | |
| refactored to use acyclic runtime imports. |
|
|
||
| def validate(x: object) -> None: | ||
| """Use assert for type validation — violates guidelines.""" | ||
| assert isinstance(x, str), "must be a string" |
There was a problem hiding this comment.
Using assert for validation is unsafe because assertions can be stripped with python -O, so this function may perform no validation in production. Raise a real exception (TypeError/ValueError) or use a Pydantic model at the boundary instead.
| assert isinstance(x, str), "must be a string" | |
| if not isinstance(x, str): | |
| raise TypeError("must be a string") |
| - **No `isinstance` checks as a substitute for proper typing.** If the type | ||
| system cannot express the constraint, refactor so it can. |
There was a problem hiding this comment.
The blanket ban on isinstance checks conflicts with existing boundary-parsing code (e.g. src/copilot_usage/parser.py uses isinstance to validate JSON-derived values). Consider scoping this rule to business logic only, or explicitly allowing runtime checks when converting untyped external data into typed models.
| - **No `isinstance` checks as a substitute for proper typing.** If the type | |
| system cannot express the constraint, refactor so it can. | |
| - **Avoid `isinstance` checks in business logic.** Use static typing and data | |
| models instead; reserve `isinstance` for validating untyped external data | |
| at I/O boundaries (e.g. parsing JSON into typed models). |
| - Use `default_factory=lambda: []` (not `default_factory=list`) for mutable | ||
| defaults — this avoids a known pyright false-positive. |
There was a problem hiding this comment.
This recommends default_factory=lambda: [] instead of default_factory=list for mutable defaults, but the codebase currently uses Field(default_factory=list) in Pydantic models (e.g. src/copilot_usage/models.py). If this guidance only applies to dataclasses.field, clarify that to avoid confusion, or align existing usage with the rule.
| - Use `default_factory=lambda: []` (not `default_factory=list`) for mutable | |
| defaults — this avoids a known pyright false-positive. | |
| - For `dataclasses.field`, use `default_factory=lambda: []` (not | |
| `default_factory=list`) for mutable defaults — this avoids a known pyright | |
| false-positive. | |
| - For Pydantic models, `Field(default_factory=list)` is acceptable and does | |
| not need the lambda workaround. |
| all code changes. Key points: | ||
|
|
||
| - **pyright strict** — every parameter and return value must be annotated. | ||
| - **No duck typing** — no `getattr`, `hasattr`, or runtime type interrogation. |
There was a problem hiding this comment.
This instruction bans runtime type checks, but the existing parser currently uses isinstance checks to safely coerce untyped JSON config/events into typed values. If the intent is to prohibit duck-typing in business logic, consider clarifying that boundary validation/parsing is exempt (or update the codebase to comply).
| - **No duck typing** — no `getattr`, `hasattr`, or runtime type interrogation. | |
| - **No duck typing in business logic** — do not use `getattr`, `hasattr`, or runtime type | |
| interrogation in core logic. Boundary validation/parsing (for example, coercing untyped | |
| JSON/config using `isinstance`) is allowed. |
| from typing import TYPE_CHECKING | ||
|
|
||
| if TYPE_CHECKING: | ||
| from loguru import Logger | ||
|
|
||
|
|
There was a problem hiding this comment.
TYPE_CHECKING blocks are introduced here, but the new CODING_GUIDELINES in this PR explicitly ban from typing import TYPE_CHECKING / if TYPE_CHECKING:. If these guidelines are meant to apply, remove the guard and resolve any import cycles by refactoring, or adjust the guidelines to allow type-only imports.
| from typing import TYPE_CHECKING | |
| if TYPE_CHECKING: | |
| from loguru import Logger |
|
Test complete — Copilot reads copilot-instructions.md from PR branch and flags violations. Closing to refine guidelines and do a proper PR. |
Test PR — DO NOT MERGE
This PR tests whether Copilot code review automatically reads
.github/copilot-instructions.mdfrom the PR head branch.What's in this PR:
.github/CODING_GUIDELINES.md— our coding standards.github/copilot-instructions.md— points Copilot to the guidelinessrc/copilot_usage/_test_violations.py— deliberate violations of the guidelines:TYPE_CHECKING(banned)getattr(banned)hasattr(banned)assertfor type validation (banned)Expected outcome:
After testing:
This PR will be closed and discarded.