Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/modules/staffing/portfolio.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 |
| Branch | master |
| Path or archive member | internal/modules/staffing/portfolio.go |
| Original SHA-256 | 3432bd6d165d91337d8827c12d9f79dae03c4a812f5c846e003909387509a8d5 |
| Git blob SHA | 6bd5778c73c0cd961b94507bd5dd8f0f6caa3122 |
| Reading-copy SHA-256 | 3432bd6d165d91337d8827c12d9f79dae03c4a812f5c846e003909387509a8d5 |
Every recorded occurrence
These 43 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/modules/staffing/portfolio.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | w3-ai-staffing-recommendations | 43d56387270ef4da4cabd794d97ca6a49909bc7d | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | w3-ai-staffing-recommendations | 43d56387270ef4da4cabd794d97ca6a49909bc7d | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / internal/modules/staffing/portfolio.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓256 lines · 9.4 KB
package staffing
import (
"context"
"sort"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/shopspring/decimal"
"github.com/missionworkforce/missionmatch/internal/modules/matching"
"github.com/missionworkforce/missionmatch/internal/modules/matching/engine"
"github.com/missionworkforce/missionmatch/internal/platform/database/dbgen"
)
// GeneratePortfolio allocates the available bench across the open requirements to maximize total value
// (POST /recommendations/portfolio). The available bench excludes candidates already committed elsewhere;
// each requirement's open slots are its quantity minus its current commitments. The optimizer arbitrates
// only among engine qualified, available candidates, and each assignment carries the value matrix
// counterfactual. Two portfolio runs for the same org serialize on a Postgres advisory lock, so a fresh
// run never interleaves its supersede and insert with another. An empty eligible bench or no open
// requirement returns an empty allocation (200), not an error; an over large problem returns
// ErrProblemTooLarge and a solve over budget returns ErrSolveBudget.
func (s *Service) GeneratePortfolio(ctx context.Context, req PortfolioRequest) (RunResponse, error) {
if s.db == nil {
return RunResponse{}, ErrNoDatabase
}
orgID, err := s.orgID(ctx)
if err != nil {
return RunResponse{}, err
}
floor, adj, verr := parseOverrides(req.StaffingFloor, req.AdjacencyThreshold)
if verr != nil {
return RunResponse{}, verr
}
cfg := s.cfg.WithOverrides(floor, adj)
asOf := s.clock()
var (
pin PortfolioInput
resByPair = map[[2]int]engine.MatchResult{}
candIDs []string // candidate index -> uuid string (available bench, stable order)
candProv []string // candidate index -> clearance provenance
candComp []decimal.Decimal // candidate index -> profile completeness
reqIDs []string // requirement index -> uuid string
valueSource string
verr2 *ValidationError
)
// Phase A (read): score the bench against each in scope open requirement and build the assignment graph.
err = s.db.RunInTenantTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
q := dbgen.New(tx)
openRows, e := q.ListOpenRequirementsWithValue(ctx, dbgen.ListOpenRequirementsWithValueParams{Limit: openRequirementCap, Offset: 0})
if e != nil {
return e
}
priorities, vs := buildPriorities(cfg, openRows)
valueSource = vs
var subset map[string]bool
if len(req.RequirementIDs) > 0 {
known := map[string]bool{}
for _, r := range openRows {
known[r.ID.String()] = true
}
subset = map[string]bool{}
for _, idStr := range req.RequirementIDs {
if _, perr := uuid.Parse(idStr); perr != nil || !known[idStr] {
verr2 = validationErr("requirement_ids", "must all be open requirement ids in this tenant")
return nil // surfaced as 422 after the tx
}
subset[idStr] = true
}
}
commitRows, e := q.ListCommitments(ctx)
if e != nil {
return e
}
commit := buildCommitments(commitRows)
cands, e := q.ListCandidates(ctx, dbgen.ListCandidatesParams{Limit: benchScanLimit, Offset: 0})
if e != nil {
return e
}
// Available bench = candidates not already committed anywhere.
var avail []dbgen.Candidate
for _, c := range cands {
if _, committed := commit.byCand[c.ID.String()]; committed {
continue
}
avail = append(avail, c)
}
candIDs = make([]string, len(avail))
candProv = make([]string, len(avail))
candComp = make([]decimal.Decimal, len(avail))
ecs := make([]engine.Candidate, len(avail))
for i, c := range avail {
ec, e := matching.LoadEngineCandidate(ctx, q, c, asOf)
if e != nil {
return e
}
candIDs[i] = c.ID.String()
candProv[i] = c.ClearanceProvenance
candComp[i] = completeness(ec)
ecs[i] = ec
}
pin.NumCandidates = len(avail)
for _, rr := range openRows {
if subset != nil && !subset[rr.ID.String()] {
continue
}
openSlots := int(rr.Quantity) - commit.countByReq[rr.ID.String()]
if openSlots <= 0 {
continue // already fully committed: no open slots to allocate
}
er, e := matching.LoadEngineRequirement(ctx, q, rr.ID)
if e != nil {
return e
}
reqIdx := len(reqIDs)
reqIDs = append(reqIDs, rr.ID.String())
pin.Slots = append(pin.Slots, openSlots)
priority := priorities[rr.ID.String()]
for candIdx, ec := range ecs {
res := engine.ScoreCandidate(ctx, ec, er, s.matcher)
if !ec.Available || res.Total.LessThan(cfg.StaffingFloor) {
continue // the optimizer only sees engine qualified, available candidates
}
v := ScaledValue(res.Total, priority, cfg.ValueScalePrecision)
if v <= 0 {
continue
}
pin.Edges = append(pin.Edges, AssignEdge{CandidateIdx: candIdx, RequirementIdx: reqIdx, Value: v})
resByPair[[2]int{candIdx, reqIdx}] = res
}
}
return nil
})
if err != nil {
return RunResponse{}, err
}
if verr2 != nil {
return RunResponse{}, verr2
}
// Phase A.5 (no tx): solve, bounded by the size cap and the solve budget.
solveCtx, cancel := context.WithTimeout(ctx, cfg.SolveBudget)
defer cancel()
sol, err := SolvePortfolio(solveCtx, pin, cfg.MaxProblemEdges, cfg.MaxProblemNodes)
if err != nil {
return RunResponse{}, err // ErrProblemTooLarge or ErrSolveBudget, surfaced as 413 or 503
}
cf := Counterfactuals(pin, sol)
// Build the recommendations: an ASSIGN per optimal assignment, a SOURCE per requirement left short.
recs := s.buildPortfolioRecs(cfg, sol, pin, cf, resByPair, candIDs, candProv, candComp, reqIDs)
// The frozen result for each assigned pair, keyed for the eval upsert in persistRun.
assignedRes := map[string]engine.MatchResult{}
for _, a := range sol.Assignments {
assignedRes[pairKey(candIDs[a.CandidateIdx], reqIDs[a.RequirementIdx])] = resByPair[[2]int{a.CandidateIdx, a.RequirementIdx}]
}
// Phase B (no tx): narrate.
enriched := s.enrich(ctx, recs)
// Phase C (write): serialize per org on an advisory lock, then persist atomically.
var run dbgen.RecommendationRun
var rows []dbgen.StaffingRecommendation
err = s.db.RunInTenantTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
// Serialize portfolio runs for this org so a fresh run never interleaves its supersede and insert
// with another (the read committed snapshot would otherwise leave two live pending sets).
if e := acquireAdvisoryLock(ctx, tx, advisoryKey(ViewPortfolio, orgID, "")); e != nil {
return e
}
var e error
run, rows, e = s.persistRun(ctx, tx, orgID, ViewPortfolio, nil, runParams(cfg, valueSource), "staffing.portfolio", enriched, assignedRes,
func(ctx context.Context, q *dbgen.Queries) error { return q.SupersedePendingPortfolio(ctx) })
return e
})
if err != nil {
return RunResponse{}, err
}
return RunResponse{Run: runView(run), Recommendations: recommendationViews(rows)}, nil
}
// buildPortfolioRecs turns the optimal allocation into ranked recommendations: ASSIGN rows (highest value
// first) with the value matrix counterfactual, then a SOURCE row per requirement whose open slots the bench
// could not fill.
func (s *Service) buildPortfolioRecs(cfg Config, sol PortfolioSolution, pin PortfolioInput, cf map[int]AssignCounterfactual, resByPair map[[2]int]engine.MatchResult, candIDs, candProv []string, candComp []decimal.Decimal, reqIDs []string) []Recommendation {
assigns := append([]Assignment(nil), sol.Assignments...)
sort.SliceStable(assigns, func(i, j int) bool {
if assigns[i].Value != assigns[j].Value {
return assigns[i].Value > assigns[j].Value
}
if assigns[i].CandidateIdx != assigns[j].CandidateIdx {
return assigns[i].CandidateIdx < assigns[j].CandidateIdx
}
return assigns[i].RequirementIdx < assigns[j].RequirementIdx
})
filled := make([]int, len(pin.Slots))
var recs []Recommendation
rank := 0
for _, a := range assigns {
filled[a.RequirementIdx]++
rank++
res := resByPair[[2]int{a.CandidateIdx, a.RequirementIdx}]
ev := Evidence{
EngineTotal: res.Total.StringFixed(2),
Band: res.Band.Code(),
Counterfactual: portfolioCounterfactual(cf[a.CandidateIdx], res, candIDs, reqIDs),
}
conf := Confidence(cfg, ScoredCandidate{Total: res.Total, Provenance: candProv[a.CandidateIdx], Completeness: candComp[a.CandidateIdx]})
value := a.Value
recs = append(recs, Recommendation{
RequirementID: reqIDs[a.RequirementIdx],
CandidateID: candIDs[a.CandidateIdx],
Action: ActionAssign,
Rank: rank,
Confidence: conf,
ValueScore: &value,
Evidence: ev,
})
}
for j := range pin.Slots {
if remaining := pin.Slots[j] - filled[j]; remaining > 0 {
rank++
rem := remaining
recs = append(recs, Recommendation{
RequirementID: reqIDs[j],
Action: ActionSource,
Rank: rank,
Confidence: decimal.NewFromInt(1),
Evidence: Evidence{OpenSlots: &rem},
})
}
}
return recs
}
func portfolioCounterfactual(cf AssignCounterfactual, res engine.MatchResult, candIDs, reqIDs []string) *Counterfactual {
c := &Counterfactual{AssignedTotal: res.Total.StringFixed(2)}
if cf.CandidateNextReqIdx >= 0 && cf.CandidateNextReqIdx < len(reqIDs) {
c.CandidateNextRequirement = reqIDs[cf.CandidateNextReqIdx]
d := cf.CandidateValueDelta
c.CandidateValueDelta = &d
}
if cf.RequirementNextCandIdx >= 0 && cf.RequirementNextCandIdx < len(candIDs) {
c.RequirementNextCandidate = candIDs[cf.RequirementNextCandIdx]
d := cf.RequirementValueDelta
c.RequirementValueDelta = &d
}
return c
}