Big-Link-Man/STORY_2.5_IMPLEMENTATION_SU...

143 lines
5.7 KiB
Markdown

# Story 2.5: Deployment Target Assignment - Implementation Summary
## Status
**COMPLETED** - All acceptance criteria met, 100% test coverage
## Overview
Implemented deployment target assignment functionality that allows job configurations to specify which generated tier1 articles should be assigned to specific sites. **Only tier1 articles can be assigned to deployment targets** - tier2/tier3 always get `site_deployment_id = null`. The implementation uses a simple round-robin assignment strategy where the first N tier1 articles are assigned to N deployment targets, and remaining tier1 articles get null assignment.
## Changes Made
### 1. Job Configuration Schema (`src/generation/job_config.py`)
- Added `deployment_targets` field (optional array of strings) to `Job` dataclass
- Added validation to ensure `deployment_targets` is an array of strings
- Job configuration now supports specifying custom hostnames for deployment target assignment
### 2. Deployment Assignment Logic (`src/generation/deployment_assignment.py`) - NEW FILE
Created new module with three core functions:
- `resolve_hostname_to_id()` - Resolves a hostname to its site_deployment_id
- `validate_and_resolve_targets()` - Validates all hostnames at job start (fail-fast approach)
- `assign_site_for_article()` - Implements round-robin assignment logic
### 3. Database Repository Updates (`src/database/repositories.py`)
- Updated `GeneratedContentRepository.create()` to accept optional `site_deployment_id` parameter
- Maintains backward compatibility - parameter defaults to `None`
### 4. Batch Processor Integration (`src/generation/batch_processor.py`)
- Added `site_deployment_repo` parameter to `BatchProcessor.__init__()`
- Validates deployment targets at job start before generating any content
- **Only applies deployment targets to tier1 articles** - tier2/tier3 always get null
- Assigns `site_deployment_id` to each tier1 article based on its index
- Logs assignment decisions at INFO level
- Passes `site_deployment_id` to repository when creating content
### 5. CLI Updates (`src/cli/commands.py`)
- Updated `generate-batch` command to initialize and pass `SiteDeploymentRepository` to `BatchProcessor`
- Fixed merge conflict markers in the file
### 6. Example Job Configuration (`jobs/example_deployment_targets.json`) - NEW FILE
Created example job file demonstrating the `deployment_targets` field with 3 sites and 10 articles.
## Test Coverage
### Unit Tests (`tests/unit/test_deployment_assignment.py`) - NEW FILE
13 unit tests covering:
- Hostname resolution (valid and invalid)
- Target validation (empty lists, valid hostnames, invalid hostnames, type checking)
- Round-robin assignment logic (edge cases, overflow, single target)
- The 10-article, 3-target scenario from the story
### Integration Tests (`tests/integration/test_deployment_target_assignment.py`) - NEW FILE
10 integration tests covering:
- Job config parsing with deployment_targets
- Job config validation (type checking, missing field handling)
- Batch processor validation at job start
- End-to-end assignment logic
- Repository backward compatibility
- **Tier1-only deployment target assignment** (tier2+ always get null)
**Total Test Results: 23/23 tests passing**
## Assignment Logic Example
Job with tier1 (10 articles), tier2 (100 articles), and 3 deployment targets:
**Tier1 articles:**
```
Article 0 → www.domain1.com (site_deployment_id = 5)
Article 1 → www.domain2.com (site_deployment_id = 8)
Article 2 → www.domain3.com (site_deployment_id = 12)
Articles 3-9 → null (no assignment)
```
**Tier2 articles:**
```
All 100 articles → null (tier2+ never get deployment targets)
```
## Usage Example
```json
{
"jobs": [{
"project_id": 2,
"deployment_targets": [
"www.domain1.com",
"www.domain2.com",
"www.domain3.com"
],
"tiers": {
"tier1": {
"count": 10
}
}
}]
}
```
## Error Handling
The implementation provides clear error messages:
1. **Invalid hostnames**: "Deployment targets not found in database: invalid.com. Please ensure these sites exist using 'list-sites' command."
2. **Missing repository**: "deployment_targets specified but SiteDeploymentRepository not provided"
3. **Invalid configuration**: Validates array type and string elements with descriptive errors
## Backward Compatibility
- All changes are backward compatible
- Jobs without `deployment_targets` continue to work as before (all articles get `site_deployment_id = null`)
- Existing tests remain passing
- No database schema changes required (field already existed from Story 2.4)
## Integration with Story 2.4
The implementation correctly integrates with Story 2.4's template selection logic:
- If `site_deployment_id` is set → Story 2.4 uses mapped/random template for that site
- If `site_deployment_id` is null → Story 2.4 uses random template selection
## Acceptance Criteria Verification
✅ Job configuration supports optional `deployment_targets` array of custom_hostnames
✅ Round-robin assignment: articles 0 through N-1 get assigned, N+ get null
✅ Missing `deployment_targets` → all articles get null
`site_deployment_id` stored in GeneratedContent at creation time
✅ Invalid hostnames cause graceful errors with clear messages
✅ Non-existent hostnames cause graceful errors
✅ Validation occurs at job start (fail-fast)
✅ Assignment decisions logged at INFO level
## Files Created
- `src/generation/deployment_assignment.py`
- `tests/unit/test_deployment_assignment.py`
- `tests/integration/test_deployment_target_assignment.py`
- `jobs/example_deployment_targets.json`
## Files Modified
- `src/generation/job_config.py`
- `src/generation/batch_processor.py`
- `src/database/repositories.py`
- `src/cli/commands.py`