diff --git a/internal/service/auto_config.go b/internal/service/auto_config.go index ae31894..548f437 100644 --- a/internal/service/auto_config.go +++ b/internal/service/auto_config.go @@ -401,8 +401,15 @@ func (s *AutoConfigService) BuildPipeline(req AutoConfigRequest, deploy bool) (* // ---- 4. Create recognition units for each video source ---- editor.Instances = editor.Instances[:0] // clear previous instances on re-deploy + usedNames := map[string]bool{} for _, srcName := range cleanSources { unitName := deriveSafeInstanceName(srcName) + // Ensure unique instance name in case different source names derive to the same unitName + baseName := unitName + for i := 1; usedNames[unitName]; i++ { + unitName = fmt.Sprintf("%s-%d", baseName, i) + } + usedNames[unitName] = true inst := ConfigProfileInstanceEditor{ Name: unitName, Template: templateName, diff --git a/internal/service/config_assets.go b/internal/service/config_assets.go index a26df11..b3d3960 100644 --- a/internal/service/config_assets.go +++ b/internal/service/config_assets.go @@ -1230,13 +1230,13 @@ func (s *ConfigPreviewService) SaveDeviceAssignment(asset DeviceAssignmentAsset) for _, ref := range asset.RecognitionUnits { profileName, _, err := parseRecognitionUnitRef(ref) if err != nil { - continue + return err } if profileName != asset.ProfileName { - continue + return fmt.Errorf("all recognition units must belong to scene template %q", asset.ProfileName) } if _, ok := seen[ref]; ok { - continue // skip duplicates + return fmt.Errorf("duplicate recognition unit: %s", ref) } seen[ref] = struct{}{} deduped = append(deduped, ref) diff --git a/safesightd-linux-arm64 b/safesightd-linux-arm64 index 323136f..0eb0212 100644 Binary files a/safesightd-linux-arm64 and b/safesightd-linux-arm64 differ