test(engine): make TestDrainTimeout deterministic + preserve subclass type in @ontology_entity#1729
Conversation
The decorator's positional overload returned type[BaseModel], which erased the concrete subclass type. Pyright reported false-positive 'no attribute' diagnostics on every @ontology_entity-decorated class (Task, Artifact, Agent, Project, Role, MeetingRecord, OrgFact, etc.). Mypy was lenient because the alternative overload returned Any. Use PEP 695 inline type parameters bound to BaseModel so the decorated class identity flows through to consumers. Static analysers now resolve Task as type[Task] instead of type[BaseModel].
stop(timeout=T) installs an outer hard-deadline at 2*T and re-raises TimeoutError when cleanup exceeds it. The original 50 ms budget left only ~50 ms for cancellation plus future-cleanup, which raced under xdist load on slow CI runners and surfaced as TimeoutError escaping stop() (e.g. PR #1727 hit this). Bump the budget to 500 ms so the cleanup margin is 500 ms instead of 50 ms. The same contract is exercised (inner drain still fires, queued futures still resolve to shutdown failure) without race sensitivity. Inline comment explains the budget choice tied to the hard-deadline ratio so the next reader does not lower it back.
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
🧰 Additional context used📓 Path-based instructions (6)**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
{src,tests}/**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
src/**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
⚙️ CodeRabbit configuration file
Files:
{src,web/src}/**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
{src,web/src}/**/*.{py,tsx,ts}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
tests/**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
⚙️ CodeRabbit configuration file
Files:
🔇 Additional comments (3)
WalkthroughThis pull request updates the type stubs for the 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Review rate limit: 3/5 reviews remaining, refill in 17 minutes and 30 seconds. Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request updates the ontology_entity decorator to use PEP 695 generic syntax, aiming to preserve concrete subclass types in static analysis, and increases a test timeout to improve CI stability. The review identifies critical runtime issues: Callable and BaseModel are imported only during type checking but are required at runtime for signature evaluation, which will cause NameError exceptions. Furthermore, the decorator factory overload is flagged for potential type erasure since the generic parameter T cannot be inferred from the factory's arguments.
| logger = get_logger(__name__) | ||
|
|
||
| if TYPE_CHECKING: | ||
| from collections.abc import Callable |
There was a problem hiding this comment.
The Callable import is placed inside a TYPE_CHECKING block, but it is used in the runtime signatures of the ontology_entity overloads (e.g., line 151). Since this module does not use from __future__ import annotations, these signatures are evaluated when the module is loaded, which will result in a NameError at runtime. This import should be moved outside the TYPE_CHECKING block.
| logger = get_logger(__name__) | |
| if TYPE_CHECKING: | |
| from collections.abc import Callable | |
| from collections.abc import Callable | |
| logger = get_logger(__name__) | |
| if TYPE_CHECKING: |
| # false-positive "no attribute" diagnostics. | ||
| @overload | ||
| def ontology_entity(cls: type[BaseModel], /) -> type[BaseModel]: ... | ||
| def ontology_entity[T: BaseModel](cls: type[T], /) -> type[T]: ... |
There was a problem hiding this comment.
The PEP 695 type parameter T uses BaseModel as its bound. In Python 3.12+, bounds of type parameters are evaluated at runtime when the function is defined. Since BaseModel is only imported within a TYPE_CHECKING block (line 27) and annotations are not deferred via from __future__ import annotations, this will cause a NameError at runtime. Additionally, the use of EntityTier and EntitySource in the subsequent overload's signature will trigger similar errors. To fix this while avoiding circular imports, you may need to use the traditional TypeVar syntax with a string forward reference for the bound: T = TypeVar("T", bound="BaseModel").
| def ontology_entity[T: BaseModel]( | ||
| *, | ||
| entity_name: str | None = None, | ||
| tier: EntityTier | None = None, | ||
| source: EntitySource | None = None, | ||
| ) -> Any: ... | ||
| ) -> Callable[[type[T]], type[T]]: ... |
There was a problem hiding this comment.
The second overload for ontology_entity (the decorator factory) appears to erase the concrete subclass type in static analysis. The type parameter T is scoped to the ontology_entity function and is bound when the factory is called. Because T is not used in the factory's arguments, it cannot be inferred and will default to its bound (BaseModel). Consequently, the returned callable is typed as Callable[[type[BaseModel]], type[BaseModel]], which erases the specific identity of the decorated class. To preserve the subclass type, the returned callable itself should be generic (e.g., by using a Protocol with a generic __call__ or using a module-level TypeVar).
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1729 +/- ##
=======================================
Coverage 84.72% 84.73%
=======================================
Files 1789 1789
Lines 102395 102395
Branches 8991 8991
=======================================
+ Hits 86756 86762 +6
+ Misses 13452 13449 -3
+ Partials 2187 2184 -3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
<!-- HIGHLIGHTS_START --> ## Highlights > _AI-generated summary (model: `openai/gpt-4.1-mini` via GitHub Models). Commit-based changelog below._ ### What you'll notice - Frontend and UX polishing improves user interface responsiveness and visual consistency. - API hygiene and validation enhancements provide smoother and more reliable interactions. ### What's new - Introduced typed-boundary helpers enabling better type safety and parse_typed workflows. - Added codebase-audit skill prompt tuning for improved project auditing. ### Under the hood - Eliminated flaky tests caused by module-level state for more stable test outcomes. - Unified image tag management under CLI and Renovate for consistent dependency updates. - Added cross-PR file-overlap analysis to the review dependency pull request skill. - Updated multiple dependencies including Python, Web, CLI, and container libraries. - Improved CI tooling and lock file maintenance for better build reliability. <!-- HIGHLIGHTS_END --> :robot: I have created a release *beep* *boop* --- ## [0.7.8](v0.7.7...v0.7.8) (2026-05-03) ### Features * **api:** typed-boundary helper + codebase-audit skill prompt tuning ([#1712](#1712)) ([40ee65b](40ee65b)) * **boundary:** RFC [#1711](#1711) Phases 2 + 3 — typed boundaries via parse_typed ([#1720](#1720)) ([7b9f409](7b9f409)) ### Bug Fixes * **api:** audit cleanup B -- API hygiene & validation ([#1719](#1719)) ([3d790d9](3d790d9)) * audit cleanup C - persistence, concurrency & data integrity ([#1708](#1708)) ([#1717](#1717)) ([bcce097](bcce097)) * **test:** exterminate xdist-flaky tests with module-level state ([#1713](#1713)) ([#1721](#1721)) ([8d258dd](8d258dd)) * **web:** audit cleanup E -- frontend & UX polish ([#1710](#1710)) ([#1718](#1718)) ([3a3591a](3a3591a)) ### Refactoring * **cli:** single source of truth for DHI image tags + Renovate manager ([#1723](#1723)) ([57980a2](57980a2)) ### Documentation * audit cleanup D -- public-facing & docs sync ([#1709](#1709)) ([#1715](#1715)) ([ade03b7](ade03b7)) ### Tests * **engine:** make TestDrainTimeout deterministic + preserve subclass type in [@Ontology](https://github.com/ontology)_entity ([#1729](#1729)) ([b00fb05](b00fb05)) ### CI/CD * Update CI tool dependencies ([#1703](#1703)) ([355a9ff](355a9ff)) ### Maintenance * add cross-PR file-overlap analysis to review-dep-pr skill ([#1722](#1722)) ([3861d8a](3861d8a)) * **ci:** unify apko-version under workflow env so Renovate manages it everywhere ([#1724](#1724)) ([9c0a7fd](9c0a7fd)) * consolidate DHI image-pin custom regex managers ([#1726](#1726)) ([b8b0cba](b8b0cba)) * **deps:** update dependency chainguard-dev/melange to v0.50.4 ([#1701](#1701)) ([8cbf83a](8cbf83a)) * Lock file maintenance ([#1705](#1705)) ([414cfea](414cfea)) * Lock file maintenance ([#1727](#1727)) ([5cb1212](5cb1212)) * Update CLI dependencies ([#1702](#1702)) ([9fb57b9](9fb57b9)) * Update Container dependencies ([#1698](#1698)) ([6d24fd6](6d24fd6)) * Update dependency @eslint-react/eslint-plugin to v5 ([#1704](#1704)) ([1cb1294](1cb1294)) * Update Python dependencies ([#1699](#1699)) ([8e7af3a](8e7af3a)) * Update Python dependencies to v4.15.0 ([#1725](#1725)) ([69164c8](69164c8)) * Update Web dependencies ([#1700](#1700)) ([715300d](715300d)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: synthorg-repo-bot[bot] <279117679+synthorg-repo-bot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
Fix the timing-sensitive
TestDrainTimeout::test_drain_timeout_resolves_pending_futuresflake hit by PR #1727'sTest (Python 3.14)job, plus a foundational fix to the@ontology_entitydecorator that surfaced as Pyright false-positives in the same file.Root cause (test flake)
PR #1545 (commit
13f3db679, "TOCTOU races + resource leaks") changedTaskEngine.stop()to install an outer hard-deadline at2 × timeoutand re-raiseTimeoutErrorwhen cleanup exceeds it. The pre-existing test calledawait eng.stop(timeout=0.05)and expectedstop()to return cleanly, leaving only ~50 ms for cancellation + future-cleanup. Under xdist load on slow Ubuntu CI runners, cleanup intermittently overruns 50 ms, the outer hard-deadline fires, andTimeoutErrorescapes to the test as1 failed, 27881 passed.Changes
tests/unit/engine/test_task_engine_integration.pystop(timeout=…)from0.05to0.5. Same contract is exercised (inner drain still fires, queued futures still resolve to shutdown failure) without race sensitivity. Cleanup margin grows from 50 ms to 500 ms — comfortably above the few milliseconds the cleanup actually needs.2 × timeouthard-deadline ratio so the next reader doesn't lower it back.src/synthorg/ontology/decorator.pytype[BaseModel], erasing concrete subclass identity. Pyright reported false-positive "no attribute" diagnostics on every@ontology_entity-decorated class (Task, Artifact, Agent, Project, Role, MeetingRecord, OrgFact, etc.). Mypy was lenient because the alternative overload returnedAny.def ontology_entity[T: BaseModel](cls: type[T], /) -> type[T]: ...), bound toBaseModel. Static analysers now resolveTaskastype[Task]instead oftype[BaseModel].Test plan
tests/unit/engine/test_task_engine_integration.py— 11/11 PASSED in 12 s.Success: no issues found in 3626 source files.Review coverage
This PR was opened directly via the GitHub MCP tool because a parallel
/pre-pr-reviewis running in another terminal on a different branch. The full pre-PR review pipeline (specialist agents, triage gate) was not invoked. The changes are narrow and verified by the gates listed above.Run
/aurelio-review-prafter external reviewers (CodeRabbit, etc.) provide feedback.