W1-019 practical opportunity qualification
This commit is contained in:
@@ -78,3 +78,5 @@ The reviewed pipeline is now `data/opportunities.json`; its bytes are unchanged.
|
||||
Historical run paths remain valid. Records retain original links, provenance,
|
||||
source conflicts and human decisions. HTTP availability is not confirmed hiring
|
||||
status; candidate outputs remain unreviewed until Ken approves promotion.
|
||||
|
||||
W1-019 adds `python w1.py practical --help` for saved-evidence practical eligibility. See [profile editing, rules and replay](docs/PRACTICAL-QUALIFICATION.md).
|
||||
|
||||
@@ -6,3 +6,5 @@ candidates or alter review decisions. Ken must approve candidate promotion.
|
||||
|
||||
The immutable test copy is under `tests/fixtures/`; historical pre-refactor bytes
|
||||
are retained under `runs/2026-09-17/w1-017/before/`.
|
||||
|
||||
`qualification-profile.json` contains owner-editable W1-019 criteria and explicitly unknown personal facts. See [editing and decision rules](../docs/PRACTICAL-QUALIFICATION.md).
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"owner": "Ken Schaefer",
|
||||
"opportunity_categories": [
|
||||
"full_time_employment",
|
||||
"part_time_employment",
|
||||
"contract",
|
||||
"consulting"
|
||||
],
|
||||
"geography": {
|
||||
"remote_countries": [
|
||||
"US"
|
||||
],
|
||||
"onsite_states": [
|
||||
"TN"
|
||||
],
|
||||
"approved_onsite_states": []
|
||||
},
|
||||
"strong_domains": [
|
||||
"enterprise architecture",
|
||||
"solution architecture",
|
||||
"technology strategy",
|
||||
"IT leadership",
|
||||
"AI strategy and architecture",
|
||||
"AI implementation",
|
||||
"Azure/cloud architecture",
|
||||
"infrastructure architecture",
|
||||
"modernization",
|
||||
"fractional CIO / technology consulting"
|
||||
],
|
||||
"role_family_policy": {
|
||||
"executive_it_leadership": "consider",
|
||||
"enterprise_architecture": "consider",
|
||||
"solution_architecture": "consider",
|
||||
"cloud_infrastructure_architecture": "consider",
|
||||
"ai_architecture_strategy": "consider",
|
||||
"consulting": "consider",
|
||||
"software_development": "specialist_review_only",
|
||||
"data_science_ml_engineering": "specialist_review_only",
|
||||
"network_engineering": "specialist_review_only",
|
||||
"support_operations": "specialist_review_only",
|
||||
"other_specialist_roles": "specialist_review_only"
|
||||
},
|
||||
"owner_facts": {
|
||||
"residence_state": "unknown",
|
||||
"us_work_authorization_without_sponsorship": "unknown",
|
||||
"us_citizenship": "unknown",
|
||||
"security_clearance": "unknown",
|
||||
"willing_to_relocate": "unknown",
|
||||
"willing_to_travel": "unknown",
|
||||
"years_of_experience": "unknown",
|
||||
"certifications": "unknown",
|
||||
"specialist_skills": "unknown"
|
||||
},
|
||||
"notes": [
|
||||
"Geographic scope does not establish actual residence or relocation willingness.",
|
||||
"Specialist mismatch means a core-function preference mismatch, not proven lack of skills.",
|
||||
"Owner can set a specialist family to consider, or add approved onsite states. Unknown requirements still need review."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
# W1-019 practical qualification
|
||||
|
||||
Run from the checkout root with Python 3.10+ (standard library only):
|
||||
|
||||
python -m unittest discover -s tests -v
|
||||
python w1.py practical --run runs/2026-09-17/lrs-162640 --profile data/qualification-profile.json --output runs/2026-09-17/lrs-162640/qualification-W1-019
|
||||
|
||||
Use a fresh output directory for each execution. No network requests occur.
|
||||
The original W1-016 command, qualify, remains available and unchanged.
|
||||
|
||||
## Owner-controlled policy
|
||||
|
||||
Edit data/qualification-profile.json as JSON, then rerun. The output captures
|
||||
the exact interpreted profile and input/code hashes so decisions are auditable.
|
||||
|
||||
- opportunity_categories: full_time_employment, part_time_employment, contract,
|
||||
consulting. All four are initially in scope.
|
||||
- geography.remote_countries: US only; other countries are not supported.
|
||||
- geography.onsite_states: TN initially. Add an explicitly reviewed state to
|
||||
approved_onsite_states to permit regular onsite/hybrid work there.
|
||||
- strong_domains: literal case-insensitive domain phrases supplement the legacy
|
||||
technical relevance rules. They never override clearly unrelated work or
|
||||
reliable visible expiration evidence.
|
||||
- role_family_policy: consider, specialist_review_only, or exclude for each
|
||||
listed family. specialist_review_only withholds the role from the brief;
|
||||
Ken can explicitly change a family to consider, then inspect remaining gaps.
|
||||
- owner_facts: residence_state is unknown or a postal abbreviation.
|
||||
Authorization, citizenship, clearance, travel and relocation accept unknown,
|
||||
yes or no. Certifications and specialist_skills accept unknown or lists.
|
||||
Specialist skill labels recognized by these rules are Python ML frameworks,
|
||||
Salesforce, ServiceNow, .NET implementation, AWS CDK, Terraform, Cisco Meraki,
|
||||
and Workday. Certification names should be specific, as advertised.
|
||||
years_of_experience accepts unknown or a nonnegative integer.
|
||||
|
||||
An in-scope Tennessee opportunity does not establish Tennessee residence.
|
||||
Relocation willingness does not override the explicit approved-state policy.
|
||||
Total tenure cannot establish years in a specific role: those requirements
|
||||
remain verification gaps. Unknown or unlisted qualifications are not failures.
|
||||
Clearance and certifications still require verification of level/current status.
|
||||
|
||||
## Decision rules
|
||||
|
||||
Stage one retains the legacy technical score and exclusion plus profile domain
|
||||
evidence. Stage two determines core role family, arrangement, geographic
|
||||
restrictions and explicit owner qualification gaps.
|
||||
|
||||
Title/function rules separate leadership, architecture and strategic consulting
|
||||
from development, ML engineering, network engineering, support and specialist
|
||||
platform work. An explicit ML-builder description can override an architect
|
||||
title. Platform consultants such as LifePRO remain specialist roles.
|
||||
|
||||
Disposition precedence is out_of_scope (technical/category/family exclusion),
|
||||
location_conflict, specialist_mismatch, insufficient_evidence (arrangement),
|
||||
known owner-fact conflict (out_of_scope), needs_owner_review, practical_match.
|
||||
All evidence remains available even when an earlier rule determines disposition.
|
||||
specialist_mismatch means a mismatch to the current role preference, not proof
|
||||
of inability. A city alone does not prove onsite work or remote permission.
|
||||
Explicit presence requirements override a Remote header; the conflict is kept.
|
||||
|
||||
Preferred certifications are labeled desired, not silently made mandatory.
|
||||
Historical 2017 metadata dates never establish closure by themselves.
|
||||
Source compensation, date and engagement conflicts remain unresolved.
|
||||
Practical fit does not confirm hiring status, pay, or authority to apply.
|
||||
|
||||
## Saved output and limits
|
||||
|
||||
All 87 saved records are assessed, including three already in the pipeline.
|
||||
The pipeline is read only. Existing matches are recorded in the audit and
|
||||
omitted from the new-candidate brief regardless of their computed disposition.
|
||||
|
||||
- audit.json: original records, saved description parts, snapshot hashes and
|
||||
full assessments, including every withheld candidate and reason.
|
||||
- practical.json: practical assessments for all records.
|
||||
- summary.json: stage-one and stage-two counts, role-family counts, existing
|
||||
pipeline matches, review counts, and reproducibility hashes.
|
||||
- profile.json: policy snapshot.
|
||||
- brief.md: at most 15 new practical_match / needs_owner_review records.
|
||||
Additional eligible candidates remain counted and available in the audit.
|
||||
|
||||
Saved manifest success/count and every detail snapshot hash are checked.
|
||||
Missing/corrupt inputs, invalid profiles and existing output directories fail
|
||||
visibly. Deterministic replay uses the saved collection date, not today's date.
|
||||
|
||||
This is deliberately a conservative source-specific ruleset, not a complete
|
||||
natural-language eligibility evaluator. Unrecognized titles fall into other
|
||||
specialist roles, and unrecognized arrangements need source clarification.
|
||||
Review the audit when expanding owner policy or encountering new wording.
|
||||
No collection, application, outreach, pipeline promotion or external commitment
|
||||
is performed. Generated runs remain local under the existing Git evidence policy.
|
||||
|
||||
@@ -0,0 +1,539 @@
|
||||
"""Practical eligibility over saved LRS evidence and owner-controlled policy."""
|
||||
|
||||
import argparse
|
||||
from collections import Counter
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
from opportunity_intelligence.collectors.lrs import (
|
||||
SourceError, deduplicate, identity, write_json,
|
||||
)
|
||||
from opportunity_intelligence.paths import PIPELINE, ROOT
|
||||
from opportunity_intelligence.qualification import lrs as technical
|
||||
|
||||
|
||||
VERSION = "W1-019-v1"
|
||||
PROFILE = ROOT / "data/qualification-profile.json"
|
||||
REVIEWABLE = {"practical_match", "needs_owner_review"}
|
||||
DISPOSITIONS = (
|
||||
"practical_match", "needs_owner_review", "out_of_scope",
|
||||
"location_conflict", "specialist_mismatch", "insufficient_evidence",
|
||||
)
|
||||
# These patterns describe job functions, never personal attributes of the owner.
|
||||
FAMILY_PATTERNS = (
|
||||
("executive_it_leadership",
|
||||
r"\b(?:CIO|CTO|chief .*officer|IT manager|IT director|"
|
||||
r"director of (?:IT|technology)|vice president)\b"),
|
||||
("other_specialist_roles",
|
||||
r"\b(?:Salesforce|SAP|D365|Dynamics|OnBase|Blue Yonder|SiteCore|LifePRO)\b"),
|
||||
("data_science_ml_engineering",
|
||||
r"\b(?:data scientist|data engineer|ML engineer|AI/ML developer|"
|
||||
r"AI/ML platform engineer|machine learning engineer)\b"),
|
||||
("software_development", r"\b(?:developer|software engineer|programmer)\b"),
|
||||
("network_engineering", r"\bnetwork engineer\b"),
|
||||
("support_operations",
|
||||
r"\b(?:help desk|service desk|desktop support|support analyst|"
|
||||
r"field services|system administrator|infrastructure engineer)\b"),
|
||||
("ai_architecture_strategy",
|
||||
r"\b(?:AI|ML|artificial intelligence)\b.*architect"),
|
||||
("cloud_infrastructure_architecture",
|
||||
r"\b(?:cloud|Azure|infrastructure)\b.*architect|architect.*\bcloud\b"),
|
||||
("enterprise_architecture", r"\benterprise architect\b"),
|
||||
("solution_architecture", r"\bsolutions? architect\b"),
|
||||
("consulting",
|
||||
r"\b(?:consultant|consulting|fractional CIO|technology strategist)\b"),
|
||||
)
|
||||
STATE_NAMES = (
|
||||
"Alabama:AL|Alaska:AK|Arizona:AZ|Arkansas:AR|California:CA|Colorado:CO|"
|
||||
"Connecticut:CT|Delaware:DE|Florida:FL|Georgia:GA|Hawaii:HI|Idaho:ID|"
|
||||
"Illinois:IL|Indiana:IN|Iowa:IA|Kansas:KS|Kentucky:KY|Louisiana:LA|"
|
||||
"Maine:ME|Maryland:MD|Massachusetts:MA|Michigan:MI|Minnesota:MN|"
|
||||
"Mississippi:MS|Missouri:MO|Montana:MT|Nebraska:NE|Nevada:NV|"
|
||||
"New Hampshire:NH|New Jersey:NJ|New Mexico:NM|New York:NY|"
|
||||
"North Carolina:NC|North Dakota:ND|Ohio:OH|Oklahoma:OK|Oregon:OR|"
|
||||
"Pennsylvania:PA|Rhode Island:RI|South Carolina:SC|South Dakota:SD|"
|
||||
"Tennessee:TN|Texas:TX|Utah:UT|Vermont:VT|Virginia:VA|Washington:WA|"
|
||||
"West Virginia:WV|Wisconsin:WI|Wyoming:WY|District of Columbia:DC"
|
||||
)
|
||||
STATES = dict(item.split(":") for item in STATE_NAMES.split("|"))
|
||||
SPECIALIST_SKILLS = {
|
||||
"Python ML frameworks": r"Python|PyTorch|TensorFlow|scikit-learn",
|
||||
"Salesforce": r"Salesforce|Apex|SOQL",
|
||||
"ServiceNow": r"ServiceNow|HRSD",
|
||||
".NET implementation": r"C#|\.NET|Entity Framework",
|
||||
"AWS CDK": r"AWS (?:CDK|Cloud Development Kit)",
|
||||
"Terraform": r"Terraform",
|
||||
"Cisco Meraki": r"Cisco Meraki",
|
||||
"Workday": r"Workday",
|
||||
}
|
||||
|
||||
|
||||
def matches(pattern, text):
|
||||
"""Search role evidence case-insensitively."""
|
||||
return bool(re.search(pattern, text, re.I))
|
||||
|
||||
|
||||
def states_in(text):
|
||||
"""Recognize full names and uppercase postal codes, not words like in."""
|
||||
return sorted({
|
||||
code for name, code in STATES.items()
|
||||
if matches(r"\b" + name + r"\b", text)
|
||||
or re.search(r"\b" + code + r"\b", text)
|
||||
})
|
||||
|
||||
|
||||
def load_profile(path):
|
||||
"""Validate owner policy; malformed configuration must fail visibly."""
|
||||
profile = json.loads(path.read_text(encoding="utf-8-sig"))
|
||||
try:
|
||||
if profile["schema_version"] != 1:
|
||||
raise ValueError("schema_version must be 1")
|
||||
categories = profile["opportunity_categories"]
|
||||
allowed_categories = {
|
||||
"full_time_employment", "part_time_employment", "contract", "consulting"
|
||||
}
|
||||
if not isinstance(categories, list) or not set(categories) <= allowed_categories:
|
||||
raise ValueError("invalid opportunity_categories")
|
||||
geography = profile["geography"]
|
||||
for key in ("onsite_states", "approved_onsite_states"):
|
||||
if not isinstance(geography[key], list):
|
||||
raise ValueError(key + " must be a list")
|
||||
if not set(geography[key]) <= set(STATES.values()):
|
||||
raise ValueError(key + " contains unknown state codes")
|
||||
if not isinstance(geography["remote_countries"], list):
|
||||
raise ValueError("remote_countries must be a list")
|
||||
if not set(geography["remote_countries"]) <= {"US"}:
|
||||
raise ValueError("only US remote geography is supported")
|
||||
if not isinstance(profile["strong_domains"], list):
|
||||
raise ValueError("strong_domains must be a list")
|
||||
families = {family for family, _ in FAMILY_PATTERNS}
|
||||
if set(profile["role_family_policy"]) != families:
|
||||
raise ValueError("role_family_policy must specify every family")
|
||||
if not set(profile["role_family_policy"].values()) <= {
|
||||
"consider", "specialist_review_only", "exclude"
|
||||
}:
|
||||
raise ValueError("invalid role_family_policy value")
|
||||
facts = profile["owner_facts"]
|
||||
for key in (
|
||||
"us_work_authorization_without_sponsorship", "us_citizenship",
|
||||
"security_clearance", "willing_to_relocate", "willing_to_travel",
|
||||
):
|
||||
if facts[key] not in ("unknown", "yes", "no"):
|
||||
raise ValueError(key + " must be unknown, yes or no")
|
||||
if facts["residence_state"] not in {"unknown", *STATES.values()}:
|
||||
raise ValueError("residence_state must be unknown or a state code")
|
||||
for key in ("certifications", "specialist_skills"):
|
||||
value = facts[key]
|
||||
if value != "unknown" and (
|
||||
not isinstance(value, list)
|
||||
or not all(isinstance(item, str) and item for item in value)
|
||||
):
|
||||
raise ValueError(key + " must be unknown or a list of names")
|
||||
years = facts["years_of_experience"]
|
||||
if years != "unknown" and (type(years) is not int or years < 0):
|
||||
raise ValueError("years_of_experience must be unknown or nonnegative")
|
||||
except (KeyError, TypeError, ValueError) as error:
|
||||
raise SourceError(f"Invalid qualification profile: {error}") from error
|
||||
return profile
|
||||
|
||||
|
||||
def classify_role(title, parts):
|
||||
"""Identify core function; explicit ML-builder work can override a title."""
|
||||
builder_evidence = [
|
||||
part for part in parts if matches(
|
||||
r"actually built or trained|not someone who has primarily customized|"
|
||||
r"AI/ML Platform Engineer", part,
|
||||
)
|
||||
]
|
||||
if matches(r"\bAI\b|\bML\b", title) and builder_evidence:
|
||||
return "data_science_ml_engineering", builder_evidence
|
||||
for family, pattern in FAMILY_PATTERNS:
|
||||
if matches(pattern, title):
|
||||
return family, [title]
|
||||
return "other_specialist_roles", [title]
|
||||
|
||||
|
||||
def geography_assessment(record, parts, profile):
|
||||
"""Separate location conflicts, uncertain arrangements and residency gaps."""
|
||||
policy = profile["geography"]
|
||||
facts = profile["owner_facts"]
|
||||
header = "; ".join(record.get("location") or [])
|
||||
onsite = [
|
||||
part for part in parts if matches(
|
||||
r"(?:role|position|work|must|requires?|requiring).{0,160}"
|
||||
r"(?:full.time onsite|on.site presence|onsite presence|in.office|"
|
||||
r"onsite in|on.site in|\d+ days.{0,25}(?:office|week))|"
|
||||
r"(?:onsite|on.site|hybrid) in |"
|
||||
r"hybrid (?:role|position|schedule|work arrangement)|"
|
||||
r"onsite.{0,50}\d+ days", part,
|
||||
)
|
||||
and not matches(r"no (?:onsite|on.site)|not required", part)
|
||||
]
|
||||
remote = matches(r"\bremote\b", header) or any(matches(
|
||||
r"fully remote|100% remote|remote \(100%\)|"
|
||||
r"(?:role|position|opportunity).{0,60}(?:is remote|remote position)", part
|
||||
) for part in parts)
|
||||
residency = [
|
||||
part for part in parts if matches(
|
||||
r"must reside|must (?:be )?(?:located|based)|residents? of|"
|
||||
r"residency requirement|only.{0,30}candidates.{0,30}(?:state|resid)",
|
||||
part,
|
||||
)
|
||||
]
|
||||
arrangement = "onsite_or_hybrid" if onsite else "remote" if remote else "unknown"
|
||||
result = {
|
||||
"header_location": header or "unknown", "arrangement": arrangement,
|
||||
"onsite_evidence": onsite, "residency_evidence": residency,
|
||||
"gaps": [], "reason": None, "disposition": None,
|
||||
}
|
||||
allowed = set(policy["onsite_states"] + policy["approved_onsite_states"])
|
||||
if onsite:
|
||||
# Explicit presence evidence takes precedence over a Remote header.
|
||||
required_states = states_in(" ".join(onsite)) or states_in(header)
|
||||
if not required_states:
|
||||
result.update(
|
||||
disposition="insufficient_evidence",
|
||||
reason="Onsite/hybrid requirement has no resolved state.",
|
||||
)
|
||||
elif not set(required_states) <= allowed:
|
||||
result.update(
|
||||
disposition="location_conflict",
|
||||
reason="Regular onsite/hybrid work outside approved states: "
|
||||
+ ", ".join(required_states),
|
||||
)
|
||||
if remote:
|
||||
result["gaps"].append("Remote text conflicts with onsite evidence.")
|
||||
elif remote:
|
||||
if "US" not in policy["remote_countries"]:
|
||||
result.update(
|
||||
disposition="location_conflict",
|
||||
reason="US remote work is outside the profile scope.",
|
||||
)
|
||||
for evidence in residency:
|
||||
required_states = states_in(evidence)
|
||||
residence = facts["residence_state"]
|
||||
if required_states and residence != "unknown" and residence not in required_states:
|
||||
result.update(
|
||||
disposition="location_conflict",
|
||||
reason="Confirmed residence is outside the advertised list.",
|
||||
)
|
||||
else:
|
||||
result["gaps"].append("Confirm residency restriction: " + evidence)
|
||||
else:
|
||||
# A city alone proves neither mandatory onsite nor permission for remote.
|
||||
result.update(
|
||||
disposition="insufficient_evidence",
|
||||
reason="Work arrangement is not explicit; do not infer relocation.",
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def owner_gaps(parts, profile):
|
||||
"""Surface explicit requirements without treating unknown facts as failures."""
|
||||
facts = profile["owner_facts"]
|
||||
gaps = []
|
||||
known_conflicts = []
|
||||
checks = (
|
||||
("us_work_authorization_without_sponsorship",
|
||||
r"must.*(?:permanent authorization|authorized)|without sponsorship"),
|
||||
("us_citizenship",
|
||||
r"must.*(?:US citizen|U.S. citizen)|citizenship.*required"),
|
||||
("security_clearance",
|
||||
r"(?:active|required|must).{0,40}security clearance"),
|
||||
("willing_to_travel",
|
||||
r"travel.{0,40}(?:required|must)|must.{0,30}travel"),
|
||||
)
|
||||
for key, pattern in checks:
|
||||
evidence = [part for part in parts if matches(pattern, part)]
|
||||
if evidence and facts[key] != "yes":
|
||||
gaps.append({
|
||||
"fact": key, "owner_value": facts[key], "evidence": evidence,
|
||||
})
|
||||
if facts[key] == "no":
|
||||
known_conflicts.append(key)
|
||||
|
||||
required_section = False
|
||||
for part in parts:
|
||||
if matches(r"^(Preferred Qualifications|Strong Candidates Will Have|Key Responsibilities)", part):
|
||||
required_section = False
|
||||
elif matches(
|
||||
r"^(Required Qualifications|Requirements|Skills.*Qualifications)", part
|
||||
):
|
||||
required_section = True
|
||||
mandatory = required_section or matches(
|
||||
r"\bmust\b|\brequired\b|expert.level", part
|
||||
)
|
||||
if matches(r"certification|certified", part):
|
||||
confirmed = facts["certifications"]
|
||||
if confirmed == "unknown" or not any(
|
||||
item.casefold() in part.casefold() for item in confirmed
|
||||
):
|
||||
gaps.append({
|
||||
"fact": "certifications", "owner_value": "unverified",
|
||||
"requirement_level": "required" if mandatory else "desired_or_unspecified",
|
||||
"evidence": [part],
|
||||
})
|
||||
if not mandatory:
|
||||
continue
|
||||
for skill, pattern in SPECIALIST_SKILLS.items():
|
||||
confirmed = facts["specialist_skills"]
|
||||
if matches(pattern, part) and (
|
||||
confirmed == "unknown" or skill not in confirmed
|
||||
):
|
||||
gaps.append({
|
||||
"fact": "specialist_skills", "skill": skill,
|
||||
"owner_value": "unverified", "evidence": [part],
|
||||
})
|
||||
if matches(r"\d+\+?.{0,8}years", part):
|
||||
# Total tenure cannot prove years in a particular specialty or role.
|
||||
gaps.append({
|
||||
"fact": "role_specific_experience", "owner_value": "unverified",
|
||||
"evidence": [part],
|
||||
})
|
||||
return gaps, known_conflicts
|
||||
|
||||
|
||||
def assess(record, text, parts, profile, as_of):
|
||||
"""Return independent technical and practical assessments with evidence."""
|
||||
stage_one = technical.evaluate(record, text, parts, as_of)
|
||||
family, family_evidence = classify_role(str(record["title"]), parts)
|
||||
family_policy = profile["role_family_policy"][family]
|
||||
geography = geography_assessment(record, parts, profile)
|
||||
gaps, known_conflicts = owner_gaps(parts, profile)
|
||||
domain_hits = [
|
||||
domain for domain in profile["strong_domains"]
|
||||
if domain.casefold() in text.casefold()
|
||||
]
|
||||
# Preserve legacy scores, but allow profile domains absent from old keywords.
|
||||
related = stage_one["exclusion_reason"] is None or (
|
||||
family_policy == "consider" and bool(domain_hits)
|
||||
and stage_one["exclusion_reason"] == "outside_target_scope"
|
||||
)
|
||||
if stage_one["group"] == "Contract":
|
||||
category = "contract"
|
||||
elif matches(r"part.time", " ".join(record.get("employment_type") or [])):
|
||||
category = "part_time_employment"
|
||||
else:
|
||||
category = "full_time_employment"
|
||||
category_allowed = category in profile["opportunity_categories"] or (
|
||||
family == "consulting"
|
||||
and "consulting" in profile["opportunity_categories"]
|
||||
)
|
||||
|
||||
if not related or not category_allowed or family_policy == "exclude":
|
||||
disposition = "out_of_scope"
|
||||
reason = stage_one["exclusion_reason"] or "Profile category/family exclusion."
|
||||
elif geography["disposition"] == "location_conflict":
|
||||
disposition, reason = "location_conflict", geography["reason"]
|
||||
elif family_policy == "specialist_review_only":
|
||||
disposition = "specialist_mismatch"
|
||||
reason = (
|
||||
"Core function is outside the target role families; "
|
||||
"this does not establish that Ken lacks the skills."
|
||||
)
|
||||
elif geography["disposition"]:
|
||||
disposition, reason = geography["disposition"], geography["reason"]
|
||||
elif known_conflicts:
|
||||
disposition = "out_of_scope"
|
||||
reason = "Explicit owner facts conflict with: " + ", ".join(known_conflicts)
|
||||
elif gaps or geography["gaps"]:
|
||||
disposition = "needs_owner_review"
|
||||
reason = "Target work and geography fit; explicit eligibility facts need verification."
|
||||
else:
|
||||
disposition = "practical_match"
|
||||
reason = "Target role and arrangement fit; hiring and terms remain unconfirmed."
|
||||
|
||||
return {
|
||||
"source_id": record["source_id"], "url": record["url"],
|
||||
"title": record["title"], "organization": record.get("organization"),
|
||||
"technical_relevance": {
|
||||
"legacy_score": stage_one["score"],
|
||||
"legacy_exclusion": stage_one["exclusion_reason"],
|
||||
"related": related, "profile_domains": domain_hits,
|
||||
},
|
||||
"role_family": family, "role_evidence": family_evidence,
|
||||
"role_policy": family_policy, "category": category,
|
||||
"disposition": disposition, "reasons": [reason], "geography": geography,
|
||||
"verification_gaps": gaps, "known_owner_conflicts": known_conflicts,
|
||||
"source_conflicts": stage_one["conflicts"],
|
||||
"source_dates": stage_one["source_dates"],
|
||||
"advertised_pay": stage_one["advertised_pay"],
|
||||
"metadata_pay": stage_one["metadata_pay"],
|
||||
"engagement": stage_one["classification"],
|
||||
"qualifications": stage_one["qualifications"],
|
||||
"status": "unreviewed", "hiring_status": "unconfirmed",
|
||||
}
|
||||
|
||||
|
||||
def render_brief(records, summary):
|
||||
"""Render only new practical matches or owner-judgment cases."""
|
||||
lines = [
|
||||
"# W1-019 — Practical opportunity review", "",
|
||||
f"Saved evidence as of {summary['as_of']}; no live collection.", "",
|
||||
"Practical fit is not confirmed hiring, verified pay, or approval to "
|
||||
"apply. Unknown qualifications remain unknown. Existing reviewed "
|
||||
"pipeline records are assessed in the audit but not repeated here.", "",
|
||||
]
|
||||
for record in records:
|
||||
organization = " / ".join(record["organization"] or ["LRS portal"])
|
||||
lines += [
|
||||
f"## {record['source_id']} — {record['title']} — {organization}", "",
|
||||
f"[Original listing]({record['url']})", "",
|
||||
f"- Disposition: **{record['disposition']}**; role: {record['role_family']}.",
|
||||
"- Location: " + record["geography"]["header_location"]
|
||||
+ "; " + record["geography"]["arrangement"] + ".",
|
||||
"- Engagement/pay: " + record["engagement"] + "; "
|
||||
+ ("; ".join(record["advertised_pay"]) or "not established")
|
||||
+ ". Advertised, not verified.",
|
||||
"- Requirements: " + " | ".join(record["qualifications"]),
|
||||
]
|
||||
# Combine repeated unknowns without losing their full audit evidence.
|
||||
groups = {}
|
||||
for gap in record["verification_gaps"]:
|
||||
label = gap.get("skill", gap["fact"])
|
||||
if gap.get("requirement_level") == "desired_or_unspecified":
|
||||
label += " (desired; not established as mandatory)"
|
||||
groups.setdefault(label, []).extend(gap["evidence"])
|
||||
for label, evidence in groups.items():
|
||||
examples = list(dict.fromkeys(evidence))
|
||||
lines.append("- Verify " + label + ": " + " | ".join(examples[:2]))
|
||||
for gap in record["geography"]["gaps"]:
|
||||
lines.append("- Verify location: " + gap)
|
||||
dates = record["source_dates"]
|
||||
lines += [
|
||||
"- Freshness: visible added "
|
||||
+ ", ".join(dates.get("visible_parsed") or ["unknown"])
|
||||
+ "; structured dates " + json.dumps(dates.get("metadata", [])) + ".",
|
||||
"- Metadata compensation: " + json.dumps(record["metadata_pay"]) + ".",
|
||||
"- Source issues: " + ", ".join(record["source_conflicts"]) + ".",
|
||||
"- Next action: Ken reviews eligibility gaps and interest before "
|
||||
"any promotion; confirm current availability and terms separately.", "",
|
||||
]
|
||||
if not records:
|
||||
lines += ["No new candidates meet the current practical review policy.", ""]
|
||||
lines += [
|
||||
"## Review limits", "",
|
||||
"Regular onsite work outside approved states and specialist-function "
|
||||
"mismatches are omitted. Missing work arrangements require source "
|
||||
"clarification, not assumed relocation. Full dispositions, restrictions, "
|
||||
"source conflicts and original records remain in audit.json.", "",
|
||||
]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def execute(run, pipeline_path, profile_path, output, limit=15):
|
||||
"""Verify saved collection bytes and create a separate reproducible audit."""
|
||||
if not 1 <= limit <= 15:
|
||||
raise SourceError("Brief limit must be between 1 and 15")
|
||||
profile = load_profile(profile_path)
|
||||
pipeline_bytes = pipeline_path.read_bytes()
|
||||
pipeline = json.loads(pipeline_bytes.decode("utf-8-sig"))
|
||||
manifest = json.loads((run / "manifest.json").read_text(encoding="utf-8"))
|
||||
records = json.loads((run / "lrs.json").read_text(encoding="utf-8"))
|
||||
if not manifest.get("success") or len(records) != manifest["collected_count"]:
|
||||
raise SourceError("Successful collection and matching record count required")
|
||||
requests = {
|
||||
item["snapshot"]: item for item in manifest["requests"]
|
||||
if "snapshot" in item
|
||||
}
|
||||
as_of = manifest["finished_at"][:10]
|
||||
audit = []
|
||||
seen = set()
|
||||
for record in records:
|
||||
source_id = record["source_id"]
|
||||
if not re.fullmatch(r"\d+", source_id) or identity(record["url"]) != source_id:
|
||||
raise SourceError("Invalid saved requisition identity")
|
||||
if source_id in seen:
|
||||
raise SourceError(f"Duplicate saved requisition: {source_id}")
|
||||
seen.add(source_id)
|
||||
name = source_id + ".html"
|
||||
raw = (run / name).read_bytes()
|
||||
digest = hashlib.sha256(raw).hexdigest()
|
||||
if digest != requests.get(name, {}).get("sha256"):
|
||||
raise SourceError(f"Snapshot hash mismatch: {name}")
|
||||
text, parts = technical.description_parts(raw.decode("utf-8", "replace"))
|
||||
result = assess(record, text, parts, profile, as_of)
|
||||
_, existing = deduplicate([record], pipeline)
|
||||
result["existing_pipeline_records"] = (
|
||||
existing[0]["pipeline_records"] if existing else []
|
||||
)
|
||||
result["reviewable_new_candidate"] = (
|
||||
result["disposition"] in REVIEWABLE and not existing
|
||||
)
|
||||
audit.append({
|
||||
"assessment": result, "original_record": record,
|
||||
"description": text, "description_parts": parts,
|
||||
"snapshot": name, "snapshot_sha256": digest,
|
||||
})
|
||||
practical = [item["assessment"] for item in audit]
|
||||
reviewable = [item for item in practical if item["reviewable_new_candidate"]]
|
||||
reviewable.sort(key=lambda item: (
|
||||
item["disposition"] != "practical_match",
|
||||
-item["technical_relevance"]["legacy_score"], int(item["source_id"]),
|
||||
))
|
||||
counts = Counter(item["disposition"] for item in practical)
|
||||
legacy_counts = Counter(
|
||||
item["technical_relevance"]["legacy_exclusion"] or "relevant"
|
||||
for item in practical
|
||||
)
|
||||
summary = {
|
||||
"version": VERSION, "as_of": as_of, "input_count": len(records),
|
||||
"legacy_technical_dispositions_all_jobs": dict(sorted(legacy_counts.items())),
|
||||
"practical_dispositions_all_jobs": {key: counts[key] for key in DISPOSITIONS},
|
||||
"role_families": dict(sorted(Counter(
|
||||
item["role_family"] for item in practical
|
||||
).items())),
|
||||
"existing_pipeline_records": sum(
|
||||
bool(item["existing_pipeline_records"]) for item in practical
|
||||
),
|
||||
"new_reviewable": len(reviewable), "brief_count": min(limit, len(reviewable)),
|
||||
"brief_deferred": max(0, len(reviewable) - limit),
|
||||
"profile_sha256": hashlib.sha256(profile_path.read_bytes()).hexdigest(),
|
||||
"pipeline_sha256": hashlib.sha256(pipeline_bytes).hexdigest(),
|
||||
"input_sha256": {
|
||||
name: hashlib.sha256((run / name).read_bytes()).hexdigest()
|
||||
for name in ("manifest.json", "lrs.json")
|
||||
},
|
||||
"rules_sha256": {
|
||||
path.name: hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
for path in (Path(__file__), Path(technical.__file__))
|
||||
},
|
||||
"pipeline_unchanged": pipeline_path.read_bytes() == pipeline_bytes,
|
||||
}
|
||||
if not summary["pipeline_unchanged"]:
|
||||
raise SourceError("Pipeline changed during qualification")
|
||||
output.mkdir(parents=True, exist_ok=False)
|
||||
write_json(output / "profile.json", profile)
|
||||
write_json(output / "audit.json", audit)
|
||||
write_json(output / "practical.json", practical)
|
||||
write_json(output / "summary.json", summary)
|
||||
(output / "brief.md").write_text(
|
||||
render_brief(reviewable[:limit], summary), encoding="utf-8"
|
||||
)
|
||||
return summary
|
||||
|
||||
|
||||
def main():
|
||||
"""Run offline practical qualification with explicit owner policy."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--run", type=Path)
|
||||
parser.add_argument("--pipeline", type=Path, default=PIPELINE)
|
||||
parser.add_argument("--profile", type=Path, default=PROFILE)
|
||||
parser.add_argument("--output", type=Path)
|
||||
parser.add_argument("--limit", type=int, default=15)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
run = args.run or technical.latest_run()
|
||||
output = args.output or run / "qualification-W1-019"
|
||||
summary = execute(run, args.pipeline, args.profile, output, args.limit)
|
||||
except (OSError, ValueError, KeyError) as error:
|
||||
raise SystemExit(f"ERROR: {error}") from error
|
||||
print(json.dumps(summary, indent=2))
|
||||
print(f"Brief: {output / 'brief.md'}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
"""Practical eligibility, owner uncertainty and saved-run preservation tests."""
|
||||
|
||||
import copy
|
||||
import json
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from context import FIXTURES
|
||||
from test_qualification import record
|
||||
from opportunity_intelligence.collectors.lrs import SourceError
|
||||
from opportunity_intelligence.qualification import practical
|
||||
|
||||
|
||||
class PracticalTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.profile = practical.load_profile(practical.PROFILE)
|
||||
|
||||
def assess(self, title="Cloud Architect", location="Remote", parts=None):
|
||||
candidate = record(title=title)
|
||||
candidate["location"] = [location]
|
||||
parts = parts or ["Lead Azure cloud architecture and modernization."]
|
||||
return practical.assess(
|
||||
candidate, " ".join(parts), parts, self.profile, "2026-09-17"
|
||||
)
|
||||
|
||||
def test_remote_architecture(self):
|
||||
self.assertEqual(self.assess()["disposition"], "practical_match")
|
||||
|
||||
def test_remote_developer_is_specialist(self):
|
||||
result = self.assess("Software Developer AI")
|
||||
self.assertEqual(result["role_family"], "software_development")
|
||||
self.assertEqual(result["disposition"], "specialist_mismatch")
|
||||
|
||||
def test_onsite_outside_tennessee(self):
|
||||
result = self.assess(location="Minneapolis, MN", parts=[
|
||||
"Enterprise architecture.", "This role requires 4 days in office."
|
||||
])
|
||||
self.assertEqual(result["disposition"], "location_conflict")
|
||||
|
||||
def test_tennessee_onsite(self):
|
||||
result = self.assess(location="Nashville, TN", parts=[
|
||||
"Azure cloud architecture.", "Onsite in Nashville, TN."
|
||||
])
|
||||
self.assertEqual(result["disposition"], "practical_match")
|
||||
|
||||
def test_ambiguous_work_arrangement(self):
|
||||
result = self.assess(location="Nashville, TN")
|
||||
self.assertEqual(result["disposition"], "insufficient_evidence")
|
||||
|
||||
def test_unknown_certification_is_not_failure(self):
|
||||
result = self.assess(parts=[
|
||||
"Azure architecture.", "Azure Solutions Architect certification required."
|
||||
])
|
||||
self.assertEqual(result["disposition"], "needs_owner_review")
|
||||
self.assertEqual(result["verification_gaps"][0]["fact"], "certifications")
|
||||
self.assertEqual(result["known_owner_conflicts"], [])
|
||||
|
||||
def test_specialist_with_architecture_keywords(self):
|
||||
for title in ("Salesforce Architect", "LifePRO Configuration Consultant"):
|
||||
with self.subTest(title=title):
|
||||
result = self.assess(title)
|
||||
self.assertEqual(result["role_family"], "other_specialist_roles")
|
||||
self.assertEqual(result["disposition"], "specialist_mismatch")
|
||||
|
||||
def test_builder_description_overrides_architect_title(self):
|
||||
result = self.assess("AI/ML Platform Architect", parts=[
|
||||
"AI architecture. Must have actually built or trained ML models."
|
||||
])
|
||||
self.assertEqual(result["role_family"], "data_science_ml_engineering")
|
||||
self.assertEqual(result["disposition"], "specialist_mismatch")
|
||||
|
||||
def test_remote_restrictions_preserved(self):
|
||||
parts = ["Azure architecture.", "Candidates must reside in Wisconsin or Illinois."]
|
||||
result = self.assess(parts=parts)
|
||||
self.assertEqual(result["disposition"], "needs_owner_review")
|
||||
self.assertIn(parts[1], result["geography"]["residency_evidence"])
|
||||
self.profile["owner_facts"]["residence_state"] = "TN"
|
||||
self.assertEqual(self.assess(parts=parts)["disposition"], "location_conflict")
|
||||
|
||||
def test_owner_can_explicitly_permit_other_onsite_states(self):
|
||||
self.profile["geography"]["approved_onsite_states"] = ["MN"]
|
||||
self.assertEqual(self.assess(location="Minneapolis, MN", parts=[
|
||||
"Azure architecture.", "Onsite in Minneapolis, MN."
|
||||
])["disposition"], "practical_match")
|
||||
|
||||
def test_desired_certifications_are_labeled(self):
|
||||
result = self.assess(parts=[
|
||||
"Azure architecture.", "Requirements:", "Cloud leadership.",
|
||||
"Strong Candidates Will Have:", "TOGAF Certification"
|
||||
])
|
||||
self.assertEqual(result["verification_gaps"][0]["requirement_level"],
|
||||
"desired_or_unspecified")
|
||||
|
||||
def test_reliable_expiry_and_historical_conflicts(self):
|
||||
result = self.assess(parts=["Azure architecture.",
|
||||
"Application deadline: 2026-09-01"])
|
||||
self.assertEqual(result["disposition"], "out_of_scope")
|
||||
result = self.assess()
|
||||
self.assertIn("historical_metadata_expiry_not_confirmed_closed",
|
||||
result["source_conflicts"])
|
||||
self.assertEqual(result["hiring_status"], "unconfirmed")
|
||||
|
||||
def test_malformed_profile_fails_visibly(self):
|
||||
profile = copy.deepcopy(self.profile)
|
||||
profile["owner_facts"]["certifications"] = True
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
path = Path(directory) / "profile.json"
|
||||
path.write_text(json.dumps(profile), encoding="utf-8")
|
||||
with self.assertRaises(SourceError):
|
||||
practical.load_profile(path)
|
||||
|
||||
def test_saved_run_reproducible_and_reviewed_pipeline_unchanged(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
pipeline = root / "opportunities.json"
|
||||
original = (FIXTURES / "opportunities.json").read_bytes()
|
||||
pipeline.write_bytes(original)
|
||||
outputs = [root / "first", root / "second"]
|
||||
for output in outputs:
|
||||
summary = practical.execute(
|
||||
FIXTURES / "lrs-run", pipeline, practical.PROFILE, output
|
||||
)
|
||||
self.assertEqual(summary["input_count"], 87)
|
||||
self.assertEqual(summary["existing_pipeline_records"], 3)
|
||||
self.assertTrue(summary["pipeline_unchanged"])
|
||||
self.assertEqual(pipeline.read_bytes(), original)
|
||||
for path in outputs[0].iterdir():
|
||||
self.assertEqual(path.read_bytes(), (outputs[1] / path.name).read_bytes())
|
||||
records = json.loads((outputs[0] / "practical.json").read_text())
|
||||
existing = [r for r in records if r["existing_pipeline_records"]]
|
||||
self.assertEqual(len(existing), 3)
|
||||
self.assertTrue(all(not r["reviewable_new_candidate"] for r in existing))
|
||||
self.assertTrue(all(r["status"] == "unreviewed" for r in records))
|
||||
with self.assertRaises(FileExistsError):
|
||||
practical.execute(
|
||||
FIXTURES / "lrs-run", pipeline, practical.PROFILE, outputs[0]
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -14,15 +14,16 @@ def main():
|
||||
"usac": "opportunity_intelligence.collectors.usac",
|
||||
"lrs": "opportunity_intelligence.collectors.lrs",
|
||||
"qualify": "opportunity_intelligence.qualification.lrs",
|
||||
"practical": "opportunity_intelligence.qualification.practical",
|
||||
}
|
||||
if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help"):
|
||||
print("Usage: python w1.py {usac,lrs,qualify} [options]")
|
||||
print("Usage: python w1.py {usac,lrs,qualify,practical} [options]")
|
||||
print("Use a command followed by --help for its existing options.")
|
||||
return
|
||||
|
||||
command = sys.argv.pop(1)
|
||||
if command not in commands:
|
||||
raise SystemExit(f"Unknown command {command!r}; choose usac, lrs or qualify.")
|
||||
raise SystemExit(f"Unknown command {command!r}; choose usac, lrs, qualify or practical.")
|
||||
runpy.run_module(commands[command], run_name="__main__")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user