Detección del Proceso de Escritura
Convierte los registros de pulsaciones de Potato en marcas auditables para respuestas de texto libre pegadas, transcritas o generadas por máquina, con umbrales que puedes leer y sobrescribir.
La detección del proceso de escritura lee la dinámica de tecleo capturada por el Registro de Pulsaciones y produce marcas con nombre y con las pruebas adjuntas, de modo que puedes ver qué valores de características dispararon cada una y descartar las que no te convenzan.
Necesita Potato 2.7.2 o posterior, y solo se ejecuta donde el registro de pulsaciones ya está activo. Como keystroke_logging.enabled es false por defecto, un proyecto que nunca lo activó no tiene nada sobre lo que detectar.
Advertencia: Las marcas son indicios para que los revise una persona. No son prueba de mala conducta, y nunca deben conectarse a rechazos automáticos, retención de pagos ni expulsiones de participantes. Alguien rápido y fluido que produce un primer borrador limpio se parece de verdad a una transcripción. Un anotador que trabaja desde el móvil se parece de verdad a alguien que pega. Las reglas de abajo están construidas para reducir esas coincidencias, y las coincidencias siguen ocurriendo. La sección de falsos positivos forma parte de la funcionalidad, no es una nota legal.
Tres niveles
| Nivel | Qué es | ¿Necesita datos etiquetados? | Por defecto |
|---|---|---|---|
| 1. Reglas | Seis marcas con nombre, con umbrales explícitos y pruebas visibles | No | Activo |
| 2. Calibración | Umbrales reajustados a los anotadores de tu propio proyecto | No | Inactivo |
| 3. Supervisado | Un clasificador que entrenas con tus propias etiquetas | Sí | Inactivo |
Potato no distribuye ningún modelo preentrenado. No hay un corpus etiquetado en el repositorio, así que cualquier coeficiente que publicáramos vendría con una cifra de validación que nos habríamos inventado. En su lugar tienes seis reglas que puedes leer y discutir. Si tienes etiquetas reales, el nivel 3 es la vía que reproduce las exactitudes de la literatura.
Nivel 1: las reglas
Cada marca devuelve los valores de las características que la dispararon, de modo que puedes defender o descartar cualquiera de ellas por separado.
paste_dominant
Gravedad: suspect. Se dispara cuando pasted_fraction >= 0.5, es decir, cuando la mitad o más del texto final llegó pegada.
Se suprime cuando todos los pegados se clasificaron como self (reordenar tu propio borrador) o instance_text (citar el pasaje que se está anotando).
silent_insertion
Gravedad: suspect. Se dispara cuando external_insert_ratio >= 0.3, es decir, cuando casi un tercio de los caracteres insertados apareció sin una pulsación correspondiente.
Esta es la señal individual de mayor valor. El pegado, el autorrelleno, el dictado y la inyección programática aparecen todos aquí, incluso cuando la página suprime el propio evento de pegado. Es una operacionalización directa del «recuento de pulsaciones anómalamente bajo en relación con la longitud de la respuesta» de Asher et al.
Se suprime con teclados en pantalla (virtual_keyboard) y durante la composición IME, donde keydown no se emite de forma fiable y toda inserción parecería silenciosa. La regla usa la proporción que tiene en cuenta el origen, así que citar de forma legítima no cuenta.
transcription_rhythm
Gravedad: review. Se dispara cuando se cumplen las tres condiciones:
iki_log_cv <= 0.06, un ritmo de tecleo metronómicorevision_ratio <= 0.02, prácticamente sin borrados- menos de 0,5 pausas de 2 segundos o más por cada 100 caracteres
Conjuntiva a propósito. Cada una por separado tiene una lectura inocente. Juntas son la firma de copiar al teclado que describen Crossley et al.: lineal, por ráfagas y con poca varianza.
Se omite por completo en respuestas de menos de 80 caracteres o 40 pulsaciones, donde no hay ritmo del que hablar.
offscreen_composition
Gravedad: suspect. Se dispara cuando una inserción grande de origen externo (80 caracteres o más) va inmediatamente después de 10 segundos o más fuera de la página. Es el patrón de «me fui a ChatGPT, volví y pegué».
Se suprime cuando el origen de la inserción era el pasaje o el propio texto del anotador, ya que apartarse un momento y luego citar el pasaje es un comportamiento normal.
implausible_speed
Gravedad: review. Se dispara por encima de 900 caracteres por minuto (unas 180 wpm) sostenidos a lo largo de toda una respuesta.
synthetic_input
Gravedad: suspect. Se dispara con cualquier evento con isTrusted === false, es decir, el navegador informando de que la entrada la generó un script y no una persona. La automatización de navegador, los scripts inyectados y algunas herramientas de accesibilidad producen esto.
Niveles de veredicto
| Nivel | Significado |
|---|---|
ok | No se disparó ninguna marca |
review | Al menos una marca de gravedad review |
suspect | Al menos una marca de gravedad suspect |
Sobrescribir umbrales
keystroke_logging:
detection:
thresholds:
paste_dominant.pasted_fraction: 0.4
silent_insertion.ratio: 0.25
transcription_rhythm.iki_log_cv: 0.05
transcription_rhythm.revision_ratio: 0.02
transcription_rhythm.pause_2s_per_100_chars: 0.5
offscreen_composition.blur_ms: 15000
offscreen_composition.insert_chars: 100
implausible_speed.chars_per_min: 1000Los umbrales se evalúan en el servidor y nunca se envían al navegador. Publicarlos le diría a un anotador con qué lentitud exacta tiene que pegar para quedarse por debajo de la marca.
Nivel 2: calibración del proyecto
Las características de pulsaciones varían bastante según la tarea de escritura (Conijn et al. 2019), y los umbrales fijos sobre una magnitud con distribución de mezcla están sesgados (Roeser et al. 2021). Un corte que funciona para una justificación de una frase está mal para un ensayo de cinco párrafos.
La calibración sitúa cada umbral en un percentil de cola de las sesiones de tu propio proyecto.
# Inspect the fit without saving it
python -m potato.typing_detect calibrate config.yaml --dry-run
# Save it
python -m potato.typing_detect calibrate config.yamlkeystroke_logging:
detection:
calibrate: true # use the saved fitLa calibración requiere al menos 30 sesiones utilizables (de 80 caracteres o más, no móviles). Por debajo de eso devuelve insufficient_data y siguen vigentes los valores por defecto.
Advertencia: Un corte por percentil es una definición relativa de valor atípico. Por construcción marca aproximadamente
tail_fraction(5 % por defecto) de las sesiones incluso en una población donde nadie está haciendo nada mal. Te dice dónde mirar primero. No es una prueba. Los umbrales calibrados se acotan además a un máximo de 3x los valores por defecto, para que una población homogénea no pueda arrastrar un corte hasta su propia mediana y empezar a marcar a anotadores honestos.
Un thresholds: explícito siempre gana a un valor calibrado, que siempre gana al valor por defecto.
Nivel 3: clasificador supervisado
Si tienes sesiones etiquetadas, entrena un modelo de verdad:
from potato import typing_store
from potato.typing_detect import fit_supervised
rows = typing_store.feature_matrix(task_dir, project)
labels = [...] # 1 = non-composed, 0 = composed
result = fit_supervised(rows, labels, model="random_forest")
print(result["cv_accuracy_mean"], result["feature_importances"])Requiere scikit-learn, que se importa de forma diferida y no es una dependencia de Potato.
Conseguir etiquetas sin un estudio aparte
La fase de entrenamiento de Potato puede generarlas por ti. Pide a los anotadores que copien un pasaje que les des como tarea de calentamiento. Sus sesiones de copia son ejemplos genuinos de transcripción y sus respuestas normales son ejemplos de redacción, lo que te da un conjunto etiquetado desde dentro de tu propio proyecto, sobre tu propia tarea y con tus propios anotadores. Esto refleja cómo construyeron su corpus Crossley et al., y el ejemplo de calibración lo monta de principio a fin.
Falsos positivos
El modo de fallo de esta funcionalidad es acusar a un anotador honesto. Estos son los casos que se parecen legítimamente a los patrones de arriba.
| Situación | A qué regla se parece | Cómo lo trata Potato |
|---|---|---|
| Citar el pasaje que se está anotando | paste_dominant, silent_insertion, offscreen_composition | Suprimido mediante paste_source: instance_text |
| Mover de sitio tu propio borrador | Las mismas | Suprimido mediante paste_source: self |
| Teclear en un móvil o una tableta | silent_insertion | Suprimido mediante virtual_keyboard |
| Entrada no latina con un IME | silent_insertion | Suprimido mediante composition_events |
| Alguien rápido y fluido, borrador limpio | transcription_rhythm, implausible_speed | Reglas conjuntivas; review y no suspect; calibración |
| Respuestas muy cortas | transcription_rhythm | Se omiten por debajo de 80 caracteres / 40 pulsaciones |
| Dictado o reconocimiento de voz | silent_insertion | Sin tratar. Va a marcar. Excluye a esos anotadores o sube el umbral. |
| Lectores de pantalla y algunas tecnologías de apoyo | synthetic_input | Tratado solo en parte. Algunas herramientas producen eventos no confiables. |
| Autocorrección en el móvil | silent_insertion | En parte. insertReplacementText cuenta como externo. |
| Extensiones del navegador como las de gramática | silent_insertion, synthetic_input | Sin tratar. Va a marcar. |
Los cuatro últimos son limitaciones reales y no descuidos. Si tu grupo de participantes incluye personas que dictan, que usan tecnología de apoyo o que usan extensiones de escritura, o dejas esas reglas fuera de tus criterios de revisión, o tratas cada marca como una invitación a preguntar al anotador y no a actuar.
Accesibilidad
synthetic_input se basa en isTrusted, que algunas tecnologías de apoyo también disparan. Marcar a un anotador con discapacidad por usar las herramientas que necesita para trabajar es un resultado inaceptable.
Esa regla no tiene umbral, así que no hay ningún valor que puedas poner para hacerla inalcanzable. Si tu estudio está abierto a personas que usan tecnología de apoyo, o excluyes synthetic_input de los criterios de revisión que escribas, o desactivas la detección por completo y analizas tú mismo las características exportadas:
keystroke_logging:
enabled: true
detection:
enabled: falseLas reglas basadas en umbrales sí se pueden hacer inalcanzables poniendo un corte absurdo, por ejemplo implausible_speed.chars_per_min: 1000000.
Intervención en tiempo real
keystroke_logging:
detection:
on_external_insert: flag # allow | warn | block | flag| Valor | Comportamiento |
|---|---|
allow | No hacer nada más allá de registrar |
warn | Aviso no bloqueante al pegar contenido externo, pero no al citarse a uno mismo ni al pasaje |
block | Impedir pegar y soltar en los campos instrumentados |
flag | Por defecto. Registrar en silencio; ya decidirás después |
block es un instrumento tosco. También bloquea las citas legítimas, y un participante decidido puede volver a teclear el texto. Usar flag y revisar después suele ser mejor.
Panel de administración
El panel Writing Process, dentro de la pestaña Behavioral del Panel de Administración, muestra las medianas por anotador, las tasas de pegado, las tasas de inserción silenciosa y cada sesión marcada con sus pruebas.
Informa de writing_process_risk, la proporción de sesiones de un usuario que dispararon cada marca, ponderada hacia las señales con la explicación inocente menos probable. Es una ayuda para ordenar, mantenida a propósito aparte del suspicion_score ya existente, para que ninguno de los dos números cambie en silencio el significado del otro.
Base en la investigación
Todas las citas de abajo están verificadas contra el registro de Crossref o de DataCite.
Crossley, Tian, Choi, Holmes y Morris (2024) recogieron 500 ensayos argumentativos, hicieron que otros trabajadores los transcribieran y separaron lo auténtico de lo transcrito con un 99 % de exactitud usando un random forest (96-98 % con otros modelos). Sus familias de características son lo que captura Potato: tiempos de pausa antes de frases y de palabras, recuentos de inserciones y borrados, relaciones producto-proceso, ráfagas, revisión y varianza del proceso. Su hallazgo es el objetivo de diseño. La escritura auténtica muestra pausas más largas, más inserciones y borrados y mayor varianza; la transcripción es lineal y va por ráfagas.
Deane, Zhang, Hao y Li, y por separado Zhang, Feng, He, Li y Zhu, confirman de forma independiente la separación entre copiar al teclado y escribir de forma natural, estos últimos con un modelo de aprendizaje profundo. Asher, Gold, Chen y Carvalho es el caso específico de crowdsourcing: una herramienta de pulsaciones en Prolific que marca a los participantes que pegan en los campos de respuesta o cuyo recuento de pulsaciones es anómalamente bajo para la longitud de su respuesta.
Para las medidas de proceso subyacentes, consulta Leijten y Van Waes (Inputlog) para las medidas de registro estándar, Chenoweth y Hayes para el constructo de ráfaga, Conijn, Roeser y van Zaanen para la dependencia de las características de pulsaciones respecto a la tarea, y Roeser, De Maeyer, Leijten y Van Waes para por qué los umbrales de pausa fijos están sesgados.
Referencias
- Crossley, S., Tian, Y., Choi, J. S., Holmes, L., & Morris, W. (2024). Plagiarism Detection Using Keystroke Logs. EDM 2024 (Short Papers). doi:10.5281/zenodo.12729864
- Deane, P., Zhang, M., Hao, J., & Li, C. Using Keystroke Dynamics to Detect Nonoriginal Text. Journal of Educational Measurement, 63(1). doi:10.1111/jedm.12431
- Asher, M. W., Gold, G., Chen, E., & Carvalho, P. F. (2026). Chatbots Are Undermining Crowdsourced Research in the Behavioral Sciences: Detecting Artificial Intelligence-Assisted Cheating With a Keystroke-Based Tool. Advances in Methods and Practices in Psychological Science, 9(1). doi:10.1177/25152459261424723
- Zhang, M., Feng, L., He, X., Li, C., & Zhu, M. (2026). Disentangling copy typing and natural writing behaviors using keystroke logs and deep learning model. Assessing Writing. doi:10.1016/j.asw.2026.101070
- Leijten, M., & Van Waes, L. (2013). Keystroke Logging in Writing Research: Using Inputlog to Analyze and Visualize Writing Processes. Written Communication, 30(3), 358-392. doi:10.1177/0741088313491692
- Chenoweth, N. A., & Hayes, J. R. (2001). Fluency in Writing: Generating Text in L1 and L2. Written Communication, 18(1), 80-98. doi:10.1177/0741088301018001004
- Conijn, R., Roeser, J., & van Zaanen, M. (2019). Understanding the keystroke log: the effect of writing task on keystroke features. Reading and Writing, 32(9), 2353-2374. doi:10.1007/s11145-019-09953-8
- Roeser, J., De Maeyer, S., Leijten, M., & Van Waes, L. (2021). Modelling typing disfluencies as finite mixture process. Reading and Writing. doi:10.1007/s11145-021-10203-z
- Lee, M., Liang, P., & Yang, Q. (2022). CoAuthor: Designing a Human-AI Collaborative Writing Dataset for Exploring Language Model Capabilities. CHI 2022. doi:10.1145/3491102.3502030
Lecturas Adicionales
- Registro de Pulsaciones - qué se captura y cómo
- Ética del Registro de Pulsaciones - IRB, consentimiento, derechos de los participantes
- Control de Calidad - verificaciones de atención y estándares de oro
- Panel de Administración - el panel Writing Process
Para detalles de implementación, consulta la documentación fuente.