validateChunk($chunkId); $this->validateTaxonomyTerm($taxonomyTermId); $this->validateConfidence($confidence); $this->validateSource($source); // Check if mapping already exists if ($this->chunkTaxonomyRepository->exists($chunkId, $taxonomyTermId)) { throw new \InvalidArgumentException( "Mapping already exists for chunk {$chunkId} and term {$taxonomyTermId}" ); } $mapping = new ChunkTaxonomyMapping( chunkId: $chunkId, taxonomyTermId: $taxonomyTermId, confidence: new Confidence($confidence), source: MappingSource::from($source) ); $id = $this->chunkTaxonomyRepository->save($mapping); $this->auditService->logCreate( table: 'chunk_taxonomy', id: $id, data: [ 'chunk_id' => $chunkId, 'taxonomy_term_id' => $taxonomyTermId, 'confidence' => $confidence, 'source' => $source, ], actor: 'system', actorType: $source === 'auto' ? 'pipeline' : 'user' ); return $id; } /** * Batch assign taxonomy terms to chunks. * * @param array $assignments * @return array{success: int, errors: array} */ public function batchAssign(array $assignments): array { $successCount = 0; $errors = []; foreach ($assignments as $index => $assignment) { try { $this->execute( chunkId: $assignment['chunk_id'], taxonomyTermId: $assignment['taxonomy_term_id'], confidence: $assignment['confidence'], source: $assignment['source'] ); $successCount++; } catch (\Exception $e) { $errors[] = "Assignment {$index}: " . $e->getMessage(); } } return [ 'success' => $successCount, 'errors' => $errors, ]; } private function validateChunk(int $chunkId): void { $chunk = $this->chunkRepository->getChunk($chunkId); if ($chunk === null) { throw new \InvalidArgumentException("Chunk {$chunkId} not found"); } } private function validateTaxonomyTerm(int $termId): void { $term = $this->taxonomyRepository->find($termId); if ($term === null) { throw new \InvalidArgumentException("Taxonomy term {$termId} not found"); } } private function validateConfidence(float $confidence): void { if ($confidence < 0.0 || $confidence > 1.0) { throw new \InvalidArgumentException( "Confidence must be between 0.0 and 1.0, got {$confidence}" ); } } private function validateSource(string $source): void { $validSources = ['auto', 'manual']; if (!in_array($source, $validSources, true)) { throw new \InvalidArgumentException( "Invalid source '{$source}'. Must be one of: " . implode(', ', $validSources) ); } } }