fix: relax Apec input and write flow
This commit is contained in:
parent
352dfcd6ce
commit
207d5c51c3
@ -5,14 +5,6 @@ def _normalize_term(raw_term: str) -> str:
|
||||
return " ".join(raw_term.split())
|
||||
|
||||
|
||||
def _normalize_constraint(raw_term: str) -> str:
|
||||
term = _normalize_term(raw_term)
|
||||
if term.lower().endswith(" only"):
|
||||
return term[:-5].rstrip()
|
||||
|
||||
return term
|
||||
|
||||
|
||||
def derive_apec_queries(profile: CandidateProfileOutput) -> list[str]:
|
||||
queries: list[str] = []
|
||||
seen: set[str] = set()
|
||||
@ -35,28 +27,22 @@ def derive_apec_queries(profile: CandidateProfileOutput) -> list[str]:
|
||||
|
||||
support_terms = [_normalize_term(term) for term in profile.strengths]
|
||||
support_terms.extend(_normalize_term(term) for term in profile.skills_to_emphasize)
|
||||
support_terms.extend(_normalize_constraint(term) for term in profile.constraints)
|
||||
|
||||
support_terms = [term for term in support_terms if term]
|
||||
|
||||
if support_terms:
|
||||
for target_role in unique_roles[:2]:
|
||||
add_query(target_role)
|
||||
for target_role in unique_roles:
|
||||
add_query(target_role)
|
||||
if len(queries) == 5:
|
||||
return queries
|
||||
|
||||
if unique_roles:
|
||||
primary_role = unique_roles[0]
|
||||
for term in support_terms:
|
||||
add_query(f"{primary_role} {term}")
|
||||
if len(queries) == 5:
|
||||
break
|
||||
else:
|
||||
for term in support_terms:
|
||||
add_query(term)
|
||||
if len(queries) == 5:
|
||||
break
|
||||
if unique_roles:
|
||||
primary_role = unique_roles[0]
|
||||
for term in support_terms:
|
||||
add_query(f"{primary_role} {term}")
|
||||
if len(queries) == 5:
|
||||
break
|
||||
else:
|
||||
for target_role in unique_roles[:5]:
|
||||
add_query(target_role)
|
||||
for term in support_terms:
|
||||
add_query(term)
|
||||
if len(queries) == 5:
|
||||
break
|
||||
|
||||
|
||||
@ -108,10 +108,8 @@ def fetch_apec(
|
||||
data_root: Path = typer.Option(
|
||||
Path("data"),
|
||||
"--data-root",
|
||||
exists=True,
|
||||
file_okay=False,
|
||||
dir_okay=True,
|
||||
readable=True,
|
||||
help="Directory containing candidate-profile.yaml and Apec run artifacts.",
|
||||
),
|
||||
) -> None:
|
||||
@ -211,11 +209,20 @@ def fetch_apec(
|
||||
listing_errors=listing_errors,
|
||||
)
|
||||
|
||||
artifact_write_errors: list[str] = []
|
||||
|
||||
try:
|
||||
_write_yaml(paths["listings"], [listing.model_dump(mode="json") for listing in deduplicated_listings])
|
||||
except OSError as exc: # pragma: no cover - defensive boundary
|
||||
artifact_write_errors.append(f"listings.yaml: {exc}")
|
||||
|
||||
try:
|
||||
_write_yaml(paths["run_meta"], run_meta.model_dump(mode="json"))
|
||||
except OSError as exc: # pragma: no cover - defensive boundary
|
||||
typer.echo(f"Unable to write Apec run artifacts: {exc}", err=True)
|
||||
artifact_write_errors.append(f"run-meta.yaml: {exc}")
|
||||
|
||||
if artifact_write_errors:
|
||||
typer.echo(f"Unable to write Apec run artifacts: {'; '.join(artifact_write_errors)}", err=True)
|
||||
raise typer.Exit(code=1)
|
||||
|
||||
typer.echo(
|
||||
|
||||
@ -22,9 +22,9 @@ def test_derive_apec_queries_preserves_order_dedupes_and_caps_at_five() -> None:
|
||||
assert queries == [
|
||||
"Data Engineer",
|
||||
"Analytics Engineer",
|
||||
"Data Engineer Python",
|
||||
"Data Engineer SQL",
|
||||
"Data Engineer BigQuery",
|
||||
"BI Engineer",
|
||||
"Junior Data Platform Engineer",
|
||||
"ML Engineer",
|
||||
]
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ def test_derive_apec_queries_uses_up_to_five_target_roles_when_no_support_terms_
|
||||
]
|
||||
|
||||
|
||||
def test_derive_apec_queries_includes_constraints_in_support_term_queries() -> None:
|
||||
def test_derive_apec_queries_uses_support_terms_without_constraints() -> None:
|
||||
profile = CandidateProfileOutput(
|
||||
target_roles=["Data Engineer"],
|
||||
strengths=["Python"],
|
||||
@ -65,6 +65,4 @@ def test_derive_apec_queries_includes_constraints_in_support_term_queries() -> N
|
||||
"Data Engineer",
|
||||
"Data Engineer Python",
|
||||
"Data Engineer BigQuery",
|
||||
"Data Engineer CDI",
|
||||
"Data Engineer France",
|
||||
]
|
||||
|
||||
@ -95,21 +95,19 @@ def _snapshot_meta(
|
||||
|
||||
|
||||
def test_fetch_apec_fails_cleanly_when_candidate_profile_is_missing(tmp_path, monkeypatch) -> None:
|
||||
data_root = tmp_path / "data"
|
||||
data_root.mkdir()
|
||||
|
||||
class SpyApecAdapter:
|
||||
def __init__(self, max_listings: int = 50) -> None:
|
||||
raise AssertionError("adapter should not be created when the profile is missing")
|
||||
|
||||
monkeypatch.chdir(tmp_path)
|
||||
monkeypatch.setattr("job_research.cli.ApecAdapter", SpyApecAdapter)
|
||||
|
||||
result = CliRunner().invoke(app, ["fetch-apec", "--data-root", str(data_root)])
|
||||
result = CliRunner().invoke(app, ["fetch-apec"])
|
||||
|
||||
assert result.exit_code == 1
|
||||
assert "candidate-profile.yaml" in result.stderr
|
||||
assert "Traceback" not in result.stderr
|
||||
assert not (data_root / "apec").exists()
|
||||
assert not (tmp_path / "data").exists()
|
||||
|
||||
|
||||
def test_fetch_apec_fails_cleanly_when_candidate_profile_yaml_is_malformed(
|
||||
@ -341,6 +339,14 @@ def test_fetch_apec_reports_final_artifact_write_failures_cleanly(
|
||||
assert adapter.search_calls == [["Role From YAML"]]
|
||||
assert adapter.fetch_calls == ["https://example.test/job/123"]
|
||||
|
||||
run_dir = data_root / "apec" / "runs" / "2026-06-01T10-00-00Z"
|
||||
if failing_filename == "listings.yaml":
|
||||
assert not (run_dir / "listings.yaml").exists()
|
||||
assert (run_dir / "run-meta.yaml").exists()
|
||||
else:
|
||||
assert (run_dir / "listings.yaml").exists()
|
||||
assert not (run_dir / "run-meta.yaml").exists()
|
||||
|
||||
|
||||
def test_fetch_apec_reads_profile_and_writes_run_artifacts(tmp_path, monkeypatch) -> None:
|
||||
data_root = tmp_path / "data"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user