# Core/services audit plan

## Scope audited
- `app/core/postgres.py`
- `app/services/workflow_persistence_service.py`
- `app/services/operations_case_management_service.py`
- `app/services/company_operational_state_service.py`
- `app/services/project_management_service.py`
- `app/services/workflow_policy_service.py`

## Oversized modules and exact split targets

### 1) `app/core/postgres.py`
Current role mixes too many concerns:
- connection/bootstrap
- project management read queries
- employee work log read/write queries
- dossier review read/write workflow queries
- payload builders
- row normalizers
- small generic JSON coercion helpers

Recommended split:
- `app/core/postgres/client.py`
  - `PostgresClient` connection lifecycle only
  - `is_enabled`, `get_connection`, `_table_exists`
- `app/core/postgres/project_management_repository.py`
  - `fetch_project_management_records`
  - `_normalize_project_management_row`
- `app/core/postgres/employee_worklog_repository.py`
  - `fetch_employee_log_records`
  - `upsert_employee_work_log_session`
  - `append_employee_work_log_action`
  - `get_employee_work_log_session_by_id`
  - `_normalize_employee_log_row`
  - `_normalize_employee_logs`
  - `_employee_pilot_logs_query` should move here or be deleted after confirming dead path
- `app/core/postgres/dossier_review_repository.py`
  - `fetch_dossier_review_sessions`
  - `create_dossier_review_session`
  - `create_dossier_review_finding`
  - `assign_dossier_review_finding`
  - `submit_dossier_review_supplement`
  - `verify_dossier_review_finding`
  - `close_dossier_review_session`
  - `_create_dossier_review_snapshot`
  - `_insert_dossier_review_action`
  - `_refresh_dossier_review_session_aggregates`
  - `_find_session_finding`
  - `_find_finding_assignment`
  - `_find_assignment_submission`
- `app/core/postgres/dossier_review_params.py`
  - `_build_create_session_params`
  - `_build_create_snapshot_params`
  - `_build_create_finding_params`
  - `_build_create_evidence_params`
  - `_build_assign_finding_params`
  - `_build_submit_supplement_params`
  - `_build_verify_finding_params`
  - `_derive_finding_status_from_assignment_status`
- `app/core/postgres/normalizers.py`
  - `_normalize_dossier_review_session_row`
  - `_normalize_dossier_review_findings`
  - `_normalize_dossier_review_evidences`
  - `_normalize_dossier_review_assignments`
  - `_normalize_dossier_review_submissions`
  - `_normalize_dossier_review_snapshots`
  - `_normalize_dossier_review_actions`
  - shared coercers `_ensure_list`, `_ensure_dict`, `_ensure_string_list`
- `app/core/postgres/worklog_params.py`
  - `_build_employee_work_log_session_params`
  - `_build_employee_work_log_action_params`

Risk hotspot:
- single class currently owns every SQL contract, so any refactor can break unrelated routes.
- repeated nested JSON SQL means result shape drift is likely.
- side effects are transaction-heavy and mixed with readback calls.

### 2) `app/services/workflow_persistence_service.py`
Current role mixes:
- orchestration
- policy interpretation
- assignment/submission/verification automation
- next-action projection
- employee log persistence
- retrigger planning
- operational state summary attachment

Recommended split:
- `app/services/workflow_persistence_service.py`
  - keep public façade only:
    - `start_review_run`
    - `build_retrigger_request`
    - `build_retrigger_summary`
- `app/services/workflow_runtime/workflow_run_orchestrator.py`
  - main end-to-end start loop now inside `start_review_run`
- `app/services/workflow_runtime/workflow_employee_log_writer.py`
  - `_persist_employee_logs`
  - `_build_employee_log_session_payload`
  - `_normalize_action_timestamp`
  - `_build_action_external_ref`
  - `_resolve_persona_from_actions`
  - `_normalize_work_log_status`
  - `_normalize_work_log_action_type`
- `app/services/workflow_runtime/workflow_automation_builders.py`
  - `_ensure_assignment`
  - `_build_auto_submission`
  - `_build_auto_verification`
  - `_build_automation_employee_actions`
- `app/services/workflow_runtime/workflow_next_actions.py`
  - `_build_next_actions`
  - `_build_post_close_actions`
  - `_build_escalation_next_actions`
- `app/services/workflow_runtime/workflow_policy_projection.py`
  - `_collect_policy_blocked_reasons`
  - `_build_manual_follow_up_reason`
  - `_find_policy_for_finding`
  - `_build_policy_employee_actions`
  - `_build_policy_summary`
- `app/services/workflow_runtime/workflow_summary_builders.py`
  - `_build_trigger_summary`
  - `_build_operational_state_snapshot`
  - `_infer_assigned_employee_code`
  - `_map_priority`
  - `_merge_string_lists`
  - `_build_review_code`

