Feature: Database repositories coverage round 3
  Targets uncovered lines in repositories.py for:
    - ActionRepository.list_all (lines 1005-1017)
    - NamespacedProjectRepository.get_context_policy all branches (lines 2982-3012)
    - ToolRegistryRepository create IntegrityError UNIQUE (line 3378)
    - ToolRepository.get, get_by_name, remove, update (lines 3690-3717)
    - SessionRepository list_all, delete error, update error (lines 4063-4173)
    - SessionMessageRepository append error, get, count (lines 4227-4298)
    - AutomationProfileRepository._to_domain legacy safety fallback (lines 4509-4514)
    - SkillRepository update return, delete, flattened tool cache (lines 4851-5085)
    - DecisionRepository full CRUD (lines 5153-5519)
    - CheckpointRepository full CRUD (lines 5564-5717)
    - CorrectionAttemptRepository full CRUD + state transitions (lines 5789-6018)

  # -- ActionRepository.list_all --

  Scenario: ActionRepository list_all returns ordered actions
    Given drcov3 an in-memory database with schema
    And drcov3 an ActionRepository instance
    And drcov3 two actions exist in different namespaces
    When drcov3 I call list_all on the action repository
    Then drcov3 it returns actions ordered by namespace then name

  Scenario: ActionRepository list_all raises DatabaseError on failure
    Given drcov3 an in-memory database with schema
    And drcov3 an ActionRepository with a broken session
    When drcov3 I call list_all expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to list all actions"

  # -- NamespacedProjectRepository.get_context_policy --

  Scenario: get_context_policy returns default when project not found
    Given drcov3 an in-memory database with schema
    And drcov3 a NamespacedProjectRepository instance
    When drcov3 I call get_context_policy for "ns/nonexistent"
    Then drcov3 the result is a default ProjectContextPolicy

  Scenario: get_context_policy returns default when context_policy_json is None
    Given drcov3 an in-memory database with schema
    And drcov3 a NamespacedProjectRepository instance
    And drcov3 a project "ns/proj1" exists with null context_policy_json
    When drcov3 I call get_context_policy for "ns/proj1"
    Then drcov3 the result is a default ProjectContextPolicy

  Scenario: get_context_policy returns parsed policy from valid JSON
    Given drcov3 an in-memory database with schema
    And drcov3 a NamespacedProjectRepository instance
    And drcov3 a project "ns/proj2" exists with valid context_policy_json
    When drcov3 I call get_context_policy for "ns/proj2"
    Then drcov3 the result is a valid ProjectContextPolicy

  Scenario: get_context_policy returns default when payload is not a dict
    Given drcov3 an in-memory database with schema
    And drcov3 a NamespacedProjectRepository instance
    And drcov3 a project "ns/proj3" exists with non-dict context_policy_json
    When drcov3 I call get_context_policy for "ns/proj3"
    Then drcov3 the result is a default ProjectContextPolicy

  Scenario: get_context_policy returns default on ValueError/TypeError
    Given drcov3 an in-memory database with schema
    And drcov3 a NamespacedProjectRepository instance
    And drcov3 a project "ns/proj4" exists with corrupt context_policy_json
    When drcov3 I call get_context_policy for "ns/proj4"
    Then drcov3 the result is a default ProjectContextPolicy

  Scenario: get_context_policy raises DatabaseError on DB failure
    Given drcov3 an in-memory database with schema
    And drcov3 a NamespacedProjectRepository with broken session
    When drcov3 I call get_context_policy expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to load project context policy"

  # -- ToolRepository legacy wrapper --

  Scenario: ToolRepository get returns None for missing tool
    Given drcov3 an in-memory database with schema
    And drcov3 a ToolRepository instance
    When drcov3 I call ToolRepository get for "ns/missing-tool"
    Then drcov3 the tool result is None

  Scenario: ToolRepository get_by_name returns None for missing tool
    Given drcov3 an in-memory database with schema
    And drcov3 a ToolRepository instance
    When drcov3 I call ToolRepository get_by_name for "ns/missing-tool"
    Then drcov3 the tool result is None

  Scenario: ToolRepository remove raises ToolNotFoundError
    Given drcov3 an in-memory database with schema
    And drcov3 a ToolRepository instance
    When drcov3 I call ToolRepository remove for "ns/missing-tool"
    Then drcov3 a ToolNotFoundError was raised

  Scenario: ToolRepository update raises ToolNotFoundError for missing tool
    Given drcov3 an in-memory database with schema
    And drcov3 a ToolRepository instance
    When drcov3 I call ToolRepository update with a non-existent tool
    Then drcov3 a ToolNotFoundError was raised

  # -- SessionRepository --

  Scenario: SessionRepository list_all returns sessions
    Given drcov3 an in-memory database with schema
    And drcov3 a SessionRepository instance
    When drcov3 I call session list_all
    Then drcov3 the session list result is a list

  Scenario: SessionRepository delete raises DatabaseError on failure
    Given drcov3 an in-memory database with schema
    And drcov3 a SessionRepository with a broken session for delete
    When drcov3 I call session delete expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to delete session"

  Scenario: SessionRepository update raises DatabaseError on failure
    Given drcov3 an in-memory database with schema
    And drcov3 a SessionRepository with a broken session for update
    When drcov3 I call session update expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to update session"

  # -- SessionMessageRepository --

  Scenario: SessionMessageRepository append raises DatabaseError on failure
    Given drcov3 an in-memory database with schema
    And drcov3 a SessionMessageRepository with a broken session
    When drcov3 I call message append expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to append message"

  Scenario: SessionMessageRepository count_for_session returns zero for empty session
    Given drcov3 an in-memory database with schema
    And drcov3 a SessionMessageRepository instance
    When drcov3 I call count_for_session with a random session id
    Then drcov3 the count result is 0

  # -- AutomationProfileRepository._to_domain legacy safety fallback --

  Scenario: AutomationProfileRepository to_domain uses legacy safety fallback
    Given drcov3 an in-memory database with schema
    And drcov3 an AutomationProfileModel row without safety_json
    When drcov3 I call _to_domain on the row
    Then drcov3 the result has a SafetyProfile from legacy columns

  # -- SkillRepository flattened tools cache --

  Scenario: SkillRepository delete returns True for existing skill
    Given drcov3 an in-memory database with schema
    And drcov3 a SkillRepository instance
    And drcov3 a skill "ns/myskill-del" exists
    When drcov3 I call skill delete for "ns/myskill-del"
    Then drcov3 the skill delete result is True

  Scenario: SkillRepository update_flattened_tools persists cache data
    Given drcov3 an in-memory database with schema
    And drcov3 a SkillRepository instance
    And drcov3 a skill "ns/myskill-flat" exists
    When drcov3 I call update_flattened_tools for "ns/myskill-flat"
    Then drcov3 the flattened tools are stored

  Scenario: SkillRepository get_flattened_tools returns cache data
    Given drcov3 an in-memory database with schema
    And drcov3 a SkillRepository instance
    And drcov3 a skill "ns/myskill-getflat" exists with flattened tools
    When drcov3 I call get_flattened_tools for "ns/myskill-getflat"
    Then drcov3 the cache dict has expected keys

  Scenario: SkillRepository needs_refresh returns True when hash differs
    Given drcov3 an in-memory database with schema
    And drcov3 a SkillRepository instance
    And drcov3 a skill "ns/myskill-refresh" exists with flattening_hash "oldhash"
    When drcov3 I call needs_refresh for "ns/myskill-refresh" with hash "newhash"
    Then drcov3 the needs_refresh result is True

  Scenario: SkillRepository recompute_flattening_hash stores new hash
    Given drcov3 an in-memory database with schema
    And drcov3 a SkillRepository instance
    And drcov3 a skill "ns/myskill-rehash" exists
    When drcov3 I call recompute_flattening_hash for "ns/myskill-rehash"
    Then drcov3 the returned hash is a sha256 hex string

  Scenario: SkillRepository invalidate_cached_summaries nulls cache fields
    Given drcov3 an in-memory database with schema
    And drcov3 a SkillRepository instance
    And drcov3 a skill "ns/myskill-inval" exists with flattened tools
    When drcov3 I call invalidate_cached_summaries for "ns/myskill-inval"
    Then drcov3 the cached fields are None

  # -- DecisionRepository full CRUD --

  Scenario: DecisionRepository create and get round-trip
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    When drcov3 I create a decision
    And drcov3 I get the decision by id
    Then drcov3 the retrieved decision matches the created one

  Scenario: DecisionRepository get_by_plan returns ordered decisions
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 multiple decisions exist for the plan
    When drcov3 I call get_by_plan
    Then drcov3 I get decisions ordered by sequence number

  Scenario: DecisionRepository get_tree returns BFS-ordered tree
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 a decision tree exists
    When drcov3 I call get_tree on the root
    Then drcov3 I get the root and its descendants in BFS order

  Scenario: DecisionRepository get_path_to_root walks up to root
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 a decision tree exists
    When drcov3 I call get_path_to_root on a leaf
    Then drcov3 I get a path from leaf to root

  Scenario: DecisionRepository get_superseded returns superseded decisions
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 a superseded decision exists
    When drcov3 I call get_superseded
    Then drcov3 I get the superseded decisions

  Scenario: DecisionRepository update_superseded_by marks a decision
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 two decisions exist for supersede test
    When drcov3 I call update_superseded_by
    Then drcov3 the decision has superseded_by set

  Scenario: DecisionRepository list_by_type filters by type
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 decisions of different types exist
    When drcov3 I call list_by_type for strategy_choice
    Then drcov3 I only get strategy_choice decisions

  Scenario: DecisionRepository delete removes a decision
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 a single decision exists for delete test
    When drcov3 I delete the decision
    Then drcov3 the delete result is True

  Scenario: DecisionRepository get_max_sequence_number returns max
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 multiple decisions exist for the plan
    When drcov3 I call get_max_sequence_number
    Then drcov3 the max sequence number is correct

  Scenario: DecisionRepository count returns the decision count
    Given drcov3 an in-memory database with schema
    And drcov3 a DecisionRepository instance
    And drcov3 a plan exists for decisions
    And drcov3 multiple decisions exist for the plan
    When drcov3 I call decision count
    Then drcov3 the decision count matches expected

  # -- CheckpointRepository full CRUD --

  Scenario: CheckpointRepository create and get_by_id round-trip
    Given drcov3 an in-memory database with schema
    And drcov3 a CheckpointRepository instance
    And drcov3 a plan exists for checkpoints
    When drcov3 I create a checkpoint
    And drcov3 I get the checkpoint by id
    Then drcov3 the retrieved checkpoint matches

  Scenario: CheckpointRepository list_by_plan returns ordered checkpoints
    Given drcov3 an in-memory database with schema
    And drcov3 a CheckpointRepository instance
    And drcov3 a plan exists for checkpoints
    And drcov3 multiple checkpoints exist for the plan
    When drcov3 I call checkpoint list_by_plan
    Then drcov3 I get checkpoints ordered by creation time

  Scenario: CheckpointRepository delete removes a checkpoint
    Given drcov3 an in-memory database with schema
    And drcov3 a CheckpointRepository instance
    And drcov3 a plan exists for checkpoints
    And drcov3 a checkpoint exists for delete test
    When drcov3 I delete the checkpoint
    Then drcov3 the checkpoint delete result is True

  Scenario: CheckpointRepository prune removes excess checkpoints
    Given drcov3 an in-memory database with schema
    And drcov3 a CheckpointRepository instance
    And drcov3 a plan exists for checkpoints
    And drcov3 five checkpoints exist for prune test
    When drcov3 I call prune with max_checkpoints 3
    Then drcov3 two interior checkpoints are removed

  # -- CorrectionAttemptRepository full CRUD --

  Scenario: CorrectionAttemptRepository create and get round-trip
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository instance
    And drcov3 a plan and decision exist for corrections
    When drcov3 I create a correction attempt
    And drcov3 I get the correction attempt by id
    Then drcov3 the retrieved correction attempt matches

  Scenario: CorrectionAttemptRepository list_by_plan returns records
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository instance
    And drcov3 a plan and decision exist for corrections
    And drcov3 a correction attempt exists for list test
    When drcov3 I call correction list_by_plan
    Then drcov3 the correction list contains the attempt

  Scenario: CorrectionAttemptRepository update_state transitions pending to executing
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository instance
    And drcov3 a plan and decision exist for corrections
    And drcov3 a pending correction attempt exists for state test
    When drcov3 I update correction state to executing
    Then drcov3 the correction state is executing

  Scenario: CorrectionAttemptRepository delete removes a record
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository instance
    And drcov3 a plan and decision exist for corrections
    And drcov3 a correction attempt exists for delete test
    When drcov3 I delete the correction attempt
    Then drcov3 the correction delete result is True

  Scenario: CorrectionAttemptRepository create raises DatabaseError on OperationalError
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository with broken session
    When drcov3 I call correction create expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to create correction attempt"

  Scenario: CorrectionAttemptRepository get raises DatabaseError on OperationalError
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository with broken session for get
    When drcov3 I call correction get expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to get correction attempt"

  Scenario: CorrectionAttemptRepository list_by_plan raises DatabaseError on failure
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository with broken session for list
    When drcov3 I call correction list_by_plan expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to list correction attempts"

  Scenario: CorrectionAttemptRepository delete raises DatabaseError on failure
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository with broken session for delete
    When drcov3 I call correction delete expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to delete correction attempt"

  Scenario: CorrectionAttemptRepository update_state raises DatabaseError on OperationalError
    Given drcov3 an in-memory database with schema
    And drcov3 a CorrectionAttemptRepository with broken session for update_state
    When drcov3 I call correction update_state expecting a DatabaseError
    Then drcov3 a DatabaseError was raised containing "Failed to update correction attempt"
