package staffing import ( "github.com/shopspring/decimal" "github.com/missionworkforce/missionmatch/internal/modules/matching/engine" ) // Action is the recommended staffing action. team is reserved for a future GraphRAG teaming build and is // never produced in v1. type Action string const ( ActionAssign Action = "assign" ActionReassign Action = "reassign" ActionReskill Action = "reskill" ActionSource Action = "source" ActionTeam Action = "team" // reserved, not implemented in v1 ) // RationaleSource records whether the rationale prose was confirmed by the faithfulness gate (ai_faithful) // or fell back to the deterministic template (deterministic). type RationaleSource string const ( RationaleAIFaithful RationaleSource = "ai_faithful" RationaleDeterministic RationaleSource = "deterministic" ) // View is the kind of recommendation run. type View string const ( ViewGap View = "gap" ViewPortfolio View = "portfolio" ViewProactive View = "proactive" ) // ReskillFact is the adjacency evidence for a reskill recommendation: the candidate holds HeldSkill, the // requirement needs MissingSkill, and the two are adjacent at cosine distance Distance. type ReskillFact struct { HeldSkill string `json:"held_skill"` MissingSkill string `json:"missing_skill"` Distance decimal.Decimal `json:"distance"` } // ReassignEvidence is the evidence for a reassign recommendation: the candidate is currently committed to // FromRequirementID and the target gap is higher priority by PriorityDelta. type ReassignEvidence struct { FromRequirementID string `json:"from_requirement_id"` PriorityDelta decimal.Decimal `json:"priority_delta"` } // Counterfactual is the per assignment explanation for a portfolio allocation, computed from the optimal // matching without exposing solver internals: why this candidate landed here and what the next best uses // were. The deltas are reported in the scaled integer objective units. type Counterfactual struct { AssignedTotal string `json:"assigned_total"` // the assigned candidate engine total for this requirement CandidateNextRequirement string `json:"candidate_next_requirement,omitempty"` // the candidate's next best requirement CandidateValueDelta *int64 `json:"candidate_value_delta,omitempty"` // scaled value lost by not placing them on their next best requirement RequirementNextCandidate string `json:"requirement_next_candidate,omitempty"` // the requirement's next best candidate if this one were removed RequirementValueDelta *int64 `json:"requirement_value_delta,omitempty"` // scaled value drop to that next best candidate } // TriggerChange records what changed to raise a proactive watch alert. type TriggerChange struct { Kind string `json:"kind"` // availability, certification, clearance, new_opportunity DetectedAt string `json:"detected_at,omitempty"` // RFC3339, the change observation time } // Evidence is the structured justification stored on a recommendation (jsonb). Only the fields relevant to // the action are populated; the rest are omitted. type Evidence struct { EngineTotal string `json:"engine_total,omitempty"` Band string `json:"band,omitempty"` Reskill *ReskillFact `json:"reskill,omitempty"` Reassign *ReassignEvidence `json:"reassign,omitempty"` Counterfactual *Counterfactual `json:"counterfactual,omitempty"` OpenSlots *int `json:"open_slots,omitempty"` Trigger *TriggerChange `json:"trigger,omitempty"` // FaithFallbackReason records WHY the faithfulness gate did not confirm the prose (could_not_confirm, // plane_timeout, circuit_open, generation_disabled). It is for narration tuning and is NEVER placed in // an audit payload. FaithFallbackReason string `json:"faith_fallback_reason,omitempty"` } // ScoredCandidate is one candidate already scored against a requirement, with the precomputed inputs the // pure classifier needs. The service builds these from the frozen engine result and the database // (commitment, provenance, completeness, adjacency); the classifier is pure. type ScoredCandidate struct { CandidateID string Available bool Total decimal.Decimal Band engine.Band ClearanceSatisfied bool // the engine clearance sub score is full, the clearance gate is met Provenance string // clearance provenance code, drives confidence Completeness decimal.Decimal // profile completeness in [0,1], drives confidence CommittedRequirementID string // "" when uncommitted; else the requirement the candidate is committed to CommittedPriority decimal.Decimal // the priority of the committed requirement, for the reassign delta Reskill *ReskillFact // non nil when a reskill path exists (an adjacent held skill for a missing one) } // GapContext is the gap being filled: the requirement, how many slots are open, and its priority. type GapContext struct { RequirementID string OpenSlots int Priority decimal.Decimal } // Recommendation is one classified, ranked, confidence scored recommended action (pure, no DB identity // yet). The service persists it as a staffing_recommendations row. type Recommendation struct { RequirementID string CandidateID string // "" for a source recommendation Action Action Rank int Confidence decimal.Decimal ValueScore *int64 // portfolio only Evidence Evidence }