Dependency hotspot:
- directly couples personas, policy service, postgres persistence, and company operational state.
- one method performs many writes followed by multiple rereads; breakage here cascades into review, operations, and operational twin endpoints.

Side-effect boundary:
- strongest candidate for a transaction boundary abstraction. Everything from review session creation through finding lifecycle automation should be conceptually one workflow run unit, even if current repository commits per method.

### 3) `app/services/operations_case_management_service.py`
Current role mixes:
- session loading/fallback
- case projection
- action queue projection
- blocker projection
- follow-up extraction from metadata/action payloads
- evidence/escalation derivation

Recommended split:
- `app/services/operations_case_management_service.py`
  - keep public API:
    - `list_cases`
    - `list_actions`
    - `list_blockers`
- `app/services/operations_case_management/session_loader.py`
  - `_load_sessions`
- `app/services/operations_case_management/case_mapper.py`
  - `_build_cases_from_session`
  - `_build_evidences`
  - `_build_escalations`
  - `_build_case_id`
  - `_derive_operational_impact`
  - `_derive_confidence_score`
  - `_derive_evidence_strength`
- `app/services/operations_case_management/action_mapper.py`
  - `_build_actions_from_session`
  - `_build_post_completion_actions`
  - `_build_expected_outcome`
  - `_build_success_criteria`
- `app/services/operations_case_management/blocker_mapper.py`
  - `_build_blockers_from_session`
  - `_collect_blocker_reasons`
  - `_collect_post_completion_blockers`
  - `_is_blocking_follow_up`
- `app/services/operations_case_management/follow_up_extractor.py`
  - `_collect_post_close_actions`
  - `_collect_post_verification_actions`
  - `_collect_follow_up_actions`
  - `_build_follow_up_from_action_payload`
  - `_deduplicate_follow_up_items`
  - `_normalize_follow_up_item`
  - `_action_matches_finding`
  - `_coerce_follow_up_items`
- `app/services/operations_case_management/common.py`
  - `_derive_priority`
  - `_merge_metadata`
  - `_ensure_list`
  - `_ensure_dict`
  - `_ensure_string_list`

Risk hotspot:
- duplicates follow-up extraction logic also present in `company_operational_state_service.py`; this is a contract drift risk.

### 4) `app/services/company_operational_state_service.py`
Current role mixes:
- source fan-out
- aggregate summary calculation
- project/risk/blocker/backlog/workforce mappers
- dossier follow-up extraction duplicate logic
- optional top-level payload shaping

Recommended split:
- `app/services/company_operational_state_service.py`
  - keep public `get_company_operational_state`
- `app/services/operational_state/source_collector.py`
  - `_fetch_dossier_reviews`
  - `_build_source_status`
  - `_attach_supported_optional_fields`
- `app/services/operational_state/project_mapper.py`
  - `_build_project_state`
  - `_build_risks`
- `app/services/operational_state/blocker_backlog_mapper.py`
  - `_build_blocked_items`
  - `_build_backlog`
  - `_build_blocked_items_from_review`
  - `_build_backlog_from_review`
  - `_derive_priority`
  - `_is_assignment_open`
- `app/services/operational_state/follow_up_projection.py`
  - `_collect_review_follow_ups`
  - `_normalize_follow_up_item`
  - `_deduplicate_follow_up_items`
  - `_derive_trigger_phase_from_key`
  - `_derive_trigger_phase_from_action_type`
  - `_action_matches_finding`
  - `_coerce_follow_up_items`
  - `_is_blocking_review_follow_up`
- `app/services/operational_state/workforce_mapper.py`
  - `_build_workforce`
- `app/services/operational_state/policy_overview.py`
  - `_build_policy_overview`
- `app/services/operational_state/common.py`
  - `_extract_string_list`
  - `_ensure_list`
  - `_ensure_dict`
  - `_merge_metadata`
  - `_is_high_severity`
  - `_is_open_status`
  - `_is_active_project`

Risk hotspot:
- repeats review-follow-up parsing already implemented elsewhere.
- depends on three other services plus direct postgres read, so it is the highest aggregation fan-in point in services.

### 5) `app/services/project_management_service.py`
Not oversized, but contains two concerns:
- fallback dataset
- postgres-backed service

Recommended split:
- `app/services/project_management_service.py`
  - keep `ProjectManagementService`
- `app/services/project_management_fallback_data.py`
  - `build_fallback_project_management_response`

This should be lowest priority.

### 6) `app/services/workflow_policy_service.py`
Moderate size, but clear internal split points:
- session-level rules
- finding-level rules
- summary generation

Recommended split:
- `app/services/workflow_policy_service.py`
  - keep façade methods
- `app/services/workflow_policy/session_policy.py`
  - `_evaluate_session_policy`
