Spaces:
Runtime error
Runtime error
| """ | |
| lib/hiring_intent.py — V6 Hiring Intent Engine | |
| Infers WHY the company is hiring, not just WHAT skills they need. | |
| A hiring manager doesn't think "I want Python" — they think | |
| "I need someone who can own production systems" or "I need a founding engineer." | |
| The intent drives downstream weight adjustments, feature emphasis, | |
| and reasoning quality. | |
| Outputs a HiringIntent dataclass with: | |
| - philosophy: list of hiring philosophy tags | |
| - ownership_expectation: how much ownership is expected | |
| - shipping_culture: scrappy vs methodical | |
| - depth_requirement: specialist vs generalist | |
| - scale_requirement: startup vs large scale | |
| - team_context: founding vs established | |
| - independence: how independently they expect work | |
| - mentorship: whether they expect mentoring | |
| - primary_need: the core thing this hire must deliver | |
| """ | |
| from __future__ import annotations | |
| import re | |
| from dataclasses import dataclass, field | |
| from lib.jd_parser import get_jd, JDUnderstanding | |
| class HiringIntent: | |
| """Structured inference of WHY the company is hiring.""" | |
| # Hiring philosophy tags (multiple can apply) | |
| philosophy: list[str] = field(default_factory=list) | |
| # Primary thing this hire must deliver | |
| primary_need: str = "general" | |
| # How much ownership is expected (0.0-1.0) | |
| ownership_expectation: float = 0.5 | |
| # Shipping culture | |
| shipping_culture: str = "balanced" # scrappy, methodical, balanced | |
| # Depth vs breadth | |
| depth_requirement: str = "generalist" # specialist, generalist, t_shaped | |
| # Scale context | |
| scale_requirement: str = "mid_scale" # startup_scale, mid_scale, large_scale | |
| # Team context | |
| team_context: str = "established" # founding, early, growing, established | |
| # Independence expected (0.0-1.0) | |
| independence: float = 0.5 | |
| # Whether they expect mentoring juniors | |
| mentorship: bool = False | |
| # Raw signals extracted from JD | |
| raw_signals: dict = field(default_factory=dict) | |
| # --------------------------------------------------------------------------- | |
| # Intent signal detectors | |
| # --------------------------------------------------------------------------- | |
| _PHILOSOPHY_PATTERNS = { | |
| "startup_builder": [ | |
| r"founding", r"first\s+hire", r"early\s+stage", r"build\s+from\s+scratch", | |
| r"ship\s+a\s+working", r"scrappy", r"0\s+to\s+1", r"ground\s+up", | |
| ], | |
| "hands_on_ic": [ | |
| r"hands\s+on", r"write\s+code", r"coding", r"implement", | |
| r"no\s+pure\s+research", r"not\s+a\s+research", r"product.engineering", | |
| ], | |
| "fast_shipper": [ | |
| r"ship\s+in\s+a\s+week", r"fast", r"quickly", r"rapid", | |
| r"iterate", r"agile", r"move\s+fast", | |
| ], | |
| "research_heavy": [ | |
| r"research", r"paper", r"publication", r"novel", r"state.of.the.art", | |
| r"cutting.edge", r"advance\s+the\s+field", | |
| ], | |
| "platform_engineer": [ | |
| r"platform", r"infrastructure", r"scalable", r"system\s+design", | |
| r"architecture", r"end.to.end", | |
| ], | |
| "specialist_depth": [ | |
| r"deep\s+technical\s+depth", r"expertise\s+in", r"specialist", | |
| r"deep\s+knowledge", r"domain\s+expert", | |
| ], | |
| "team_leader": [ | |
| r"mentor", r"lead", r"senior", r"guide", r"coach", | |
| r"team\s+of", r"manage\s+engineers", | |
| ], | |
| "customer_facing": [ | |
| r"customer", r"user.facing", r"production", r"real\s+users", | |
| r"live\s+traffic", r"on.call", | |
| ], | |
| "scale_focused": [ | |
| r"at\s+scale", r"large.scale", r"millions?\s+of\s+users", r"high\s+throughput", | |
| r"low\s+latency", r"distributed", | |
| ], | |
| } | |
| _OWNERSHIP_PATTERNS = { | |
| "founding": [r"founding", r"first\s+hire", r"build\s+the", r"own\s+the"], | |
| "senior_ic": [r"senior", r"staff", r"lead", r"own", r"independent"], | |
| "team_lead": [r"lead\s+a\s+team", r"manage", r"mentor", r"guide"], | |
| "contributor": [r"contribute", r"part\s+of", r"join", r"work\s+with"], | |
| } | |
| _SHIPPING_PATTERNS = { | |
| "scrappy": [r"ship\s+in\s+a\s+week", r"scrappy", r"just\s+ship\s+it", r"willing\s+to\s+ship"], | |
| "methodical": [r"rigorous", r"systematic", r"process", r"methodology", r"thorough"], | |
| "balanced": [], # default | |
| } | |
| _DEPTH_PATTERNS = { | |
| "specialist": [r"deep\s+technical\s+depth", r"specialist", r"expert\s+in", r"deep\s+dive"], | |
| "generalist": [r"full\s+stack", r"generalist", r"versatile", r"broad"], | |
| "t_shaped": [r"deep\s+in\s+one", r"broad\s+knowledge", r"t.shaped", r"depth.*breadth"], | |
| } | |
| _SCALE_PATTERNS = { | |
| "startup_scale": [r"startup", r"early\s+stage", r"small\s+team", r"series\s+[ab]"], | |
| "mid_scale": [r"scale", r"growing", r"product.company", r"thousands"], | |
| "large_scale": [r"millions", r"enterprise", r"global", r"large.scale"], | |
| } | |
| _TEAM_PATTERNS = { | |
| "founding": [r"founding\s+team", r"first\s+engineer", r"employee\s+#"], | |
| "early": [r"early\s+team", r"small\s+team", r"core\s+team"], | |
| "growing": [r"growing\s+team", r"scaling\s+team", r"hiring\s+team"], | |
| "established": [r"team\s+of\s+\d+", r"large\s+team", r"department"], | |
| } | |
| def _detect_signals(jd_text: str) -> dict[str, list[str]]: | |
| """Detect all intent signals from JD text.""" | |
| signals = {} | |
| # Philosophy | |
| signals["philosophy"] = [] | |
| for tag, patterns in _PHILOSOPHY_PATTERNS.items(): | |
| if any(re.search(p, jd_text, re.IGNORECASE) for p in patterns): | |
| signals["philosophy"].append(tag) | |
| # Ownership | |
| signals["ownership"] = [] | |
| for level, patterns in _OWNERSHIP_PATTERNS.items(): | |
| if any(re.search(p, jd_text, re.IGNORECASE) for p in patterns): | |
| signals["ownership"].append(level) | |
| # Shipping culture | |
| signals["shipping"] = [] | |
| for culture, patterns in _SHIPPING_PATTERNS.items(): | |
| if culture == "balanced": | |
| continue | |
| if any(re.search(p, jd_text, re.IGNORECASE) for p in patterns): | |
| signals["shipping"].append(culture) | |
| # Depth | |
| signals["depth"] = [] | |
| for depth, patterns in _DEPTH_PATTERNS.items(): | |
| if any(re.search(p, jd_text, re.IGNORECASE) for p in patterns): | |
| signals["depth"].append(depth) | |
| # Scale | |
| signals["scale"] = [] | |
| for scale, patterns in _SCALE_PATTERNS.items(): | |
| if any(re.search(p, jd_text, re.IGNORECASE) for p in patterns): | |
| signals["scale"].append(scale) | |
| # Team context | |
| signals["team"] = [] | |
| for ctx, patterns in _TEAM_PATTERNS.items(): | |
| if any(re.search(p, jd_text, re.IGNORECASE) for p in patterns): | |
| signals["team"].append(ctx) | |
| return signals | |
| def _compute_ownership_expectation(signals: dict) -> float: | |
| """Compute ownership expectation level from signals.""" | |
| levels = signals.get("ownership", []) | |
| if "founding" in levels: | |
| return 0.95 | |
| if "senior_ic" in levels: | |
| return 0.80 | |
| if "team_lead" in levels: | |
| return 0.70 | |
| return 0.50 | |
| def _determine_primary_need(jd: JDUnderstanding, signals: dict) -> str: | |
| """Determine the primary thing this hire must deliver.""" | |
| # Check for explicit production ownership | |
| if "customer_facing" in signals.get("philosophy", []): | |
| return "production_systems" | |
| if "platform_engineer" in signals.get("philosophy", []): | |
| return "platform_engineering" | |
| if "research_heavy" in signals.get("philosophy", []): | |
| return "research" | |
| if "startup_builder" in signals.get("philosophy", []): | |
| return "build_from_scratch" | |
| if "specialist_depth" in signals.get("philosophy", []): | |
| return "specialist_contribution" | |
| return "general" | |
| def _compute_independence(jd_text: str, signals: dict) -> float: | |
| """How independently is this person expected to work?""" | |
| score = 0.5 # baseline | |
| indie_patterns = [ | |
| (r"independently", 0.15), (r"own\s+initiative", 0.10), | |
| (r"async", 0.08), (r"self.directed", 0.10), | |
| (r"decides?\s+quickly", 0.08), (r"disagrees?\s+openly", 0.05), | |
| (r"minimal\s+supervision", 0.10), (r"autonom", 0.10), | |
| ] | |
| for pattern, bonus in indie_patterns: | |
| if re.search(pattern, jd_text, re.IGNORECASE): | |
| score = min(1.0, score + bonus) | |
| return score | |
| # --------------------------------------------------------------------------- | |
| # Main API | |
| # --------------------------------------------------------------------------- | |
| def analyze(jd: JDUnderstanding | None = None) -> HiringIntent: | |
| """ | |
| Analyze a JD to infer hiring intent. | |
| Returns a HiringIntent dataclass that drives downstream weight adjustments, | |
| feature emphasis, and reasoning. | |
| """ | |
| if jd is None: | |
| jd = get_jd() | |
| jd_text = jd.raw_text.lower() | |
| signals = _detect_signals(jd_text) | |
| # Build the intent | |
| philosophy = signals.get("philosophy", []) | |
| if not philosophy: | |
| philosophy = ["general"] | |
| ownership_levels = signals.get("ownership", []) | |
| ownership_expectation = _compute_ownership_expectation(signals) | |
| shipping_cultures = signals.get("shipping", []) | |
| shipping_culture = shipping_cultures[0] if shipping_cultures else "balanced" | |
| depths = signals.get("depth", []) | |
| depth_requirement = depths[0] if depths else "generalist" | |
| scales = signals.get("scale", []) | |
| scale_requirement = scales[0] if scales else "mid_scale" | |
| teams = signals.get("team", []) | |
| team_context = teams[0] if teams else "established" | |
| independence = _compute_independence(jd_text, signals) | |
| mentorship = bool( | |
| re.search(r"mentor|guide|coach|senior\s+to|teach", jd_text, re.IGNORECASE) | |
| ) | |
| primary_need = _determine_primary_need(jd, signals) | |
| return HiringIntent( | |
| philosophy=philosophy, | |
| primary_need=primary_need, | |
| ownership_expectation=ownership_expectation, | |
| shipping_culture=shipping_culture, | |
| depth_requirement=depth_requirement, | |
| scale_requirement=scale_requirement, | |
| team_context=team_context, | |
| independence=independence, | |
| mentorship=mentorship, | |
| raw_signals=signals, | |
| ) | |
| # Singleton | |
| _intent_cache: HiringIntent | None = None | |
| def get_intent() -> HiringIntent: | |
| """Get the hiring intent (cached after first analysis).""" | |
| global _intent_cache | |
| if _intent_cache is None: | |
| _intent_cache = analyze() | |
| return _intent_cache |