cyclo 22

quietlight
May 4, 2026, 7:19 PM
T2WZBTVFHVWPKL6AKEWSEVQBR3HWWWUPUNUP2MULF4WXEAZP46KQC

Dependencies

  • [2] LBWQJEDH minor refactor and more tests for utils/
  • [3] GPQSOVBP cyclo complexity over 25
  • [4] KZKLAINJ run out of space on nest, cleaned out

Change contents

  • edit in utils/fs.go at line 22
    [2.3830][2.3830:3876]()
    extTarget := strings.ToLower(opts.Extension)
  • replacement in utils/fs.go at line 24
    [2.3898][2.3898:4025]()
    err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
    if err != nil {
    return err
    }
    [2.3898]
    [2.4025]
    if err := filepath.Walk(rootPath, makeWalkFunc(&results, opts, rootPath)); err != nil {
    return nil, err
    }
    } else {
    if err := scanFlatDir(rootPath, &results, opts); err != nil {
    return nil, err
    }
    }
  • replacement in utils/fs.go at line 33
    [2.4026][2.4026:4049]()
    name := info.Name()
    [2.4026]
    [2.4049]
    sort.Strings(results)
    return results, nil
    }
  • replacement in utils/fs.go at line 37
    [2.4050][2.4050:4239]()
    // Skip hidden files/directories
    if opts.SkipHidden && strings.HasPrefix(name, ".") && path != rootPath {
    if info.IsDir() {
    return filepath.SkipDir
    }
    return nil
    }
    [2.4050]
    [2.4239]
    // makeWalkFunc returns a filepath.WalkFunc that collects matching files.
    func makeWalkFunc(results *[]string, opts FindFilesOptions, rootPath string) filepath.WalkFunc {
    return func(path string, info os.FileInfo, err error) error {
    if err != nil {
    return err
    }
    name := info.Name()
  • replacement in utils/fs.go at line 45
    [2.4240][2.4240:4464]()
    // Check directory skip prefixes
    if info.IsDir() && path != rootPath {
    for _, prefix := range opts.SkipPrefixes {
    if strings.HasPrefix(name, prefix) {
    return filepath.SkipDir
    }
    }
    return nil
    [2.4240]
    [2.4464]
    // Skip hidden files/directories
    if opts.SkipHidden && strings.HasPrefix(name, ".") && path != rootPath {
    if info.IsDir() {
    return filepath.SkipDir
  • edit in utils/fs.go at line 50
    [2.4469]
    [2.4469]
    return nil
    }
  • replacement in utils/fs.go at line 53
    [2.4470][2.4470:4635]()
    // Check file
    if !info.IsDir() {
    if strings.ToLower(filepath.Ext(name)) == extTarget && info.Size() >= opts.MinSize {
    results = append(results, path)
    [2.4470]
    [2.4635]
    // Check directory skip prefixes
    if info.IsDir() && path != rootPath {
    for _, prefix := range opts.SkipPrefixes {
    if strings.HasPrefix(name, prefix) {
    return filepath.SkipDir
  • edit in utils/fs.go at line 60
    [2.4646][2.4646:4647]()
  • edit in utils/fs.go at line 61
    [2.4661][2.4661:4793]()
    })
    if err != nil {
    return nil, err
    }
    } else {
    entries, err := os.ReadDir(rootPath)
    if err != nil {
    return nil, err
  • replacement in utils/fs.go at line 63
    [2.4798][2.4798:4867]()
    for _, entry := range entries {
    if entry.IsDir() {
    continue
    [2.4798]
    [2.4867]
    // Check file
    if !info.IsDir() {
    if fileMatches(name, info, opts) {
    *results = append(*results, path)
  • edit in utils/fs.go at line 68
    [2.4872]
    [2.4872]
    }
  • replacement in utils/fs.go at line 70
    [2.4873][2.4873:4971]()
    name := entry.Name()
    if opts.SkipHidden && strings.HasPrefix(name, ".") {
    continue
    }
    [2.4873]
    [2.4971]
    return nil
    }
    }
  • replacement in utils/fs.go at line 74
    [2.4972][2.4972:5202]()
    if strings.ToLower(filepath.Ext(name)) == extTarget {
    path := filepath.Join(rootPath, name)
    if info, err := os.Stat(path); err == nil && info.Size() >= opts.MinSize {
    results = append(results, path)
    }
    }
    }
    [2.4972]
    [2.5202]
    // fileMatches checks if a file name meets the extension and size criteria.
    func fileMatches(name string, info os.FileInfo, opts FindFilesOptions) bool {
    if !strings.EqualFold(filepath.Ext(name), opts.Extension) {
    return false
    }
    if info.Size() < opts.MinSize {
    return false
  • edit in utils/fs.go at line 82
    [2.5205]
    [2.5205]
    return true
    }
  • replacement in utils/fs.go at line 85
    [2.5206][2.5206:5250]()
    sort.Strings(results)
    return results, nil
    [2.5206]
    [2.5250]
    // scanFlatDir scans a single directory level for matching files.
    func scanFlatDir(rootPath string, results *[]string, opts FindFilesOptions) error {
    entries, err := os.ReadDir(rootPath)
    if err != nil {
    return err
    }
    for _, entry := range entries {
    if entry.IsDir() {
    continue
    }
    name := entry.Name()
    if opts.SkipHidden && strings.HasPrefix(name, ".") {
    continue
    }
    if !strings.EqualFold(filepath.Ext(name), opts.Extension) {
    continue
    }
    path := filepath.Join(rootPath, name)
    if info, err := os.Stat(path); err == nil && info.Size() >= opts.MinSize {
    *results = append(*results, path)
    }
    }
    return nil
  • replacement in tools/sql.go at line 69
    [4.261229][4.261229:261369]()
    // Validate query is not empty
    if strings.TrimSpace(input.Query) == "" {
    return ExecuteSQLOutput{}, fmt.Errorf("query cannot be empty")
    [4.261229]
    [4.261369]
    if err := validateSQLQuery(input.Query, input.Limit); err != nil {
    return ExecuteSQLOutput{}, err
  • replacement in tools/sql.go at line 73
    [4.261373][4.261373:261552]()
    // Validate query starts with SELECT or WITH
    if !selectPattern.MatchString(input.Query) {
    return ExecuteSQLOutput{}, fmt.Errorf("only SELECT and WITH queries are allowed")
    }
    [4.261373]
    [4.261552]
    limit := resolveLimit(input.Limit)
    query, autoAddedLimit := applyLimit(input.Query, limit)
  • replacement in tools/sql.go at line 76
    [4.261553][4.261553:261803]()
    // Check for forbidden keywords (defense in depth - database is already read-only)
    if forbiddenPattern.MatchString(input.Query) {
    return ExecuteSQLOutput{}, fmt.Errorf("query contains forbidden keywords (INSERT/UPDATE/DELETE/DROP/CREATE/ALTER)")
    [4.261553]
    [4.261803]
    database, err := db.OpenReadOnlyDB(dbPath)
    if err != nil {
    return ExecuteSQLOutput{}, fmt.Errorf("database connection failed: %w", err)
  • edit in tools/sql.go at line 80
    [4.261806]
    [4.261806]
    defer database.Close()
  • replacement in tools/sql.go at line 82
    [4.261807][4.261807:262042]()
    // Determine row limit
    limit := defaultLimit
    if input.Limit != nil {
    if *input.Limit < 1 || *input.Limit > maxLimit {
    return ExecuteSQLOutput{}, fmt.Errorf("limit must be between 1 and %d", maxLimit)
    }
    limit = *input.Limit
    [4.261807]
    [4.262042]
    rows, err := executeSQLQuery(ctx, database, query, input.Parameters)
    if err != nil {
    return ExecuteSQLOutput{}, err
  • edit in tools/sql.go at line 86
    [4.262045]
    [4.262045]
    defer rows.Close()
  • replacement in tools/sql.go at line 88
    [4.262046][4.262046:262312]()
    // Add LIMIT clause if not present
    // Query for limit+1 rows to detect truncation
    query := input.Query
    autoAddedLimit := false
    if !limitPattern.MatchString(query) {
    query = fmt.Sprintf("%s LIMIT %d", strings.TrimSpace(query), limit+1)
    autoAddedLimit = true
    [4.262046]
    [4.262312]
    columnInfo, columns, err := buildColumnInfo(rows)
    if err != nil {
    return ExecuteSQLOutput{}, err
  • replacement in tools/sql.go at line 93
    [4.262316][4.262316:262413]()
    // Get database connection (read-only for security)
    database, err := db.OpenReadOnlyDB(dbPath)
    [4.262316]
    [4.262413]
    results, err := scanResultRows(rows, columns)
  • replacement in tools/sql.go at line 95
    [4.262430][4.262430:262509]()
    return ExecuteSQLOutput{}, fmt.Errorf("database connection failed: %w", err)
    [4.262430]
    [4.262509]
    return ExecuteSQLOutput{}, err
  • edit in tools/sql.go at line 97
    [4.262512][4.262512:262562]()
    defer database.Close() // Always close when done
  • replacement in tools/sql.go at line 98
    [4.262563][4.262563:262776]()
    // Execute query with parameters
    var rows *sql.Rows
    if len(input.Parameters) > 0 {
    rows, err = database.QueryContext(ctx, query, input.Parameters...)
    } else {
    rows, err = database.QueryContext(ctx, query)
    [4.262563]
    [4.262776]
    // Handle empty results (return empty array, not error)
    if results == nil {
    results = []map[string]any{}
  • replacement in tools/sql.go at line 102
    [4.262779][4.262779:262871]()
    if err != nil {
    return ExecuteSQLOutput{}, fmt.Errorf("query execution failed: %w", err)
    [4.262779]
    [4.262871]
    // Detect truncation: if we auto-added limit+1 and got more than limit rows
    limited := false
    if autoAddedLimit && len(results) > limit {
    limited = true
    results = results[:limit]
  • replacement in tools/sql.go at line 109
    [4.262874][4.262874:262894]()
    defer rows.Close()
    [4.262874]
    [4.262894]
    queryReported := buildQueryReported(input.Query, autoAddedLimit, limit)
    return ExecuteSQLOutput{
    Rows: results,
    RowCount: len(results),
    Columns: columnInfo,
    Limited: limited,
    Query: queryReported,
    }, nil
    }
  • replacement in tools/sql.go at line 121
    [4.262895][4.262895:262919]()
    // Get column metadata
    [4.262895]
    [4.262919]
    // validateSQLQuery checks the query is a safe SELECT/WITH statement.
    func validateSQLQuery(query string, limit *int) error {
    if strings.TrimSpace(query) == "" {
    return fmt.Errorf("query cannot be empty")
    }
    if !selectPattern.MatchString(query) {
    return fmt.Errorf("only SELECT and WITH queries are allowed")
    }
    if forbiddenPattern.MatchString(query) {
    return fmt.Errorf("query contains forbidden keywords (INSERT/UPDATE/DELETE/DROP/CREATE/ALTER)")
    }
    if limit != nil {
    if *limit < 1 || *limit > maxLimit {
    return fmt.Errorf("limit must be between 1 and %d", maxLimit)
    }
    }
    return nil
    }
    // resolveLimit returns the effective row limit from input or default.
    func resolveLimit(limit *int) int {
    if limit != nil {
    return *limit
    }
    return defaultLimit
    }
    // applyLimit appends a LIMIT clause if not already present.
    // Returns the modified query and whether a limit was auto-added.
    func applyLimit(query string, limit int) (string, bool) {
    if !limitPattern.MatchString(query) {
    return fmt.Sprintf("%s LIMIT %d", strings.TrimSpace(query), limit+1), true
    }
    return query, false
    }
    // executeSQLQuery runs the query and returns the result rows.
    func executeSQLQuery(ctx context.Context, database *sql.DB, query string, params []any) (*sql.Rows, error) {
    if len(params) > 0 {
    return database.QueryContext(ctx, query, params...)
    }
    return database.QueryContext(ctx, query)
    }
    // buildColumnInfo extracts column metadata from the result set.
    func buildColumnInfo(rows *sql.Rows) ([]ColumnInfo, []string, error) {
  • replacement in tools/sql.go at line 169
    [4.262968][4.262968:263042]()
    return ExecuteSQLOutput{}, fmt.Errorf("failed to get columns: %w", err)
    [4.262968]
    [4.263042]
    return nil, nil, fmt.Errorf("failed to get columns: %w", err)
  • edit in tools/sql.go at line 171
    [4.263045][4.263045:263046]()
  • replacement in tools/sql.go at line 173
    [4.263103][4.263103:263182]()
    return ExecuteSQLOutput{}, fmt.Errorf("failed to get column types: %w", err)
    [4.263103]
    [4.263182]
    return nil, nil, fmt.Errorf("failed to get column types: %w", err)
  • edit in tools/sql.go at line 175
    [4.263185][4.263185:263208]()
    // Build column info
  • edit in tools/sql.go at line 182
    [4.263398]
    [4.263398]
    return columnInfo, columns, nil
    }
  • replacement in tools/sql.go at line 185
    [4.263399][4.263399:263416]()
    // Process rows
    [4.263399]
    [4.263416]
    // scanResultRows scans all rows from the result set into maps.
    func scanResultRows(rows *sql.Rows, columns []string) ([]map[string]any, error) {
  • edit in tools/sql.go at line 188
    [4.263446][4.263446:263447]()
  • edit in tools/sql.go at line 189
    [4.263466][4.263466:263506]()
    // Create slice to hold column values
  • edit in tools/sql.go at line 194
    [4.263644][4.263644:263659]()
    // Scan row
  • replacement in tools/sql.go at line 195
    [4.263709][4.263709:263778]()
    return ExecuteSQLOutput{}, fmt.Errorf("row scan failed: %w", err)
    [4.263709]
    [4.263778]
    return nil, fmt.Errorf("row scan failed: %w", err)
  • edit in tools/sql.go at line 197
    [4.263782][4.263782:263824]()
    // Convert to map with type conversion
  • edit in tools/sql.go at line 201
    [4.263934][4.263934:263935]()
  • replacement in tools/sql.go at line 203
    [4.263974][4.263974:264121]()
    // Check for errors during iteration
    if err = rows.Err(); err != nil {
    return ExecuteSQLOutput{}, fmt.Errorf("row iteration failed: %w", err)
    [4.263974]
    [4.264121]
    if err := rows.Err(); err != nil {
    return nil, fmt.Errorf("row iteration failed: %w", err)
  • edit in tools/sql.go at line 206
    [4.264124]
    [4.264124]
    return results, nil
    }
  • replacement in tools/sql.go at line 209
    [4.264125][4.264125:264533]()
    // Handle empty results (return empty array, not error)
    if results == nil {
    results = []map[string]any{}
    }
    // Detect truncation: if we auto-added limit+1 and got more than limit rows
    limited := false
    if autoAddedLimit && len(results) > limit {
    limited = true
    results = results[:limit]
    }
    // Build the query string to report (show effective limit, not internal limit+1)
    queryReported := query
    [4.264125]
    [4.264533]
    // buildQueryReported constructs the query string to report in output.
    func buildQueryReported(originalQuery string, autoAddedLimit bool, limit int) string {
  • replacement in tools/sql.go at line 212
    [4.264554][4.264554:264818]()
    queryReported = fmt.Sprintf("%s LIMIT %d", strings.TrimSpace(input.Query), limit)
    }
    // Create output structure
    output := ExecuteSQLOutput{
    Rows: results,
    RowCount: len(results),
    Columns: columnInfo,
    Limited: limited,
    Query: queryReported,
    [4.264554]
    [4.264818]
    return fmt.Sprintf("%s LIMIT %d", strings.TrimSpace(originalQuery), limit)
  • replacement in tools/sql.go at line 214
    [4.264821][4.264821:264842]()
    return output, nil
    [4.264821]
    [4.264842]
    return originalQuery
  • edit in tools/location.go at line 5
    [4.288327]
    [4.288327]
    "database/sql"
  • edit in tools/location.go at line 68
    [4.290256][4.290256:290372]()
    func createLocation(ctx context.Context, input LocationInput) (LocationOutput, error) {
    var output LocationOutput
  • replacement in tools/location.go at line 69
    [4.290373][4.290373:290413]()
    // Validate required fields for create
    [4.290373]
    [4.290413]
    // validateCreateFields validates required fields for creating a location.
    func validateCreateFields(input LocationInput) error {
  • replacement in tools/location.go at line 72
    [4.290487][4.290487:290566]()
    return output, fmt.Errorf("dataset_id is required when creating a location")
    [4.290487]
    [4.290566]
    return fmt.Errorf("dataset_id is required when creating a location")
  • replacement in tools/location.go at line 75
    [4.290633][4.290633:290706]()
    return output, fmt.Errorf("name is required when creating a location")
    [4.290633]
    [4.290706]
    return fmt.Errorf("name is required when creating a location")
  • replacement in tools/location.go at line 78
    [4.290737][4.290737:290814]()
    return output, fmt.Errorf("latitude is required when creating a location")
    [4.290737]
    [4.290814]
    return fmt.Errorf("latitude is required when creating a location")
  • replacement in tools/location.go at line 81
    [4.290846][4.290846:290924]()
    return output, fmt.Errorf("longitude is required when creating a location")
    [4.290846]
    [4.290924]
    return fmt.Errorf("longitude is required when creating a location")
  • replacement in tools/location.go at line 84
    [4.291003][4.291003:291083]()
    return output, fmt.Errorf("timezone_id is required when creating a location")
    [4.291003]
    [4.291083]
    return fmt.Errorf("timezone_id is required when creating a location")
  • edit in tools/location.go at line 86
    [4.291086][4.291086:291125]()
    // Validate ID format for dataset_id
  • replacement in tools/location.go at line 87
    [4.291204][4.291204:291225]()
    return output, err
    [4.291204]
    [4.291225]
    return err
  • edit in tools/location.go at line 89
    [4.291228]
    [4.291228]
    return validateLocationFields(input)
    }
  • replacement in tools/location.go at line 92
    [4.291229][4.291229:291284]()
    if err := validateLocationFields(input); err != nil {
    [4.291229]
    [4.291284]
    // fetchLocationByID scans a full location row from a query that selects
    // id, dataset_id, name, latitude, longitude, description, created_at, last_modified, active, timezone_id.
    func fetchLocationByID(ctx context.Context, queryer interface {
    QueryRowContext(context.Context, string, ...any) *sql.Row
    }, id string) (db.Location, error) {
    const selectCols = "SELECT id, dataset_id, name, latitude, longitude, description, created_at, last_modified, active, timezone_id FROM location WHERE id = ?"
    var loc db.Location
    err := queryer.QueryRowContext(ctx, selectCols, id).Scan(
    &loc.ID, &loc.DatasetID, &loc.Name, &loc.Latitude, &loc.Longitude,
    &loc.Description, &loc.CreatedAt, &loc.LastModified, &loc.Active, &loc.TimezoneID)
    return loc, err
    }
    func createLocation(ctx context.Context, input LocationInput) (LocationOutput, error) {
    var output LocationOutput
    if err := validateCreateFields(input); err != nil {
  • replacement in tools/location.go at line 130
    [4.291755][4.291755:292249]()
    // Verify dataset exists and is active
    var datasetExists, datasetActive bool
    err = tx.QueryRowContext(ctx,
    "SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?), COALESCE((SELECT active FROM dataset WHERE id = ?), false)",
    *input.DatasetID, *input.DatasetID,
    ).Scan(&datasetExists, &datasetActive)
    if err != nil {
    return output, fmt.Errorf("failed to verify dataset: %w", err)
    }
    if !datasetExists {
    return output, fmt.Errorf("dataset with ID '%s' does not exist", *input.DatasetID)
    [4.291755]
    [4.292249]
    if err := verifyDatasetExistsAndActive(ctx, tx, *input.DatasetID); err != nil {
    return output, err
  • edit in tools/location.go at line 133
    [4.292252][4.292252:292356]()
    if !datasetActive {
    return output, fmt.Errorf("dataset (ID: %s) is not active", *input.DatasetID)
    }
  • replacement in tools/location.go at line 142
    [4.292642][4.292642:293577]()
    // Location with this name already exists in dataset - return existing (consistent duplicate handling)
    var location db.Location
    err = tx.QueryRowContext(ctx,
    "SELECT id, dataset_id, name, latitude, longitude, description, created_at, last_modified, active, timezone_id FROM location WHERE id = ?",
    existingID,
    ).Scan(&location.ID, &location.DatasetID, &location.Name, &location.Latitude, &location.Longitude,
    &location.Description, &location.CreatedAt, &location.LastModified, &location.Active, &location.TimezoneID)
    if err != nil {
    return output, fmt.Errorf("failed to fetch existing location: %w", err)
    }
    if err = tx.Commit(); err != nil {
    return output, fmt.Errorf("failed to commit transaction: %w", err)
    }
    output.Location = location
    output.Message = fmt.Sprintf("Location '%s' already exists in dataset (ID: %s) - returning existing location", location.Name, location.ID)
    return output, nil
    [4.292642]
    [4.293577]
    return returnExistingLocation(ctx, tx, existingID, output)
  • replacement in tools/location.go at line 161
    [4.294201][4.294201:294616]()
    var location db.Location
    err = tx.QueryRowContext(ctx,
    "SELECT id, dataset_id, name, latitude, longitude, description, created_at, last_modified, active, timezone_id FROM location WHERE id = ?",
    id,
    ).Scan(&location.ID, &location.DatasetID, &location.Name, &location.Latitude, &location.Longitude,
    &location.Description, &location.CreatedAt, &location.LastModified, &location.Active, &location.TimezoneID)
    [4.294201]
    [4.294616]
    location, err := fetchLocationByID(ctx, tx, id)
  • edit in tools/location.go at line 173
    [4.295033]
    [4.295033]
    return output, nil
    }
  • edit in tools/location.go at line 176
    [4.295034]
    [4.295034]
    // returnExistingLocation handles the case where a location already exists in the dataset.
    func returnExistingLocation(ctx context.Context, tx *db.LoggedTx, existingID string, output LocationOutput) (LocationOutput, error) {
    location, err := fetchLocationByID(ctx, tx, existingID)
    if err != nil {
    return output, fmt.Errorf("failed to fetch existing location: %w", err)
    }
    if err = tx.Commit(); err != nil {
    return output, fmt.Errorf("failed to commit transaction: %w", err)
    }
    output.Location = location
    output.Message = fmt.Sprintf("Location '%s' already exists in dataset (ID: %s) - returning existing location", location.Name, location.ID)
  • edit in tools/location.go at line 190
    [4.295057]
    [4.295057]
    // verifyDatasetExistsAndActive checks that a dataset exists and is active.
    func verifyDatasetExistsAndActive(ctx context.Context, queryer interface {
    QueryRowContext(context.Context, string, ...any) *sql.Row
    }, datasetID string) error {
    var exists, active bool
    err := queryer.QueryRowContext(ctx,
    "SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?), COALESCE((SELECT active FROM dataset WHERE id = ?), false)",
    datasetID, datasetID,
    ).Scan(&exists, &active)
    if err != nil {
    return fmt.Errorf("failed to verify dataset: %w", err)
    }
    if !exists {
    return fmt.Errorf("dataset with ID '%s' does not exist", datasetID)
    }
    if !active {
    return fmt.Errorf("dataset (ID: %s) is not active", datasetID)
    }
    return nil
    }
  • replacement in tools/location.go at line 236
    [4.295735][4.295735:296416]()
    // Verify location exists and check active status
    var exists, active bool
    var currentDatasetID string
    err = database.QueryRow(
    "SELECT EXISTS(SELECT 1 FROM location WHERE id = ?), COALESCE((SELECT active FROM location WHERE id = ?), false), COALESCE((SELECT dataset_id FROM location WHERE id = ?), '')",
    locationID, locationID, locationID,
    ).Scan(&exists, &active, &currentDatasetID)
    if err != nil {
    return output, fmt.Errorf("failed to query location: %w", err)
    }
    if !exists {
    return output, fmt.Errorf("location not found: %s", locationID)
    }
    if !active {
    return output, fmt.Errorf("location '%s' is not active (cannot update inactive locations)", locationID)
    [4.295735]
    [4.296416]
    if err := verifyLocationExistsAndActive(database, locationID); err != nil {
    return output, err
  • replacement in tools/location.go at line 242
    [4.296524][4.296524:296787]()
    var datasetExists, datasetActive bool
    err = database.QueryRow(
    "SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?), COALESCE((SELECT active FROM dataset WHERE id = ?), false)",
    *input.DatasetID, *input.DatasetID,
    ).Scan(&datasetExists, &datasetActive)
    [4.296524]
    [4.296787]
    if err := verifyDatasetExistsAndActive(context.Background(), database, *input.DatasetID); err != nil {
    return output, err
    }
    }
    updates, args, err := buildLocationUpdates(input, locationID)
    if err != nil {
    return output, err
    }
    query := fmt.Sprintf("UPDATE location SET %s WHERE id = ?", strings.Join(updates, ", "))
    // Begin logged transaction for update
    tx, err := db.BeginLoggedTx(ctx, database, "create_or_update_location")
    if err != nil {
    return output, fmt.Errorf("failed to begin transaction: %w", err)
    }
    defer func() {
  • replacement in tools/location.go at line 260
    [4.296805][4.296805:296870]()
    return output, fmt.Errorf("failed to query dataset: %w", err)
    [4.296805]
    [4.296870]
    tx.Rollback()
  • replacement in tools/location.go at line 262
    [4.296874][4.296874:297075]()
    if !datasetExists {
    return output, fmt.Errorf("dataset not found: %s", *input.DatasetID)
    }
    if !datasetActive {
    return output, fmt.Errorf("dataset '%s' is not active", *input.DatasetID)
    }
    [4.296874]
    [4.297075]
    }()
    _, err = tx.ExecContext(ctx, query, args...)
    if err != nil {
    return output, fmt.Errorf("failed to update location: %w", err)
    }
    // Fetch the updated location
    location, err := fetchLocationByID(ctx, tx, locationID)
    if err != nil {
    return output, fmt.Errorf("failed to fetch updated location: %w", err)
    }
    if err = tx.Commit(); err != nil {
    return output, fmt.Errorf("failed to commit transaction: %w", err)
    }
    output.Location = location
    output.Message = fmt.Sprintf("Successfully updated location '%s' (ID: %s)", location.Name, location.ID)
    return output, nil
    }
    // verifyLocationExistsAndActive checks that a location exists and is active.
    func verifyLocationExistsAndActive(queryer interface {
    QueryRow(string, ...any) *sql.Row
    }, locationID string) error {
    var exists, active bool
    err := queryer.QueryRow(
    "SELECT EXISTS(SELECT 1 FROM location WHERE id = ?), COALESCE((SELECT active FROM location WHERE id = ?), false)",
    locationID, locationID,
    ).Scan(&exists, &active)
    if err != nil {
    return fmt.Errorf("failed to query location: %w", err)
    }
    if !exists {
    return fmt.Errorf("location not found: %s", locationID)
    }
    if !active {
    return fmt.Errorf("location '%s' is not active (cannot update inactive locations)", locationID)
  • edit in tools/location.go at line 302
    [4.297078]
    [4.297078]
    return nil
    }
  • replacement in tools/location.go at line 305
    [4.297079][4.297079:297110]()
    // Build dynamic UPDATE query
    [4.297079]
    [4.297110]
    // buildLocationUpdates builds the dynamic SET clauses and args for an UPDATE.
    func buildLocationUpdates(input LocationInput, locationID string) ([]string, []any, error) {
  • replacement in tools/location.go at line 336
    [4.297871][4.297871:297931]()
    return output, fmt.Errorf("no fields provided to update")
    [4.297871]
    [4.297931]
    return nil, nil, fmt.Errorf("no fields provided to update")
  • edit in tools/location.go at line 339
    [4.297935][4.297935:297967]()
    // Always update last_modified
  • replacement in tools/location.go at line 341
    [4.298052][4.298052:299339]()
    query := fmt.Sprintf("UPDATE location SET %s WHERE id = ?", strings.Join(updates, ", "))
    // Begin logged transaction for update
    tx, err := db.BeginLoggedTx(ctx, database, "create_or_update_location")
    if err != nil {
    return output, fmt.Errorf("failed to begin transaction: %w", err)
    }
    defer func() {
    if err != nil {
    tx.Rollback()
    }
    }()
    _, err = tx.ExecContext(ctx, query, args...)
    if err != nil {
    return output, fmt.Errorf("failed to update location: %w", err)
    }
    // Fetch the updated location
    var location db.Location
    err = tx.QueryRow(
    "SELECT id, dataset_id, name, latitude, longitude, description, created_at, last_modified, active, timezone_id FROM location WHERE id = ?",
    locationID,
    ).Scan(&location.ID, &location.DatasetID, &location.Name, &location.Latitude, &location.Longitude,
    &location.Description, &location.CreatedAt, &location.LastModified, &location.Active, &location.TimezoneID)
    if err != nil {
    return output, fmt.Errorf("failed to fetch updated location: %w", err)
    }
    if err = tx.Commit(); err != nil {
    return output, fmt.Errorf("failed to commit transaction: %w", err)
    }
    output.Location = location
    output.Message = fmt.Sprintf("Successfully updated location '%s' (ID: %s)", location.Name, location.ID)
    return output, nil
    [4.298052]
    [4.299339]
    return updates, args, nil
  • replacement in tools/export.go at line 89
    [4.361152][4.361152:361392]()
    // Verify dataset exists and get name/type
    var datasetName, datasetType string
    err = sourceDB.QueryRowContext(ctx,
    "SELECT name, type FROM dataset WHERE id = ? AND active = true",
    input.DatasetID,
    ).Scan(&datasetName, &datasetType)
    [4.361152]
    [4.361392]
    datasetName, err := verifyExportDataset(ctx, sourceDB, input)
  • replacement in tools/export.go at line 92
    [4.361428][4.361428:361498]()
    return output, fmt.Errorf("dataset not found: %s", input.DatasetID)
    [4.361428]
    [4.361498]
    return output, err
  • replacement in tools/export.go at line 96
    [4.361536][4.361536:361615]()
    // Only structured datasets can be exported
    if datasetType != "structured" {
    [4.361536]
    [4.361615]
    if err := checkOutputFile(input); err != nil {
  • replacement in tools/export.go at line 98
    [4.361634][4.361634:361996]()
    return output, fmt.Errorf("cannot export dataset of type '%s': only structured datasets are supported", datasetType)
    }
    // Check if output file exists
    if !input.DryRun {
    if _, err := os.Stat(input.Output); err == nil && !input.Force {
    sourceDB.Close()
    return output, fmt.Errorf("output file exists: %s (use --force to overwrite)", input.Output)
    }
    [4.361634]
    [4.361996]
    return output, err
  • replacement in tools/export.go at line 101
    [4.362000][4.362000:362069]()
    // Get FK order for tables
    fkOrder, err := db.GetFKOrder(sourceDB)
    [4.362000]
    [4.362069]
    orderedTables, err := getOrderedTableManifest(sourceDB)
  • replacement in tools/export.go at line 104
    [4.362105][4.362105:362175]()
    return output, fmt.Errorf("failed to compute table order: %w", err)
    [4.362105]
    [4.362175]
    return output, err
  • edit in tools/export.go at line 106
    [4.362178][4.362178:362275]()
    // Sort our manifest by FK order
    orderedTables := orderByFKDependency(datasetTables, fkOrder)
  • replacement in tools/export.go at line 107
    [4.362276][4.362276:362598]()
    // Calculate row counts for each table
    for _, tr := range orderedTables {
    count, err := countTableRows(ctx, sourceDB, tr, input.DatasetID)
    if err != nil {
    sourceDB.Close()
    return output, fmt.Errorf("failed to count rows in %s: %w", tr.Table, err)
    }
    if count > 0 {
    output.RowCounts[tr.Table] = count
    }
    [4.362276]
    [4.362598]
    if err := countAllTableRows(ctx, sourceDB, orderedTables, input.DatasetID, &output); err != nil {
    sourceDB.Close()
    return output, err
  • replacement in tools/export.go at line 122
    [4.362887][4.362887:363142]()
    // Create output directory if needed
    outputDir := filepath.Dir(input.Output)
    if outputDir != "" && outputDir != "." {
    if err := os.MkdirAll(outputDir, 0755); err != nil {
    return output, fmt.Errorf("failed to create output directory: %w", err)
    }
    [4.362887]
    [4.363142]
    if err := createOutputDir(input.Output); err != nil {
    return output, err
  • edit in tools/export.go at line 126
    [4.363146][4.363146:363173]()
    // Create output database
  • edit in tools/export.go at line 129
    [4.363316][4.363316:363543]()
    }
    defer outputDB.Close()
    // Attach source database
    _, err = outputDB.ExecContext(ctx, fmt.Sprintf("ATTACH '%s' AS source", dbPath))
    if err != nil {
    return output, fmt.Errorf("failed to attach source database: %w", err)
  • replacement in tools/export.go at line 131
    [4.363547][4.363547:363925]()
    // Copy data in FK order
    for _, tr := range orderedTables {
    if tr.Relation == "copy" {
    // Copy entire table as-is
    err = copyTableAsIs(ctx, outputDB, tr.Table)
    } else {
    // Owned or owned-via: filter by dataset
    err = copyTableData(ctx, outputDB, tr, input.DatasetID)
    }
    if err != nil {
    return output, fmt.Errorf("failed to copy %s: %w", tr.Table, err)
    }
    [4.363547]
    [4.363925]
    if err := copyDataToOutput(ctx, outputDB, orderedTables, input.DatasetID); err != nil {
    return output, err
  • replacement in tools/export.go at line 136
    [4.363947][4.363947:364017]()
    _, err = outputDB.ExecContext(ctx, "DETACH source")
    if err != nil {
    [4.363947]
    [4.364017]
    if _, err := outputDB.ExecContext(ctx, "DETACH source"); err != nil {
  • edit in tools/export.go at line 140
    [4.364094][4.364094:364139]()
    // Close output DB before getting file size
  • edit in tools/export.go at line 141
    [4.364157][4.364157:364173]()
    outputDB = nil
  • edit in tools/export.go at line 163
    [4.364788]
    [4.364788]
    // checkOutputFile returns an error if the output file already exists and force is not set.
    func checkOutputFile(input ExportDatasetInput) error {
    if input.DryRun {
    return nil
    }
    if _, err := os.Stat(input.Output); err == nil && !input.Force {
    return fmt.Errorf("output file exists: %s (use --force to overwrite)", input.Output)
    }
    return nil
    }
    // verifyExportDataset checks the dataset exists, is active, and is structured.
    func verifyExportDataset(ctx context.Context, sourceDB *sql.DB, input ExportDatasetInput) (string, error) {
    var datasetName, datasetType string
    err := sourceDB.QueryRowContext(ctx,
    "SELECT name, type FROM dataset WHERE id = ? AND active = true",
    input.DatasetID,
    ).Scan(&datasetName, &datasetType)
    if err != nil {
    return "", fmt.Errorf("dataset not found: %s", input.DatasetID)
    }
    if datasetType != "structured" {
    return "", fmt.Errorf("cannot export dataset of type '%s': only structured datasets are supported", datasetType)
    }
    return datasetName, nil
    }
    // getOrderedTableManifest returns the dataset tables sorted by FK dependency.
    func getOrderedTableManifest(sourceDB *sql.DB) ([]TableRelationship, error) {
    fkOrder, err := db.GetFKOrder(sourceDB)
    if err != nil {
    return nil, fmt.Errorf("failed to compute table order: %w", err)
    }
    return orderByFKDependency(datasetTables, fkOrder), nil
    }
    // countAllTableRows populates output.RowCounts for all tables in the manifest.
    func countAllTableRows(ctx context.Context, sourceDB *sql.DB, tables []TableRelationship, datasetID string, output *ExportDatasetOutput) error {
    for _, tr := range tables {
    count, err := countTableRows(ctx, sourceDB, tr, datasetID)
    if err != nil {
    return fmt.Errorf("failed to count rows in %s: %w", tr.Table, err)
    }
    if count > 0 {
    output.RowCounts[tr.Table] = count
    }
    }
    return nil
    }
    // createOutputDir creates the output directory if needed.
    func createOutputDir(outputPath string) error {
    outputDir := filepath.Dir(outputPath)
    if outputDir != "" && outputDir != "." {
    if err := os.MkdirAll(outputDir, 0755); err != nil {
    return fmt.Errorf("failed to create output directory: %w", err)
    }
    }
    return nil
    }
    // copyDataToOutput attaches the source DB and copies all tables in FK order.
    func copyDataToOutput(ctx context.Context, outputDB *sql.DB, tables []TableRelationship, datasetID string) error {
    _, err := outputDB.ExecContext(ctx, fmt.Sprintf("ATTACH '%s' AS source", dbPath))
    if err != nil {
    return fmt.Errorf("failed to attach source database: %w", err)
    }
    for _, tr := range tables {
    if tr.Relation == "copy" {
    err = copyTableAsIs(ctx, outputDB, tr.Table)
    } else {
    err = copyTableData(ctx, outputDB, tr, datasetID)
    }
    if err != nil {
    return fmt.Errorf("failed to copy %s: %w", tr.Table, err)
    }
    }
    return nil
    }
  • replacement in tools/calls_detect_anomalies.go at line 124
    [4.536263][4.536263:536803]()
    // Collect ALL labeled segments per model — no scope filtering here.
    // Scope is applied to anchor selection only, so a "Don't Know" label in model[1]
    // against a "Kiwi" anchor in model[0] is correctly surfaced as a label_mismatch.
    modelSegs := make(map[string][]labeledSeg, len(models))
    for _, seg := range df.Segments {
    for _, lbl := range seg.Labels {
    for _, model := range models {
    if lbl.Filter == model {
    modelSegs[model] = append(modelSegs[model], labeledSeg{seg: seg, label: lbl})
    break
    }
    }
    }
    }
    [4.536263]
    [4.536803]
    modelSegs := collectModelSegments(df, models)
  • edit in tools/calls_detect_anomalies.go at line 134
    [4.536964][4.536964:537119]()
    // Use models[0] as anchor. Scope filtering applies here only — other models
    // contribute whatever they actually say for the overlapping time range.
  • replacement in tools/calls_detect_anomalies.go at line 135
    [4.537166][4.537166:537364]()
    if len(scope) > 0 {
    key := anchor.label.Species
    if anchor.label.CallType != "" {
    key += "+" + anchor.label.CallType
    }
    if !scope[key] && !scope[anchor.label.Species] {
    continue
    [4.537166]
    [4.537364]
    if !inScope(anchor, scope) {
    continue
    }
    if matches := findOverlappingMatches(anchor, models, modelSegs); matches == nil {
    continue
    } else {
    group := buildComparisonGroup(anchor, models, matches)
    if a := checkGroupAnomaly(group, path, models); a != nil {
    anomalies = append(anomalies, *a)
  • edit in tools/calls_detect_anomalies.go at line 146
    [4.537373]
    [4.537373]
    }
    return anomalies
    }
  • replacement in tools/calls_detect_anomalies.go at line 150
    [4.537374][4.537374:537689]()
    // Find overlapping segments in every other model.
    matches := make(map[string][]labeledSeg, len(models)-1)
    lonely := false
    for _, model := range models[1:] {
    for _, candidate := range modelSegs[model] {
    if overlaps(anchor.seg, candidate.seg) {
    matches[model] = append(matches[model], candidate)
    [4.537374]
    [4.537689]
    // collectModelSegments groups labeled segments by model filter name.
    func collectModelSegments(df *utils.DataFile, models []string) map[string][]labeledSeg {
    modelSegs := make(map[string][]labeledSeg, len(models))
    for _, seg := range df.Segments {
    for _, lbl := range seg.Labels {
    for _, model := range models {
    if lbl.Filter == model {
    modelSegs[model] = append(modelSegs[model], labeledSeg{seg: seg, label: lbl})
    break
  • edit in tools/calls_detect_anomalies.go at line 161
    [4.537700][4.537700:537766]()
    if len(matches[model]) == 0 {
    lonely = true
    break
    }
  • replacement in tools/calls_detect_anomalies.go at line 162
    [4.537770][4.537770:537800]()
    if lonely {
    continue
    }
    [4.537770]
    [4.537800]
    }
    return modelSegs
    }
  • replacement in tools/calls_detect_anomalies.go at line 166
    [4.537801][4.537801:538041]()
    // Build comparison group: anchor + first overlapping match per other model
    // (consistent with propagate's approach).
    group := []labeledSeg{anchor}
    for _, model := range models[1:] {
    group = append(group, matches[model][0])
    }
    [4.537801]
    [4.538041]
    // inScope returns true if the anchor's label is within the species scope filter.
    func inScope(anchor labeledSeg, scope map[string]bool) bool {
    if len(scope) == 0 {
    return true
    }
    key := anchor.label.Species
    if anchor.label.CallType != "" {
    key += "+" + anchor.label.CallType
    }
    return scope[key] || scope[anchor.label.Species]
    }
  • replacement in tools/calls_detect_anomalies.go at line 178
    [4.538042][4.538042:538323]()
    // Check species+calltype agreement.
    refSpecies := group[0].label.Species
    refCallType := group[0].label.CallType
    labelMatch := true
    for _, ls := range group[1:] {
    if ls.label.Species != refSpecies || ls.label.CallType != refCallType {
    labelMatch = false
    break
    [4.538042]
    [4.538323]
    // findOverlappingMatches returns matches[model] = overlapping segments from that model,
    // or nil if any model has no overlap (lonely anchor).
    func findOverlappingMatches(anchor labeledSeg, models []string, modelSegs map[string][]labeledSeg) map[string][]labeledSeg {
    matches := make(map[string][]labeledSeg, len(models)-1)
    for _, model := range models[1:] {
    for _, candidate := range modelSegs[model] {
    if overlaps(anchor.seg, candidate.seg) {
    matches[model] = append(matches[model], candidate)
  • edit in tools/calls_detect_anomalies.go at line 188
    [4.538332]
    [4.538332]
    if len(matches[model]) == 0 {
    return nil
    }
    }
    return matches
    }
  • replacement in tools/calls_detect_anomalies.go at line 195
    [4.538333][4.538333:538489]()
    if !labelMatch {
    anomalies = append(anomalies, Anomaly{File: path, Type: "label_mismatch", Segments: buildAnomalySegs(group, models)})
    continue
    }
    [4.538333]
    [4.538489]
    // buildComparisonGroup assembles anchor + first match per other model.
    func buildComparisonGroup(anchor labeledSeg, models []string, matches map[string][]labeledSeg) []labeledSeg {
    group := []labeledSeg{anchor}
    for _, model := range models[1:] {
    group = append(group, matches[model][0])
    }
    return group
    }
  • replacement in tools/calls_detect_anomalies.go at line 204
    [4.538490][4.538490:538789]()
    // Labels agree — check certainty.
    refCertainty := group[0].label.Certainty
    for _, ls := range group[1:] {
    if ls.label.Certainty != refCertainty {
    anomalies = append(anomalies, Anomaly{File: path, Type: "certainty_mismatch", Segments: buildAnomalySegs(group, models)})
    break
    }
    [4.538490]
    [4.538789]
    // checkGroupAnomaly checks a comparison group for label or certainty mismatches.
    func checkGroupAnomaly(group []labeledSeg, path string, models []string) *Anomaly {
    refSpecies := group[0].label.Species
    refCallType := group[0].label.CallType
    for _, ls := range group[1:] {
    if ls.label.Species != refSpecies || ls.label.CallType != refCallType {
    a := Anomaly{File: path, Type: "label_mismatch", Segments: buildAnomalySegs(group, models)}
    return &a
  • replacement in tools/calls_detect_anomalies.go at line 214
    [4.538796][4.538796:538815]()
    return anomalies
    [4.538796]
    [4.538815]
    refCertainty := group[0].label.Certainty
    for _, ls := range group[1:] {
    if ls.label.Certainty != refCertainty {
    a := Anomaly{File: path, Type: "certainty_mismatch", Segments: buildAnomalySegs(group, models)}
    return &a
    }
    }
    return nil
  • edit in tools/calls_clip_labels.go at line 87
    [4.552934]
    [3.20047]
  • edit in tools/calls_clip_labels.go at line 262
    [4.557611]
    [4.557611]
    }
    segs := resolveSegments(df.Segments, input.Filter, input.MinLabelOverlap, mapping, classIdx, out)
    rel, err := computeWavRelPath(path, cwd, folderAbs)
    if err != nil {
    return nil, err
  • edit in tools/calls_clip_labels.go at line 270
    [4.557614]
    [4.557614]
    return labelClipWindows(windows, segs, rel, classes, input.MinLabelOverlap, out), nil
    }
  • replacement in tools/calls_clip_labels.go at line 274
    [4.557615][4.557615:557928]()
    // Resolve segments against the mapping. Skip:
    // - filter mismatch (when --filter set)
    // - annotation duration < min_label_overlap
    // - species not in mapping
    segs := make([]resolvedSeg, 0, len(df.Segments))
    for _, seg := range df.Segments {
    if seg.EndTime-seg.StartTime < input.MinLabelOverlap {
    [4.557615]
    [4.557928]
    // resolveSegments maps segments to their classification and filters out mismatches.
    func resolveSegments(
    segments []*utils.Segment,
    filter string,
    minLabelOverlap float64,
    mapping utils.MappingFile,
    classIdx map[string]int,
    out *CallsClipLabelsOutput,
    ) []resolvedSeg {
    segs := make([]resolvedSeg, 0, len(segments))
    for _, seg := range segments {
    if seg.EndTime-seg.StartTime < minLabelOverlap {
  • replacement in tools/calls_clip_labels.go at line 289
    [4.557979][4.557979:558036]()
    if input.Filter != "" && lbl.Filter != input.Filter {
    [4.557979]
    [4.558036]
    if filter != "" && lbl.Filter != filter {
  • replacement in tools/calls_clip_labels.go at line 299
    [4.558205][4.558205:558306]()
    segs = append(segs, resolvedSeg{
    start: seg.StartTime, end: seg.EndTime, kind: kind,
    })
    [4.558205]
    [4.558306]
    segs = append(segs, resolvedSeg{start: seg.StartTime, end: seg.EndTime, kind: kind})
  • replacement in tools/calls_clip_labels.go at line 301
    [4.558332][4.558332:558433]()
    segs = append(segs, resolvedSeg{
    start: seg.StartTime, end: seg.EndTime, kind: kind,
    })
    [4.558332]
    [4.558433]
    segs = append(segs, resolvedSeg{start: seg.StartTime, end: seg.EndTime, kind: kind})
  • replacement in tools/calls_clip_labels.go at line 307
    [4.558534][4.558534:558650]()
    segs = append(segs, resolvedSeg{
    start: seg.StartTime, end: seg.EndTime, kind: kind, classIdx: idx,
    })
    [4.558534]
    [4.558650]
    segs = append(segs, resolvedSeg{start: seg.StartTime, end: seg.EndTime, kind: kind, classIdx: idx})
  • edit in tools/calls_clip_labels.go at line 311
    [4.558662]
    [4.558662]
    return segs
    }
  • replacement in tools/calls_clip_labels.go at line 314
    [4.558663][4.558663:558768]()
    // Compute relative path for the WAV file.
    wavName := strings.TrimSuffix(filepath.Base(path), ".data")
    [4.558663]
    [4.558768]
    // computeWavRelPath computes the relative path from cwd to the WAV file corresponding to a .data file.
    func computeWavRelPath(dataPath, cwd, folderAbs string) (string, error) {
    wavName := strings.TrimSuffix(filepath.Base(dataPath), ".data")
  • edit in tools/calls_clip_labels.go at line 326
    [4.559111]
    [4.559111]
    return rel, nil
    }
  • replacement in tools/calls_clip_labels.go at line 329
    [4.559112][4.559112:559140]()
    // Label each clip window.
    [4.559112]
    [4.559140]
    // labelClipWindows classifies each clip window and builds the output rows.
    func labelClipWindows(windows []utils.ClipWindow, segs []resolvedSeg, rel string, classes []string, minLabelOverlap float64, out *CallsClipLabelsOutput) []clipLabelsRow {
  • replacement in tools/calls_clip_labels.go at line 333
    [4.559195][4.559195:559276]()
    dispo, classHits := classifyClip(w, segs, input.MinLabelOverlap, len(classes))
    [4.559195]
    [4.559276]
    dispo, classHits := classifyClip(w, segs, minLabelOverlap, len(classes))
  • edit in tools/calls_clip_labels.go at line 350
    [4.559525][4.559525:559589]()
    // flags stay all-False — __NEGATIVE__ overrides positives
  • replacement in tools/calls_clip_labels.go at line 362
    [4.559813][4.559813:559832]()
    return rows, nil
    [4.559813]
    [4.559832]
    return rows