services/api/src/modules/reconciliation/erasing-claim-evidence.js
Overview
Este módulo define la evidencia pura y determinista para reconciliar asignaciones MediaFileClaim que quedaron en erasing. No realiza E/S, no usa dependencias externas y solo transforma datos en decisiones. Su objetivo es separar la evidencia de identidad, la elegibilidad de la asignación y la clasificación de observaciones del proveedor.
[!NOTE] El módulo no decide la reconciliación completa. Solo produce evidencia y estados de clasificación que otra capa consume.
How it works
flowchart TD
LSP[listingScopePrefixes]
PFI[persistedFileIdentity]
SI[sameInstant]
ECE[erasingClaimEligibility]
PPE[PROVIDER_EVIDENCE]
CPE[classifyProviderEvidence]
LSP --> PFI
PFI --> ECE
SI --> ECE
PPE --> CPE
Primero, el módulo construye prefijos seguros de ámbito para un Listing. Después, valida si fileId tiene identidad persistida dentro de ese ámbito. Luego comprueba si una asignación sigue siendo elegible para reconciliación. Finalmente, clasifica las observaciones del proveedor como EXISTS, NOT_FOUND_CONFIRMED o UNKNOWN. El flujo de clasificación exige una secuencia coherente, con referencia confirmada y observaciones consistentes. fileciteturn0file1turn0file13
Key components
{
"title": "PROVIDER_EVIDENCE",
"content": "Conjunto congelado de estados de evidencia del proveedor. Expone EXISTS, NOT_FOUND_CONFIRMED y UNKNOWN.",
"type": "enum",
"filePath": "services/api/src/modules/reconciliation/erasing-claim-evidence.js",
"badges": [
"public"
]
}
{
"title": "listingScopePrefixes",
"content": "Calcula los prefijos de ruta v\u00e1lidos para un Listing. Usa el mismo \u00e1mbito que el adjunto de media.",
"type": "function",
"filePath": "services/api/src/modules/reconciliation/erasing-claim-evidence.js",
"badges": [
"public"
]
}
{
"title": "persistedFileIdentity",
"content": "Verifica si un Listing guarda identidad persistida para un fileId. Rechaza rutas inseguras, ambiguas o fuera de \u00e1mbito.",
"type": "function",
"filePath": "services/api/src/modules/reconciliation/erasing-claim-evidence.js",
"badges": [
"public"
]
}
{
"title": "sameInstant",
"content": "Compara dos marcas temporales con igualdad exacta de instante. Solo devuelve true cuando ambas fechas coinciden al milisegundo.",
"type": "function",
"filePath": "services/api/src/modules/reconciliation/erasing-claim-evidence.js",
"badges": [
"read-only"
]
}
{
"title": "erasingClaimEligibility",
"content": "Eval\u00faa si una asignaci\u00f3n en erasing sigue siendo candidata a reconciliaci\u00f3n. Devuelve un estado determinista y, si aplica, la identidad persistida.",
"type": "function",
"filePath": "services/api/src/modules/reconciliation/erasing-claim-evidence.js",
"badges": [
"public"
]
}
{
"title": "classifyProviderEvidence",
"content": "Clasifica las observaciones de un proveedor externo. Exige secuencia v\u00e1lida, referencia confirmada y respuestas coherentes.",
"type": "function",
"filePath": "services/api/src/modules/reconciliation/erasing-claim-evidence.js",
"badges": [
"public"
]
}
Data & fields
Constantes internas
IMAGEKIT_ROOT— Base fija de rutas del ámbito. Su valor es/plano.OBJECT_ID— Expresión regular que valida IDs MongoDB de 24 caracteres hexadecimales.
PROVIDER_EVIDENCE
EXISTS[badge:read-only] — El archivo existe según las observaciones del proveedor.NOT_FOUND_CONFIRMED[badge:read-only] — El archivo no existe y esa ausencia quedó confirmada.UNKNOWN[badge:read-only] — La evidencia es insuficiente o contradictoria.
persistedFileIdentity
[
{
"name": "listing",
"type": "object",
"required": true,
"description": "Documento Listing desde el que se intenta demostrar identidad persistida.",
"children": [
{
"name": "_id",
"type": "string",
"required": true,
"description": "Identificador del Listing."
},
{
"name": "createdBy",
"type": "string",
"required": true,
"description": "Propietario del Listing."
},
{
"name": "media",
"type": "array",
"description": "Entradas de media del Listing."
},
{
"name": "sourceDocuments",
"type": "array",
"description": "Documentos fuente del Listing."
}
]
},
{
"name": "fileId",
"type": "string",
"required": true,
"description": "Identificador del archivo observado."
}
]
- Devuelve
{ present: true, filePath }cuando la identidad está demostrada. - Devuelve
{ present: false, reason }cuando falta evidencia o hay contradicción.
erasingClaimEligibility
[
{
"name": "fileId",
"type": "string",
"required": true,
"description": "Identificador del archivo en evaluación."
},
{
"name": "expected",
"type": "object",
"required": true,
"description": "Estado esperado observado antes de consultar al proveedor.",
"children": [
{
"name": "listingId",
"type": "string",
"required": true,
"description": "Listing esperado de la asignación."
},
{
"name": "holder",
"type": "string",
"required": true,
"description": "Holder esperado de la asignación."
},
{
"name": "updatedAt",
"type": "date or string",
"required": true,
"description": "Marca temporal esperada de la asignación."
}
]
},
{
"name": "claim",
"type": "object",
"description": "Documento MediaFileClaim leído desde persistencia."
},
{
"name": "listing",
"type": "object",
"description": "Documento Listing asociado a la asignación."
},
{
"name": "foreignReferences",
"type": "integer",
"required": true,
"description": "Número de referencias externas al Listing propio."
}
]
- Devuelve
eligiblesolo cuando la asignación sigue estable y la identidad persistida existe. - Devuelve
not_found,not_erasing,changedomanual_onlycuando la evidencia no permite continuar.
classifyProviderEvidence
[
{
"name": "fileId",
"type": "string",
"required": true,
"description": "Archivo objetivo cuya ausencia o existencia se clasifica."
},
{
"name": "identity",
"type": "object",
"required": true,
"description": "Identidad persistida del archivo objetivo.",
"children": [
{
"name": "present",
"type": "boolean",
"required": true,
"description": "Indica si la identidad está demostrada."
},
{
"name": "filePath",
"type": "string",
"description": "Ruta segura persistida del archivo."
}
]
},
{
"name": "reference",
"type": "object",
"required": true,
"description": "Archivo de referencia usado para confirmar credenciales y cuenta.",
"children": [
{
"name": "fileId",
"type": "string",
"required": true,
"description": "Identificador del archivo de referencia."
},
{
"name": "filePath",
"type": "string",
"required": true,
"description": "Ruta persistida del archivo de referencia."
}
]
},
{
"name": "observations",
"type": "array",
"required": true,
"description": "Secuencia de observaciones del proveedor.",
"children": [
{
"name": "subject",
"type": "string",
"required": true,
"description": "reference o target."
},
{
"name": "fileId",
"type": "string",
"required": true,
"description": "Archivo observado."
},
{
"name": "kind",
"type": "string",
"required": true,
"description": "exists, not_found o error."
},
{
"name": "file",
"type": "object",
"description": "Datos devueltos por el proveedor cuando existe."
},
{
"name": "status",
"type": "number",
"description": "Código HTTP observado."
},
{
"name": "errorClass",
"type": "string",
"description": "Clase de error cuando kind es error."
}
]
}
]
- Devuelve
EXISTScuando el objetivo existe y coincide con la identidad esperada. - Devuelve
NOT_FOUND_CONFIRMEDcuando el objetivo produce 404 coherentes. - Devuelve
UNKNOWNante cualquier inconsistencia, error o contradicción.
Behaviors
listingScopePrefixes— Construye prefijos de ruta válidos paralistingIdyownerId. Solo incluye valores que pasenOBJECT_ID.persistedFileIdentity— Busca evidencia persistida de que unfileIdpertenece al Listing. Rechaza documentos fuente, rutas inseguras, rutas contradictorias y rutas fuera de ámbito.sameInstant— Compara dos fechas por instante exacto. Devuelvefalsesiano es unDateválido.erasingClaimEligibility— Verifica que la asignación siga enerasing, que coincida con el estado esperado y que no existan referencias externas. Solo entonces devuelveeligible.classifyProviderEvidence— Valida la secuencia de observaciones y clasifica el resultado del proveedor. Si hay errores, devuelveUNKNOWN.unknown— Construye siempre una respuesta{ evidence: UNKNOWN, reason }.
persistedFileIdentityLISTING_GONESOURCE_DOCUMENT_WITHOUT_PATHNOT_REFERENCED_BY_OWN_LISTINGNOT_AN_IMAGEKIT_ENTRYCONTRADICTORY_PERSISTED_PATHSPERSISTED_PATH_MISSINGPERSISTED_PATH_UNSAFEPERSISTED_PATH_OUT_OF_SCOPE
erasingClaimEligibilityEXPECTED_INVALIDCLAIM_NOT_FOUNDSTATE_<STATE>HOLDER_MISSINGCLAIM_CHANGEDEVIDENCE_INCOMPLETEERASING_STILL_REFERENCEDLISTING_GONEOWN_LISTING_STILL_REFERENCESREMOVAL_LEFTOVERIDENTITY_<reason>
classifyProviderEvidenceIDENTITY_EVIDENCE_MISSINGREFERENCE_UNAVAILABLEPROBE_SEQUENCE_INVALIDOBSERVATION_IDENTITY_MISMATCHPROVIDER_ERROR_<class>UNEXPECTED_OBSERVATIONREFERENCE_NOT_CONFIRMEDCONTRADICTORY_PROVIDER_RESPONSESCONTRADICTORY_FILE_IDENTITYTARGET_NOT_FOUND_WITH_EVIDENCENOT_FOUND_WITHOUT_STATUS
Gotchas & edge cases
[!WARNING]
sourceDocumentsnunca demuestran identidad persistida. El código los trata como evidencia insuficiente.
[!WARNING]
persistedFileIdentityrechaza rutas con.., barras dobles, barras invertidas,%, espacios o controles. También exige que la ruta esté dentro del ámbito del Listing.
[!CAUTION]
erasingClaimEligibilitysolo continúa cuandoclaim.state === "erasing",foreignReferenceses un entero y vale0, y el Listing sigue siendo unrequirementcondeletion.status === "pending".
[!IMPORTANT]
classifyProviderEvidenceexige una secuencia válida. Debe empezar y terminar con la referencia, y la referencia debe quedar confirmada antes y después.
[!WARNING] Si cualquier observación trae
kind: "error", la clasificación cae aUNKNOWN. El módulo no interpreta ese caso como ausencia confirmada.
Related
Este módulo es consumido por services/api/src/modules/reconciliation/erasing-claim-reconciliation.service.js. Ese servicio importa PROVIDER_EVIDENCE, classifyProviderEvidence, erasingClaimEligibility y persistedFileIdentity para ejecutar la reconciliación de erasing. fileciteturn0file10turn0file14
La suite services/api/test/erasing-reconciliation.test.js valida los caminos principales del módulo. Cubre NOT_FOUND_CONFIRMED, EXISTS y varios motivos de rechazo de elegibilidad y clasificación. fileciteturn0file6turn0file7
El comentario inicial del archivo confirma su intención: resolver evidencia para reconciliar asignaciones atrapadas en erasing, con funciones puras, deterministas y sin E/S.