Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/platform/database/dbgen/candidates.sql.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 |
| Branch | ws9-bench-ingestion |
| Path or archive member | internal/platform/database/dbgen/candidates.sql.go |
| Original SHA-256 | cd8a4e6c1288eca0a0ebf2c5fb3fb09999287efc98b1338ad9ea2aa3c7a04275 |
| Git blob SHA | 596cb996b1ea0b334c9982fae04b6b7b1bd216b0 |
| Reading-copy SHA-256 | cd8a4e6c1288eca0a0ebf2c5fb3fb09999287efc98b1338ad9ea2aa3c7a04275 |
Recovered source transcript
Download complete source text ↓944 lines · 35.4 KB
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: candidates.sql
package dbgen
import (
"context"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
pgvector "github.com/pgvector/pgvector-go"
)
const addCandidateCertification = `-- name: AddCandidateCertification :exec
INSERT INTO candidate_certifications (organization_id, candidate_id, name)
VALUES ($1,$2,$3)
ON CONFLICT (candidate_id, name) DO NOTHING
`
type AddCandidateCertificationParams struct {
OrganizationID uuid.UUID `json:"organization_id"`
CandidateID uuid.UUID `json:"candidate_id"`
Name string `json:"name"`
}
func (q *Queries) AddCandidateCertification(ctx context.Context, arg AddCandidateCertificationParams) error {
_, err := q.db.Exec(ctx, addCandidateCertification, arg.OrganizationID, arg.CandidateID, arg.Name)
return err
}
const addCandidateCustomerExperience = `-- name: AddCandidateCustomerExperience :exec
INSERT INTO candidate_customer_experience (organization_id, candidate_id, agency)
VALUES ($1,$2,$3)
ON CONFLICT (candidate_id, agency) DO NOTHING
`
type AddCandidateCustomerExperienceParams struct {
OrganizationID uuid.UUID `json:"organization_id"`
CandidateID uuid.UUID `json:"candidate_id"`
Agency string `json:"agency"`
}
func (q *Queries) AddCandidateCustomerExperience(ctx context.Context, arg AddCandidateCustomerExperienceParams) error {
_, err := q.db.Exec(ctx, addCandidateCustomerExperience, arg.OrganizationID, arg.CandidateID, arg.Agency)
return err
}
const addCandidateSkill = `-- name: AddCandidateSkill :exec
INSERT INTO candidate_skills (organization_id, candidate_id, skill_id)
VALUES ($1,$2,$3)
ON CONFLICT (candidate_id, skill_id) DO NOTHING
`
type AddCandidateSkillParams struct {
OrganizationID uuid.UUID `json:"organization_id"`
CandidateID uuid.UUID `json:"candidate_id"`
SkillID uuid.UUID `json:"skill_id"`
}
func (q *Queries) AddCandidateSkill(ctx context.Context, arg AddCandidateSkillParams) error {
_, err := q.db.Exec(ctx, addCandidateSkill, arg.OrganizationID, arg.CandidateID, arg.SkillID)
return err
}
const anonymizeCandidate = `-- name: AnonymizeCandidate :execrows
UPDATE candidates SET
full_name = '[erased]',
email = NULL,
headline = NULL,
location = NULL,
resume_embedding = NULL,
external_id = NULL,
available = false,
anonymized_at = now(),
updated_at = now()
WHERE id = $1 AND anonymized_at IS NULL
`
// Right to erasure as anonymize in place: wipe the identifying PII while KEEPING the row so the de
// identified scored outcomes (slate_members) and the demographic bucket survive for the adverse impact
// record. Once the name, email, contact, and resume vector are gone the row is no longer personal data,
// so erasure is satisfied and the compliance history is preserved. Idempotent on anonymized_at.
func (q *Queries) AnonymizeCandidate(ctx context.Context, id uuid.UUID) (int64, error) {
result, err := q.db.Exec(ctx, anonymizeCandidate, id)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const countCandidateMissionTags = `-- name: CountCandidateMissionTags :one
SELECT count(*) FROM candidate_mission_tags
`
// A tiny RLS scoped probe: how many candidate_mission_tags rows exist for the caller's tenant. The WS7
// retrieval branch uses it to decide between the structured tagged query (when the tenant has been backfilled
// by the tagging pass) and the WS6 text filter fallback (when it has not), so a not yet tagged tenant keeps
// exact WS6 behavior. RLS scopes the count to the caller's org, so it never observes another tenant's tags.
func (q *Queries) CountCandidateMissionTags(ctx context.Context) (int64, error) {
row := q.db.QueryRow(ctx, countCandidateMissionTags)
var count int64
err := row.Scan(&count)
return count, err
}
const createCandidate = `-- name: CreateCandidate :one
INSERT INTO candidates (
organization_id, full_name, email, headline,
clearance_level, clearance_poly, clearance_status,
years_experience, location, remote, relocatable, available, resume_embedding
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
RETURNING id, organization_id, full_name, email, headline, clearance_level, clearance_poly, clearance_status, clearance_granted_at, clearance_expires_at, reinvestigation_due_at, years_experience, location, remote, relocatable, available, resume_embedding, search_tsv, created_at, updated_at, deleted_at, source, external_id, anonymized_at, clearance_provenance, clearance_verified_at, clearance_compartments
`
type CreateCandidateParams struct {
OrganizationID uuid.UUID `json:"organization_id"`
FullName string `json:"full_name"`
Email *string `json:"email"`
Headline *string `json:"headline"`
ClearanceLevel string `json:"clearance_level"`
ClearancePoly string `json:"clearance_poly"`
ClearanceStatus string `json:"clearance_status"`
YearsExperience int32 `json:"years_experience"`
Location *string `json:"location"`
Remote bool `json:"remote"`
Relocatable bool `json:"relocatable"`
Available bool `json:"available"`
ResumeEmbedding *pgvector.Vector `json:"resume_embedding"`
}
func (q *Queries) CreateCandidate(ctx context.Context, arg CreateCandidateParams) (Candidate, error) {
row := q.db.QueryRow(ctx, createCandidate,
arg.OrganizationID,
arg.FullName,
arg.Email,
arg.Headline,
arg.ClearanceLevel,
arg.ClearancePoly,
arg.ClearanceStatus,
arg.YearsExperience,
arg.Location,
arg.Remote,
arg.Relocatable,
arg.Available,
arg.ResumeEmbedding,
)
var i Candidate
err := row.Scan(
&i.ID,
&i.OrganizationID,
&i.FullName,
&i.Email,
&i.Headline,
&i.ClearanceLevel,
&i.ClearancePoly,
&i.ClearanceStatus,
&i.ClearanceGrantedAt,
&i.ClearanceExpiresAt,
&i.ReinvestigationDueAt,
&i.YearsExperience,
&i.Location,
&i.Remote,
&i.Relocatable,
&i.Available,
&i.ResumeEmbedding,
&i.SearchTsv,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Source,
&i.ExternalID,
&i.AnonymizedAt,
&i.ClearanceProvenance,
&i.ClearanceVerifiedAt,
&i.ClearanceCompartments,
)
return i, err
}
const findCandidateByEmail = `-- name: FindCandidateByEmail :one
SELECT id FROM candidates
WHERE organization_id = $1 AND deleted_at IS NULL AND email IS NOT NULL AND lower(email) = lower($2)
ORDER BY created_at LIMIT 1
`
type FindCandidateByEmailParams struct {
OrganizationID uuid.UUID `json:"organization_id"`
Lower string `json:"lower"`
}
// Identity resolution blocking key 1: an exact (case insensitive) email match in the same org. Email is
// the strongest identity signal, so a sourced lead with a known email merges into the existing person.
func (q *Queries) FindCandidateByEmail(ctx context.Context, arg FindCandidateByEmailParams) (uuid.UUID, error) {
row := q.db.QueryRow(ctx, findCandidateByEmail, arg.OrganizationID, arg.Lower)
var id uuid.UUID
err := row.Scan(&id)
return id, err
}
const findCandidateByNameLocation = `-- name: FindCandidateByNameLocation :one
SELECT id FROM candidates
WHERE organization_id = $1 AND deleted_at IS NULL
AND lower(full_name) = lower($2) AND lower(COALESCE(location, '')) = lower($3)
ORDER BY created_at LIMIT 1
`
type FindCandidateByNameLocationParams struct {
OrganizationID uuid.UUID `json:"organization_id"`
Lower string `json:"lower"`
Lower_2 string `json:"lower_2"`
}
// Identity resolution blocking key 2: same normalized full name AND same normalized location in the org.
// Name alone is too weak (two John Smiths); name plus location is a defensible second signal. The caller
// only invokes this with a non empty location.
func (q *Queries) FindCandidateByNameLocation(ctx context.Context, arg FindCandidateByNameLocationParams) (uuid.UUID, error) {
row := q.db.QueryRow(ctx, findCandidateByNameLocation, arg.OrganizationID, arg.Lower, arg.Lower_2)
var id uuid.UUID
err := row.Scan(&id)
return id, err
}
const getCandidate = `-- name: GetCandidate :one
SELECT id, organization_id, full_name, email, headline, clearance_level, clearance_poly, clearance_status, clearance_granted_at, clearance_expires_at, reinvestigation_due_at, years_experience, location, remote, relocatable, available, resume_embedding, search_tsv, created_at, updated_at, deleted_at, source, external_id, anonymized_at, clearance_provenance, clearance_verified_at, clearance_compartments FROM candidates WHERE id = $1 AND deleted_at IS NULL
`
func (q *Queries) GetCandidate(ctx context.Context, id uuid.UUID) (Candidate, error) {
row := q.db.QueryRow(ctx, getCandidate, id)
var i Candidate
err := row.Scan(
&i.ID,
&i.OrganizationID,
&i.FullName,
&i.Email,
&i.Headline,
&i.ClearanceLevel,
&i.ClearancePoly,
&i.ClearanceStatus,
&i.ClearanceGrantedAt,
&i.ClearanceExpiresAt,
&i.ReinvestigationDueAt,
&i.YearsExperience,
&i.Location,
&i.Remote,
&i.Relocatable,
&i.Available,
&i.ResumeEmbedding,
&i.SearchTsv,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Source,
&i.ExternalID,
&i.AnonymizedAt,
&i.ClearanceProvenance,
&i.ClearanceVerifiedAt,
&i.ClearanceCompartments,
)
return i, err
}
const linkSourcedCandidate = `-- name: LinkSourcedCandidate :exec
UPDATE candidates SET
external_id = COALESCE(external_id, $2),
headline = COALESCE(headline, $3),
years_experience = GREATEST(years_experience, $4),
updated_at = now()
WHERE id = $1
`
type LinkSourcedCandidateParams struct {
ID uuid.UUID `json:"id"`
ExternalID *string `json:"external_id"`
Headline *string `json:"headline"`
YearsExperience int32 `json:"years_experience"`
}
// Identity resolution merge: link a sourced lead to an existing candidate. Sets the external id and
// backfills headline and years ONLY where the existing row is empty or lower, never clobbering curated
// bench data. Source is intentionally left unchanged so a verified bench person stays a bench person.
func (q *Queries) LinkSourcedCandidate(ctx context.Context, arg LinkSourcedCandidateParams) error {
_, err := q.db.Exec(ctx, linkSourcedCandidate,
arg.ID,
arg.ExternalID,
arg.Headline,
arg.YearsExperience,
)
return err
}
const listCandidateCertifications = `-- name: ListCandidateCertifications :many
SELECT name FROM candidate_certifications WHERE candidate_id = $1 ORDER BY name
`
func (q *Queries) ListCandidateCertifications(ctx context.Context, candidateID uuid.UUID) ([]string, error) {
rows, err := q.db.Query(ctx, listCandidateCertifications, candidateID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []string{}
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return nil, err
}
items = append(items, name)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listCandidateCustomerExperience = `-- name: ListCandidateCustomerExperience :many
SELECT agency FROM candidate_customer_experience WHERE candidate_id = $1 ORDER BY agency
`
func (q *Queries) ListCandidateCustomerExperience(ctx context.Context, candidateID uuid.UUID) ([]string, error) {
rows, err := q.db.Query(ctx, listCandidateCustomerExperience, candidateID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []string{}
for rows.Next() {
var agency string
if err := rows.Scan(&agency); err != nil {
return nil, err
}
items = append(items, agency)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listCandidateSkills = `-- name: ListCandidateSkills :many
SELECT s.id, s.name
FROM candidate_skills cs
JOIN skills s ON s.id = cs.skill_id
WHERE cs.candidate_id = $1
ORDER BY s.name
`
type ListCandidateSkillsRow struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
}
func (q *Queries) ListCandidateSkills(ctx context.Context, candidateID uuid.UUID) ([]ListCandidateSkillsRow, error) {
rows, err := q.db.Query(ctx, listCandidateSkills, candidateID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListCandidateSkillsRow{}
for rows.Next() {
var i ListCandidateSkillsRow
if err := rows.Scan(&i.ID, &i.Name); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listCandidates = `-- name: ListCandidates :many
SELECT id, organization_id, full_name, email, headline, clearance_level, clearance_poly, clearance_status, clearance_granted_at, clearance_expires_at, reinvestigation_due_at, years_experience, location, remote, relocatable, available, resume_embedding, search_tsv, created_at, updated_at, deleted_at, source, external_id, anonymized_at, clearance_provenance, clearance_verified_at, clearance_compartments FROM candidates
WHERE deleted_at IS NULL
ORDER BY created_at DESC, id DESC
LIMIT $1 OFFSET $2
`
type ListCandidatesParams struct {
Limit int32 `json:"limit"`
Offset int32 `json:"offset"`
}
// id is a unique trailing sort key so created_at ties give a total order and stable LIMIT/OFFSET paging.
func (q *Queries) ListCandidates(ctx context.Context, arg ListCandidatesParams) ([]Candidate, error) {
rows, err := q.db.Query(ctx, listCandidates, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Candidate{}
for rows.Next() {
var i Candidate
if err := rows.Scan(
&i.ID,
&i.OrganizationID,
&i.FullName,
&i.Email,
&i.Headline,
&i.ClearanceLevel,
&i.ClearancePoly,
&i.ClearanceStatus,
&i.ClearanceGrantedAt,
&i.ClearanceExpiresAt,
&i.ReinvestigationDueAt,
&i.YearsExperience,
&i.Location,
&i.Remote,
&i.Relocatable,
&i.Available,
&i.ResumeEmbedding,
&i.SearchTsv,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Source,
&i.ExternalID,
&i.AnonymizedAt,
&i.ClearanceProvenance,
&i.ClearanceVerifiedAt,
&i.ClearanceCompartments,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listCandidatesForIntel = `-- name: ListCandidatesForIntel :many
SELECT id, organization_id, full_name, email, headline, clearance_level, clearance_poly, clearance_status, clearance_granted_at, clearance_expires_at, reinvestigation_due_at, years_experience, location, remote, relocatable, available, resume_embedding, search_tsv, created_at, updated_at, deleted_at, source, external_id, anonymized_at, clearance_provenance, clearance_verified_at, clearance_compartments FROM candidates
WHERE deleted_at IS NULL
ORDER BY available DESC, updated_at DESC, created_at DESC, id
LIMIT $1
`
// Available (staffable) candidates first, most recently updated next, so the workforce intelligence
// surface leads with the talent you can deploy and newly staffed or sourced people are always scored.
// The trailing id makes the order total, so the same set is selected before the LIMIT cut every run.
func (q *Queries) ListCandidatesForIntel(ctx context.Context, limit int32) ([]Candidate, error) {
rows, err := q.db.Query(ctx, listCandidatesForIntel, limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Candidate{}
for rows.Next() {
var i Candidate
if err := rows.Scan(
&i.ID,
&i.OrganizationID,
&i.FullName,
&i.Email,
&i.Headline,
&i.ClearanceLevel,
&i.ClearancePoly,
&i.ClearanceStatus,
&i.ClearanceGrantedAt,
&i.ClearanceExpiresAt,
&i.ReinvestigationDueAt,
&i.YearsExperience,
&i.Location,
&i.Remote,
&i.Relocatable,
&i.Available,
&i.ResumeEmbedding,
&i.SearchTsv,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Source,
&i.ExternalID,
&i.AnonymizedAt,
&i.ClearanceProvenance,
&i.ClearanceVerifiedAt,
&i.ClearanceCompartments,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const searchCandidatesHybrid = `-- name: SearchCandidatesHybrid :many
WITH vec_raw AS MATERIALIZED (
SELECT id, (resume_embedding <=> $1::vector) AS distance
FROM candidates
WHERE deleted_at IS NULL AND resume_embedding IS NOT NULL
ORDER BY resume_embedding <=> $1::vector, id
LIMIT $2
),
vec AS (
SELECT id, ROW_NUMBER() OVER (ORDER BY distance, id) AS rnk
FROM vec_raw
),
fts AS (
SELECT id, ROW_NUMBER() OVER (
ORDER BY ts_rank(search_tsv, websearch_to_tsquery('english', $3)) DESC, id
) AS rnk
FROM candidates
WHERE deleted_at IS NULL AND search_tsv @@ websearch_to_tsquery('english', $3)
ORDER BY ts_rank(search_tsv, websearch_to_tsquery('english', $3)) DESC, id
LIMIT $2
)
SELECT c.id, c.organization_id, c.full_name, c.email, c.headline, c.clearance_level, c.clearance_poly, c.clearance_status, c.clearance_granted_at, c.clearance_expires_at, c.reinvestigation_due_at, c.years_experience, c.location, c.remote, c.relocatable, c.available, c.resume_embedding, c.search_tsv, c.created_at, c.updated_at, c.deleted_at, c.source, c.external_id, c.anonymized_at, c.clearance_provenance, c.clearance_verified_at, c.clearance_compartments,
(COALESCE(1.0/(60+vec.rnk), 0) + COALESCE(1.0/(60+fts.rnk), 0))::float8 AS rrf_score
FROM candidates c
LEFT JOIN vec ON vec.id = c.id
LEFT JOIN fts ON fts.id = c.id
WHERE (vec.id IS NOT NULL OR fts.id IS NOT NULL) AND c.deleted_at IS NULL
ORDER BY rrf_score DESC, c.created_at DESC, c.id
LIMIT $2
`
type SearchCandidatesHybridParams struct {
Column1 pgvector.Vector `json:"column_1"`
Limit int32 `json:"limit"`
WebsearchToTsquery string `json:"websearch_to_tsquery"`
}
type SearchCandidatesHybridRow struct {
ID uuid.UUID `json:"id"`
OrganizationID uuid.UUID `json:"organization_id"`
FullName string `json:"full_name"`
Email *string `json:"email"`
Headline *string `json:"headline"`
ClearanceLevel string `json:"clearance_level"`
ClearancePoly string `json:"clearance_poly"`
ClearanceStatus string `json:"clearance_status"`
ClearanceGrantedAt pgtype.Date `json:"clearance_granted_at"`
ClearanceExpiresAt pgtype.Date `json:"clearance_expires_at"`
ReinvestigationDueAt pgtype.Date `json:"reinvestigation_due_at"`
YearsExperience int32 `json:"years_experience"`
Location *string `json:"location"`
Remote bool `json:"remote"`
Relocatable bool `json:"relocatable"`
Available bool `json:"available"`
ResumeEmbedding *pgvector.Vector `json:"resume_embedding"`
SearchTsv interface{} `json:"search_tsv"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at"`
Source string `json:"source"`
ExternalID *string `json:"external_id"`
AnonymizedAt *time.Time `json:"anonymized_at"`
ClearanceProvenance string `json:"clearance_provenance"`
ClearanceVerifiedAt *time.Time `json:"clearance_verified_at"`
ClearanceCompartments []string `json:"clearance_compartments"`
RrfScore float64 `json:"rrf_score"`
}
// Hybrid retrieval: pgvector cosine kNN fused with full-text rank via Reciprocal Rank Fusion (k=60).
// RLS already scopes both legs to the caller's org. $1=query embedding, $2=limit, $3=text query.
// The vector arm is MATERIALIZED so the relaxed_order HNSW output is re-sorted by TRUE cosine distance
// before it is ranked: under hnsw.iterative_scan = relaxed_order the index returns rows slightly out of
// distance order, and ranking them without the re-sort would mis-rank the nearest neighbors at scale
// (pgvector 0.8 README; AWS pgvector 0.8 Aurora guidance). Every ORDER BY carries a unique tiebreaker
// (id) so results are byte-stable for fixed inputs, the AEDT reproducibility mandate. The caller SETs
// LOCAL hnsw.ef_search and hnsw.iterative_scan first.
func (q *Queries) SearchCandidatesHybrid(ctx context.Context, arg SearchCandidatesHybridParams) ([]SearchCandidatesHybridRow, error) {
rows, err := q.db.Query(ctx, searchCandidatesHybrid, arg.Column1, arg.Limit, arg.WebsearchToTsquery)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchCandidatesHybridRow{}
for rows.Next() {
var i SearchCandidatesHybridRow
if err := rows.Scan(
&i.ID,
&i.OrganizationID,
&i.FullName,
&i.Email,
&i.Headline,
&i.ClearanceLevel,
&i.ClearancePoly,
&i.ClearanceStatus,
&i.ClearanceGrantedAt,
&i.ClearanceExpiresAt,
&i.ReinvestigationDueAt,
&i.YearsExperience,
&i.Location,
&i.Remote,
&i.Relocatable,
&i.Available,
&i.ResumeEmbedding,
&i.SearchTsv,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Source,
&i.ExternalID,
&i.AnonymizedAt,
&i.ClearanceProvenance,
&i.ClearanceVerifiedAt,
&i.ClearanceCompartments,
&i.RrfScore,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const searchCandidatesHybridMission = `-- name: SearchCandidatesHybridMission :many
WITH vec_raw AS MATERIALIZED (
SELECT id, (resume_embedding <=> $2::vector) AS distance
FROM candidates
WHERE deleted_at IS NULL AND resume_embedding IS NOT NULL
AND search_tsv @@ websearch_to_tsquery('english', $3)
ORDER BY resume_embedding <=> $2::vector, id
LIMIT $1
),
vec AS (
SELECT id, ROW_NUMBER() OVER (ORDER BY distance, id) AS rnk
FROM vec_raw
),
fts AS (
SELECT id, ROW_NUMBER() OVER (
ORDER BY ts_rank(search_tsv, websearch_to_tsquery('english', $4)) DESC, id
) AS rnk
FROM candidates
WHERE deleted_at IS NULL
AND search_tsv @@ websearch_to_tsquery('english', $4)
AND search_tsv @@ websearch_to_tsquery('english', $3)
ORDER BY ts_rank(search_tsv, websearch_to_tsquery('english', $4)) DESC, id
LIMIT $1
)
SELECT c.id, c.organization_id, c.full_name, c.email, c.headline, c.clearance_level, c.clearance_poly, c.clearance_status, c.clearance_granted_at, c.clearance_expires_at, c.reinvestigation_due_at, c.years_experience, c.location, c.remote, c.relocatable, c.available, c.resume_embedding, c.search_tsv, c.created_at, c.updated_at, c.deleted_at, c.source, c.external_id, c.anonymized_at, c.clearance_provenance, c.clearance_verified_at, c.clearance_compartments,
(COALESCE(1.0/(60+vec.rnk), 0) + COALESCE(1.0/(60+fts.rnk), 0))::float8 AS rrf_score
FROM candidates c
LEFT JOIN vec ON vec.id = c.id
LEFT JOIN fts ON fts.id = c.id
WHERE (vec.id IS NOT NULL OR fts.id IS NOT NULL) AND c.deleted_at IS NULL
ORDER BY rrf_score DESC, c.created_at DESC, c.id
LIMIT $1
`
type SearchCandidatesHybridMissionParams struct {
RowLimit int32 `json:"row_limit"`
QueryVector pgvector.Vector `json:"query_vector"`
MissionQuery string `json:"mission_query"`
TextQuery string `json:"text_query"`
}
type SearchCandidatesHybridMissionRow struct {
ID uuid.UUID `json:"id"`
OrganizationID uuid.UUID `json:"organization_id"`
FullName string `json:"full_name"`
Email *string `json:"email"`
Headline *string `json:"headline"`
ClearanceLevel string `json:"clearance_level"`
ClearancePoly string `json:"clearance_poly"`
ClearanceStatus string `json:"clearance_status"`
ClearanceGrantedAt pgtype.Date `json:"clearance_granted_at"`
ClearanceExpiresAt pgtype.Date `json:"clearance_expires_at"`
ReinvestigationDueAt pgtype.Date `json:"reinvestigation_due_at"`
YearsExperience int32 `json:"years_experience"`
Location *string `json:"location"`
Remote bool `json:"remote"`
Relocatable bool `json:"relocatable"`
Available bool `json:"available"`
ResumeEmbedding *pgvector.Vector `json:"resume_embedding"`
SearchTsv interface{} `json:"search_tsv"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at"`
Source string `json:"source"`
ExternalID *string `json:"external_id"`
AnonymizedAt *time.Time `json:"anonymized_at"`
ClearanceProvenance string `json:"clearance_provenance"`
ClearanceVerifiedAt *time.Time `json:"clearance_verified_at"`
ClearanceCompartments []string `json:"clearance_compartments"`
RrfScore float64 `json:"rrf_score"`
}
// Mission scoped hybrid retrieval (WS6 Option A): identical to SearchCandidatesHybrid, but BOTH arms are
// additionally constrained to candidates whose search_tsv matches the mission keyword(s) in mission_query,
// so a question can be scoped to a mission area (for example SIGINT) using only candidate text match. The
// search_tsv is built from full_name, headline, and location (migration 0002), NOT the resume body. This is
// the only mission filter available without structured mission tags: those are WS7 work. It filters on that
// TEXT, never on a semantic mission alignment, and that limit is documented in docs/AI_RESEARCH.md.
// RLS still scopes both legs to the caller's org; every ORDER BY keeps the unique id tiebreaker so the
// output is byte stable for fixed inputs, the AEDT reproducibility mandate. The caller SETs LOCAL
// hnsw.ef_search and hnsw.iterative_scan first, exactly as for the unscoped query.
func (q *Queries) SearchCandidatesHybridMission(ctx context.Context, arg SearchCandidatesHybridMissionParams) ([]SearchCandidatesHybridMissionRow, error) {
rows, err := q.db.Query(ctx, searchCandidatesHybridMission,
arg.RowLimit,
arg.QueryVector,
arg.MissionQuery,
arg.TextQuery,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchCandidatesHybridMissionRow{}
for rows.Next() {
var i SearchCandidatesHybridMissionRow
if err := rows.Scan(
&i.ID,
&i.OrganizationID,
&i.FullName,
&i.Email,
&i.Headline,
&i.ClearanceLevel,
&i.ClearancePoly,
&i.ClearanceStatus,
&i.ClearanceGrantedAt,
&i.ClearanceExpiresAt,
&i.ReinvestigationDueAt,
&i.YearsExperience,
&i.Location,
&i.Remote,
&i.Relocatable,
&i.Available,
&i.ResumeEmbedding,
&i.SearchTsv,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Source,
&i.ExternalID,
&i.AnonymizedAt,
&i.ClearanceProvenance,
&i.ClearanceVerifiedAt,
&i.ClearanceCompartments,
&i.RrfScore,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const searchCandidatesHybridMissionTagged = `-- name: SearchCandidatesHybridMissionTagged :many
WITH vec_raw AS MATERIALIZED (
SELECT id, (resume_embedding <=> $2::vector) AS distance
FROM candidates
WHERE deleted_at IS NULL AND resume_embedding IS NOT NULL
AND EXISTS (SELECT 1 FROM candidate_mission_tags t
WHERE t.candidate_id = candidates.id AND t.mission_code = $3)
ORDER BY resume_embedding <=> $2::vector, id
LIMIT $1
),
vec AS (
SELECT id, ROW_NUMBER() OVER (ORDER BY distance, id) AS rnk
FROM vec_raw
),
fts AS (
SELECT id, ROW_NUMBER() OVER (
ORDER BY ts_rank(search_tsv, websearch_to_tsquery('english', $4)) DESC, id
) AS rnk
FROM candidates
WHERE deleted_at IS NULL
AND search_tsv @@ websearch_to_tsquery('english', $4)
AND EXISTS (SELECT 1 FROM candidate_mission_tags t
WHERE t.candidate_id = candidates.id AND t.mission_code = $3)
ORDER BY ts_rank(search_tsv, websearch_to_tsquery('english', $4)) DESC, id
LIMIT $1
)
SELECT c.id, c.organization_id, c.full_name, c.email, c.headline, c.clearance_level, c.clearance_poly, c.clearance_status, c.clearance_granted_at, c.clearance_expires_at, c.reinvestigation_due_at, c.years_experience, c.location, c.remote, c.relocatable, c.available, c.resume_embedding, c.search_tsv, c.created_at, c.updated_at, c.deleted_at, c.source, c.external_id, c.anonymized_at, c.clearance_provenance, c.clearance_verified_at, c.clearance_compartments,
(COALESCE(1.0/(60+vec.rnk), 0) + COALESCE(1.0/(60+fts.rnk), 0))::float8 AS rrf_score
FROM candidates c
LEFT JOIN vec ON vec.id = c.id
LEFT JOIN fts ON fts.id = c.id
WHERE (vec.id IS NOT NULL OR fts.id IS NOT NULL) AND c.deleted_at IS NULL
ORDER BY rrf_score DESC, c.created_at DESC, c.id
LIMIT $1
`
type SearchCandidatesHybridMissionTaggedParams struct {
RowLimit int32 `json:"row_limit"`
QueryVector pgvector.Vector `json:"query_vector"`
MissionCode string `json:"mission_code"`
TextQuery string `json:"text_query"`
}
type SearchCandidatesHybridMissionTaggedRow struct {
ID uuid.UUID `json:"id"`
OrganizationID uuid.UUID `json:"organization_id"`
FullName string `json:"full_name"`
Email *string `json:"email"`
Headline *string `json:"headline"`
ClearanceLevel string `json:"clearance_level"`
ClearancePoly string `json:"clearance_poly"`
ClearanceStatus string `json:"clearance_status"`
ClearanceGrantedAt pgtype.Date `json:"clearance_granted_at"`
ClearanceExpiresAt pgtype.Date `json:"clearance_expires_at"`
ReinvestigationDueAt pgtype.Date `json:"reinvestigation_due_at"`
YearsExperience int32 `json:"years_experience"`
Location *string `json:"location"`
Remote bool `json:"remote"`
Relocatable bool `json:"relocatable"`
Available bool `json:"available"`
ResumeEmbedding *pgvector.Vector `json:"resume_embedding"`
SearchTsv interface{} `json:"search_tsv"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at"`
Source string `json:"source"`
ExternalID *string `json:"external_id"`
AnonymizedAt *time.Time `json:"anonymized_at"`
ClearanceProvenance string `json:"clearance_provenance"`
ClearanceVerifiedAt *time.Time `json:"clearance_verified_at"`
ClearanceCompartments []string `json:"clearance_compartments"`
RrfScore float64 `json:"rrf_score"`
}
// Structured mission scoped hybrid retrieval (WS7 upgrade of the WS6 Option A text filter). It is identical
// in shape to SearchCandidatesHybridMission, but the mission constraint on BOTH arms is a STRUCTURED
// predicate on candidate_mission_tags (the deterministic classifier output) instead of the search_tsv
// mission keyword text match. A candidate is in scope only when a candidate_mission_tags row binds it to the
// requested mission_code, so the scope is the real, classified mission of the candidate, not a name or
// headline string coincidence. This lifts the WS6 limit (a candidate whose mission is in the resume body but
// not in the full_name, headline, or location text is now reachable once the tenant is tagged). The text
// query ($text_query) still drives the FTS arm and the embedding arm still drives recall, so only the mission
// gate changed. candidate_mission_tags is RLS scoped to the caller's org, so the EXISTS subquery cannot cross
// a tenant boundary; the candidates table is RLS scoped too. Every ORDER BY keeps the unique id tiebreaker so
// the output is byte stable for fixed inputs, the AEDT reproducibility mandate. The caller SETs LOCAL
// hnsw.ef_search and hnsw.iterative_scan first, exactly as for the unscoped and the WS6 text scoped queries.
func (q *Queries) SearchCandidatesHybridMissionTagged(ctx context.Context, arg SearchCandidatesHybridMissionTaggedParams) ([]SearchCandidatesHybridMissionTaggedRow, error) {
rows, err := q.db.Query(ctx, searchCandidatesHybridMissionTagged,
arg.RowLimit,
arg.QueryVector,
arg.MissionCode,
arg.TextQuery,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchCandidatesHybridMissionTaggedRow{}
for rows.Next() {
var i SearchCandidatesHybridMissionTaggedRow
if err := rows.Scan(
&i.ID,
&i.OrganizationID,
&i.FullName,
&i.Email,
&i.Headline,
&i.ClearanceLevel,
&i.ClearancePoly,
&i.ClearanceStatus,
&i.ClearanceGrantedAt,
&i.ClearanceExpiresAt,
&i.ReinvestigationDueAt,
&i.YearsExperience,
&i.Location,
&i.Remote,
&i.Relocatable,
&i.Available,
&i.ResumeEmbedding,
&i.SearchTsv,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Source,
&i.ExternalID,
&i.AnonymizedAt,
&i.ClearanceProvenance,
&i.ClearanceVerifiedAt,
&i.ClearanceCompartments,
&i.RrfScore,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const setCandidateClearanceProvenance = `-- name: SetCandidateClearanceProvenance :execrows
UPDATE candidates
SET clearance_provenance = $2, clearance_verified_at = $3, updated_at = now()
WHERE id = $1 AND deleted_at IS NULL
`
type SetCandidateClearanceProvenanceParams struct {
ID uuid.UUID `json:"id"`
ClearanceProvenance string `json:"clearance_provenance"`
ClearanceVerifiedAt *time.Time `json:"clearance_verified_at"`
}
// An org FSO records HOW a candidate's clearance is known. RLS scopes this to the caller's own org.
// verified_at is the date the FSO confirmed it; it is NULL for a self reported indicator. The platform
// never verifies a clearance itself, it records the org's authoritative assertion.
func (q *Queries) SetCandidateClearanceProvenance(ctx context.Context, arg SetCandidateClearanceProvenanceParams) (int64, error) {
result, err := q.db.Exec(ctx, setCandidateClearanceProvenance, arg.ID, arg.ClearanceProvenance, arg.ClearanceVerifiedAt)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const softDeleteCandidate = `-- name: SoftDeleteCandidate :exec
UPDATE candidates SET deleted_at = now(), updated_at = now() WHERE id = $1
`
func (q *Queries) SoftDeleteCandidate(ctx context.Context, id uuid.UUID) error {
_, err := q.db.Exec(ctx, softDeleteCandidate, id)
return err
}
const updateCandidateEmbedding = `-- name: UpdateCandidateEmbedding :exec
UPDATE candidates SET resume_embedding = $1::vector, updated_at = now() WHERE id = $2
`
type UpdateCandidateEmbeddingParams struct {
Embedding pgvector.Vector `json:"embedding"`
ID uuid.UUID `json:"id"`
}
// Writes a precomputed resume embedding onto a candidate, used by the bench import path AFTER the embed
// network call has already run in the caller, so the migrator write transaction never holds open across
// the inference round trip (the embed lock window rule). The vector is composed from name free structured
// tokens only, never raw resume PII. A candidate with a NULL embedding is left embeddable by the
// embed-backfill only-missing fallback, so a skipped embed never wedges a row.
func (q *Queries) UpdateCandidateEmbedding(ctx context.Context, arg UpdateCandidateEmbeddingParams) error {
_, err := q.db.Exec(ctx, updateCandidateEmbedding, arg.Embedding, arg.ID)
return err
}