- `app/services/workflow_policy/finding_policy.py`
  - `_evaluate_finding_policy`
- `app/services/workflow_policy/policy_summary.py`
  - `summarize_policy_outcome`

Risk hotspot:
- hardcoded department escalation map and persona escalation use are business-policy contracts; changes here affect automation branching.

## Cross-module dependency hotspots
1. `WorkflowPersistenceService -> PostgresClient`
   - strongest side effects and deepest contract dependency.
2. `WorkflowPersistenceService -> WorkflowPolicyService -> personas`
   - policy decisions alter write path, close behavior, and employee log generation.
3. `CompanyOperationalStateService -> ProjectManagementService + EmployeeLogsService + OperationsCaseManagementService + PostgresClient`
   - broadest aggregation point.
4. `OperationsCaseManagementService` and `CompanyOperationalStateService`
   - duplicate follow-up parsing logic; high risk of divergent results.
5. `PostgresClient` dossier review methods
   - coupled to nested schema payloads used by routes and services.

## Candidate shared helper modules
To reduce duplication after refactor:
- `app/services/shared/follow_up_action_utils.py`
  - coerce/normalize/dedup/action-match helpers used by both operations and operational-state services
- `app/services/shared/priority_utils.py`
  - derive priority from severity/impact/blocking
- `app/services/shared/status_utils.py`
  - open/closed/active/assignment-open status helpers
- `app/core/postgres/json_coercion.py`
  - ensure list/dict/string-list helpers if repository split keeps pure functions

## Prioritized test surfaces

### Priority 1: unit tests
- `tests/unit/services/test_workflow_policy_service.py`
  - session violations, warnings, circuit breaker, escalation, manual review
- `tests/unit/services/test_workflow_persistence_summary_builders.py`
  - `_map_priority`, `_build_review_code`, `_normalize_action_timestamp`, `_normalize_work_log_status`, `_normalize_work_log_action_type`
- `tests/unit/services/test_operations_case_follow_up_extractor.py`
  - metadata/action payload extraction, dedup, blocker detection
- `tests/unit/services/test_company_operational_state_follow_up_projection.py`
  - same contract as operations layer until shared helper exists
- `tests/unit/core/postgres/test_dossier_review_param_builders.py`
  - payload serialization and status derivation
- `tests/unit/core/postgres/test_normalizers.py`
  - nested JSON normalization for dossier review and employee logs

### Priority 2: service-level integration tests with mocked postgres/service dependencies
- `tests/integration/services/test_workflow_persistence_service_run_flow.py`
  - success path: create -> assign -> submit -> verify -> close
  - manual follow-up path when policy blocks
- `tests/integration/services/test_operations_case_management_service.py`
  - case/action/blocker projections from one synthetic session
- `tests/integration/services/test_company_operational_state_service.py`
  - source aggregation, summary counts, optional fields
- `tests/integration/services/test_project_management_service.py`
  - fallback path, postgres success path, empty-postgres fallback
- `tests/integration/services/test_workflow_policy_to_persistence_interop.py`
  - policy outputs drive expected automation_status/manual flags

### Priority 3: repository/DB integration tests
Future pytest + test DB:
- `tests/integration/core/postgres/test_dossier_review_repository.py`
- `tests/integration/core/postgres/test_employee_worklog_repository.py`
- `tests/integration/core/postgres/test_project_management_repository.py`

Focus:
- nested JSON query shape
- aggregate refresh behavior
- transaction/commit expectations
- assignment/submission/verification state transitions

### Current runnable non-pytest verification scripts to keep/add later under `tmp/`
- `tmp/verify_workflow_persistence_end_to_end.py`
- `tmp/verify_operations_case_projection_contract.py`
- `tmp/verify_company_operational_state_aggregation.py`
- `tmp/verify_postgres_dossier_review_roundtrip.py`

## Refactor order recommendation
1. Extract pure helpers first:
   - follow-up helpers
   - priority/status helpers
   - workflow summary/normalization helpers
2. Split `workflow_policy_service.py`
3. Split `operations_case_management_service.py`
4. Split `company_operational_state_service.py` and make it consume shared follow-up helpers
5. Split `postgres.py` repositories/param builders/normalizers
6. Split `workflow_persistence_service.py` last, after repository and helper boundaries are stable

## Main risk notes
- Do not change response shapes while splitting; nested review/session/finding contracts are heavily reused.
- `PostgresClient` currently hides commit semantics inside service call patterns; moving methods across repositories must preserve transaction expectations.
- Follow-up action parsing exists twice with similar but not identical logic; unify carefully with characterization tests first.
- Policy decisions currently depend on persona registry and hardcoded department escalation mapping; preserve exact outputs before “improving” rules.
- `workflow_persistence_service.py` rereads persisted sessions after writes; tests should lock expected reread behavior before introducing transaction batching.