Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/platform/benchimport/benchimport.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 |
| Branch | master |
| Path or archive member | internal/platform/benchimport/benchimport.go |
| Original SHA-256 | e26977e52686bab69be8c3cb7bb18ebe572576b7e3cfe467d205556c6a76d8cd |
| Git blob SHA | 92322e4383866367e5335f55c45951284170678d |
| Reading-copy SHA-256 | e26977e52686bab69be8c3cb7bb18ebe572576b7e3cfe467d205556c6a76d8cd |
Every recorded occurrence
These 23 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | feature/aioe-upgrade | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | feature/aioe-upgrade | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 | Open original |
| Janady13/missionmatch / internal/platform/benchimport/benchimport.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓90 lines · 5.3 KB
// Package benchimport is the CUI safe bulk loader port for a real cleared workforce bench. It turns a
// directory of resumes and a structured CSV or JSONL roster into normalized records mapped onto the
// existing sourcing.SourcedPerson, so the same dedup, skills, certs, and agency writes that back a
// sourced lead also back an imported bench person. It is a platform package: it may read files, call the
// pure Go docextract reader and the deterministic extraction.Extractor, and shape sourcing types, but it
// never imports the scoring engine and never touches the database. Ingestion (dedup, embed, tag) is the
// caller's job through sourcing and the import command.
//
// Two invariants are encoded in the types here. First, BenchRecord carries ONLY structured workforce
// tokens and NO demographic field, so no protected attribute can ride into the matching plane (the AEDT
// rule). Second, the resume mapping keeps a person name, an email, and a phone OUT of every embeddable or
// scored field: a full name lands only on the candidate name column, never in a job title, a role, or a
// headline that is composed into the embed profile (invariant 5).
package benchimport
import (
"context"
"github.com/missionworkforce/missionmatch/internal/platform/sourcing"
)
// BenchRecord is a normalized bench entry: structured workforce tokens only, never a demographic field
// and never a raw resume span. Every field here is a scoring or routing signal, none is a protected
// attribute or a close proxy. The clearance field holds a self reported DB CODE captured for triage only;
// it is recorded against bench_import_log, never written to candidates.clearance_level (invariant 3), so
// a resume regex can never score as a held clearance.
//
// The full name is carried so the candidate row gets a name, but the mapping to SourcedPerson places it
// ONLY on the name field that lands in candidates.full_name. A name, an email, or a phone is NEVER placed
// into JobTitle, Role, or any field that the embed profile composer reads (invariant 5).
type BenchRecord struct {
FullName string // person name, lands ONLY on candidates.full_name, never embedded
Location string // a work location, "City, ST"
JobTitle string // a sanitized title token, never a name or an email
Skills []string // structured skill tokens
Certs []string // structured certification tokens
Agencies []string // structured customer or agency tokens
Years int // years of experience
ClearanceCode string // self reported clearance DB code, triage only, NEVER scored as held
ExternalID string // a stable per record id for dedup, empty for resumes without one
Email string // a contact email, used only for dedup, NEVER embedded
Phone string // a contact phone, used only for dedup, NEVER embedded
}
// ToSourcedPerson maps a BenchRecord onto the sourcing.SourcedPerson the ingest path already knows how to
// dedup and write. It enforces invariant 5 at the boundary: FullName goes only to SourcedPerson.FullName
// (which the upsert routes to candidates.full_name), the email and phone go only to the contact slices
// (used for dedup, never embedded), and JobTitle is the only title token, so a name or an email can never
// reach a headline or a scored field. The clearance code is intentionally NOT mapped onto SourcedPerson,
// which has no clearance field, so it can never reach a clearance column; the caller records it against
// bench_import_log for triage only.
func (r BenchRecord) ToSourcedPerson() sourcing.SourcedPerson {
sp := sourcing.SourcedPerson{
ExternalID: r.ExternalID,
FullName: r.FullName,
JobTitle: r.JobTitle,
Location: r.Location,
Skills: append([]string(nil), r.Skills...),
Years: r.Years,
}
if r.Email != "" {
sp.Emails = []string{r.Email}
}
if r.Phone != "" {
sp.Phones = []string{r.Phone}
}
return sp
}
// BatchResult counts the outcome of one import run, for the single append only audit summary the import
// command writes (counts and the model only, never PII).
type BatchResult struct {
Read int // files or rows read from the source
Skipped int // malformed or empty entries skipped rather than aborting the batch
Mapped int // entries that produced a usable BenchRecord
}
// FileSource yields bench records from local files. Resumes walks a directory of resume files (PDF, DOCX,
// HTML, or text) and yields one record per readable file. Profiles decodes a structured CSV or JSONL
// roster and yields one record per well formed row, skipping a malformed row rather than aborting. An
// implementation is pure: it reads files and shapes records, it never writes to the database.
type FileSource interface {
// Resumes walks dir, extracts each resume to text, and yields a BenchRecord per readable file along
// with the file path for the compliance log. It returns the running counts in the BatchResult.
Resumes(ctx context.Context, dir string, yield func(rec BenchRecord, file string) error) (BatchResult, error)
// Profiles decodes the CSV or JSONL roster at path and yields a BenchRecord per well formed row,
// skipping a malformed row. It returns the running counts in the BatchResult.
Profiles(ctx context.Context, path string, yield func(rec BenchRecord, batch string) error) (BatchResult, error)
}