Skip to content

feat(assistant): candidate selection with Claude assessor and read model columns (PR 3a) - #9

Merged
jcmoro merged 1 commit into
mainfrom
feature/assistant-recommend
Oct 27, 2026
Merged

jcmoro merged 1 commit into
mainfrom
feature/assistant-recommend

Conversation

@jcmoro

@jcmoro jcmoro commented Oct 27, 2026

Copy link
Copy Markdown
Owner

Qué

PR 3a del plan (docs/plan-assistant-genai.md): read model y selección de candidatos. Todavía no tiene punto de entrada: RecommendCandidate solo lo ejercitan sus tests hasta que el PR 3b añada la herramienta del agente. No cambia ningún comportamiento existente.

  • Read model: la migración ff5e81205e1e añade a product_documents las columnas sku (índice único), name, price_cents y currency.
    • Las rellena IndexCatalog desde el DTO del catálogo.
    • Las filas a las que les falta alguna columna cuentan como cambiadas, así que el reindexado las rellena.
    • Los huérfanos confirmados se borran antes del upsert, para que un SKU reutilizado no choque con el índice único.
  • Selección: el modelo lee y el código decide.
    • Cada candidato se evalúa por separado con una rúbrica de dos noul: meets_requirements (filtro) y suitable_for_use (ordenación).
    • select es una función pura: filtra, ordena, desempata por retrieval_score y después por product_id, y aplica los umbrales con >=.
  • ClaudeCandidateAssessor:
    • usa salida estructurada con 3 muestras y la frecuencia del «sí» como probabilidad;
    • aplica un límite de concurrencia por llamada;
    • usa effort: "low" y selector_max_tokens = 1024;
    • comparte la clasificación de errores con el adaptador del PR 1.
  • RecommendCandidate:
    • pasa al evaluador solo el top selector_top_n;
    • aplica un plazo global;
    • si se cancela la petición, cancela todas las evaluaciones;
    • un error de configuración se propaga en el acto;
    • si no se puede evaluar ningún candidato, devuelve un fallback determinista;
    • escribe una línea de log por selección, solo con ids y con la razón de cada candidato sin evaluar.

Especificación, decisiones con su porqué, criterios A1–A12 y evidencia: docs/step-17-assistant-recommend.md.

Code review

/code-review medium dio 10 hallazgos, y se comprobó cada uno contra el código. Se aplicaron 6, cada uno con un test que fallaba antes:

# Corrección Rojo → verde
CR1 Concurrencia por llamada; las muestras de un candidato salen juntas Con llamadas lentas, 0 candidatos evaluados → algunos evaluados
CR2 Un candidato solo participa con las 3 muestras válidas; razones invalid_sample / error / deadline en el log Una muestra inválida daba 0,67 → sin evaluar
CR3 Cancelar todo al cancelar la petición; cortar en el acto ante un error de configuración Esperaba el plazo entero y cancelaba 0 de 3 → inmediato y 3 de 3
CR4 El error transitorio lleva el uso acumulado (AssessmentUnavailableError) Se perdían los tokens → se suman
CR5 Fuera los proveedores sin uso; en el 3b, un solo cliente de Anthropic grep
CR6 selector_max_tokens propio (1024); un corte por max_tokens es una muestra inválida El setting no existía

Los 3 falsos positivos y sus motivos están en el doc.

Verificación

  • make lint: ruff OK, pylint 10.00/10, mypy strict sin errores (80 ficheros).
  • make test: 192 passed (antes 137).
  • make reindex real tras la migración: indexed=3 unchanged=0 deleted=0 (relleno) y después indexed=0 unchanged=3 deleted=0.
  • catalog sin cambios; los e2e del PR 2 sin cambios; ningún type: ignore, noqa ni pylint: disable nuevo.
  • En este PR no hay ninguna llamada real a Anthropic: el evaluador se prueba con httpx2.MockTransport.

Al desplegar

Aplicar la migración ff5e81205e1e y ejecutar make reindex una vez, para rellenar las columnas nuevas.

🤖 Generated with Claude Code

@jcmoro
jcmoro merged commit 3f562bc into main Oct 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants