8dc55655e9
CI / push-validation (push) Successful in 41s
CI / helm (push) Successful in 42s
CI / benchmark-publish (push) Failing after 56s
CI / build (push) Successful in 1m6s
CI / lint (push) Successful in 1m13s
CI / quality (push) Successful in 1m34s
CI / typecheck (push) Successful in 2m12s
CI / security (push) Successful in 2m13s
CI / e2e_tests (push) Successful in 3m45s
CI / integration_tests (push) Successful in 3m57s
CI / unit_tests (push) Successful in 4m53s
CI / docker (push) Successful in 1m34s
CI / coverage (push) Successful in 11m27s
CI / status-check (push) Successful in 3s
CI / benchmark-publish (pull_request) Has been skipped
CI / helm (pull_request) Successful in 32s
CI / push-validation (pull_request) Successful in 33s
CI / build (pull_request) Successful in 53s
CI / lint (pull_request) Successful in 59s
CI / quality (pull_request) Successful in 1m28s
CI / security (pull_request) Successful in 1m29s
CI / typecheck (pull_request) Successful in 1m32s
CI / e2e_tests (pull_request) Successful in 4m1s
CI / integration_tests (pull_request) Successful in 5m4s
CI / unit_tests (pull_request) Successful in 5m51s
CI / docker (pull_request) Successful in 1m27s
CI / coverage (pull_request) Successful in 11m51s
CI / status-check (pull_request) Successful in 3s
Replace the DB-persistence approach for built-in actors with in-memory virtual resolution. Built-in actors (e.g. openai/gpt-4o, anthropic/claude-sonnet) are now resolved on-demand from ProviderRegistry at query time and merged with persisted custom actors — no database writes occur for built-in actors. Key changes: - Add ActorRegistry._resolve_virtual_builtin_actors(): generates virtual Actor objects in-memory from configured providers (is_built_in=True, id=None) - ActorRegistry.list()/list_actors(): merges virtual built-ins with custom DB actors; custom actors win on name collision; result sorted alphabetically - ActorRegistry.get()/get_actor(): DB-first, virtual built-in fallback, NotFoundError if neither - ActorRegistry.remove()/remove_actor(): rejects virtual built-in names with ValidationError - ActorRegistry.set_default_actor(): stores only the actor name string via new actor_preferences singleton table; no actor row created for virtual built-ins - ActorRegistry.get_default_actor(): reads preference name, resolves via DB→virtual chain, returns actor with is_default=True - Remove ensure_built_in_actors() entirely — 20+ call sites cleaned up including plan.py - Remove ActorRepository.upsert_built_in() — no longer needed - Remove is_built_in from ActorModel DB column (kept on Actor domain model for virtual actors) - New Alembic migration m10_001_virtual_builtin_actors: drops is_built_in column, adds actor_preferences singleton table - Add ActorService.set_default_actor_name() and get_default_actor_name() for preference storage without requiring a DB actor row - Update 15+ Behave step files and 5 feature files; add new features/virtual_builtin_actors.feature with 8 scenarios covering list, show, remove, set-default, get-default, no-DB-writes guarantees - Rewrite tests/actor/test_registry_builtin_yaml.py: TestEnsureBuiltInActorsWithYaml → TestResolveVirtualBuiltinActors plus new TestListActors, TestGetActor, TestRemoveActor, TestDefaultActor test classes Quality gates: lint ✓, typecheck ✓, unit_tests ✓ (15674 scenarios), coverage ✓ (97.10%), integration_tests ✓ (1997 tests) ISSUES CLOSED: #10923
177 lines
8.2 KiB
Gherkin
177 lines
8.2 KiB
Gherkin
Feature: Database Repository Error Handling Coverage
|
|
As a developer
|
|
I want to ensure database repositories handle edge cases properly
|
|
So that missing entities and failed updates are handled gracefully
|
|
|
|
@phase1
|
|
Scenario: ProjectRepository get_by_id returns None for non-existent project
|
|
Given I have a project repository with database session
|
|
When I query for a project with non-existent ID 99999
|
|
Then the repository should return None for missing project
|
|
|
|
@phase1
|
|
Scenario: ProjectRepository update method handles successful project updates
|
|
Given I have a project repository with database session
|
|
And I have created a project named "test-project"
|
|
When I modify the project name to "updated-project"
|
|
Then the project should be updated in the database
|
|
And the updated_at timestamp should be refreshed
|
|
|
|
@phase1
|
|
Scenario: ProjectRepository update returns unchanged object for non-existent project
|
|
Given I have a project repository with database session
|
|
When I attempt to update a project that does not exist
|
|
Then the update operation should complete without error
|
|
And the original project object should be returned unchanged
|
|
|
|
@phase1
|
|
Scenario: PlanRepository get_current_for_project returns None when no current plan exists
|
|
Given I have a plan repository with database session
|
|
When I query for current plan of non-existent project 99999
|
|
Then the repository should return None for missing current plan
|
|
|
|
@phase1
|
|
Scenario: PlanRepository get_by_id returns plan with None build when no build exists
|
|
Given I have a plan repository with database session
|
|
And I have created a plan without build information
|
|
When I retrieve the plan by ID
|
|
Then the plan should be returned with null build field
|
|
|
|
@phase1
|
|
Scenario: ProjectRepository create raises database error on OperationalError
|
|
Given I have a project repository with a session that fails on create
|
|
When I attempt to create a project named "failing-project" with that failing session
|
|
Then a database error should be raised when creating the project
|
|
And the session rollback should be triggered for the project create failure
|
|
|
|
@phase1
|
|
Scenario: ProjectRepository get_by_id wraps OperationalError in DatabaseError
|
|
Given I have a project repository with a session that fails on query
|
|
When I query the project repository for ID 42 expecting a failure
|
|
Then a database error should be raised for the project lookup
|
|
|
|
@phase1
|
|
Scenario: PlanRepository get_by_id returns None for unknown plan
|
|
Given I have a plan repository with database session
|
|
When I query for a plan with non-existent ID 99999
|
|
Then the plan repository should return None for missing plan
|
|
|
|
@phase1
|
|
Scenario: PlanRepository update persists applied_at field when provided
|
|
Given I have a plan repository with database session
|
|
And I have created a plan without build information
|
|
When I update the plan with a new applied timestamp
|
|
Then the plan record should store the applied timestamp value
|
|
|
|
@phase1
|
|
Scenario: PlanRepository get_current returns None when no plan is marked current
|
|
Given I have a plan repository with database session
|
|
And I have created a plan without build information
|
|
When I request the current plan for the project
|
|
Then the repository should return None for missing current plan
|
|
|
|
@phase1
|
|
Scenario: ChangeRepository get_all returns persisted changes
|
|
Given I have a plan repository with database session
|
|
And I have created a plan without build information
|
|
And I have a change repository with the shared database session
|
|
And I have added a change for the plan
|
|
When I request all changes for the plan
|
|
Then the repository should include the added change
|
|
|
|
@phase1
|
|
Scenario: DebugAttemptRepository get returns None for missing attempt
|
|
Given I have a debug attempt repository with database session
|
|
When I query for a debug attempt with non-existent ID 404
|
|
Then the debug attempt repository should return None for missing attempt
|
|
|
|
@phase1
|
|
Scenario: DebugAttemptRepository update raises error when attempt missing
|
|
Given I have a debug attempt repository with database session
|
|
When I attempt to update a debug attempt that does not exist
|
|
Then the debug attempt repository should raise an error for missing attempt
|
|
|
|
@phase1
|
|
Scenario: DebugAttemptRepository get_all returns persisted attempts
|
|
Given I have a debug attempt repository with database session
|
|
And I have stored multiple debug attempts for the plan
|
|
When I request all debug attempts
|
|
Then the repository should return all persisted debug attempts
|
|
|
|
@phase1
|
|
Scenario: DebugAttemptRepository clear_for_plan removes attempts
|
|
Given I have a debug attempt repository with database session
|
|
And I have stored multiple debug attempts for the plan
|
|
When I clear debug attempts for the plan
|
|
Then the repository should return no debug attempts for that plan
|
|
|
|
@phase1
|
|
Scenario: ActorRepository list_all returns actors ordered by name
|
|
Given I have an actor repository with database session
|
|
And I have stored custom actors "provider/beta" and "provider/alpha"
|
|
When I list actors from the repository
|
|
Then the repository should return the actors ordered by name
|
|
|
|
@phase1
|
|
Scenario: ActorRepository allows overwriting existing actors (built-in protection removed)
|
|
Given I have an actor repository with database session
|
|
And I have stored a built-in actor named "provider/model"
|
|
When I try to upsert a custom actor with the same name
|
|
Then the actor repository should succeed when upserting over any actor
|
|
|
|
@phase1
|
|
Scenario: ActorRepository upsert updates existing actor values
|
|
Given I have an actor repository with database session
|
|
And I have stored a custom actor named "local/test-actor"
|
|
When I update that actor with new configuration values
|
|
Then the repository should persist the updated actor values
|
|
|
|
@phase1
|
|
Scenario: ActorRepository upsert stores actor correctly (upsert_built_in removed)
|
|
Given I have an actor repository with database session
|
|
When I upsert a built-in actor named "provider/built-in"
|
|
Then the actor should be stored as built-in in the repository
|
|
|
|
@phase1
|
|
Scenario: ActorRepository delete handles missing, default, and custom actors
|
|
Given I have an actor repository with database session
|
|
And I have stored a default actor named "provider/default"
|
|
And I have stored a custom actor named "local/deletable"
|
|
When I delete a non-existent actor named "provider/missing"
|
|
And I attempt to delete the default actor named "provider/default"
|
|
And I delete the custom actor named "local/deletable"
|
|
Then the default actor deletion should raise an error
|
|
And the custom actor should be removed successfully
|
|
|
|
@phase1
|
|
Scenario: ActorRepository set_default raises when actor is missing
|
|
Given I have an actor repository with database session
|
|
When I set the default actor to "provider/missing"
|
|
Then the actor repository should raise when setting default for missing actor
|
|
|
|
@phase1
|
|
Scenario: ActorPreferencesModel get_default_name returns None when no preference is set
|
|
Given I have an actor repository with database session
|
|
When I read the default actor name preference
|
|
Then the default actor name preference should be None
|
|
|
|
@phase1
|
|
Scenario: ActorPreferencesModel set_default_name creates singleton row and returns name
|
|
Given I have an actor repository with database session
|
|
When I set the default actor name preference to "openai/gpt-4o"
|
|
Then the default actor name preference should be "openai/gpt-4o"
|
|
|
|
@phase1
|
|
Scenario: ActorPreferencesModel set_default_name updates existing singleton row
|
|
Given I have an actor repository with database session
|
|
When I set the default actor name preference to "openai/gpt-4o"
|
|
And I set the default actor name preference to "anthropic/claude"
|
|
Then the default actor name preference should be "anthropic/claude"
|
|
|
|
@phase1
|
|
Scenario: ActorPreferencesModel get_default_name falls back to legacy is_default actor row
|
|
Given I have an actor repository with database session
|
|
And I have stored a default actor named "local/legacy-default"
|
|
When I read the default actor name preference
|
|
Then the default actor name preference should be "local/legacy-default"
|