Skip to content

refactor: adopt NotBlankStr across all models (#108)#120

Merged
Aureliolo merged 3 commits intomainfrom
refactor/adopt-notblankstr-108
Mar 6, 2026
Merged

refactor: adopt NotBlankStr across all models (#108)#120
Aureliolo merged 3 commits intomainfrom
refactor/adopt-notblankstr-108

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

@Aureliolo Aureliolo commented Mar 6, 2026

Summary

  • Replace manual @model_validator whitespace checks with NotBlankStr across all 15 source modules in core/, budget/, communication/, and observability/
  • Rename validate_non_blank_unique_stringsvalidate_unique_strings — blank-check responsibility moved to the NotBlankStr type annotation; the helper now only enforces uniqueness
  • Add NotBlankStr type alias in core/types.py: Annotated[str, StringConstraints(min_length=1), AfterValidator(_check_not_whitespace)] — rejects both empty and whitespace-only strings with distinct error messages
  • Update DESIGN_SPEC.md — mark NotBlankStr convention as "Adopted" (was "Planned"), update §3.1 current state note
  • Update CLAUDE.md — promote NotBlankStr to "Adopted" convention, document all variants (scalar, optional, tuple)
  • Fix 3 stale docstrings in communication/ that still said "non-blank and unique" after blank-check moved to type level
  • Add comprehensive type-level tests in tests/unit/core/test_types.py for scalar, optional, and tuple NotBlankStr variants
  • Add empty-string deadline rejection tests for Project and Task
  • Net reduction of ~155 lines (297 added, 452 removed) — eliminates boilerplate while preserving equivalent validation behavior

Test plan

  • uv run ruff check src/ tests/ — all checks passed
  • uv run ruff format src/ tests/ — no changes needed
  • uv run mypy src/ tests/ — no issues in 200 source files
  • uv run pytest tests/ -n auto --cov=ai_company --cov-fail-under=80 — 1811 passed, 94.98% coverage
  • Pre-commit hooks pass (trailing whitespace, ruff, gitleaks, commitizen)

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. 6 findings addressed, 0 skipped.

Closes #108

Aureliolo and others added 2 commits March 6, 2026 10:20
Replace str + Field(min_length=1) + manual @model_validator whitespace
checks with NotBlankStr type annotation from core.types across 15 source
files. Migrate 80+ fields (scalar and tuple), delete 25+ redundant
validators, rename validate_non_blank_unique_strings to
validate_unique_strings. Net reduction of ~295 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update CLAUDE.md: NotBlankStr convention from "Planned" to "Adopted",
  include optional and tuple variants in documentation
- Fix 3 stale docstrings in communication/ that still said "non-blank
  and unique" after blank-check moved to NotBlankStr type annotation
- Add empty-string deadline rejection tests for Project and Task
- Simplify fragile assertion pattern in test_types.py

Pre-reviewed by 9 agents, 6 findings addressed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 6, 2026 09:33
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 6, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough

Walkthrough

This PR systematically replaces manual string validation with the NotBlankStr custom type across core domain models and budget/communication modules. Runtime whitespace validators are removed, their logic shifted to type-level validation. The helper function validate_non_blank_unique_strings is renamed to validate_unique_strings, dropping non-blank enforcement and relying on field-level NotBlankStr typing instead. Tests are updated to expect new error message patterns from NotBlankStr validation.

Changes

Cohort / File(s) Summary
Documentation
CLAUDE.md, DESIGN_SPEC.md
Updated design notes to reflect NotBlankStr adoption across all identifier/name fields, including optional and tuple variants, replacing previous Field(min_length=1) plus manual validators approach.
Validation Type & Core Exports
src/ai_company/core/types.py, src/ai_company/core/__init__.py
Renamed validate_non_blank_unique_strings to validate_unique_strings; removed non-blank checking logic from function, now only validates uniqueness; updated exports accordingly.
Core Models: Agent & Artifact
src/ai_company/core/agent.py, src/ai_company/core/artifact.py
Replaced string and string-tuple fields (traits, skills, tools, provider, model_id, path, id) with NotBlankStr and tuple[NotBlankStr, ...]; removed corresponding @model_validator whitespace checks.
Core Models: Company, Project, Role, Task
src/ai_company/core/company.py, src/ai_company/core/project.py, src/ai_company/core/role.py, src/ai_company/core/task.py
Replaced name, identifier, and collection-element fields with NotBlankStr and tuple[NotBlankStr, ...]; removed per-field whitespace validators; task.py and project.py added new deadline format validators; task.py added assignment consistency validator; project.py restructured collection validation for uniqueness.
Budget Models
src/ai_company/budget/config.py, src/ai_company/budget/cost_record.py, src/ai_company/budget/hierarchy.py, src/ai_company/budget/spending_summary.py
Converted agent_id, task_id, provider, model, team_name, department_name, and alias fields to NotBlankStr; removed explicit whitespace validators; config.py added normalization step for downgrade_map aliases.
Communication Models
src/ai_company/communication/channel.py, src/ai_company/communication/config.py
Changed subscribers/channels/participants from tuple[str, ...] to tuple[NotBlankStr, ...]; replaced validate_non_blank_unique_strings calls with validate_unique_strings; removed non-blank checks from validators.
Observability Config
src/ai_company/observability/config.py
Changed log_dir from str to NotBlankStr; removed non-blank check from validator, retaining path-traversal validation only.
Test Updates: Core Models
tests/unit/core/test_*.py (agent, artifact, company, project, role, task)
Updated ValidationError message expectations to match NotBlankStr error patterns ("at least 1 character" for empty, "whitespace-only" for whitespace); added test_types.py covering NotBlankStr scalar, optional, and tuple validation across all contexts.
Test Updates: Budget & Communication
tests/unit/budget/test_config.py, tests/unit/communication/test_*.py, tests/unit/observability/test_config.py
Adjusted error message expectations in validation tests to match revised NotBlankStr and validate_unique_strings error patterns.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Issue #108: Directly implements the proposal to replace str+manual validators with NotBlankStr across core.agent, core.task, budget, and communication modules; removes redundant model validators.

Possibly related PRs

  • PR #74: Updates communication models (Channel, MessageBusConfig, MeetingTypeConfig) to use NotBlankStr and replaces validate_non_blank_unique_strings with validate_unique_strings—directly overlaps with communication cohort changes.
  • PR #71: Introduces and refactors Task, Project, Artifact, Budget, CostRecord models; main PR extends those modules with NotBlankStr adoption and validator consolidation.
  • PR #69: Introduces core model modules (Agent, Role, Company) now being refactored with NotBlankStr type adoption and validator removal in this PR.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.82% which is insufficient. The required threshold is 100.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor: adopt NotBlankStr across all models (#108)' clearly and concisely summarizes the main change: the adoption of NotBlankStr type across the codebase to replace manual validators.
Description check ✅ Passed The PR description provides a comprehensive summary of changes, including the NotBlankStr type replacement, validator renaming, documentation updates, test additions, and net line reduction.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/adopt-notblankstr-108

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 refactors string validation across the codebase by introducing and adopting a custom NotBlankStr Pydantic type. This change centralizes and standardizes the enforcement of non-empty and non-whitespace string requirements, moving validation from manual @model_validator methods to the type annotation level. The refactoring simplifies model definitions, reduces boilerplate, and improves the clarity and consistency of data validation, ensuring that string fields adhere to defined constraints more robustly.

Highlights

  • Adopted NotBlankStr Across Models: Replaced manual @model_validator whitespace checks with the NotBlankStr type across 15 source modules in core/, budget/, communication/, and observability/.
  • Refactored String Validation Helper: Renamed validate_non_blank_unique_strings to validate_unique_strings and removed its responsibility for blank string checks, which is now handled by NotBlankStr.
  • Introduced NotBlankStr Type Alias: Added a NotBlankStr type alias in core/types.py using Annotated[str, StringConstraints(min_length=1), AfterValidator(_check_not_whitespace)] to reject both empty and whitespace-only strings with distinct error messages.
  • Documentation Updates: Updated DESIGN_SPEC.md and CLAUDE.md to reflect the adoption of the NotBlankStr convention, including its scalar, optional, and tuple variants.
  • Docstring Corrections: Fixed 3 stale docstrings in communication/ that incorrectly mentioned 'non-blank and unique' validation after the blank-check logic was moved to the type level.
  • Enhanced Type-Level Testing: Added comprehensive type-level tests in tests/unit/core/test_types.py for scalar, optional, and tuple NotBlankStr variants, along with empty-string deadline rejection tests for Project and Task.
  • Codebase Reduction: Achieved a net reduction of approximately 155 lines of code by eliminating boilerplate validation while maintaining equivalent behavior.
Changelog
  • CLAUDE.md
    • Updated the Models convention to mark NotBlankStr as adopted and documented its variants.
  • DESIGN_SPEC.md
    • Updated the Current state (M2) note to reflect NotBlankStr adoption for identifier/name fields.
    • Changed the String validation convention status from 'Planned' to 'Adopted' and updated its description.
  • src/ai_company/budget/config.py
    • Imported NotBlankStr.
    • Updated downgrade_map field type to use NotBlankStr.
    • Removed manual whitespace validation for source and target aliases in _validate_downgrade_map.
  • src/ai_company/budget/cost_record.py
    • Imported NotBlankStr.
    • Updated agent_id, task_id, provider, and model field types to NotBlankStr.
    • Removed the _validate_no_blank_strings model validator.
  • src/ai_company/budget/hierarchy.py
    • Imported NotBlankStr.
    • Updated team_name and department_name field types to NotBlankStr.
    • Removed manual whitespace validation for team_name and department_name.
  • src/ai_company/budget/spending_summary.py
    • Imported NotBlankStr.
    • Updated agent_id and department_name field types to NotBlankStr.
    • Removed manual whitespace validation for agent_id and department_name.
  • src/ai_company/communication/channel.py
    • Renamed validate_non_blank_unique_strings to validate_unique_strings.
    • Updated subscribers field type to tuple[NotBlankStr, ...].
    • Updated _validate_subscribers docstring and call to validate_unique_strings.
  • src/ai_company/communication/config.py
    • Renamed validate_non_blank_unique_strings to validate_unique_strings.
    • Updated channels and participants field types to tuple[NotBlankStr, ...].
    • Updated _validate_channels and _validate_participants docstrings and calls to validate_unique_strings.
  • src/ai_company/core/init.py
    • Updated import of validate_non_blank_unique_strings to validate_unique_strings.
    • Updated __all__ export list to reflect the validate_unique_strings rename.
  • src/ai_company/core/agent.py
    • Imported NotBlankStr.
    • Updated traits, communication_style, primary, secondary, provider, model_id, fallback_model, allowed, denied, name, role, and department field types to NotBlankStr or tuple[NotBlankStr, ...].
    • Removed manual whitespace validation for personality traits, skills, model identifiers, tool permissions, and agent identity fields.
  • src/ai_company/core/artifact.py
    • Removed Self import and model_validator import.
    • Imported NotBlankStr.
    • Updated path, id, task_id, and created_by field types to NotBlankStr.
    • Removed manual whitespace validation for artifact paths and identifiers.
  • src/ai_company/core/company.py
    • Imported NotBlankStr.
    • Updated name, lead, members, head, communication_pattern, tool_access_default, active_agents, available_roles, and hiring_queue field types to NotBlankStr or tuple[NotBlankStr, ...].
    • Removed manual whitespace validation for team, department, company config, and HR registry fields.
  • src/ai_company/core/project.py
    • Imported NotBlankStr.
    • Updated id, name, team, lead, and task_ids field types to NotBlankStr or tuple[NotBlankStr, ...].
    • Removed manual whitespace validation for project identifiers, names, lead, team members, and task IDs.
    • Updated _validate_fields to _validate_deadline_format and removed string field validation.
  • src/ai_company/core/role.py
    • Removed Self import and model_validator import.
    • Imported NotBlankStr.
    • Updated name, can_approve, reports_to, can_delegate_to, authority_scope, typical_model_tier, cost_tier, required_skills, tool_access, system_prompt_template, and suggested_model field types to NotBlankStr or tuple[NotBlankStr, ...].
    • Removed manual whitespace validation for skill names, authority fields, seniority info, and role fields.
  • src/ai_company/core/task.py
    • Imported NotBlankStr.
    • Updated description, id, title, project, created_by, assigned_to, reviewers, and dependencies field types to NotBlankStr or tuple[NotBlankStr, ...].
    • Removed manual whitespace validation for acceptance criterion descriptions, task identifiers, titles, descriptions, project, creator, assignee, reviewers, and dependencies.
    • Updated _validate_fields to _validate_deadline_format and removed string field validation.
  • src/ai_company/core/types.py
    • Renamed validate_non_blank_unique_strings function to validate_unique_strings.
    • Removed the blank string validation loop from validate_unique_strings.
  • src/ai_company/observability/config.py
    • Imported NotBlankStr.
    • Updated log_dir field type to NotBlankStr.
    • Removed manual blank validation for log_dir in _validate_log_dir_safe.
  • tests/unit/budget/test_config.py
    • Updated expected ValidationError messages for empty/whitespace-only source and target aliases to match NotBlankStr messages.
  • tests/unit/communication/test_channel.py
    • Updated expected ValidationError messages for empty/whitespace-only subscribers to match NotBlankStr messages.
  • tests/unit/communication/test_config.py
    • Updated expected ValidationError messages for empty/whitespace-only channels and participants to match NotBlankStr messages.
  • tests/unit/core/test_agent.py
    • Updated expected ValidationError messages for empty/whitespace-only personality traits, skills, and tool names to match NotBlankStr messages.
  • tests/unit/core/test_artifact.py
    • Updated expected ValidationError messages for empty/whitespace-only artifact paths, IDs, task IDs, and created-by fields to match NotBlankStr messages.
  • tests/unit/core/test_company.py
    • Updated expected ValidationError messages for empty/whitespace-only team members, tool access entries, active agents, available roles, and hiring queue entries to match NotBlankStr messages.
  • tests/unit/core/test_project.py
    • Added a test case to reject empty string deadlines.
    • Updated expected ValidationError messages for empty/whitespace-only project IDs, names, leads, team members, and task IDs to match NotBlankStr messages.
  • tests/unit/core/test_role.py
    • Updated expected ValidationError messages for empty/whitespace-only can_approve entries, can_delegate_to entries, required skills, and tool access entries to match NotBlankStr messages.
  • tests/unit/core/test_task.py
    • Added a test case to reject empty string deadlines.
    • Updated expected ValidationError messages for empty/whitespace-only acceptance criterion descriptions, task IDs, titles, descriptions, projects, creators, assignees, reviewers, and dependencies to match NotBlankStr messages.
  • tests/unit/core/test_types.py
    • Added a new test file to provide comprehensive unit tests for NotBlankStr (scalar, optional, tuple variants) and validate_unique_strings.
Activity
  • The pull request was pre-reviewed by 9 agents: code-reviewer, python-reviewer, pr-test-analyzer, silent-failure-hunter, comment-analyzer, type-design-analyzer, logging-audit, resilience-audit, and docs-consistency.
  • 6 findings from the pre-reviews were addressed, and 0 were skipped.
  • All automated checks passed, including ruff check, ruff format, mypy, and pytest with 94.98% coverage.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR completes the migration of all 15 source modules to use NotBlankStr (a Annotated[str, StringConstraints(min_length=1), AfterValidator] alias defined in core/types.py) for identifier and name fields, eliminating ~155 lines of boilerplate @model_validator whitespace checks while preserving equivalent validation behaviour. It also renames the public helper validate_non_blank_unique_stringsvalidate_unique_strings to reflect its narrowed responsibility (uniqueness only), and updates CLAUDE.md and DESIGN_SPEC.md to mark the convention as "Adopted".

Key changes:

  • core/types.pyNotBlankStr type alias with distinct error messages for empty ("at least 1 character") and whitespace-only ("must not be whitespace-only") inputs; validate_unique_strings replaces the old combined helper.
  • All 15 source modules — manual per-field @model_validator whitespace checks removed; fields annotated with NotBlankStr, NotBlankStr | None, or tuple[NotBlankStr, ...] as appropriate.
  • budget/config.py_normalize_downgrade_map (mode="before") made more defensive: non-conforming list items are passed through unchanged so Pydantic can surface proper field-level errors, replacing an implicit unpack that would raise a bare ValueError.
  • observability/config.pySinkConfig.file_path intentionally kept as str | None because its blank check is embedded inside a conditional path-safety validator; converting to NotBlankStr | None would not simplify that logic.
  • Tests — new test_types.py covers scalar, optional, and tuple NotBlankStr variants; existing test suites updated for the renamed helper and new empty/whitespace rejection cases.

Confidence Score: 5/5

  • This PR is safe to merge — it's a well-scoped refactoring with equivalent validation behaviour, comprehensive tests (1811 passing, 94.98% coverage), and no logic changes outside string validation.
  • All validation behaviour is preserved: NotBlankStr rejects the same inputs that the previous Field(min_length=1) + manual @model_validator combination rejected. The rename of validate_non_blank_unique_stringsvalidate_unique_strings is a clean breaking change confined to the public core/__init__.__all__ and verified by grep to have zero stale references. The _normalize_downgrade_map defensive improvement is a strict improvement over the previous implicit unpack. No logic changes were made to validators unrelated to blank-string checking.
  • No files require special attention.

Important Files Changed

Filename Overview
src/ai_company/core/types.py Defines NotBlankStr (Annotated[str, StringConstraints(min_length=1), AfterValidator]) and renames validate_non_blank_unique_stringsvalidate_unique_strings; clean, correct implementation with distinct error messages for empty vs whitespace-only strings.
src/ai_company/budget/config.py Adopts NotBlankStr for downgrade_map entries and makes _normalize_downgrade_map more defensive — non-conforming items are passed through unchanged so Pydantic surfaces proper field-level errors instead of crashing with an unpack error.
src/ai_company/core/agent.py Removes four manual @model_validator whitespace checks across PersonalityConfig, SkillSet, ModelConfig, and ToolPermissions in favour of NotBlankStr; adopts `NotBlankStr
src/ai_company/observability/config.py Migrates log_dir and logger-name elements to NotBlankStr; SinkConfig.file_path intentionally remains `str
src/ai_company/core/task.py All identifier/name fields migrated to NotBlankStr or `NotBlankStr
src/ai_company/core/project.py Adopts NotBlankStr / `NotBlankStr
src/ai_company/communication/channel.py Upgrades subscribers to tuple[NotBlankStr, ...] and updates the validator call to validate_unique_strings; docstring updated to reflect that blank-check responsibility moved to the type.
src/ai_company/communication/config.py Upgrades channels and participants fields to tuple[NotBlankStr, ...]; validator docstrings corrected to say "unique" instead of "non-blank and unique".
src/ai_company/core/role.py All string identifier fields across Skill, Authority, SeniorityInfo, Role, and CustomRole migrated to NotBlankStr; CustomRole.department keeps a custom field_validator since the field accepts a `DepartmentName
tests/unit/core/test_types.py New test file with comprehensive coverage of scalar, optional, and tuple NotBlankStr variants, verifying distinct error messages for empty vs whitespace-only strings and correct validate_unique_strings behavior.
src/ai_company/budget/cost_record.py Removes the manual _validate_no_blank_strings model validator across four fields and replaces with NotBlankStr; the remaining _validate_token_consistency validator is unchanged.
src/ai_company/core/init.py Public API updated cleanly — validate_non_blank_unique_strings removed from both the import and __all__, replaced by validate_unique_strings; no stale references remain.
src/ai_company/providers/models.py Adopts NotBlankStr for ToolDefinition.name, ToolCall.id/name, ToolResult.tool_call_id, and CompletionResponse.model; no logic changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Raw field input (str)"] --> B{"StringConstraints\nmin_length=1"}
    B -- "empty string ''" --> C["❌ ValidationError\n'at least 1 character'"]
    B -- "len ≥ 1" --> D{"AfterValidator\n_check_not_whitespace"}
    D -- "value.strip() == ''" --> E["❌ ValidationError\n'must not be whitespace-only'"]
    D -- "has non-whitespace content" --> F["✅ Valid NotBlankStr"]

    F --> G{Field type}
    G -- "NotBlankStr" --> H["Scalar field\ne.g. agent_id, name"]
    G -- "NotBlankStr | None" --> I["Optional field\ne.g. fallback_model, lead"]
    G -- "tuple[NotBlankStr, ...]" --> J["Collection field\ne.g. traits, subscribers"]

    J --> K{"validate_unique_strings\ncalled in @model_validator"}
    K -- "duplicates found" --> L["❌ ValidationError\n'Duplicate entries in ...'"]
    K -- "all unique" --> M["✅ Valid tuple"]
Loading

Last reviewed commit: fbe0ecd

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is an excellent and extensive refactoring to adopt the NotBlankStr type across all Pydantic models, which significantly reduces boilerplate validation code and improves maintainability. The changes are applied consistently, and the addition of comprehensive tests for the new type is a great enhancement. My review found one minor issue in the test suite where the expected validation error message for whitespace-only strings was incorrect.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors string validation across the codebase by centralizing “non-empty + not whitespace-only” enforcement into a shared NotBlankStr type, removing repeated per-model validators and updating tests/docs accordingly.

Changes:

  • Introduce and adopt NotBlankStr across core/budget/communication/observability Pydantic models to replace manual whitespace validators.
  • Rename validate_non_blank_unique_stringsvalidate_unique_strings (uniqueness-only), and update call sites/exports.
  • Add and update unit tests + documentation to reflect the new type-level validation behavior and error messages.

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/unit/observability/test_config.py Updates validation-error matching for log_dir now validated via NotBlankStr.
tests/unit/core/test_types.py Adds new unit tests covering scalar/optional/tuple NotBlankStr and validate_unique_strings.
tests/unit/core/test_task.py Updates error-message assertions and adds empty-deadline rejection coverage.
tests/unit/core/test_role.py Updates error-message assertions to align with type-level validation.
tests/unit/core/test_project.py Updates error-message assertions and adds empty-deadline rejection coverage.
tests/unit/core/test_company.py Updates tuple-entry error-message assertions to match new validation sources.
tests/unit/core/test_artifact.py Updates whitespace error-message assertions for NotBlankStr fields.
tests/unit/core/test_agent.py Updates tuple-entry error-message assertions for NotBlankStr fields.
tests/unit/communication/test_config.py Updates error-message assertions for channel/participant tuple validation.
tests/unit/communication/test_channel.py Updates error-message assertions for subscriber tuple validation.
tests/unit/budget/test_config.py Updates error-message assertions for downgrade_map aliases validated via NotBlankStr.
src/ai_company/observability/config.py Switches log_dir to NotBlankStr and removes redundant blank-check validator logic.
src/ai_company/core/types.py Adds NotBlankStr and renames uniqueness helper to validate_unique_strings.
src/ai_company/core/task.py Migrates identifiers and tuple fields to NotBlankStr; simplifies validators to deadline/uniqueness logic.
src/ai_company/core/role.py Migrates identifier and tuple fields to NotBlankStr; removes redundant whitespace validators.
src/ai_company/core/project.py Migrates identifiers and tuple fields to NotBlankStr; simplifies validators to deadline/uniqueness logic.
src/ai_company/core/company.py Migrates identifiers and tuple fields to NotBlankStr; removes redundant whitespace validators.
src/ai_company/core/artifact.py Migrates identifier/path fields to NotBlankStr; removes redundant whitespace validators.
src/ai_company/core/agent.py Migrates identifiers and tuple fields to NotBlankStr; removes redundant whitespace validators.
src/ai_company/core/init.py Updates exports/imports to validate_unique_strings.
src/ai_company/communication/config.py Migrates tuple fields to tuple[NotBlankStr, ...] and updates uniqueness helper usage.
src/ai_company/communication/channel.py Migrates subscribers to tuple[NotBlankStr, ...] and updates uniqueness helper usage.
src/ai_company/budget/spending_summary.py Migrates identifier fields to NotBlankStr and removes redundant whitespace validators.
src/ai_company/budget/hierarchy.py Migrates team/department names to NotBlankStr and removes redundant whitespace validators.
src/ai_company/budget/cost_record.py Migrates identifier fields to NotBlankStr and removes redundant whitespace validators.
src/ai_company/budget/config.py Migrates downgrade_map tuple entries to NotBlankStr.
DESIGN_SPEC.md Marks NotBlankStr string validation convention as adopted and updates current-state notes.
CLAUDE.md Updates documented conventions to reflect NotBlankStr adoption (scalar/optional/tuple variants).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 17 to 22
NotBlankStr = Annotated[
str,
StringConstraints(min_length=1),
AfterValidator(_check_not_whitespace),
]
"""A string that must be non-empty and not consist solely of whitespace."""
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The standalone string literal after the NotBlankStr alias (line 22) is not a docstring for the alias and has no effect at runtime; it’s easy to miss and can be flagged as a “pointless statement” by linters. Consider turning this into a normal comment above the alias (or using a TypeAlias assignment with an adjacent comment) so the intent is clear.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/ai_company/budget/config.py (1)

97-108: ⚠️ Potential issue | 🟠 Major

Guard malformed downgrade_map entries in the pre-validator.

This mode="before" normalizer assumes every item is a 2-tuple of strings. Inputs like [(123, "sonnet")] or [("opus", None)] will fail inside .strip() before Pydantic can report a field-level ValidationError, which makes config errors escape as raw runtime exceptions instead of structured validation failures.

Suggested fix
     `@model_validator`(mode="before")
     `@classmethod`
     def _normalize_downgrade_map(cls, data: Any) -> Any:
         """Strip whitespace from downgrade_map alias strings."""
         if isinstance(data, dict) and "downgrade_map" in data:
             raw_map = data["downgrade_map"]
             if isinstance(raw_map, (list, tuple)):
+                normalized: list[Any] = []
+                for item in raw_map:
+                    if (
+                        isinstance(item, (list, tuple))
+                        and len(item) == 2
+                        and isinstance(item[0], str)
+                        and isinstance(item[1], str)
+                    ):
+                        normalized.append((item[0].strip(), item[1].strip()))
+                    else:
+                        normalized.append(item)
                 return {
                     **data,
-                    "downgrade_map": tuple((s.strip(), t.strip()) for s, t in raw_map),
+                    "downgrade_map": tuple(normalized),
                 }
         return data

As per coding guidelines: Validate at system boundaries: user input, external APIs, config files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ai_company/budget/config.py` around lines 97 - 108, The pre-validator
_normalize_downgrade_map currently assumes every entry in downgrade_map is a
2-tuple of strings and calls .strip() unguarded; modify _normalize_downgrade_map
so it only transforms entries when each item is an iterable of length 2 and both
elements are str (e.g., check isinstance(item, (list, tuple)) and len(item) == 2
and isinstance(s, str) and isinstance(t, str)), otherwise do not attempt to
strip and return the original data unchanged so Pydantic can surface a proper
field-level ValidationError for malformed entries in downgrade_map.
src/ai_company/core/__init__.py (1)

53-100: ⚠️ Potential issue | 🟠 Major

Keep a backwards-compatible export for validate_non_blank_unique_strings.

Removing the old symbol from ai_company.core makes this a breaking package-API change for any downstream from ai_company.core import validate_non_blank_unique_strings. Please keep a temporary alias for at least one deprecation cycle, or explicitly document the break in release notes.

Suggested compatibility shim
 from ai_company.core.types import NotBlankStr, validate_unique_strings
+
+validate_non_blank_unique_strings = validate_unique_strings
 
 __all__ = [
@@
     "validate_transition",
+    "validate_non_blank_unique_strings",
     "validate_unique_strings",
 ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ai_company/core/__init__.py` around lines 53 - 100, The export removed
the old symbol validate_non_blank_unique_strings causing a breaking API change;
restore backwards compatibility by adding a temporary alias in
ai_company.core.__init__.py that sets validate_non_blank_unique_strings =
validate_unique_strings and include "validate_non_blank_unique_strings" in
__all__; optionally emit a DeprecationWarning in the alias (e.g., using
warnings.warn) so callers are notified while keeping the symbol for one
deprecation cycle.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@DESIGN_SPEC.md`:
- Line 109: The DESIGN_SPEC.md line describing field types omits the optional
variant; update the sentence referencing NotBlankStr and tuple[NotBlankStr, ...]
to also document the optional form NotBlankStr | None (and tuple[NotBlankStr,
...] | None where appropriate) so the spec matches the implementation and
CLAUDE.md; mention AgentIdentity (frozen Pydantic model in core/agent.py) as
using NotBlankStr, NotBlankStr | None for optional identifier/name fields and
tuple[NotBlankStr, ...] (and its optional variant) for tuple fields to keep
documentation consistent.

---

Outside diff comments:
In `@src/ai_company/budget/config.py`:
- Around line 97-108: The pre-validator _normalize_downgrade_map currently
assumes every entry in downgrade_map is a 2-tuple of strings and calls .strip()
unguarded; modify _normalize_downgrade_map so it only transforms entries when
each item is an iterable of length 2 and both elements are str (e.g., check
isinstance(item, (list, tuple)) and len(item) == 2 and isinstance(s, str) and
isinstance(t, str)), otherwise do not attempt to strip and return the original
data unchanged so Pydantic can surface a proper field-level ValidationError for
malformed entries in downgrade_map.

In `@src/ai_company/core/__init__.py`:
- Around line 53-100: The export removed the old symbol
validate_non_blank_unique_strings causing a breaking API change; restore
backwards compatibility by adding a temporary alias in
ai_company.core.__init__.py that sets validate_non_blank_unique_strings =
validate_unique_strings and include "validate_non_blank_unique_strings" in
__all__; optionally emit a DeprecationWarning in the alias (e.g., using
warnings.warn) so callers are notified while keeping the symbol for one
deprecation cycle.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 92df3fa7-e139-40ed-bd8c-dd13c158a4c0

📥 Commits

Reviewing files that changed from the base of the PR and between c0bab18 and c6192d3.

📒 Files selected for processing (28)
  • CLAUDE.md
  • DESIGN_SPEC.md
  • src/ai_company/budget/config.py
  • src/ai_company/budget/cost_record.py
  • src/ai_company/budget/hierarchy.py
  • src/ai_company/budget/spending_summary.py
  • src/ai_company/communication/channel.py
  • src/ai_company/communication/config.py
  • src/ai_company/core/__init__.py
  • src/ai_company/core/agent.py
  • src/ai_company/core/artifact.py
  • src/ai_company/core/company.py
  • src/ai_company/core/project.py
  • src/ai_company/core/role.py
  • src/ai_company/core/task.py
  • src/ai_company/core/types.py
  • src/ai_company/observability/config.py
  • tests/unit/budget/test_config.py
  • tests/unit/communication/test_channel.py
  • tests/unit/communication/test_config.py
  • tests/unit/core/test_agent.py
  • tests/unit/core/test_artifact.py
  • tests/unit/core/test_company.py
  • tests/unit/core/test_project.py
  • tests/unit/core/test_role.py
  • tests/unit/core/test_task.py
  • tests/unit/core/test_types.py
  • tests/unit/observability/test_config.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 (3)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do not use from __future__ import annotations in Python files — Python 3.14 has PEP 649 native lazy annotations
Use PEP 758 except syntax with except A, B: (no parentheses) for multiple exception handlers in Python 3.14
Include type hints on all public functions in Python
Use Google-style docstrings (required on public classes and functions, enforced by ruff D rules)
Create new objects for immutability — never mutate existing ones. For non-Pydantic internal collections, use copy.deepcopy() at construction and MappingProxyType for read-only enforcement
Use copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization) for dict/list fields in frozen Pydantic models
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models with model_copy(update=...) for runtime state that evolves
Use Pydantic v2 conventions: BaseModel, model_validator, computed_field, ConfigDict. Use @computed_field for derived values instead of storing redundant fields
Use NotBlankStr from core.types for non-optional identifier and name fields in Pydantic models instead of manual whitespace validators
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations (multiple tool invocations, parallel agent calls) instead of bare create_task
Keep functions under 50 lines and files under 800 lines
Handle errors explicitly — never silently swallow exceptions
Validate at system boundaries: user input, external APIs, config files
Set line length to 88 characters (enforced by ruff)

Files:

  • tests/unit/core/test_artifact.py
  • tests/unit/communication/test_config.py
  • tests/unit/core/test_role.py
  • src/ai_company/observability/config.py
  • src/ai_company/budget/config.py
  • src/ai_company/budget/cost_record.py
  • src/ai_company/core/project.py
  • tests/unit/communication/test_channel.py
  • src/ai_company/core/__init__.py
  • src/ai_company/communication/channel.py
  • src/ai_company/budget/hierarchy.py
  • src/ai_company/budget/spending_summary.py
  • src/ai_company/communication/config.py
  • tests/unit/core/test_task.py
  • tests/unit/budget/test_config.py
  • src/ai_company/core/types.py
  • tests/unit/core/test_project.py
  • tests/unit/core/test_company.py
  • tests/unit/core/test_types.py
  • src/ai_company/core/role.py
  • tests/unit/core/test_agent.py
  • src/ai_company/core/company.py
  • src/ai_company/core/artifact.py
  • tests/unit/observability/test_config.py
  • src/ai_company/core/agent.py
  • src/ai_company/core/task.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 vendor-agnostic fixture identifiers (e.g., test-haiku-001, test-provider) — never use real vendor model IDs to avoid coupling tests to external providers

Files:

  • tests/unit/core/test_artifact.py
  • tests/unit/communication/test_config.py
  • tests/unit/core/test_role.py
  • tests/unit/communication/test_channel.py
  • tests/unit/core/test_task.py
  • tests/unit/budget/test_config.py
  • tests/unit/core/test_project.py
  • tests/unit/core/test_company.py
  • tests/unit/core/test_types.py
  • tests/unit/core/test_agent.py
  • tests/unit/observability/test_config.py
src/ai_company/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/ai_company/**/*.py: Every module with business logic must import logger with from ai_company.observability import get_logger then logger = get_logger(__name__)
Never use import logging, logging.getLogger(), or print() in application code — use the project's logger setup
Always use logger as the variable name for the logger, not _logger or log
Use constants from ai_company.observability.events for event names (e.g., PROVIDER_CALL_START, BUDGET_RECORD_ADDED, TOOL_INVOKE_START), imported directly
Use structured logging: logger.info(EVENT, key=value) — never use logger.info("msg %s", val)
Log all error paths at WARNING or ERROR with context before raising
Log all state transitions at INFO level
Use DEBUG logging for object creation, internal flow, and entry/exit of key functions

Files:

  • src/ai_company/observability/config.py
  • src/ai_company/budget/config.py
  • src/ai_company/budget/cost_record.py
  • src/ai_company/core/project.py
  • src/ai_company/core/__init__.py
  • src/ai_company/communication/channel.py
  • src/ai_company/budget/hierarchy.py
  • src/ai_company/budget/spending_summary.py
  • src/ai_company/communication/config.py
  • src/ai_company/core/types.py
  • src/ai_company/core/role.py
  • src/ai_company/core/company.py
  • src/ai_company/core/artifact.py
  • src/ai_company/core/agent.py
  • src/ai_company/core/task.py
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to **/*.py : Use `NotBlankStr` from `core.types` for non-optional identifier and name fields in Pydantic models instead of manual whitespace validators
📚 Learning: 2026-03-06T08:46:25.159Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to **/*.py : Use `NotBlankStr` from `core.types` for non-optional identifier and name fields in Pydantic models instead of manual whitespace validators

Applied to files:

  • src/ai_company/observability/config.py
  • src/ai_company/budget/config.py
  • src/ai_company/core/project.py
  • src/ai_company/budget/hierarchy.py
  • src/ai_company/budget/spending_summary.py
  • tests/unit/core/test_types.py
  • DESIGN_SPEC.md
  • src/ai_company/core/role.py
  • src/ai_company/core/artifact.py
  • src/ai_company/core/task.py
📚 Learning: 2026-03-06T08:46:25.159Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to src/ai_company/**/*.py : Use constants from `ai_company.observability.events` for event names (e.g., PROVIDER_CALL_START, BUDGET_RECORD_ADDED, TOOL_INVOKE_START), imported directly

Applied to files:

  • src/ai_company/observability/config.py
  • src/ai_company/core/__init__.py
  • src/ai_company/core/task.py
📚 Learning: 2026-03-06T08:46:25.159Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to **/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. Use `computed_field` for derived values instead of storing redundant fields

Applied to files:

  • src/ai_company/observability/config.py
  • DESIGN_SPEC.md
  • 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 : Validate all LLM outputs by checking required fields, verifying data types, handling malformed responses, and using Pydantic models for structured data

Applied to files:

  • src/ai_company/budget/cost_record.py
  • CLAUDE.md
  • src/ai_company/core/agent.py
📚 Learning: 2026-03-06T08:46:25.159Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config and identity; use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves

Applied to files:

  • DESIGN_SPEC.md
  • CLAUDE.md
📚 Learning: 2026-01-24T16:33:29.354Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-24T16:33:29.354Z
Learning: Applies to {src/memory/**/*.py,src/services/**/*.py} : Story state is maintained through `src/memory/story_state.py` module using Pydantic models for validation (StoryState, Character, Chapter, etc.)

Applied to files:

  • DESIGN_SPEC.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/agents/**/*.py : Agents must extend `BaseAgent`, use retry logic, and implement configurable timeout via settings.

Applied to files:

  • DESIGN_SPEC.md
  • 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/memory/story_state.py : Story state must be maintained through `src/memory/story_state.py` module using Pydantic models for validation (StoryState, Character, Chapter, etc.)

Applied to files:

  • DESIGN_SPEC.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 : Use `StoryState` from `memory/story_state.py` for context management and balance context size vs. token limits when passing story context

Applied to files:

  • DESIGN_SPEC.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 : Update story state by directly modifying fields on Pydantic model instances (append to chapters list, find and modify characters by ID)

Applied to files:

  • DESIGN_SPEC.md
📚 Learning: 2026-03-06T08:46:25.159Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to **/*.py : Use `copy.deepcopy()` at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization) for `dict`/`list` fields in frozen Pydantic models

Applied to files:

  • DESIGN_SPEC.md
  • CLAUDE.md
📚 Learning: 2026-03-06T08:46:25.159Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to **/*.py : Create new objects for immutability — never mutate existing ones. For non-Pydantic internal collections, use `copy.deepcopy()` at construction and `MappingProxyType` for read-only enforcement

Applied to files:

  • DESIGN_SPEC.md
  • 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 type hints where appropriate. Use Pydantic models for data validation in `src/memory/story_state.py`, dataclasses in `src/settings.py`.

Applied to files:

  • DESIGN_SPEC.md
  • 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: 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-06T08:46:25.159Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to **/*.py : Use Google-style docstrings (required on public classes and functions, enforced by ruff D rules)

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 : Line length: 100 characters (enforced by Ruff)

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 **/*.py : Maintain line length at 100 characters per Ruff formatting rules.

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/test*.py : Agent tests should cover: successful generation with valid output, handling malformed LLM responses, error conditions (network errors, timeouts), output format validation, and integration with story state

Applied to files:

  • tests/unit/core/test_agent.py
📚 Learning: 2026-03-06T08:46:25.159Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T08:46:25.159Z
Learning: Applies to src/ai_company/**/*.py : Every module with business logic must import logger with `from ai_company.observability import get_logger` then `logger = get_logger(__name__)`

Applied to files:

  • src/ai_company/core/task.py
🪛 LanguageTool
DESIGN_SPEC.md

[style] ~109-~109: Consider using the typographical ellipsis character here instead.
Context: ... whitespace rejection; tuple fields use tuple[NotBlankStr, ...] for per-element validation. ```yaml ...

(ELLIPSIS)


[style] ~1442-~1442: Consider using the typographical ellipsis character here instead.
Context: ...lds use NotBlankStr; tuple fields use tuple[NotBlankStr, ...] for per-element validation. | | **Sha...

(ELLIPSIS)

CLAUDE.md

[style] ~71-~71: Consider using the typographical ellipsis character here instead.
Context: ...ional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants — instead of manual whitesp...

(ELLIPSIS)

🔇 Additional comments (32)
src/ai_company/budget/cost_record.py (1)

11-11: The non-blank constraint is cleanly centralized here.

Using NotBlankStr on the identifier/provider fields keeps field-level validation in one place and leaves the model validator focused on token consistency only.

Also applies to: 34-37

src/ai_company/communication/channel.py (1)

8-10: Validation responsibility is cleanly separated.

tuple[NotBlankStr, ...] now handles blank/whitespace subscriber entries, while validate_unique_strings() keeps the model validator scoped to uniqueness only.

Also applies to: 30-39

tests/unit/communication/test_channel.py (1)

47-53: These assertions match the new two-path validation behavior.

The updated expectations now cover both the empty-string branch and the whitespace-only branch for subscriber entries.

tests/unit/communication/test_config.py (1)

47-52: The updated expectations are consistent across channels and participants.

These assertions now track the separate empty-string and whitespace-only failures introduced by the shared non-blank type.

Also applies to: 156-168

src/ai_company/core/agent.py (1)

17-17: The type-level migration is consistent across the nested agent models.

This moves the non-blank rule to the field/item types for scalar, optional, and tuple cases without reintroducing per-model whitespace checks.

Also applies to: 33-40, 65-72, 88-104, 146-153, 196-198

tests/unit/core/test_agent.py (1)

75-83: Good coverage update for tuple-item validation.

These assertions now exercise the separate empty-string and whitespace-only failures across traits, skills, and tool names.

Also applies to: 119-127, 344-352

tests/unit/observability/test_config.py (1)

233-235: This assertion now lines up with the shared non-blank validator.

Matching the whitespace-only branch here keeps the observability config tests consistent with the rest of the migration.

tests/unit/core/test_artifact.py (1)

32-34: The artifact tests now match the shared validation contract.

Using the same whitespace-only expectation across these identifier and path fields keeps this suite aligned with the type-level validator.

Also applies to: 91-133

tests/unit/core/test_types.py (1)

14-128: Good coverage for the new type-level contract.

These tests pin down the scalar, optional, and tuple forms of NotBlankStr, plus the duplicate-reporting behavior of validate_unique_strings, which is the main regression surface in this refactor.

src/ai_company/core/project.py (4)

10-10: LGTM on import.

The # noqa: TC001 is appropriate here since NotBlankStr is used in runtime type annotations for Pydantic fields.


34-51: LGTM on NotBlankStr field adoption.

The field type changes correctly apply NotBlankStr to identifier and name fields (id, name, lead, team, task_ids), aligning with the coding guidelines. The optional lead field correctly uses NotBlankStr | None.


66-78: LGTM on deadline validation.

The validator correctly:

  1. Checks for whitespace-only strings before format parsing
  2. Validates ISO 8601 format using datetime.fromisoformat
  3. Uses from None to suppress the chained exception for cleaner error messages

80-91: LGTM on collection uniqueness validation.

The validator is correctly narrowed to uniqueness-only checks since NotBlankStr now handles the non-blank validation at the type level for each tuple element.

src/ai_company/core/company.py (7)

28-33: LGTM on Team field updates.

The name, lead, and members fields correctly use NotBlankStr and tuple[NotBlankStr, ...] for identifier fields.


35-42: LGTM on duplicate member validation.

The validator correctly focuses only on uniqueness since NotBlankStr handles non-blank validation at the type level.


61-62: LGTM on Department field updates.

name and head correctly use NotBlankStr for identifier fields.


108-115: LGTM on CompanyConfig field updates.

communication_pattern and tool_access_default correctly use NotBlankStr variants for pattern names and tool identifiers.


132-143: LGTM on HRRegistry field updates.

The tuple fields correctly use tuple[NotBlankStr, ...]. The design decision to allow duplicates in available_roles and hiring_queue (per the docstring) while enforcing uniqueness only on active_agents is sensible and correctly implemented.


145-153: LGTM on active agents uniqueness validation.

The validator correctly enforces uniqueness only for active_agents as documented, leaving available_roles and hiring_queue to allow duplicates for multiple openings.


175-175: LGTM on Company.name field update.

The name field correctly uses NotBlankStr. The id field appropriately remains as UUID since it's not a string identifier.

src/ai_company/core/role.py (6)

25-25: LGTM on Skill.name field update.

The name field correctly uses NotBlankStr for the skill identifier.


45-56: LGTM on Authority field updates.

The fields correctly use NotBlankStr variants: can_approve and can_delegate_to as tuples, reports_to as optional. This ensures task types and role references are non-blank.


77-85: LGTM on SeniorityInfo field updates.

The authority_scope, typical_model_tier, and cost_tier fields correctly use NotBlankStr for descriptive string fields that should never be blank.


103-122: LGTM on Role field updates.

The field type changes correctly apply NotBlankStr to name, required_skills, tool_access, and system_prompt_template. The optional system_prompt_template correctly uses NotBlankStr | None.


147-166: LGTM on CustomRole field updates.

The field type changes correctly apply NotBlankStr variants to name, required_skills, system_prompt_template, and suggested_model.


168-178: LGTM on department validator retention.

The _department_not_empty validator is correctly retained for CustomRole.department since it's a union type DepartmentName | str. NotBlankStr cannot be applied directly to a union with an enum, so manual validation for the str branch is appropriate.

src/ai_company/core/task.py (6)

29-31: LGTM on AcceptanceCriterion.description field update.

The description field correctly uses NotBlankStr to ensure criterion text is never blank.


66-93: LGTM on Task identifier field updates.

The field type changes correctly apply NotBlankStr to all identifier and text fields: id, title, description, project, created_by, assigned_to, reviewers, and dependencies. The optional assigned_to correctly uses NotBlankStr | None.


120-132: LGTM on deadline validation.

The validator correctly matches the pattern in project.py:

  1. Whitespace-only check before parsing
  2. ISO 8601 format validation via datetime.fromisoformat
  3. Clean exception handling with from None

This consistency across Project and Task deadline validation is good.


134-148: LGTM on collection validation.

The validator correctly:

  1. Prevents self-dependency
  2. Enforces uniqueness for both dependencies and reviewers

Non-blank validation is now handled at the type level by NotBlankStr.


150-171: LGTM on assignment consistency validation.

The validator correctly enforces status-based assignment rules. This is business logic orthogonal to the NotBlankStr migration.


173-206: LGTM on with_transition method.

The method correctly:

  1. Prevents status override in favor of explicit target parameter
  2. Validates transitions via validate_transition
  3. Uses model_validate to run all validators on the new instance
  4. Uses structured logging with the TASK_STATUS_CHANGED constant

This aligns with the coding guidelines for logging. Based on learnings: "Use constants from ai_company.observability.events for event names".

DESIGN_SPEC.md Outdated
- **Runtime state (mutable-via-copy)**: current status, active task, conversation history, execution metrics. Evolves during agent operation. Represented as Pydantic models using `model_copy(update=...)` for state transitions — never mutated in place.

> **Current state (M2):** Only the config layer exists as `AgentIdentity` (frozen Pydantic model in `core/agent.py`). The runtime state layer will be introduced in M3 when the agent execution engine is implemented. Non-optional identifier fields currently use `str` with `Field(min_length=1)` + a manual `@model_validator`; migration to `NotBlankStr` (from `core.types`) is planned.
> **Current state (M2):** Only the config layer exists as `AgentIdentity` (frozen Pydantic model in `core/agent.py`). The runtime state layer will be introduced in M3 when the agent execution engine is implemented. All identifier/name fields use `NotBlankStr` (from `core.types`) for automatic whitespace rejection; tuple fields use `tuple[NotBlankStr, ...]` for per-element validation.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Document the optional NotBlankStr | None variant here too.

These two spec updates now mention scalar and tuple usage, but the adopted convention in this PR also covers optional fields. Since DESIGN_SPEC.md is the required source of truth, leaving that variant out here will keep it out of sync with CLAUDE.md and the implementation.

Based on learnings: 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.

Also applies to: 1442-1442

🧰 Tools
🪛 LanguageTool

[style] ~109-~109: Consider using the typographical ellipsis character here instead.
Context: ... whitespace rejection; tuple fields use tuple[NotBlankStr, ...] for per-element validation. ```yaml ...

(ELLIPSIS)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@DESIGN_SPEC.md` at line 109, The DESIGN_SPEC.md line describing field types
omits the optional variant; update the sentence referencing NotBlankStr and
tuple[NotBlankStr, ...] to also document the optional form NotBlankStr | None
(and tuple[NotBlankStr, ...] | None where appropriate) so the spec matches the
implementation and CLAUDE.md; mention AgentIdentity (frozen Pydantic model in
core/agent.py) as using NotBlankStr, NotBlankStr | None for optional
identifier/name fields and tuple[NotBlankStr, ...] (and its optional variant)
for tuple fields to keep documentation consistent.

…ilot

- Guard malformed downgrade_map entries in before-validator (CodeRabbit)
- Clarify _normalize_downgrade_map docstring purpose (comment-analyzer)
- Use NotBlankStr for logger_levels logger name (type-design-analyzer)
- Add NotBlankStr | None optional variant to DESIGN_SPEC.md (CodeRabbit)
- Fix CostRecord JSON example removing non-existent total_tokens (docs-consistency)
- Rename misleading test names: empty → whitespace (pr-test-analyzer)
- Remove redundant "(must be non-blank)" from ToolDefinition docstring (comment-analyzer)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Aureliolo Aureliolo merged commit ef89b90 into main Mar 6, 2026
10 checks passed
@Aureliolo Aureliolo deleted the refactor/adopt-notblankstr-108 branch March 6, 2026 10:00
Aureliolo added a commit that referenced this pull request Mar 10, 2026
🤖 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).
Aureliolo added a commit that referenced this pull request Mar 11, 2026
🤖 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adopt NotBlankStr across all models to eliminate redundant whitespace validators

2 participants