5.7 KiB
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_targetsfield (optional array of strings) toJobdataclass - Added validation to ensure
deployment_targetsis 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_idvalidate_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 optionalsite_deployment_idparameter - Maintains backward compatibility - parameter defaults to
None
4. Batch Processor Integration (src/generation/batch_processor.py)
- Added
site_deployment_repoparameter toBatchProcessor.__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_idto each tier1 article based on its index - Logs assignment decisions at INFO level
- Passes
site_deployment_idto repository when creating content
5. CLI Updates (src/cli/commands.py)
- Updated
generate-batchcommand to initialize and passSiteDeploymentRepositorytoBatchProcessor - 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
{
"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:
- Invalid hostnames: "Deployment targets not found in database: invalid.com. Please ensure these sites exist using 'list-sites' command."
- Missing repository: "deployment_targets specified but SiteDeploymentRepository not provided"
- Invalid configuration: Validates array type and string elements with descriptive errors
Backward Compatibility
- All changes are backward compatible
- Jobs without
deployment_targetscontinue to work as before (all articles getsite_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_idis set → Story 2.4 uses mapped/random template for that site - If
site_deployment_idis 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.pytests/unit/test_deployment_assignment.pytests/integration/test_deployment_target_assignment.pyjobs/example_deployment_targets.json
Files Modified
src/generation/job_config.pysrc/generation/batch_processor.pysrc/database/repositories.pysrc/cli/commands.py