refactor: split events.py into per-domain event modules#136
Conversation
Replace monolithic observability/events.py with a per-domain package (events/config.py, events/provider.py, events/budget.py, etc.) for better locality and scalability as new domains are added in M3+. Update all 37 source and test imports to use domain-specific modules. No backwards-compat re-exports — clean break. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update DESIGN_SPEC.md §15.5 event constants row from "Adopted (flat)" to "Adopted (per-domain)" to reflect the new package structure - Add attr.isupper() guard to _all_event_names() test helper to prevent accidental inclusion of non-constant string attributes - Add __all__: list[str] = [] to events/__init__.py to explicitly signal no re-exports from the package - Soften docstring convention from strict "domain.noun.verb" to "domain.noun[.verb]" to accommodate two-segment event names - Add spot-check tests for execution, routing, prompt, and tool domains Pre-reviewed by 9 agents, 5 findings addressed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (14)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe PR reorganizes observability event constants from a single flat module ( Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the organization and maintainability of event constants by transitioning from a single, large module to a structured package with domain-specific submodules. This change improves code discoverability, reduces potential merge conflicts as the system grows, and ensures a clearer separation of concerns for observability events. The refactoring also involved comprehensive updates to all affected imports and relevant documentation, ensuring consistency across the codebase. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Greptile SummaryThis PR successfully refactors the monolithic Migration completeness: All 104 constants are accounted for across the 10 new modules with no renames, losses, or duplicates. The old flat Import updates: All 23 source files correctly import from their domain-specific modules using the pattern Package structure: The Test coverage: Comprehensive test suite with dynamic Documentation: The refactoring is purely mechanical with zero functional changes and thorough test validation. Confidence Score: 5/5
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
subgraph NEW["After: events/ package"]
PKG["events/__init__.py\n(package marker, __all__=)"]
B["events/budget.py - 7 constants"]
C["events/config.py - 9 constants"]
EX["events/execution.py - 11 constants"]
P["events/prompt.py - 7 constants"]
PR["events/provider.py - 27 constants"]
RO["events/role.py - 1 constant"]
RT["events/routing.py - 11 constants"]
T["events/task.py - 3 constants"]
TM["events/template.py - 13 constants"]
TL["events/tool.py - 15 constants"]
end
PKG --- B & C & EX & P & PR & RO & RT & T & TM & TL
BC["budget/tracker.py"] -->|"from events.budget import ..."| B
CF["config/loader.py"] -->|"from events.config import ..."| C
EP["engine/prompt.py"] -->|"from events.prompt import ..."| P
PB["providers/base.py"] -->|"from events.provider import ..."| PR
TR["providers/routing/router.py"] -->|"from events.routing import ..."| RT
Last reviewed commit: 1274c70 |
There was a problem hiding this comment.
Pull request overview
Refactors observability event constants by replacing the monolithic src/ai_company/observability/events.py with a per-domain src/ai_company/observability/events/ package, and updates internal imports/tests/docs to use domain-scoped event modules.
Changes:
- Split event constants into per-domain modules (
events/{budget,config,execution,prompt,provider,role,routing,task,template,tool}.py) and removed the old flatevents.py. - Updated source + test imports to
from ai_company.observability.events.<domain> import <CONSTANT>. - Updated docs (CLAUDE.md, DESIGN_SPEC.md) and expanded/adjusted event constant tests to enumerate modules under the new package.
Reviewed changes
Copilot reviewed 50 out of 50 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/templates/test_renderer.py | Updates template event imports to events.template. |
| tests/unit/providers/test_registry.py | Updates provider event imports to events.provider. |
| tests/unit/providers/test_base_provider.py | Updates provider event imports to events.provider. |
| tests/unit/providers/routing/test_router.py | Updates routing event imports to events.routing (including in-function import). |
| tests/unit/providers/resilience/test_retry.py | Updates resilience/provider event imports to events.provider. |
| tests/unit/providers/resilience/test_rate_limiter.py | Updates rate-limiter/provider event imports to events.provider. |
| tests/unit/observability/test_events.py | Updates event constant discovery to iterate per-domain modules; adds spot-check assertions for all domains. |
| tests/unit/engine/test_task_execution.py | Updates execution event imports to events.execution. |
| tests/unit/engine/test_context.py | Updates execution event imports to events.execution. |
| tests/unit/core/test_task_transitions.py | Updates task transition event imports to events.task. |
| tests/unit/core/test_task.py | Updates task event imports to events.task. |
| tests/unit/config/test_loader.py | Updates config event imports to events.config. |
| tests/unit/budget/test_tracker.py | Updates budget event imports to events.budget. |
| src/ai_company/tools/registry.py | Updates tool event imports to events.tool. |
| src/ai_company/tools/invoker.py | Updates tool event imports to events.tool. |
| src/ai_company/tools/base.py | Updates tool event import to events.tool. |
| src/ai_company/templates/renderer.py | Updates template event imports to events.template. |
| src/ai_company/templates/loader.py | Updates template event imports to events.template. |
| src/ai_company/providers/routing/strategies.py | Updates routing event imports to events.routing. |
| src/ai_company/providers/routing/router.py | Updates routing event imports to events.routing. |
| src/ai_company/providers/routing/resolver.py | Updates routing event imports to events.routing. |
| src/ai_company/providers/resilience/retry.py | Updates provider/resilience event imports to events.provider. |
| src/ai_company/providers/resilience/rate_limiter.py | Updates provider/resilience event imports to events.provider. |
| src/ai_company/providers/registry.py | Updates provider registry event imports to events.provider. |
| src/ai_company/providers/drivers/mappers.py | Updates provider driver event imports to events.provider. |
| src/ai_company/providers/drivers/litellm_driver.py | Updates provider driver event imports to events.provider. |
| src/ai_company/providers/base.py | Updates provider base event imports to events.provider. |
| src/ai_company/observability/events/budget.py | New per-domain budget event constants module. |
| src/ai_company/observability/events/config.py | New per-domain config event constants module. |
| src/ai_company/observability/events/execution.py | New per-domain execution event constants module. |
| src/ai_company/observability/events/prompt.py | New per-domain prompt event constants module. |
| src/ai_company/observability/events/provider.py | New per-domain provider/resilience event constants module. |
| src/ai_company/observability/events/role.py | New per-domain role event constants module. |
| src/ai_company/observability/events/routing.py | New per-domain routing event constants module. |
| src/ai_company/observability/events/task.py | New per-domain task event constants module. |
| src/ai_company/observability/events/template.py | New per-domain template event constants module. |
| src/ai_company/observability/events/tool.py | New per-domain tool event constants module. |
| src/ai_company/observability/events/init.py | Adds package docstring + explicitly avoids re-exports (__all__ = []). |
| src/ai_company/observability/events.py | Removes the legacy flat module containing all event constants. |
| src/ai_company/engine/task_execution.py | Updates execution event imports to events.execution. |
| src/ai_company/engine/prompt.py | Updates prompt event imports to events.prompt. |
| src/ai_company/engine/context.py | Updates execution event imports to events.execution. |
| src/ai_company/core/task_transitions.py | Updates task transition event imports to events.task. |
| src/ai_company/core/task.py | Updates task event import to events.task. |
| src/ai_company/core/role_catalog.py | Updates role event import to events.role. |
| src/ai_company/config/schema.py | Updates config validation event import to events.config. |
| src/ai_company/config/loader.py | Updates config loader event imports to events.config. |
| src/ai_company/budget/tracker.py | Updates budget event imports to events.budget. |
| DESIGN_SPEC.md | Updates project tree + event constants convention to “per-domain” modules. |
| CLAUDE.md | Updates logging guidance to import event constants from events.<domain>. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ``events.provider``, ``events.budget``, ``events.tool``). | ||
| """ | ||
|
|
||
| __all__: list[str] = [] |
There was a problem hiding this comment.
Changing ai_company.observability.events from a flat module to a package with __all__ = [] removes the previously supported import style (from ai_company.observability.events import CONFIG_LOADED / events.CONFIG_LOADED). This is a breaking API change and also conflicts with issue #110’s acceptance criterion that existing imports keep working. Consider adding a backwards-compat shim (e.g., restore observability/events.py as a thin re-export layer and optionally emit a DeprecationWarning), or re-export constants from events/__init__.py for one release cycle while enforcing the new domain-specific imports via lint/docs.
| __all__: list[str] = [] | |
| from importlib import import_module | |
| from typing import Any | |
| import warnings | |
| # Public submodules for the new, domain-specific import style. | |
| __all__: list[str] = ["config", "provider", "budget", "tool"] | |
| # Internal list of modules to search for legacy, flat-namespace attributes. | |
| _BACKCOMPAT_MODULES: tuple[str, ...] = tuple(__all__) | |
| def __getattr__(name: str) -> Any: | |
| """Backwards-compat attribute access for legacy flat-module imports. | |
| This allows older code such as: | |
| from ai_company.observability.events import CONFIG_LOADED | |
| events.CONFIG_LOADED | |
| to keep working by resolving constants from the appropriate domain | |
| submodule, while emitting a DeprecationWarning to encourage the | |
| new import style:: | |
| from ai_company.observability.events.config import CONFIG_LOADED | |
| """ | |
| # First, allow attribute-style access to submodules themselves, e.g. | |
| # ai_company.observability.events.config | |
| if name in _BACKCOMPAT_MODULES: | |
| module = import_module(f"{__name__}.{name}") | |
| globals()[name] = module | |
| return module | |
| # Next, search each known domain module for the requested attribute. | |
| for module_name in _BACKCOMPAT_MODULES: | |
| module = import_module(f"{__name__}.{module_name}") | |
| if hasattr(module, name): | |
| warnings.warn( | |
| f"`ai_company.observability.events.{name}` is deprecated; " | |
| f"import it from `ai_company.observability.events.{module_name}` instead.", | |
| DeprecationWarning, | |
| stacklevel=2, | |
| ) | |
| value = getattr(module, name) | |
| # Cache the resolved attribute on this module for faster reuse. | |
| globals()[name] = value | |
| return value | |
| raise AttributeError(f"module {__name__!r} has no attribute {name!r}") |
There was a problem hiding this comment.
Code Review
This pull request refactors the ai_company.observability.events module by transitioning from a single, monolithic events.py file to a package structure (events/) containing multiple domain-specific submodules (e.g., events.budget, events.config, events.provider). This change aims to enhance discoverability, co-locate event constants with their relevant domain logic, and mitigate merge conflicts as the codebase expands. Documentation in CLAUDE.md and DESIGN_SPEC.md has been updated to reflect this new structure and the recommended import pattern. Consequently, all application code and unit tests that previously imported event constants from the singular events.py file have been updated to import them from their new, specific domain submodules.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/ai_company/providers/drivers/litellm_driver.py (1)
44-58:⚠️ Potential issue | 🟠 MajorEnsure backward compatibility for event constant imports across the codebase.
The direct submodule imports (lines 44-58) correctly follow the guidelines. However,
src/ai_company/observability/events/__init__.pyexports no uppercase constants (__all__is empty), which breaks any external or internal imports using the package-root patternfrom ai_company.observability.events import PROVIDER_CALL_ERROR. If this migration is intentional, confirm it doesn't conflict with other modules in the PR or external consumers. If backward compatibility is required, expose constants via__all__at the package root.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/ai_company/providers/drivers/litellm_driver.py` around lines 44 - 58, The package root for observability events doesn't export the uppercase constants, breaking imports like "from ai_company.observability.events import PROVIDER_CALL_ERROR"; update the package entry (the observability.events __init__.py) to re-export the required constants (e.g., PROVIDER_AUTH_ERROR, PROVIDER_CALL_ERROR, PROVIDER_CONNECTION_ERROR, PROVIDER_MODEL_INFO_UNAVAILABLE, PROVIDER_MODEL_INFO_UNEXPECTED_ERROR, PROVIDER_MODEL_NOT_FOUND, PROVIDER_RATE_LIMITED, PROVIDER_RETRY_AFTER_PARSE_FAILED, PROVIDER_STREAM_CHUNK_NO_DELTA, PROVIDER_STREAM_DONE, PROVIDER_TOOL_CALL_ARGUMENTS_PARSE_FAILED, PROVIDER_TOOL_CALL_ARGUMENTS_TRUNCATED, PROVIDER_TOOL_CALL_INCOMPLETE) by adding them to __all__ or explicitly importing and exposing them so existing imports using the package-root pattern continue to work.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/ai_company/providers/drivers/litellm_driver.py`:
- Around line 44-58: The package root for observability events doesn't export
the uppercase constants, breaking imports like "from
ai_company.observability.events import PROVIDER_CALL_ERROR"; update the package
entry (the observability.events __init__.py) to re-export the required constants
(e.g., PROVIDER_AUTH_ERROR, PROVIDER_CALL_ERROR, PROVIDER_CONNECTION_ERROR,
PROVIDER_MODEL_INFO_UNAVAILABLE, PROVIDER_MODEL_INFO_UNEXPECTED_ERROR,
PROVIDER_MODEL_NOT_FOUND, PROVIDER_RATE_LIMITED,
PROVIDER_RETRY_AFTER_PARSE_FAILED, PROVIDER_STREAM_CHUNK_NO_DELTA,
PROVIDER_STREAM_DONE, PROVIDER_TOOL_CALL_ARGUMENTS_PARSE_FAILED,
PROVIDER_TOOL_CALL_ARGUMENTS_TRUNCATED, PROVIDER_TOOL_CALL_INCOMPLETE) by adding
them to __all__ or explicitly importing and exposing them so existing imports
using the package-root pattern continue to work.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c9c9db61-2b8c-424d-be0d-4bfd61919be2
📒 Files selected for processing (50)
CLAUDE.mdDESIGN_SPEC.mdsrc/ai_company/budget/tracker.pysrc/ai_company/config/loader.pysrc/ai_company/config/schema.pysrc/ai_company/core/role_catalog.pysrc/ai_company/core/task.pysrc/ai_company/core/task_transitions.pysrc/ai_company/engine/context.pysrc/ai_company/engine/prompt.pysrc/ai_company/engine/task_execution.pysrc/ai_company/observability/events.pysrc/ai_company/observability/events/__init__.pysrc/ai_company/observability/events/budget.pysrc/ai_company/observability/events/config.pysrc/ai_company/observability/events/execution.pysrc/ai_company/observability/events/prompt.pysrc/ai_company/observability/events/provider.pysrc/ai_company/observability/events/role.pysrc/ai_company/observability/events/routing.pysrc/ai_company/observability/events/task.pysrc/ai_company/observability/events/template.pysrc/ai_company/observability/events/tool.pysrc/ai_company/providers/base.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/registry.pysrc/ai_company/providers/resilience/rate_limiter.pysrc/ai_company/providers/resilience/retry.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/routing/router.pysrc/ai_company/providers/routing/strategies.pysrc/ai_company/templates/loader.pysrc/ai_company/templates/renderer.pysrc/ai_company/tools/base.pysrc/ai_company/tools/invoker.pysrc/ai_company/tools/registry.pytests/unit/budget/test_tracker.pytests/unit/config/test_loader.pytests/unit/core/test_task.pytests/unit/core/test_task_transitions.pytests/unit/engine/test_context.pytests/unit/engine/test_task_execution.pytests/unit/observability/test_events.pytests/unit/providers/resilience/test_rate_limiter.pytests/unit/providers/resilience/test_retry.pytests/unit/providers/routing/test_router.pytests/unit/providers/test_base_provider.pytests/unit/providers/test_registry.pytests/unit/templates/test_renderer.py
💤 Files with no reviewable changes (1)
- src/ai_company/observability/events.py
📜 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). (2)
- GitHub Check: Agent
- GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Nofrom __future__ import annotations— Python 3.14 has PEP 649 native lazy annotations
Use PEP 758 except syntax:except A, B:without parentheses — ruff enforces this on Python 3.14
Add type hints to all public functions; ensure mypy strict mode compliance
Use Google-style docstrings on all public classes and functions — required and enforced by ruff D rules
Create new objects instead of mutating existing ones; for non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction and wrap with MappingProxyType for read-only enforcement
For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and use copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization)
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models for runtime state that evolves — never mix static config fields with mutable runtime fields in one model
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict); adopt@computed_fieldfor derived values instead of storing redundant fields; use NotBlankStr for all identifier/name fields including optional and tuple variants
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls) — prefer structured concurrency over bare create_task
Keep functions under 50 lines; keep files under 800 lines
Handle errors explicitly; never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)
Line length must be 88 characters — enforced by ruff
Files:
src/ai_company/config/loader.pytests/unit/providers/routing/test_router.pytests/unit/providers/test_registry.pysrc/ai_company/providers/base.pytests/unit/core/test_task.pysrc/ai_company/observability/events/execution.pysrc/ai_company/providers/drivers/litellm_driver.pytests/unit/engine/test_context.pysrc/ai_company/observability/events/role.pysrc/ai_company/observability/events/prompt.pytests/unit/templates/test_renderer.pysrc/ai_company/providers/resilience/rate_limiter.pysrc/ai_company/providers/routing/strategies.pysrc/ai_company/providers/routing/router.pysrc/ai_company/observability/events/config.pytests/unit/engine/test_task_execution.pysrc/ai_company/observability/events/template.pysrc/ai_company/observability/events/provider.pysrc/ai_company/observability/events/budget.pysrc/ai_company/engine/task_execution.pysrc/ai_company/tools/base.pysrc/ai_company/engine/context.pysrc/ai_company/budget/tracker.pytests/unit/providers/resilience/test_retry.pysrc/ai_company/templates/loader.pysrc/ai_company/observability/events/routing.pysrc/ai_company/engine/prompt.pysrc/ai_company/templates/renderer.pytests/unit/observability/test_events.pysrc/ai_company/core/task_transitions.pysrc/ai_company/tools/invoker.pysrc/ai_company/core/role_catalog.pytests/unit/config/test_loader.pytests/unit/budget/test_tracker.pytests/unit/providers/resilience/test_rate_limiter.pytests/unit/core/test_task_transitions.pysrc/ai_company/config/schema.pysrc/ai_company/providers/resilience/retry.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/registry.pysrc/ai_company/core/task.pysrc/ai_company/observability/events/__init__.pysrc/ai_company/observability/events/tool.pysrc/ai_company/tools/registry.pytests/unit/providers/test_base_provider.pysrc/ai_company/observability/events/task.py
src/ai_company/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
src/ai_company/**/*.py: Every module with business logic must import and use logger:from ai_company.observability import get_loggerthenlogger = get_logger(__name__)— use variable namelogger(not_logger, notlog)
Never useimport logging,logging.getLogger(), orprint()in application code — use the standardized logger from ai_company.observability
Always use event name constants from ai_company.observability.events (e.g. PROVIDER_CALL_START, BUDGET_RECORD_ADDED, TOOL_INVOKE_START) — import directly and log structured kwargs as logger.info(EVENT, key=value), never logger.info('msg %s', val)
All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; use DEBUG for object creation, internal flow, and entry/exit of key functions
Files:
src/ai_company/config/loader.pysrc/ai_company/providers/base.pysrc/ai_company/observability/events/execution.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/observability/events/role.pysrc/ai_company/observability/events/prompt.pysrc/ai_company/providers/resilience/rate_limiter.pysrc/ai_company/providers/routing/strategies.pysrc/ai_company/providers/routing/router.pysrc/ai_company/observability/events/config.pysrc/ai_company/observability/events/template.pysrc/ai_company/observability/events/provider.pysrc/ai_company/observability/events/budget.pysrc/ai_company/engine/task_execution.pysrc/ai_company/tools/base.pysrc/ai_company/engine/context.pysrc/ai_company/budget/tracker.pysrc/ai_company/templates/loader.pysrc/ai_company/observability/events/routing.pysrc/ai_company/engine/prompt.pysrc/ai_company/templates/renderer.pysrc/ai_company/core/task_transitions.pysrc/ai_company/tools/invoker.pysrc/ai_company/core/role_catalog.pysrc/ai_company/config/schema.pysrc/ai_company/providers/resilience/retry.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/registry.pysrc/ai_company/core/task.pysrc/ai_company/observability/events/__init__.pysrc/ai_company/observability/events/tool.pysrc/ai_company/tools/registry.pysrc/ai_company/observability/events/task.py
src/ai_company/config/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Set RetryConfig and RateLimiterConfig per-provider in ProviderConfig
Files:
src/ai_company/config/loader.pysrc/ai_company/config/schema.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
tests/**/*.py: Mark tests with@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e, or@pytest.mark.slow
Use asyncio_mode = 'auto' for async tests — no manual@pytest.mark.asyncioneeded
Use fake model IDs and vendor-agnostic fixture names in tests (e.g. test-haiku-001, test-provider) — never use real vendor model IDs; tests must not be coupled to external providers
Files:
tests/unit/providers/routing/test_router.pytests/unit/providers/test_registry.pytests/unit/core/test_task.pytests/unit/engine/test_context.pytests/unit/templates/test_renderer.pytests/unit/engine/test_task_execution.pytests/unit/providers/resilience/test_retry.pytests/unit/observability/test_events.pytests/unit/config/test_loader.pytests/unit/budget/test_tracker.pytests/unit/providers/resilience/test_rate_limiter.pytests/unit/core/test_task_transitions.pytests/unit/providers/test_base_provider.py
src/ai_company/providers/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
src/ai_company/providers/**/*.py: All provider calls go through BaseCompletionProvider which applies retry and rate limiting automatically — never implement retry logic in driver subclasses or calling code
Mark retryable errors with is_retryable=True: RateLimitError, ProviderTimeoutError, ProviderConnectionError, ProviderInternalError — all other errors raise immediately without retry
Rate limiter respects RateLimitError.retry_after from providers — automatically pauses future requests
Files:
src/ai_company/providers/base.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/resilience/rate_limiter.pysrc/ai_company/providers/routing/strategies.pysrc/ai_company/providers/routing/router.pysrc/ai_company/providers/resilience/retry.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/registry.py
src/ai_company/engine/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
RetryExhaustedError signals all retries failed — the engine layer catches this to trigger fallback chains
Files:
src/ai_company/engine/task_execution.pysrc/ai_company/engine/context.pysrc/ai_company/engine/prompt.py
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/**/*.py : Always use event name constants from ai_company.observability.events (e.g. PROVIDER_CALL_START, BUDGET_RECORD_ADDED, TOOL_INVOKE_START) — import directly and log structured kwargs as logger.info(EVENT, key=value), never logger.info('msg %s', val)
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/**/*.py : Always use event name constants from ai_company.observability.events (e.g. PROVIDER_CALL_START, BUDGET_RECORD_ADDED, TOOL_INVOKE_START) — import directly and log structured kwargs as logger.info(EVENT, key=value), never logger.info('msg %s', val)
Applied to files:
src/ai_company/config/loader.pyCLAUDE.mdtests/unit/providers/routing/test_router.pytests/unit/providers/test_registry.pysrc/ai_company/providers/base.pytests/unit/core/test_task.pysrc/ai_company/observability/events/execution.pysrc/ai_company/providers/drivers/litellm_driver.pytests/unit/engine/test_context.pysrc/ai_company/observability/events/prompt.pytests/unit/templates/test_renderer.pysrc/ai_company/providers/resilience/rate_limiter.pysrc/ai_company/providers/routing/strategies.pysrc/ai_company/providers/routing/router.pysrc/ai_company/observability/events/config.pytests/unit/engine/test_task_execution.pysrc/ai_company/observability/events/template.pysrc/ai_company/observability/events/provider.pysrc/ai_company/observability/events/budget.pysrc/ai_company/engine/task_execution.pysrc/ai_company/tools/base.pysrc/ai_company/engine/context.pysrc/ai_company/budget/tracker.pytests/unit/providers/resilience/test_retry.pyDESIGN_SPEC.mdsrc/ai_company/templates/loader.pysrc/ai_company/observability/events/routing.pysrc/ai_company/engine/prompt.pysrc/ai_company/templates/renderer.pytests/unit/observability/test_events.pysrc/ai_company/core/task_transitions.pysrc/ai_company/tools/invoker.pysrc/ai_company/core/role_catalog.pytests/unit/config/test_loader.pytests/unit/budget/test_tracker.pytests/unit/providers/resilience/test_rate_limiter.pysrc/ai_company/config/schema.pysrc/ai_company/providers/resilience/retry.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/registry.pysrc/ai_company/core/task.pysrc/ai_company/observability/events/__init__.pysrc/ai_company/observability/events/tool.pysrc/ai_company/tools/registry.pytests/unit/providers/test_base_provider.pysrc/ai_company/observability/events/task.py
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/**/*.py : Never use `import logging`, `logging.getLogger()`, or `print()` in application code — use the standardized logger from ai_company.observability
Applied to files:
src/ai_company/config/loader.pyCLAUDE.mdsrc/ai_company/providers/base.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/resilience/rate_limiter.pysrc/ai_company/providers/routing/strategies.pysrc/ai_company/providers/routing/router.pysrc/ai_company/engine/task_execution.pysrc/ai_company/engine/context.pysrc/ai_company/budget/tracker.pysrc/ai_company/templates/loader.pysrc/ai_company/engine/prompt.pysrc/ai_company/templates/renderer.pysrc/ai_company/core/task_transitions.pysrc/ai_company/tools/invoker.pysrc/ai_company/core/role_catalog.pytests/unit/config/test_loader.pysrc/ai_company/config/schema.pysrc/ai_company/providers/resilience/retry.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/registry.pysrc/ai_company/observability/events/__init__.pysrc/ai_company/tools/registry.py
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/**/*.py : Every module with business logic must import and use logger: `from ai_company.observability import get_logger` then `logger = get_logger(__name__)` — use variable name `logger` (not `_logger`, not `log`)
Applied to files:
src/ai_company/config/loader.pyCLAUDE.mdsrc/ai_company/providers/base.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/resilience/rate_limiter.pysrc/ai_company/providers/routing/strategies.pysrc/ai_company/providers/routing/router.pysrc/ai_company/engine/task_execution.pysrc/ai_company/engine/context.pysrc/ai_company/budget/tracker.pysrc/ai_company/templates/loader.pysrc/ai_company/core/task_transitions.pysrc/ai_company/core/role_catalog.pysrc/ai_company/config/schema.pysrc/ai_company/providers/resilience/retry.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/observability/events/__init__.pysrc/ai_company/tools/registry.py
📚 Learning: 2026-02-26T17:43:50.902Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-26T17:43:50.902Z
Learning: When making changes that affect architecture, services, key files, settings, or workflows, update the relevant sections of existing documentation (CLAUDE.md, README.md, etc.) to reflect those changes.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; use DEBUG for object creation, internal flow, and entry/exit of key functions
Applied to files:
CLAUDE.mdsrc/ai_company/providers/routing/strategies.pysrc/ai_company/providers/routing/router.pysrc/ai_company/engine/task_execution.pysrc/ai_company/engine/context.pysrc/ai_company/templates/loader.pysrc/ai_company/core/task_transitions.pysrc/ai_company/config/schema.py
📚 Learning: 2026-01-26T08:59:32.818Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-26T08:59:32.818Z
Learning: Applies to **/*.py : All functions and methods should have appropriate logging for debugging and traceability. Use `logger.debug()` for routine operations, `logger.info()` for significant events, `logger.warning()` for unexpected but recoverable situations, and `logger.error()` for failures.
Applied to files:
CLAUDE.md
📚 Learning: 2026-02-26T17:43:50.902Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-26T17:43:50.902Z
Learning: Applies to src/**/*.py : All functions and methods should have appropriate logging using `logger.debug()` for routine operations, `logger.info()` for significant events, `logger.warning()` for unexpected but recoverable situations, and `logger.error()` for failures.
Applied to files:
CLAUDE.md
📚 Learning: 2026-01-26T08:59:32.818Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-26T08:59:32.818Z
Learning: Applies to **/*.py : Use logging levels: debug (routine), info (significant), warning (unexpected but recoverable), error (failures)
Applied to files:
CLAUDE.md
📚 Learning: 2026-01-26T08:59:32.818Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-26T08:59:32.818Z
Learning: Applies to **/*.py : Logs must be written to `output/logs/story_factory.log` using `logger = logging.getLogger(__name__)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-01-24T09:54:45.426Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/agents.instructions.md:0-0
Timestamp: 2026-01-24T09:54:45.426Z
Learning: Applies to agents/*.py : Log all significant operations using Python logging with appropriate levels: debug for detailed info, info for successes, warning for retries, error for failures
Applied to files:
CLAUDE.md
📚 Learning: 2026-01-26T08:59:32.818Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-26T08:59:32.818Z
Learning: Applies to src/services/**/*.py : Services in `src/services/` must be business logic layer with no UI imports, receiving settings via dependency injection
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/config/**/*.py : Set RetryConfig and RateLimiterConfig per-provider in ProviderConfig
Applied to files:
tests/unit/providers/routing/test_router.pytests/unit/providers/test_registry.pysrc/ai_company/providers/resilience/rate_limiter.pysrc/ai_company/providers/routing/router.pysrc/ai_company/observability/events/provider.pytests/unit/providers/resilience/test_retry.pytests/unit/providers/resilience/test_rate_limiter.pysrc/ai_company/providers/resilience/retry.pysrc/ai_company/providers/routing/resolver.py
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/providers/**/*.py : All provider calls go through BaseCompletionProvider which applies retry and rate limiting automatically — never implement retry logic in driver subclasses or calling code
Applied to files:
src/ai_company/providers/base.pysrc/ai_company/providers/resilience/rate_limiter.pytests/unit/providers/resilience/test_retry.pysrc/ai_company/providers/resilience/retry.pytests/unit/providers/test_base_provider.py
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/providers/**/*.py : Rate limiter respects RateLimitError.retry_after from providers — automatically pauses future requests
Applied to files:
src/ai_company/providers/resilience/rate_limiter.pytests/unit/providers/resilience/test_retry.pytests/unit/providers/resilience/test_rate_limiter.pysrc/ai_company/providers/resilience/retry.py
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/providers/**/*.py : Mark retryable errors with is_retryable=True: RateLimitError, ProviderTimeoutError, ProviderConnectionError, ProviderInternalError — all other errors raise immediately without retry
Applied to files:
tests/unit/providers/resilience/test_retry.pysrc/ai_company/providers/resilience/retry.py
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to **/*.py : Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict); adopt computed_field for derived values instead of storing redundant fields; use NotBlankStr for all identifier/name fields including optional and tuple variants
Applied to files:
DESIGN_SPEC.md
📚 Learning: 2026-03-06T11:57:38.189Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T11:57:38.189Z
Learning: Applies to src/ai_company/engine/**/*.py : RetryExhaustedError signals all retries failed — the engine layer catches this to trigger fallback chains
Applied to files:
src/ai_company/providers/resilience/retry.py
🔇 Additional comments (44)
src/ai_company/observability/events/__init__.py (1)
10-14: No changes needed; the package-level import surface is correctly designed.All event constants are imported directly from domain modules (e.g.,
from ai_company.observability.events.config import CONFIG_LOADED), and the__init__.pydocstring correctly documents this pattern. The codebase contains zero imports of the formfrom ai_company.observability.events import CONFIG_LOADED, so there is no backward compatibility requirement to maintain. The empty__all__and module-level docstring are appropriate and align with the intended usage pattern shown throughout the codebase.src/ai_company/observability/events/config.py (1)
1-13: LGTM!Clean, well-organized config event constants. The naming convention (
CONFIG_*prefix) and value namespacing (config.<category>.<action>) are consistent and follow the established pattern for observability events.src/ai_company/config/schema.py (1)
16-16: LGTM!Import path correctly updated to the domain-specific module. The usage at line 228 follows the structured logging convention with kwargs.
src/ai_company/config/loader.py (1)
21-31: LGTM!Import path correctly updated to the domain-specific config events module. All 9 imported constants match those defined in
events/config.py, and their usage throughout the file follows the structured logging convention.DESIGN_SPEC.md (2)
2119-2130: LGTM!The project structure tree accurately reflects the new per-domain events package layout with all 10 domain modules (budget, config, execution, prompt, provider, role, routing, task, template, tool) plus the package marker
__init__.py.
2247-2247: LGTM!The engineering conventions table clearly documents the adopted per-domain event constants approach, including the import pattern and rationale for the split (discoverability, co-location, reduced merge conflicts).
CLAUDE.md (1)
83-83: LGTM!The logging guidance is correctly updated to reflect the per-domain module structure. The examples (
PROVIDER_CALL_STARTfromevents.provider,BUDGET_RECORD_ADDEDfromevents.budget) and the import pattern are clear and actionable.src/ai_company/observability/events/routing.py (1)
1-15: LGTM!Well-organized routing event constants with consistent naming (
ROUTING_*prefix) and proper value namespacing (routing.<category>.<action>). All constants are confirmed to be used correctly in the routing subsystem (router.py, resolver.py, strategies.py).src/ai_company/observability/events/execution.py (1)
1-15: LGTM!Complete set of execution lifecycle event constants. All 11 constants are properly typed as
Final[str]with consistent naming (EXECUTION_*) and value namespacing (execution.<category>.<action>). The constants are correctly split between task execution concerns (5 constants used bytask_execution.py) and agent context concerns (6 constants used bycontext.py).src/ai_company/engine/task_execution.py (1)
17-23: LGTM!Import path correctly updated to the domain-specific execution events module. All 5 imported constants are used appropriately throughout the file with structured kwargs and proper log levels (DEBUG for creation/cost, INFO for transitions, WARNING/ERROR for failures).
src/ai_company/observability/events/template.py (1)
1-17: LGTM!The template event constants module is well-structured with all 13 constants properly typed as
Final[str]. All constants required byloader.pyandrenderer.pyare present and correctly named.src/ai_company/templates/renderer.py (1)
23-31: LGTM!The import path correctly points to the new domain-specific module
ai_company.observability.events.template. All 7 imported constants are properly defined in the template module and are used with structured logging throughout the file.src/ai_company/templates/loader.py (1)
24-31: LGTM!The import path correctly points to the new domain-specific module
ai_company.observability.events.template. All 6 imported constants are properly defined in the template module.src/ai_company/observability/events/tool.py (1)
1-19: LGTM!The tool event constants module is well-structured with all 15 constants properly typed as
Final[str]. All constants required byinvoker.py,registry.py, andbase.pyare present and correctly named.src/ai_company/tools/base.py (1)
15-15: LGTM!The import path correctly points to the new domain-specific module
ai_company.observability.events.tool. TheTOOL_BASE_INVALID_NAMEconstant is properly used with structured logging.src/ai_company/tools/invoker.py (1)
19-30: LGTM!The import path correctly points to the new domain-specific module
ai_company.observability.events.tool. All 10 imported constants are properly defined in the tool module and are used with structured logging throughout the file.src/ai_company/tools/registry.py (1)
11-16: LGTM!The import path correctly points to the new domain-specific module
ai_company.observability.events.tool. All 4 imported constants are properly defined in the tool module and are used with structured logging throughout the file.src/ai_company/observability/events/provider.py (1)
1-42: LGTM!The provider event constants module is well-structured with all 27 constants properly typed as
Final[str]. The module is well-organized with clear section comments separating lifecycle events from resilience events. All constants required by the consumers (base.py,retry.py,rate_limiter.py,litellm_driver.py) are present and correctly named.tests/unit/providers/resilience/test_retry.py (1)
8-13: Provider event import update looks correct.This keeps the test aligned with the new per-domain event layout without changing the asserted event names or behavior.
src/ai_company/providers/resilience/rate_limiter.py (1)
8-11: Domain-specific provider event imports are wired correctly.The logger calls still consume the same constants, so this stays a pure organizational change in this module.
src/ai_company/providers/drivers/mappers.py (1)
13-18: Mapper logging imports are consistent with the split.These constants remain provider-specific, so moving them into the provider events module is the right fit.
tests/unit/core/test_task.py (1)
16-16: Task event import is updated cleanly.The test continues to validate the same emitted event while matching the new task-domain module layout.
src/ai_company/providers/routing/resolver.py (1)
13-17: Routing event imports are correctly localized.This preserves the existing resolver logging behavior while matching the new routing-specific event module.
tests/unit/providers/resilience/test_rate_limiter.py (1)
10-13: Rate-limiter test imports were updated cleanly.The assertions still target the same provider events, so this remains a straightforward namespace migration.
tests/unit/providers/test_registry.py (1)
9-12: Provider registry event imports look good.The test continues to assert the same event emissions while following the new provider-domain module structure.
tests/unit/providers/routing/test_router.py (1)
8-11: Routing test imports are consistently updated.Both the module-level and scoped event imports now point at the routing domain module, with no change to the tested logging behavior.
Also applies to: 156-156
tests/unit/budget/test_tracker.py (1)
12-16: Budget test import matches the new domain split.The assertions still target the same
BUDGET_*event names, so the test intent stays unchanged.src/ai_company/providers/routing/strategies.py (1)
16-22: Routing strategy events are sourced from the right module.This keeps routing-specific constants colocated without changing strategy behavior.
tests/unit/core/test_task_transitions.py (1)
8-8: Task transition logging test stays aligned.Only the source module changed; the test still validates the same task event.
src/ai_company/budget/tracker.py (1)
25-33: Budget tracker import split looks clean.The module continues to use direct
BUDGET_*constants and structured logging after the move.tests/unit/config/test_loader.py (1)
29-33: Config loader logging tests remain targeted.Switching to
events.configkeeps the assertedCONFIG_*events explicit.tests/unit/engine/test_task_execution.py (1)
13-19: Execution event assertions remain clear.The tests still exercise the same
EXECUTION_*event names after the module split.src/ai_company/providers/routing/router.py (1)
9-14: Router event import update is consistent.The router keeps using direct routing constants while following the new package layout.
src/ai_company/providers/registry.py (1)
12-17: LGTM!The import path correctly references the domain-specific provider events module. All four constants (
PROVIDER_DRIVER_FACTORY_MISSING,PROVIDER_DRIVER_INSTANTIATED,PROVIDER_DRIVER_NOT_REGISTERED,PROVIDER_REGISTRY_BUILT) are properly defined inai_company.observability.events.providerand used consistently throughout the file.tests/unit/engine/test_context.py (1)
18-25: LGTM!The import path correctly references the domain-specific execution events module, aligning with the source module
src/ai_company/engine/context.py. All six execution event constants are properly used in the test assertions to verify logging behavior.src/ai_company/providers/base.py (1)
15-20: LGTM!The import path correctly references the domain-specific provider events module. The four provider call lifecycle constants are properly imported and used throughout the file for structured logging.
src/ai_company/engine/context.py (1)
20-27: LGTM!The import path correctly references the domain-specific execution events module. All six execution context event constants are properly imported and used with appropriate log levels: DEBUG for creation/snapshots, INFO for turn completion, and ERROR/WARNING for error paths. This aligns with the coding guidelines.
src/ai_company/providers/resilience/retry.py (1)
8-13: LGTM!The import path correctly references the domain-specific provider events module. The four provider resilience constants (
PROVIDER_CALL_ERROR,PROVIDER_RETRY_ATTEMPT,PROVIDER_RETRY_EXHAUSTED,PROVIDER_RETRY_SKIPPED) are properly defined inai_company.observability.events.provider(lines 37-40 per the context snippet) and used appropriately throughout the retry handler.tests/unit/templates/test_renderer.py (1)
10-13: LGTM!The import path correctly references the domain-specific template events module. Both constants (
TEMPLATE_RENDER_START,TEMPLATE_RENDER_SUCCESS) are properly defined inai_company.observability.events.templateper context snippet 4 and used correctly in the logging test.tests/unit/providers/test_base_provider.py (1)
8-13: LGTM!The import path correctly references the domain-specific provider events module, aligning with the source module
src/ai_company/providers/base.py. All four provider call event constants are properly used in the test assertions to verify logging behavior.tests/unit/observability/test_events.py (3)
36-47: LGTM!The refactored
_all_event_names()helper correctly discovers event constants from all submodules usingpkgutil.iter_modules(). Theattr.isupper()guard on line 45 adds robustness by ensuring only uppercase string attributes (constants) are collected, filtering out any helper functions or other module-level attributes.
10-29: LGTM!The imports correctly reference all 10 domain-specific event modules (budget, config, execution, prompt, provider, role, routing, task, template, tool), providing comprehensive spot-check coverage for the per-domain event structure.
90-103: LGTM!Good addition of spot-check tests for the four newly covered domain modules (budget, execution, routing, prompt, tool). This ensures all 10 domain modules have explicit validation tests, completing the coverage expansion mentioned in the PR objectives.
src/ai_company/observability/events/budget.py (1)
1-11: LGTM.Clean domain-local constant module. The names are explicit, stable, and support the direct-import logging convention expected by the codebase. Based on learnings: "Always use event name constants from ai_company.observability.events (e.g. PROVIDER_CALL_START, BUDGET_RECORD_ADDED, TOOL_INVOKE_START) — import directly and log structured kwargs as logger.info(EVENT, key=value), never logger.info('msg %s', val)".
- Fix inaccurate naming convention in events/__init__.py docstring (domain.noun[.verb] → domain.subject[.qualifier]) - Replace hardcoded event strings in test_prompt.py with constant imports - Update DESIGN_SPEC.md tree comment for events/__init__.py - Add test_all_domain_modules_discovered to verify all 10 modules - Standardize docstring format across all 10 event domain modules Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- ## [0.1.1](ai-company-v0.1.0...ai-company-v0.1.1) (2026-03-10) ### Features * add autonomy levels and approval timeout policies ([#42](#42), [#126](#126)) ([#197](#197)) ([eecc25a](eecc25a)) * add CFO cost optimization service with anomaly detection, reports, and approval decisions ([#186](#186)) ([a7fa00b](a7fa00b)) * add code quality toolchain (ruff, mypy, pre-commit, dependabot) ([#63](#63)) ([36681a8](36681a8)) * add configurable cost tiers and subscription/quota-aware tracking ([#67](#67)) ([#185](#185)) ([9baedfa](9baedfa)) * add container packaging, Docker Compose, and CI pipeline ([#269](#269)) ([435bdfe](435bdfe)), closes [#267](#267) * add coordination error taxonomy classification pipeline ([#146](#146)) ([#181](#181)) ([70c7480](70c7480)) * add cost-optimized, hierarchical, and auction assignment strategies ([#175](#175)) ([ce924fa](ce924fa)), closes [#173](#173) * add design specification, license, and project setup ([8669a09](8669a09)) * add env var substitution and config file auto-discovery ([#77](#77)) ([7f53832](7f53832)) * add FastestStrategy routing + vendor-agnostic cleanup ([#140](#140)) ([09619cb](09619cb)), closes [#139](#139) * add HR engine and performance tracking ([#45](#45), [#47](#47)) ([#193](#193)) ([2d091ea](2d091ea)) * add issue auto-search and resolution verification to PR review skill ([#119](#119)) ([deecc39](deecc39)) * add memory retrieval, ranking, and context injection pipeline ([#41](#41)) ([873b0aa](873b0aa)) * add pluggable MemoryBackend protocol with models, config, and events ([#180](#180)) ([46cfdd4](46cfdd4)) * add pluggable MemoryBackend protocol with models, config, and events ([#32](#32)) ([46cfdd4](46cfdd4)) * add pluggable PersistenceBackend protocol with SQLite implementation ([#36](#36)) ([f753779](f753779)) * add progressive trust and promotion/demotion subsystems ([#43](#43), [#49](#49)) ([3a87c08](3a87c08)) * add retry handler, rate limiter, and provider resilience ([#100](#100)) ([b890545](b890545)) * add SecOps security agent with rule engine, audit log, and ToolInvoker integration ([#40](#40)) ([83b7b6c](83b7b6c)) * add shared org memory and memory consolidation/archival ([#125](#125), [#48](#48)) ([4a0832b](4a0832b)) * design unified provider interface ([#86](#86)) ([3e23d64](3e23d64)) * expand template presets, rosters, and add inheritance ([#80](#80), [#81](#81), [#84](#84)) ([15a9134](15a9134)) * implement agent runtime state vs immutable config split ([#115](#115)) ([4cb1ca5](4cb1ca5)) * implement AgentEngine core orchestrator ([#11](#11)) ([#143](#143)) ([f2eb73a](f2eb73a)) * implement basic tool system (registry, invocation, results) ([#15](#15)) ([c51068b](c51068b)) * implement built-in file system tools ([#18](#18)) ([325ef98](325ef98)) * implement communication foundation — message bus, dispatcher, and messenger ([#157](#157)) ([8e71bfd](8e71bfd)) * implement company template system with 7 built-in presets ([#85](#85)) ([cbf1496](cbf1496)) * implement conflict resolution protocol ([#122](#122)) ([#166](#166)) ([e03f9f2](e03f9f2)) * implement core entity and role system models ([#69](#69)) ([acf9801](acf9801)) * implement crash recovery with fail-and-reassign strategy ([#149](#149)) ([e6e91ed](e6e91ed)) * implement engine extensions — Plan-and-Execute loop and call categorization ([#134](#134), [#135](#135)) ([#159](#159)) ([9b2699f](9b2699f)) * implement enterprise logging system with structlog ([#73](#73)) ([2f787e5](2f787e5)) * implement graceful shutdown with cooperative timeout strategy ([#130](#130)) ([6592515](6592515)) * implement hierarchical delegation and loop prevention ([#12](#12), [#17](#17)) ([6be60b6](6be60b6)) * implement LiteLLM driver and provider registry ([#88](#88)) ([ae3f18b](ae3f18b)), closes [#4](#4) * implement LLM decomposition strategy and workspace isolation ([#174](#174)) ([aa0eefe](aa0eefe)) * implement meeting protocol system ([#123](#123)) ([ee7caca](ee7caca)) * implement message and communication domain models ([#74](#74)) ([560a5d2](560a5d2)) * implement model routing engine ([#99](#99)) ([d3c250b](d3c250b)) * implement parallel agent execution ([#22](#22)) ([#161](#161)) ([65940b3](65940b3)) * implement per-call cost tracking service ([#7](#7)) ([#102](#102)) ([c4f1f1c](c4f1f1c)) * implement personality injection and system prompt construction ([#105](#105)) ([934dd85](934dd85)) * implement single-task execution lifecycle ([#21](#21)) ([#144](#144)) ([c7e64e4](c7e64e4)) * implement subprocess sandbox for tool execution isolation ([#131](#131)) ([#153](#153)) ([3c8394e](3c8394e)) * implement task assignment subsystem with pluggable strategies ([#172](#172)) ([c7f1b26](c7f1b26)), closes [#26](#26) [#30](#30) * implement task decomposition and routing engine ([#14](#14)) ([9c7fb52](9c7fb52)) * implement Task, Project, Artifact, Budget, and Cost domain models ([#71](#71)) ([81eabf1](81eabf1)) * implement tool permission checking ([#16](#16)) ([833c190](833c190)) * implement YAML config loader with Pydantic validation ([#59](#59)) ([ff3a2ba](ff3a2ba)) * implement YAML config loader with Pydantic validation ([#75](#75)) ([ff3a2ba](ff3a2ba)) * initialize project with uv, hatchling, and src layout ([39005f9](39005f9)) * initialize project with uv, hatchling, and src layout ([#62](#62)) ([39005f9](39005f9)) * Litestar REST API, WebSocket feed, and approval queue (M6) ([#189](#189)) ([29fcd08](29fcd08)) * make TokenUsage.total_tokens a computed field ([#118](#118)) ([c0bab18](c0bab18)), closes [#109](#109) * parallel tool execution in ToolInvoker.invoke_all ([#137](#137)) ([58517ee](58517ee)) * testing framework, CI pipeline, and M0 gap fixes ([#64](#64)) ([f581749](f581749)) * wire all modules into observability system ([#97](#97)) ([f7a0617](f7a0617)) ### Bug Fixes * address Greptile post-merge review findings from PRs [#170](https://github.com/Aureliolo/ai-company/issues/170)-[#175](https://github.com/Aureliolo/ai-company/issues/175) ([#176](#176)) ([c5ca929](c5ca929)) * address post-merge review feedback from PRs [#164](https://github.com/Aureliolo/ai-company/issues/164)-[#167](https://github.com/Aureliolo/ai-company/issues/167) ([#170](#170)) ([3bf897a](3bf897a)), closes [#169](#169) * enforce strict mypy on test files ([#89](#89)) ([aeeff8c](aeeff8c)) * harden Docker sandbox, MCP bridge, and code runner ([#50](#50), [#53](#53)) ([d5e1b6e](d5e1b6e)) * harden git tools security + code quality improvements ([#150](#150)) ([000a325](000a325)) * harden subprocess cleanup, env filtering, and shutdown resilience ([#155](#155)) ([d1fe1fb](d1fe1fb)) * incorporate post-merge feedback + pre-PR review fixes ([#164](#164)) ([c02832a](c02832a)) * pre-PR review fixes for post-merge findings ([#183](#183)) ([26b3108](26b3108)) * strengthen immutability for BaseTool schema and ToolInvoker boundaries ([#117](#117)) ([7e5e861](7e5e861)) ### Performance * harden non-inferable principle implementation ([#195](#195)) ([02b5f4e](02b5f4e)), closes [#188](#188) ### Refactoring * adopt NotBlankStr across all models ([#108](#108)) ([#120](#120)) ([ef89b90](ef89b90)) * extract _SpendingTotals base class from spending summary models ([#111](#111)) ([2f39c1b](2f39c1b)) * harden BudgetEnforcer with error handling, validation extraction, and review fixes ([#182](#182)) ([c107bf9](c107bf9)) * harden personality profiles, department validation, and template rendering ([#158](#158)) ([10b2299](10b2299)) * pre-PR review improvements for ExecutionLoop + ReAct loop ([#124](#124)) ([8dfb3c0](8dfb3c0)) * split events.py into per-domain event modules ([#136](#136)) ([e9cba89](e9cba89)) ### Documentation * add ADR-001 memory layer evaluation and selection ([#178](#178)) ([db3026f](db3026f)), closes [#39](#39) * add agent scaling research findings to DESIGN_SPEC ([#145](#145)) ([57e487b](57e487b)) * add CLAUDE.md, contributing guide, and dev documentation ([#65](#65)) ([55c1025](55c1025)), closes [#54](#54) * add crash recovery, sandboxing, analytics, and testing decisions ([#127](#127)) ([5c11595](5c11595)) * address external review feedback with MVP scope and new protocols ([#128](#128)) ([3b30b9a](3b30b9a)) * expand design spec with pluggable strategy protocols ([#121](#121)) ([6832db6](6832db6)) * finalize 23 design decisions (ADR-002) ([#190](#190)) ([8c39742](8c39742)) * update project docs for M2.5 conventions and add docs-consistency review agent ([#114](#114)) ([99766ee](99766ee)) ### Tests * add e2e single agent integration tests ([#24](#24)) ([#156](#156)) ([f566fb4](f566fb4)) * add provider adapter integration tests ([#90](#90)) ([40a61f4](40a61f4)) ### CI/CD * add Release Please for automated versioning and GitHub Releases ([#278](#278)) ([a488758](a488758)) * bump actions/checkout from 4 to 6 ([#95](#95)) ([1897247](1897247)) * bump actions/upload-artifact from 4 to 7 ([#94](#94)) ([27b1517](27b1517)) * harden CI/CD pipeline ([#92](#92)) ([ce4693c](ce4693c)) * split vulnerability scans into critical-fail and high-warn tiers ([#277](#277)) ([aba48af](aba48af)) ### Maintenance * add /worktree skill for parallel worktree management ([#171](#171)) ([951e337](951e337)) * add design spec context loading to research-link skill ([8ef9685](8ef9685)) * add post-merge-cleanup skill ([#70](#70)) ([f913705](f913705)) * add pre-pr-review skill and update CLAUDE.md ([#103](#103)) ([92e9023](92e9023)) * add research-link skill and rename skill files to SKILL.md ([#101](#101)) ([651c577](651c577)) * bump aiosqlite from 0.21.0 to 0.22.1 ([#191](#191)) ([3274a86](3274a86)) * bump pyyaml from 6.0.2 to 6.0.3 in the minor-and-patch group ([#96](#96)) ([0338d0c](0338d0c)) * bump ruff from 0.15.4 to 0.15.5 ([a49ee46](a49ee46)) * fix M0 audit items ([#66](#66)) ([c7724b5](c7724b5)) * pin setup-uv action to full SHA ([#281](#281)) ([4448002](4448002)) * post-audit cleanup — PEP 758, loggers, bug fixes, refactoring, tests, hookify rules ([#148](#148)) ([c57a6a9](c57a6a9)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
🤖 I have created a release *beep* *boop* --- ## [0.1.0](v0.0.0...v0.1.0) (2026-03-11) ### Features * add autonomy levels and approval timeout policies ([#42](#42), [#126](#126)) ([#197](#197)) ([eecc25a](eecc25a)) * add CFO cost optimization service with anomaly detection, reports, and approval decisions ([#186](#186)) ([a7fa00b](a7fa00b)) * add code quality toolchain (ruff, mypy, pre-commit, dependabot) ([#63](#63)) ([36681a8](36681a8)) * add configurable cost tiers and subscription/quota-aware tracking ([#67](#67)) ([#185](#185)) ([9baedfa](9baedfa)) * add container packaging, Docker Compose, and CI pipeline ([#269](#269)) ([435bdfe](435bdfe)), closes [#267](#267) * add coordination error taxonomy classification pipeline ([#146](#146)) ([#181](#181)) ([70c7480](70c7480)) * add cost-optimized, hierarchical, and auction assignment strategies ([#175](#175)) ([ce924fa](ce924fa)), closes [#173](#173) * add design specification, license, and project setup ([8669a09](8669a09)) * add env var substitution and config file auto-discovery ([#77](#77)) ([7f53832](7f53832)) * add FastestStrategy routing + vendor-agnostic cleanup ([#140](#140)) ([09619cb](09619cb)), closes [#139](#139) * add HR engine and performance tracking ([#45](#45), [#47](#47)) ([#193](#193)) ([2d091ea](2d091ea)) * add issue auto-search and resolution verification to PR review skill ([#119](#119)) ([deecc39](deecc39)) * add mandatory JWT + API key authentication ([#256](#256)) ([c279cfe](c279cfe)) * add memory retrieval, ranking, and context injection pipeline ([#41](#41)) ([873b0aa](873b0aa)) * add pluggable MemoryBackend protocol with models, config, and events ([#180](#180)) ([46cfdd4](46cfdd4)) * add pluggable MemoryBackend protocol with models, config, and events ([#32](#32)) ([46cfdd4](46cfdd4)) * add pluggable output scan response policies ([#263](#263)) ([b9907e8](b9907e8)) * add pluggable PersistenceBackend protocol with SQLite implementation ([#36](#36)) ([f753779](f753779)) * add progressive trust and promotion/demotion subsystems ([#43](#43), [#49](#49)) ([3a87c08](3a87c08)) * add retry handler, rate limiter, and provider resilience ([#100](#100)) ([b890545](b890545)) * add SecOps security agent with rule engine, audit log, and ToolInvoker integration ([#40](#40)) ([83b7b6c](83b7b6c)) * add shared org memory and memory consolidation/archival ([#125](#125), [#48](#48)) ([4a0832b](4a0832b)) * design unified provider interface ([#86](#86)) ([3e23d64](3e23d64)) * expand template presets, rosters, and add inheritance ([#80](#80), [#81](#81), [#84](#84)) ([15a9134](15a9134)) * implement agent runtime state vs immutable config split ([#115](#115)) ([4cb1ca5](4cb1ca5)) * implement AgentEngine core orchestrator ([#11](#11)) ([#143](#143)) ([f2eb73a](f2eb73a)) * implement AuditRepository for security audit log persistence ([#279](#279)) ([94bc29f](94bc29f)) * implement basic tool system (registry, invocation, results) ([#15](#15)) ([c51068b](c51068b)) * implement built-in file system tools ([#18](#18)) ([325ef98](325ef98)) * implement communication foundation — message bus, dispatcher, and messenger ([#157](#157)) ([8e71bfd](8e71bfd)) * implement company template system with 7 built-in presets ([#85](#85)) ([cbf1496](cbf1496)) * implement conflict resolution protocol ([#122](#122)) ([#166](#166)) ([e03f9f2](e03f9f2)) * implement core entity and role system models ([#69](#69)) ([acf9801](acf9801)) * implement crash recovery with fail-and-reassign strategy ([#149](#149)) ([e6e91ed](e6e91ed)) * implement engine extensions — Plan-and-Execute loop and call categorization ([#134](#134), [#135](#135)) ([#159](#159)) ([9b2699f](9b2699f)) * implement enterprise logging system with structlog ([#73](#73)) ([2f787e5](2f787e5)) * implement graceful shutdown with cooperative timeout strategy ([#130](#130)) ([6592515](6592515)) * implement hierarchical delegation and loop prevention ([#12](#12), [#17](#17)) ([6be60b6](6be60b6)) * implement LiteLLM driver and provider registry ([#88](#88)) ([ae3f18b](ae3f18b)), closes [#4](#4) * implement LLM decomposition strategy and workspace isolation ([#174](#174)) ([aa0eefe](aa0eefe)) * implement meeting protocol system ([#123](#123)) ([ee7caca](ee7caca)) * implement message and communication domain models ([#74](#74)) ([560a5d2](560a5d2)) * implement model routing engine ([#99](#99)) ([d3c250b](d3c250b)) * implement parallel agent execution ([#22](#22)) ([#161](#161)) ([65940b3](65940b3)) * implement per-call cost tracking service ([#7](#7)) ([#102](#102)) ([c4f1f1c](c4f1f1c)) * implement personality injection and system prompt construction ([#105](#105)) ([934dd85](934dd85)) * implement single-task execution lifecycle ([#21](#21)) ([#144](#144)) ([c7e64e4](c7e64e4)) * implement subprocess sandbox for tool execution isolation ([#131](#131)) ([#153](#153)) ([3c8394e](3c8394e)) * implement task assignment subsystem with pluggable strategies ([#172](#172)) ([c7f1b26](c7f1b26)), closes [#26](#26) [#30](#30) * implement task decomposition and routing engine ([#14](#14)) ([9c7fb52](9c7fb52)) * implement Task, Project, Artifact, Budget, and Cost domain models ([#71](#71)) ([81eabf1](81eabf1)) * implement tool permission checking ([#16](#16)) ([833c190](833c190)) * implement YAML config loader with Pydantic validation ([#59](#59)) ([ff3a2ba](ff3a2ba)) * implement YAML config loader with Pydantic validation ([#75](#75)) ([ff3a2ba](ff3a2ba)) * initialize project with uv, hatchling, and src layout ([39005f9](39005f9)) * initialize project with uv, hatchling, and src layout ([#62](#62)) ([39005f9](39005f9)) * Litestar REST API, WebSocket feed, and approval queue (M6) ([#189](#189)) ([29fcd08](29fcd08)) * make TokenUsage.total_tokens a computed field ([#118](#118)) ([c0bab18](c0bab18)), closes [#109](#109) * parallel tool execution in ToolInvoker.invoke_all ([#137](#137)) ([58517ee](58517ee)) * testing framework, CI pipeline, and M0 gap fixes ([#64](#64)) ([f581749](f581749)) * wire all modules into observability system ([#97](#97)) ([f7a0617](f7a0617)) ### Bug Fixes * address Greptile post-merge review findings from PRs [#170](https://github.com/Aureliolo/ai-company/issues/170)-[#175](https://github.com/Aureliolo/ai-company/issues/175) ([#176](#176)) ([c5ca929](c5ca929)) * address post-merge review feedback from PRs [#164](https://github.com/Aureliolo/ai-company/issues/164)-[#167](https://github.com/Aureliolo/ai-company/issues/167) ([#170](#170)) ([3bf897a](3bf897a)), closes [#169](#169) * enforce strict mypy on test files ([#89](#89)) ([aeeff8c](aeeff8c)) * harden Docker sandbox, MCP bridge, and code runner ([#50](#50), [#53](#53)) ([d5e1b6e](d5e1b6e)) * harden git tools security + code quality improvements ([#150](#150)) ([000a325](000a325)) * harden subprocess cleanup, env filtering, and shutdown resilience ([#155](#155)) ([d1fe1fb](d1fe1fb)) * incorporate post-merge feedback + pre-PR review fixes ([#164](#164)) ([c02832a](c02832a)) * pre-PR review fixes for post-merge findings ([#183](#183)) ([26b3108](26b3108)) * resolve circular imports, bump litellm, fix release tag format ([#286](#286)) ([a6659b5](a6659b5)) * strengthen immutability for BaseTool schema and ToolInvoker boundaries ([#117](#117)) ([7e5e861](7e5e861)) ### Performance * harden non-inferable principle implementation ([#195](#195)) ([02b5f4e](02b5f4e)), closes [#188](#188) ### Refactoring * adopt NotBlankStr across all models ([#108](#108)) ([#120](#120)) ([ef89b90](ef89b90)) * extract _SpendingTotals base class from spending summary models ([#111](#111)) ([2f39c1b](2f39c1b)) * harden BudgetEnforcer with error handling, validation extraction, and review fixes ([#182](#182)) ([c107bf9](c107bf9)) * harden personality profiles, department validation, and template rendering ([#158](#158)) ([10b2299](10b2299)) * pre-PR review improvements for ExecutionLoop + ReAct loop ([#124](#124)) ([8dfb3c0](8dfb3c0)) * split events.py into per-domain event modules ([#136](#136)) ([e9cba89](e9cba89)) ### Documentation * add ADR-001 memory layer evaluation and selection ([#178](#178)) ([db3026f](db3026f)), closes [#39](#39) * add agent scaling research findings to DESIGN_SPEC ([#145](#145)) ([57e487b](57e487b)) * add CLAUDE.md, contributing guide, and dev documentation ([#65](#65)) ([55c1025](55c1025)), closes [#54](#54) * add crash recovery, sandboxing, analytics, and testing decisions ([#127](#127)) ([5c11595](5c11595)) * address external review feedback with MVP scope and new protocols ([#128](#128)) ([3b30b9a](3b30b9a)) * expand design spec with pluggable strategy protocols ([#121](#121)) ([6832db6](6832db6)) * finalize 23 design decisions (ADR-002) ([#190](#190)) ([8c39742](8c39742)) * update project docs for M2.5 conventions and add docs-consistency review agent ([#114](#114)) ([99766ee](99766ee)) ### Tests * add e2e single agent integration tests ([#24](#24)) ([#156](#156)) ([f566fb4](f566fb4)) * add provider adapter integration tests ([#90](#90)) ([40a61f4](40a61f4)) ### CI/CD * add Release Please for automated versioning and GitHub Releases ([#278](#278)) ([a488758](a488758)) * bump actions/checkout from 4 to 6 ([#95](#95)) ([1897247](1897247)) * bump actions/upload-artifact from 4 to 7 ([#94](#94)) ([27b1517](27b1517)) * bump anchore/scan-action from 6.5.1 to 7.3.2 ([#271](#271)) ([80a1c15](80a1c15)) * bump docker/build-push-action from 6.19.2 to 7.0.0 ([#273](#273)) ([dd0219e](dd0219e)) * bump docker/login-action from 3.7.0 to 4.0.0 ([#272](#272)) ([33d6238](33d6238)) * bump docker/metadata-action from 5.10.0 to 6.0.0 ([#270](#270)) ([baee04e](baee04e)) * bump docker/setup-buildx-action from 3.12.0 to 4.0.0 ([#274](#274)) ([5fc06f7](5fc06f7)) * bump sigstore/cosign-installer from 3.9.1 to 4.1.0 ([#275](#275)) ([29dd16c](29dd16c)) * harden CI/CD pipeline ([#92](#92)) ([ce4693c](ce4693c)) * split vulnerability scans into critical-fail and high-warn tiers ([#277](#277)) ([aba48af](aba48af)) ### Maintenance * add /worktree skill for parallel worktree management ([#171](#171)) ([951e337](951e337)) * add design spec context loading to research-link skill ([8ef9685](8ef9685)) * add post-merge-cleanup skill ([#70](#70)) ([f913705](f913705)) * add pre-pr-review skill and update CLAUDE.md ([#103](#103)) ([92e9023](92e9023)) * add research-link skill and rename skill files to SKILL.md ([#101](#101)) ([651c577](651c577)) * bump aiosqlite from 0.21.0 to 0.22.1 ([#191](#191)) ([3274a86](3274a86)) * bump pyyaml from 6.0.2 to 6.0.3 in the minor-and-patch group ([#96](#96)) ([0338d0c](0338d0c)) * bump ruff from 0.15.4 to 0.15.5 ([a49ee46](a49ee46)) * fix M0 audit items ([#66](#66)) ([c7724b5](c7724b5)) * **main:** release ai-company 0.1.1 ([#282](#282)) ([2f4703d](2f4703d)) * pin setup-uv action to full SHA ([#281](#281)) ([4448002](4448002)) * post-audit cleanup — PEP 758, loggers, bug fixes, refactoring, tests, hookify rules ([#148](#148)) ([c57a6a9](c57a6a9)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Signed-off-by: Aurelio <19254254+Aureliolo@users.noreply.github.com>
Summary
observability/events.py(104 constants) into 10 per-domain submodules underobservability/events/(budget,config,execution,prompt,provider,role,routing,task,template,tool)from ai_company.observability.events.<domain> import CONSTANT)__init__.pyis a docstring-only marker with__all__ = []— no re-exports, enforcing direct domain importsattr.isupper()guard to test helper for robustnessCloses #110
Test plan
pytest -n auto)Review coverage
Pre-reviewed by 9 agents: code-reviewer, python-reviewer, pr-test-analyzer, silent-failure-hunter, comment-analyzer, type-design-analyzer, logging-audit, resilience-audit, docs-consistency. 5 findings addressed, 2 minor items skipped (stylistic).