{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/githunt-ai/json-schema/githunt-ai-search-response-schema.json",
  "title": "SearchResponse",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/githunt-ai-openapi.yaml#/components/schemas/SearchResponse",
  "type": "object",
  "properties": {
    "success": {
      "type": "boolean",
      "const": true
    },
    "data": {
      "type": "object",
      "properties": {
        "matchedCount": {
          "type": "integer",
          "description": "Results in this page."
        },
        "totalCount": {
          "type": "integer"
        },
        "offset": {
          "type": "integer",
          "description": "Echoes the applied offset."
        },
        "locationSuggestions": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Similar supported locations (\"City, Country\"), present only when the search returned zero results because the location matched no known city or country."
        },
        "results": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/SearchResult"
          }
        }
      }
    },
    "meta": {
      "type": "object",
      "properties": {
        "requestId": {
          "type": "string"
        },
        "dataSource": {
          "type": "string"
        },
        "quota": {
          "$ref": "#/$defs/Quota"
        },
        "coverage": {
          "type": "object",
          "description": "What the search actually read, so an empty page is never mistaken for an exhaustive absence.",
          "properties": {
            "locations_searched": {
              "type": "integer"
            },
            "locations_dropped": {
              "type": "integer",
              "description": "Locations left unsearched because region expansion exceeded the per-request location cap."
            },
            "partial": {
              "type": "boolean",
              "description": "True when retrieval was bounded (a capped partition, a per-location read cap, a timed-out location read, or a failed pool read)."
            },
            "candidates_fetched": {
              "type": "integer",
              "description": "Pool candidates that passed the request's exclusions across all searched locations, before ranking."
            },
            "candidates_scored": {
              "type": "integer",
              "description": "Candidates handed to the ranker. Scaled with the number of locations under a per-request ceiling and the time budget, so a region search does not split one location's budget across its countries."
            },
            "unlocated_included": {
              "type": "boolean",
              "description": "Present only when the request set `includeUnlocated`. Results may include candidates with no stated location, which are screening leads, not verified geography."
            }
          }
        },
        "skill_recency": {
          "type": "object",
          "description": "Present only when the request carried `skillRecency`. Counts come from every candidate seen in the queried partitions, not from the returned page.",
          "properties": {
            "evaluated": {
              "type": "integer"
            },
            "supported": {
              "type": "integer"
            },
            "unknown": {
              "type": "integer",
              "description": "Candidates whose signals could not answer the filter, because they are missing, failed, expired (older than the 30-day signal refresh window) or partial (the years the answer depends on could not be fetched). Not a negative finding; they are excluded from the scored selection, and queued for enrichment so a later search can judge them on evidence."
            },
            "contradicted": {
              "type": "integer",
              "description": "Candidates the signals positively rule out. A bound that only an unfetched year could have met is `unknown`, not `contradicted`."
            },
            "partial": {
              "type": "boolean",
              "description": "True when retrieval was bounded (a capped partition or a failed pool read), so an empty page is not evidence of absence."
            }
          }
        },
        "exclude_list": {
          "type": "object",
          "description": "Present only when the request carried `excludeList`.",
          "properties": {
            "name": {
              "type": "string"
            },
            "logins": {
              "type": "integer",
              "description": "Logins merged into the exclusion from the list."
            },
            "truncated": {
              "type": "boolean",
              "description": "True when the list exceeded the 5000-login read bound."
            }
          }
        }
      }
    }
  },
  "$defs": {
    "DomainEvidence": {
      "type": "object",
      "description": "Present when `domains` were given, keyed by pack name (e.g. \"payments\").",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "score": {
            "type": "number"
          },
          "tier": {
            "type": "string",
            "enum": [
              "core",
              "adjacent",
              "generic",
              "none"
            ],
            "description": "Strongest vocabulary tier the candidate actually matched. Ranking uses this rather than `score`, because a score sums tiers and so cannot separate several generic words from one core term."
          },
          "summary": {
            "type": "string"
          },
          "core_terms": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    },
    "Evidence": {
      "type": "array",
      "description": "Where each matched skill/keyword was found on the candidate.",
      "items": {
        "type": "object",
        "properties": {
          "keyword": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "repo_name",
              "repo_description",
              "repo_language",
              "bio",
              "company",
              "skill_fallback"
            ]
          },
          "repo": {
            "type": "string",
            "description": "Bare repository name (no owner), present when the match came from a repository. Use `top_repositories` or the evidence report for owner-qualified names."
          },
          "snippet": {
            "type": "string",
            "description": "Short surrounding text for bio/company matches"
          }
        }
      }
    },
    "InferredUtcOffset": {
      "type": [
        "object",
        "null"
      ],
      "description": "UTC offset inferred from the candidate's own commit author timestamps, used when GitHub's `location` field is empty or unresolvable. Null when no signal is available.",
      "properties": {
        "offset": {
          "type": "number"
        },
        "confidence": {
          "type": "string",
          "enum": [
            "none",
            "low",
            "medium",
            "high"
          ]
        },
        "sample_size": {
          "type": "integer",
          "description": "Number of commits the inference was based on"
        },
        "share": {
          "type": "number",
          "description": "Fraction of sampled commits at the dominant offset"
        },
        "latest_commit": {
          "type": "string",
          "format": "date-time"
        }
      }
    },
    "LocationResolution": {
      "type": "object",
      "description": "How the candidate's stated base resolved at the run timestamp. Attached to every result whenever the request carried an exclusion or a `skillRecency` filter. Discovery stays permissive: `ambiguous` and `unresolved` candidates are still returned, and belong in a screening queue rather than a geographically eligible shortlist. Commit timezone is never `resolved` - an author-side commit offset can support discovery but cannot establish a country or a current base, and never excludes a candidate on its own - see `screening_reason`.",
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "resolved",
            "ambiguous",
            "unresolved"
          ]
        },
        "country": {
          "type": [
            "string",
            "null"
          ],
          "description": "Null unless the stated location settles a single country."
        },
        "utc_offset": {
          "type": [
            "object",
            "null"
          ],
          "description": "Offset band in hours at the run timestamp, daylight saving applied. `min` equals `max` when the location pins a single zone.",
          "properties": {
            "min": {
              "type": "number"
            },
            "max": {
              "type": "number"
            }
          }
        },
        "basis": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "stated_location",
            "commit_timezone"
          ]
        },
        "screening_reason": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "inferred_offset_in_excluded_band"
          ],
          "description": "Why this candidate needs a screening question before being counted as geographically eligible. `inferred_offset_in_excluded_band` means the stated location did not resolve and the candidate's commit timezone falls inside the `excludeUtcOffsets` band the request asked to exclude. Such candidates are deliberately returned rather than excluded: a commit offset cannot establish a country or a current base, so it is a question to ask, not an answer. Null when no screening flag applies."
        },
        "observed_at": {
          "type": "string",
          "format": "date-time",
          "description": "The run's frozen evaluation instant."
        }
      }
    },
    "OrgAffinity": {
      "type": "object",
      "description": "Present when `organizations` or `sectors` were given in the request.",
      "properties": {
        "score": {
          "type": "number"
        },
        "matches": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "org": {
                "type": "string"
              },
              "company": {
                "type": "string"
              },
              "sector": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "Quota": {
      "type": "object",
      "properties": {
        "used": {
          "type": "integer"
        },
        "limit": {
          "type": "integer",
          "description": "-1 means unlimited"
        },
        "month": {
          "type": "string"
        },
        "cost": {
          "type": "integer",
          "description": "Credits this request debited (search: 1, get user: 1, evidence report: 3 when a report is returned and 0 while pending, analyze profile: 3, list operations: 0). `used` already reflects this charge."
        },
        "rollover": {
          "type": "integer",
          "description": "Unused credits banked from the previous month and available on top of `limit` this month (`remaining` = limit + rollover - used). Only present on the Team plan, capped at one extra month's allowance (so at most 2x the allowance is usable in a month)."
        }
      }
    },
    "SearchResult": {
      "type": "object",
      "properties": {
        "login": {
          "type": "string"
        },
        "score": {
          "type": "number"
        },
        "profile_score": {
          "type": "number"
        },
        "tech_stack_score": {
          "type": "number"
        },
        "activity_score": {
          "type": "number"
        },
        "github_experience": {
          "type": "number"
        },
        "matching_keywords": {
          "type": "string",
          "description": "Comma-separated list of matched keywords"
        },
        "avatar_url": {
          "type": "string"
        },
        "email": {
          "type": [
            "string",
            "null"
          ]
        },
        "name": {
          "type": [
            "string",
            "null"
          ]
        },
        "company": {
          "type": [
            "string",
            "null"
          ]
        },
        "location": {
          "type": [
            "string",
            "null"
          ]
        },
        "followers": {
          "type": "integer"
        },
        "bio": {
          "type": [
            "string",
            "null"
          ]
        },
        "profile_url": {
          "type": "string"
        },
        "blog": {
          "type": "string"
        },
        "twitter_username": {
          "type": "string"
        },
        "hireable": {
          "type": "string",
          "enum": [
            "Yes",
            "No"
          ]
        },
        "created_at": {
          "type": "string",
          "format": "date-time"
        },
        "updated_at": {
          "type": "string",
          "format": "date-time"
        },
        "last_active_date": {
          "type": [
            "string",
            "null"
          ],
          "description": "Date of the candidate's most recent GitHub activity. Usually a date (YYYY-MM-DD); may be a full ISO date-time when derived from fallback sources."
        },
        "commits_per_month": {
          "type": [
            "number",
            "null"
          ],
          "description": "Average commits per month over recent history"
        },
        "commit_frequency_label": {
          "type": [
            "string",
            "null"
          ],
          "description": "Human label for commit activity (e.g. Very Active, Active, Unknown)"
        },
        "semantic_commit_percentage": {
          "type": [
            "number",
            "null"
          ],
          "description": "Percentage of analyzed commits with semantic/descriptive messages"
        },
        "commit_message_quality_label": {
          "type": [
            "string",
            "null"
          ],
          "description": "Human label for commit message quality (e.g. Excellent, Good, Insufficient Data)"
        },
        "top_repositories": {
          "$ref": "#/$defs/TopRepositories"
        },
        "top_oss_contributions": {
          "$ref": "#/$defs/TopOssContributions"
        },
        "evidence": {
          "$ref": "#/$defs/Evidence"
        },
        "org_affinity": {
          "$ref": "#/$defs/OrgAffinity"
        },
        "domain_evidence": {
          "$ref": "#/$defs/DomainEvidence"
        },
        "inferred_utc_offset": {
          "$ref": "#/$defs/InferredUtcOffset"
        },
        "location_resolution": {
          "$ref": "#/$defs/LocationResolution"
        },
        "rank_breakdown": {
          "type": "object",
          "description": "Present when the request named languages, skills, sectors, organizations or domains. Components in [0,1] of the evidence ranking formula rank = base * (1 + 0.6*recency + 0.4*org + 0.5*domain); unknown evidence scores 0 and never lowers a row.",
          "properties": {
            "base": {
              "type": "number"
            },
            "recency": {
              "type": "number"
            },
            "org": {
              "type": "number"
            },
            "domain": {
              "type": "number"
            },
            "final": {
              "type": "number"
            }
          }
        },
        "score_boosts": {
          "type": "object",
          "description": "Ranking boosts applied on top of the base score (present only when non-zero). `score` stays clamped to 0-100. When the request names languages, skills, sectors, organizations or domains, ordering is not this boosted value: results are ranked by the base score scaled by how recently the requested skills were used and how strongly the candidate matches the requested employers and domains, so a result may sit above one with a higher `score`.",
          "properties": {
            "org_affinity": {
              "type": "number"
            },
            "domain_evidence": {
              "type": "number"
            }
          }
        }
      }
    },
    "TopOssContributions": {
      "type": "array",
      "maxItems": 3,
      "description": "Notable open-source projects the candidate contributed to",
      "items": {
        "type": "object",
        "properties": {
          "repository": {
            "type": "string",
            "description": "Full repository name (owner/name)"
          },
          "tier_label": {
            "type": "string",
            "description": "Project prominence tier (e.g. Elite, Popular, Notable)"
          },
          "commits": {
            "type": "integer"
          },
          "language": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    },
    "TopRepositories": {
      "type": "array",
      "maxItems": 3,
      "description": "The candidate's top repositories, as shown on the website candidate card",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "stars": {
            "type": "integer"
          },
          "language": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    }
  }
}