Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/rescue-retriever/llms.txt

Use this file to discover all available pages before exploring further.

The scoring algorithm assigns each animal a score from 0–100 for every rescue program. The formula weights breed most heavily because it correlates most strongly with the physical traits and behavioral drives required for search-and-rescue work. Sex and age are weighted equally as secondary criteria. Every animal in the dataset receives a score — no animal is excluded from ranking — but only animals that satisfy all three criteria simultaneously are considered strict qualifiers.

Score Formula

The full scoring implementation lives in lib/filterUtils.js. The three functions below handle normalization, breed matching, and final score computation:
filterUtils.js
// Normalize breed string for matching
function normalizeBreed(breed) {
  return breed
    .toLowerCase()
    .replace(/\bmixed?\b/g, "")
    .replace(/\bdog\b/g, "")
    .replace(/[^a-z0-9]+/g, " ")
    .replace(/\s+/g, " ")
    .trim();
}

// Check if animal breed matches any profile breed
function breedMatches(animalBreed, profileBreeds) {
  const normalized = normalizeBreed(animalBreed);
  return profileBreeds.some(pb => {
    const n = normalizeBreed(pb);
    return normalized.includes(n) || n.includes(normalized);
  });
}

// Score an animal against a single program profile
function scoreAnimal(animal, profile) {
  const age = Math.round(animal.ageWeeks);
  const breedMatch = breedMatches(animal.breed, profile.breeds);
  const sexMatch = animal.sex === profile.sex;
  const ageMatch = age >= profile.minAgeWeeks && age <= profile.maxAgeWeeks;
  const matchScore = Math.min(100,
    (breedMatch ? 50 : 12) +
    (sexMatch   ? 25 :  5) +
    (ageMatch   ? 25 :  5)
  );
  return {
    programId: profile.id,
    matchScore,
    breedMatch,
    sexMatch,
    ageMatch,
    qualifies: breedMatch && sexMatch && ageMatch,
    rationale: [
      breedMatch
        ? `Breed matches the ${profile.shortName} profile.`
        : `Breed is outside the preferred ${profile.shortName} list.`,
      sexMatch
        ? `Sex matches the preferred ${profile.sex} criterion.`
        : `Sex differs from the preferred ${profile.sex} criterion.`,
      ageMatch
        ? `Age is within the ${profile.minAgeWeeks}${profile.maxAgeWeeks} week range.`
        : `Age is outside the ${profile.minAgeWeeks}${profile.maxAgeWeeks} week range.`
    ]
  };
}
scoreAnimal returns a plain object — no side effects, no DOM interaction. The same function is called for every animal–program pair in the application.

Point Breakdown

Each of the three criteria contributes points whether it matches or not. A non-matching criterion still contributes a small baseline score rather than zero, which preserves meaningful ranking between animals that miss on different criteria.
CriterionMatchNo Match
Breed5012
Sex255
Age255
Total range22–100
The formula is capped at 100 with Math.min(100, ...), though the maximum achievable sum is exactly 100 (50 + 25 + 25), so the cap has no practical effect on real scores.

All Possible Score Values

Because each criterion has exactly two point values, there are eight possible score combinations:
BreedSexAgeScoreNotes
✅ Match✅ Match✅ Match100Strict qualifier
✅ Match✅ Match❌ No match80Right breed and sex, outside age window
✅ Match❌ No match✅ Match80Right breed and age, wrong sex
✅ Match❌ No match❌ No match60Breed only
❌ No match✅ Match✅ Match62Sex and age only
❌ No match✅ Match❌ No match42Sex only
❌ No match❌ No match✅ Match42Age only
❌ No match❌ No match❌ No match22No criteria met
A score of 62 (sex + age, no breed) ranks higher than 60 (breed only, no sex or age). This reflects the design intent: two secondary criteria together carry slightly more weight than the primary criterion alone.

Strict Qualification

The qualifies flag is computed as:
qualifies: breedMatch && sexMatch && ageMatch
Only animals with qualifies: true — always score 100 — are displayed in strict candidate lists on the Reports page and surfaced with program badges in the Dashboard. However, all animals receive a score for every program and are ranked accordingly in the full Dashboard view. The rationale array on the score object provides three human-readable explanation strings — one per criterion — describing the match or mismatch in plain language. These strings are displayed verbatim in the Candidate Detail view.

Multi-Program Scoring

Every animal is scored against all three programs simultaneously using scoreAllPrograms:
filterUtils.js
function scoreAllPrograms(animal) {
  return rescueProfiles.map(profile => scoreAnimal(animal, profile))
    .sort((a, b) => b.matchScore - a.matchScore);
}
getBestScore(animal) returns the single highest-scoring program result for that animal. This best score is used whenever the Dashboard is set to “All Animals” mode. To find all programs an animal strictly qualifies for, getQualifyingPrograms(animal) filters the scored results to those with breedMatch && sexMatch && ageMatch and returns their program IDs:
filterUtils.js
function getQualifyingPrograms(animal) {
  return scoreAllPrograms(animal)
    .filter(s => s.breedMatch && s.sexMatch && s.ageMatch)
    .map(s => s.programId);
}

Sorting Behavior

Sorting logic is handled by two functions in lib/filterUtils.js: sortByProgram(animals, programId) — Used when a specific program filter is active:
  • Sort primary: that program’s matchScore descending
  • Sort secondary: ageWeeks ascending (younger animals rank higher among ties)
getStrictCandidates(animals, programId) — Used for the Reports page:
  • Filter: keep only animals where getQualifyingPrograms includes the given program ID
  • Sort primary: that program’s matchScore descending
  • Sort secondary: ageWeeks ascending
“All Animals” mode — When no specific program is selected:
  • Sort primary: getBestScore(animal).matchScore descending
  • Sort secondary: ageWeeks ascending
The age tiebreaker ensures that among animals with identical scores, younger candidates appear first — a practical preference since younger animals typically have longer potential training careers.
Breed matching is a normalized substring check, not an exact match. An animal recorded as "German Shepherd Mix" will match the "German Shepherd" profile breed because the normalized form of the animal breed ("german shepherd") contains the normalized profile breed ("german shepherd"). See the Data Model for the full normalization algorithm.

Data Model

Animal record fields and RescueProfile schema

Filter Utilities

Full API reference for filterUtils.js

Programs Overview

Water, Mountain, and Disaster program details

Build docs developers (and LLMs) love