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. fileciteturn0file1turn0file13

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 eligible solo cuando la asignación sigue estable y la identidad persistida existe.
  • Devuelve not_found, not_erasing, changed o manual_only cuando 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 EXISTS cuando el objetivo existe y coincide con la identidad esperada.
  • Devuelve NOT_FOUND_CONFIRMED cuando el objetivo produce 404 coherentes.
  • Devuelve UNKNOWN ante cualquier inconsistencia, error o contradicción.

Behaviors

  • listingScopePrefixes — Construye prefijos de ruta válidos para listingId y ownerId. Solo incluye valores que pasen OBJECT_ID.
  • persistedFileIdentity — Busca evidencia persistida de que un fileId pertenece al Listing. Rechaza documentos fuente, rutas inseguras, rutas contradictorias y rutas fuera de ámbito.
  • sameInstant — Compara dos fechas por instante exacto. Devuelve false si a no es un Date válido.
  • erasingClaimEligibility — Verifica que la asignación siga en erasing, que coincida con el estado esperado y que no existan referencias externas. Solo entonces devuelve eligible.
  • classifyProviderEvidence — Valida la secuencia de observaciones y clasifica el resultado del proveedor. Si hay errores, devuelve UNKNOWN.
  • unknown — Construye siempre una respuesta { evidence: UNKNOWN, reason }.
  • persistedFileIdentity
    • LISTING_GONE
    • SOURCE_DOCUMENT_WITHOUT_PATH
    • NOT_REFERENCED_BY_OWN_LISTING
    • NOT_AN_IMAGEKIT_ENTRY
    • CONTRADICTORY_PERSISTED_PATHS
    • PERSISTED_PATH_MISSING
    • PERSISTED_PATH_UNSAFE
    • PERSISTED_PATH_OUT_OF_SCOPE
  • erasingClaimEligibility
    • EXPECTED_INVALID
    • CLAIM_NOT_FOUND
    • STATE_<STATE>
    • HOLDER_MISSING
    • CLAIM_CHANGED
    • EVIDENCE_INCOMPLETE
    • ERASING_STILL_REFERENCED
    • LISTING_GONE
    • OWN_LISTING_STILL_REFERENCES
    • REMOVAL_LEFTOVER
    • IDENTITY_<reason>
  • classifyProviderEvidence
    • IDENTITY_EVIDENCE_MISSING
    • REFERENCE_UNAVAILABLE
    • PROBE_SEQUENCE_INVALID
    • OBSERVATION_IDENTITY_MISMATCH
    • PROVIDER_ERROR_<class>
    • UNEXPECTED_OBSERVATION
    • REFERENCE_NOT_CONFIRMED
    • CONTRADICTORY_PROVIDER_RESPONSES
    • CONTRADICTORY_FILE_IDENTITY
    • TARGET_NOT_FOUND_WITH_EVIDENCE
    • NOT_FOUND_WITHOUT_STATUS

Gotchas & edge cases

[!WARNING] sourceDocuments nunca demuestran identidad persistida. El código los trata como evidencia insuficiente.

[!WARNING] persistedFileIdentity rechaza rutas con .., barras dobles, barras invertidas, %, espacios o controles. También exige que la ruta esté dentro del ámbito del Listing.

[!CAUTION] erasingClaimEligibility solo continúa cuando claim.state === "erasing", foreignReferences es un entero y vale 0, y el Listing sigue siendo un requirement con deletion.status === "pending".

[!IMPORTANT] classifyProviderEvidence exige 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 a UNKNOWN. El módulo no interpreta ese caso como ausencia confirmada.

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. fileciteturn0file10turn0file14

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. fileciteturn0file6turn0file7

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.