services/api/src/modules/match/match-response.js
Overview
Este archivo define el mapeo público de Match para candidatos internos. Su trabajo es traducir un candidato ya calculado a una metadata segura para cruzar el límite HTTP, sin exponer la estructura interna completa del motor.
La lógica del módulo es deliberadamente restrictiva. Solo publica presentationState, warningCode, matchedCriteria, differenceCriteria y pendingCriteria. No reexpone signals, blockers completos, ni valores internos como score, porcentaje o presentationPosition.
[!IMPORTANT] Este archivo no decide presentabilidad ni orden por sí mismo. Solo serializa información ya resuelta por otras partes del flujo, y reusa
candidate-presentation.jscomo fuente de verdad para el estado y la advertencia.
How it works
flowchart TB
Candidate[Candidato interno de Match]
Presentation[candidate-presentation.js]
WarningMap[resolveWarningCode]
CriteriaMap[mapSignalsToCriteriaCodes]
PublicMeta[toPublicMatchMetadata]
PublicOut[Metadata publica]
Candidate --> Presentation
Candidate --> WarningMap
Candidate --> CriteriaMap
Presentation --> PublicMeta
WarningMap --> PublicMeta
CriteriaMap --> PublicMeta
PublicMeta --> PublicOut
El flujo parte de un candidato interno producido por Match. Primero, toPublicMatchMetadata() obtiene el presentationState con getCandidatePresentationState(). Luego evalúa si aplica un warningCode con isApprovedBudgetWarningCandidate() y, si corresponde, lo resuelve con resolveWarningCode().
Después, el módulo traduce señales internas a códigos públicos de criterio. Lo hace con listas de outcomes permitidos y con allowlists explícitas de campos. Si un campo o un reason interno no está mapeado, el módulo lo omite o falla de forma ruidosa, según el caso.
[!NOTE] La conversión es por allowlist, no por redacción sustractiva. El módulo construye cada campo público de forma explícita.
Key components
{
"title": "resolveWarningCode",
"content": "Funci\u00f3n interna que traduce el reason interno de un blocker de price a un c\u00f3digo p\u00fablico de warning. Solo se usa cuando el candidato ya est\u00e1 confirmado como budget_warning.",
"type": "function",
"filePath": "services/api/src/modules/match/match-response.js",
"badges": []
}
{
"title": "mapSignalsToCriteriaCodes",
"content": "Funci\u00f3n interna que filtra signals por outcomes permitidos y traduce sus fields a c\u00f3digos p\u00fablicos de criterio. Ignora outcomes y fields no permitidos.",
"type": "function",
"filePath": "services/api/src/modules/match/match-response.js",
"badges": []
}
{
"title": "toPublicMatchMetadata",
"content": "Funci\u00f3n p\u00fablica que convierte un candidato interno en la metadata p\u00fablica de Match. Devuelve el estado de presentaci\u00f3n, el warningCode y las listas p\u00fablicas de criterios.",
"type": "function",
"filePath": "services/api/src/modules/match/match-response.js",
"badges": [
"public"
]
}
Data & fields
[
{
"name": "candidate",
"type": "object",
"required": true,
"description": "Candidato interno de Match ya generado por evaluateCandidatePair() y generateCandidatesForRequirement().",
"children": [
{
"name": "signals",
"type": "array<object>",
"description": "Se usa para construir matchedCriteria y pendingCriteria."
},
{
"name": "blockers",
"type": "array<object>",
"description": "Se usa para construir differenceCriteria y warningCode cuando el estado lo permite.",
"children": [
{
"name": "field",
"type": "string",
"description": "Nombre interno del campo bloqueante."
},
{
"name": "outcome",
"type": "string",
"description": "Outcome interno del blocker."
},
{
"name": "reason",
"type": "string",
"description": "Reason interno usado solo para el warning de presupuesto."
}
]
}
]
},
{
"name": "presentationState",
"type": "string",
"required": true,
"description": "Estado público devuelto por getCandidatePresentationState()."
},
{
"name": "warningCode",
"type": "string|null",
"description": "Código público de warning. Solo existe para candidatos aprobados como budget_warning."
},
{
"name": "matchedCriteria",
"type": "array<object>",
"required": true,
"description": "Criterios públicos construidos a partir de signals con outcome pass.",
"children": [
{
"name": "code",
"type": "string",
"required": true,
"description": "Código público del criterio."
}
]
},
{
"name": "differenceCriteria",
"type": "array<object>",
"required": true,
"description": "Criterios públicos que explican una diferencia conocida y aprobada. Solo aplica a budget_warning y alternative.",
"children": [
{
"name": "code",
"type": "string",
"required": true,
"description": "Código público del criterio diferencial."
}
]
},
{
"name": "pendingCriteria",
"type": "array<object>",
"required": true,
"description": "Criterios públicos construidos a partir de signals con outcome pending_unknown o pending_gate.",
"children": [
{
"name": "code",
"type": "string",
"required": true,
"description": "Código público del criterio pendiente."
}
]
}
]
Códigos de warning
El módulo traduce reason internos a códigos públicos mediante una allowlist fija. Solo reconoce dos razones internas para budget_warning.
ABOVE_BUDGET_MAX→BUDGET_ABOVE_DECLARED_MAXBELOW_BUDGET_MIN→BUDGET_BELOW_DECLARED_MIN
Códigos de criterio
El módulo también traduce field internos a códigos públicos de criterio.
propertyType→PROPERTY_TYPEprice→PRICEterm→RENTAL_TERMlocation→GEOGRAPHYbedrooms→BEDROOMSbathrooms→BATHROOMShalfBathrooms→HALF_BATHROOMSparkingSpots→PARKING_SPOTSconstructionArea→CONSTRUCTION_AREAlandArea→LAND_AREAfrontage→FRONTAGEdepth→DEPTHwater→WATER_INFRASTRUCTUREelectricity→ELECTRICITY_INFRASTRUCTUREdrainage→DRAINAGE_INFRASTRUCTURE
Outcomes admitidos
pass→ entra enmatchedCriteriapending_unknown→ entra enpendingCriteriapending_gate→ entra enpendingCriteria
Estados con diferencia conocida
budget_warningalternative
El archivo documenta, pero no expone, varios datos internos de Match.
signalscrudos no se publican.blockerscrudos no se publican.pendingRequiredno se publica.pendingGatesno se publica.unknownsno se publica.notApplicableno se publica.evidenceno se publica.requirementValueno se publica.offerValueno se publica.hardFailno se publica.contributesToRankingno se publica.scoreno se publica.porcentajeno se publica.presentationPositionno se publica.
Behaviors
resolveWarningCode()— Busca el blocker deprice, lee sureasoninterno y devuelve el código público correspondiente.mapSignalsToCriteriaCodes()— Recorre una lista de signals, filtra por outcomes permitidos y devuelve códigos públicos de criterio.toPublicMatchMetadata()— Construye el objeto público final con estado, warning y listas de criterios.
Workflows
- El candidato llega desde la lógica interna de Match.
getCandidatePresentationState()determina elpresentationState.isApprovedBudgetWarningCandidate()valida si existe un warning público.resolveWarningCode()traduce el reason interno de presupuesto, si aplica.mapSignalsToCriteriaCodes()convierte señales internas en criterios públicos.toPublicMatchMetadata()devuelve la metadata pública final.
[!WARNING]
resolveWarningCode()lanza un error si aparece unreasonno mapeado. El módulo no inventa un código público nuevo.
[!IMPORTANT]
toPublicMatchMetadata()no filtra candidatoshidden. El filtrado previo pertenece al caller, tal como indica el código.
Gotchas & edge cases
[!WARNING] Si
candidate.blockerscontiene unreasondesconocido parabudget_warning, el módulo falla con unError. Esto evita exponer un reason interno sin contrato público.
[!NOTE]
differenceCriteriasolo se calcula parabudget_warningyalternative. En otros estados, devuelve una lista vacía.
[!NOTE] El criterio
amenitiesqueda fuera del mapeo público. El archivo asume que su resultado no producepassnipending_*.
[!CAUTION]
mapSignalsToCriteriaCodes()ignora cualquierfieldno incluido en la allowlist. El campo no se publica, aunque exista dentro del candidato interno.
Related
Este módulo depende directamente de ./candidate-presentation.js. Allí se define la fuente de verdad para getCandidatePresentationState() e isApprovedBudgetWarningCandidate(). El comentario del archivo también lo conecta con evaluateCandidatePair() y generateCandidatesForRequirement(), que producen el candidato interno que luego se traduce aquí.
También está relacionado con la capa de comparación y generación de Match, porque los campos públicos salen de los signals que esas piezas producen. En la superficie pública, este archivo actúa como frontera de serialización entre el motor interno y la respuesta HTTP.