fix(ci): restore green backend CI — ruff config + unused import cleanup #117

Merged
pyr0ball merged 6 commits from fix/ci-ruff-lint into main 2026-05-21 12:05:51 -07:00
13 changed files with 97 additions and 22 deletions
Showing only changes of commit 7dcdf551fc - Show all commits

View file

@ -14,7 +14,6 @@ Enhanced features:
import argparse
import csv
import json
import os
import random
import re

View file

@ -31,7 +31,6 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
from scripts.classifier_adapters import (
LABELS,
LABEL_DESCRIPTIONS,
ClassifierAdapter,
GLiClassAdapter,
RerankerAdapter,

View file

@ -5,7 +5,6 @@ push updates the existing event rather than creating a duplicate.
"""
from __future__ import annotations
import uuid
import yaml
from datetime import datetime, timedelta, timezone
from pathlib import Path

View file

@ -121,6 +121,17 @@ CREATE TABLE IF NOT EXISTS survey_responses (
);
"""
CREATE_RESUME_CORRECTIONS = """
CREATE TABLE IF NOT EXISTS resume_optimizer_corrections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
job_id INTEGER NOT NULL REFERENCES jobs(id),
section TEXT NOT NULL,
proposed_json TEXT NOT NULL,
accepted_json TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
);
"""
CREATE_DIGEST_QUEUE = """
CREATE TABLE IF NOT EXISTS digest_queue (
id INTEGER PRIMARY KEY,
@ -205,9 +216,10 @@ def _migrate_db(db_path: Path) -> None:
conn.execute("ALTER TABLE background_tasks ADD COLUMN params TEXT")
except sqlite3.OperationalError:
pass # column already exists
# Ensure references tables exist (CREATE IF NOT EXISTS is idempotent)
# Ensure tables that can't be added via ALTER TABLE exist (all idempotent).
conn.execute(CREATE_REFERENCES)
conn.execute(CREATE_JOB_REFERENCES)
conn.execute(CREATE_RESUME_CORRECTIONS)
conn.commit()
conn.close()
@ -223,6 +235,7 @@ def init_db(db_path: Path = DEFAULT_DB) -> None:
conn.execute(CREATE_DIGEST_QUEUE)
conn.execute(CREATE_REFERENCES)
conn.execute(CREATE_JOB_REFERENCES)
conn.execute(CREATE_RESUME_CORRECTIONS)
conn.commit()
conn.close()
_migrate_db(db_path)
@ -1241,3 +1254,76 @@ def set_training_exclusion(db_path: Path, job_id: int, excluded: bool) -> None:
conn.commit()
finally:
conn.close()
# ── Resume optimizer corrections ──────────────────────────────────────────────
def save_resume_correction(
db_path: Path,
job_id: int,
section: str,
proposed: object,
accepted: object,
) -> None:
"""Persist a (proposed, accepted) correction pair from the resume review UI.
Called when a user edits an LLM-proposed value and accepts it. The pair
becomes a supervised fine-tuning (SFT) candidate routed through Avocet.
Args:
section: 'summary' or 'experience:<title>|<company>'
proposed: Original LLM output (string for summary, list for bullets).
accepted: User-edited value (same type as proposed).
"""
import json as _json
conn = sqlite3.connect(db_path)
try:
conn.execute(
"""INSERT INTO resume_optimizer_corrections
(job_id, section, proposed_json, accepted_json)
VALUES (?, ?, ?, ?)""",
(job_id, section, _json.dumps(proposed), _json.dumps(accepted)),
)
conn.commit()
finally:
conn.close()
def get_resume_corrections(
db_path: Path,
limit: int = 200,
job_id: int | None = None,
) -> list[dict]:
"""Return pending resume corrections for Avocet export.
Args:
limit: Maximum rows to return.
job_id: If set, filter to corrections for a specific job.
"""
import json as _json
conn = sqlite3.connect(db_path)
conn.row_factory = sqlite3.Row
try:
if job_id is not None:
rows = conn.execute(
"SELECT * FROM resume_optimizer_corrections WHERE job_id=? ORDER BY created_at DESC LIMIT ?",
(job_id, limit),
).fetchall()
else:
rows = conn.execute(
"SELECT * FROM resume_optimizer_corrections ORDER BY created_at DESC LIMIT ?",
(limit,),
).fetchall()
finally:
conn.close()
return [
{
"id": r["id"],
"job_id": r["job_id"],
"section": r["section"],
"proposed": _json.loads(r["proposed_json"]),
"accepted": _json.loads(r["accepted_json"]),
"created_at": r["created_at"],
}
for r in rows
]

View file

@ -186,7 +186,7 @@ def build_prompt(
)
parts.append(f"{recruiter_note}\n")
parts.append(f"Now write a new cover letter for:")
parts.append("Now write a new cover letter for:")
parts.append(f" Role: {title}")
parts.append(f" Company: {company}")
if description:

View file

@ -1,5 +1,5 @@
from __future__ import annotations
from datetime import datetime, timedelta, timezone
from datetime import datetime
from scripts.integrations.base import IntegrationBase

View file

@ -25,7 +25,6 @@ import argparse
import shutil
import sys
from pathlib import Path
from textwrap import dedent
import yaml

View file

@ -348,14 +348,14 @@ def write_compose_override(ports: dict[str, dict]) -> None:
for name, info in to_disable.items():
lines += [
f" {name}: # adopted — host service on :{info['resolved']}",
f" entrypoint: [\"/bin/sh\", \"-c\", \"sleep infinity\"]",
f" ports: []",
f" healthcheck:",
f" test: [\"CMD\", \"true\"]",
f" interval: 1s",
f" timeout: 1s",
f" start_period: 0s",
f" retries: 1",
" entrypoint: [\"/bin/sh\", \"-c\", \"sleep infinity\"]",
" ports: []",
" healthcheck:",
" test: [\"CMD\", \"true\"]",
" interval: 1s",
" timeout: 1s",
" start_period: 0s",
" retries: 1",
]
OVERRIDE_YML.write_text("\n".join(lines) + "\n")

View file

@ -19,7 +19,6 @@ from __future__ import annotations
import json
import logging
import re
from pathlib import Path
from typing import Any
log = logging.getLogger(__name__)

View file

@ -9,11 +9,9 @@ Falls back to empty dict on unrecoverable errors — caller shows the form build
from __future__ import annotations
import io
import json
import logging
import re
import zipfile
from pathlib import Path
from xml.etree import ElementTree as ET
import pdfplumber

View file

@ -7,7 +7,6 @@ FastAPI application. Callable directly or via the survey_analyze background task
from __future__ import annotations
import json
import logging
from pathlib import Path
from typing import Optional

View file

@ -341,7 +341,6 @@ def _run_task(db_path: Path, task_id: int, task_type: str, job_id: int,
prioritize_gaps,
rewrite_for_ats,
hallucination_check,
render_resume_text,
)
from scripts.user_profile import load_user_profile

View file

@ -15,13 +15,11 @@ Public API (unchanged — callers do not need to change):
from __future__ import annotations
import logging
import os
import threading
from pathlib import Path
from typing import Callable, Optional
from circuitforge_core.tasks.scheduler import (
TaskSpec, # re-export unchanged
LocalScheduler as _CoreTaskScheduler,
)