Colectica-routing-toolkit
Extrae y valida de forma cruzada la lógica de enrutamiento de cuestionarios a partir de exportaciones de Colectica DDI y Forsta+ (Confirmit Horizons): extracción de esquemas, gráficos de enrutamiento, diff estructural de enrutamiento, simulación de entrevistas y un servidor MCP de solo lectura sobre los resultados.
Documentación
Sistema de Cuestionarios Flowise
Una aplicación Django para analizar y simular archivos JSON de cuestionarios en formato Colectica (p. ej., oleadas de Understanding Society Mainstage). Permite a los diseñadores subir un módulo de cuestionario, extraer su esquema de preguntas y su lógica de enrutamiento, construir un grafo de flujo visual, ejecutar una revisión consultiva asistida por IA mediante Flowise y simular interactivamente el recorrido del cuestionario como encuestado.
También puede ingerir una exportación XML de Forsta+ (Confirmit Horizons) de la misma oleada de cuestionario y comparar estructuralmente su enrutamiento con el enrutamiento derivado de Colectica, mostrando cualquier discrepancia — ramas faltantes, condiciones no coincidentes, ramas "else" solo de Forsta+ — en una GUI dedicada de diff de enrutamiento, con una vista de grafos lado a lado por discrepancia.
Principio arquitectónico central
Django posee todos los datos, la lógica de enrutamiento y la validación. Flowise es solo consultivo.
Flowise (una plataforma externa de agentes LLM) se utiliza para dos propósitos limitados, y su salida siempre es validada/procesada posteriormente por Django antes de ser considerada fiable:
- Module Review agentflow — revisa el enrutamiento/cobertura en busca de problemas de diseño. Django envía un payload compacto y valida posteriormente la respuesta contra hechos conocidos, rechazando cualquier cosa que invente nombres de preguntas o modifique el enrutamiento.
- Interview Wording agentflow — reformatea el texto/opciones de las preguntas visibles para el encuestado durante el simulador de entrevista. Django valida la respuesta y recurre a un mensaje determinista construido localmente si Flowise no está disponible o devuelve algo inválido — el simulador siempre funciona incluso si Flowise está caído.
Pipeline de procesamiento
Aplicado en la UI/vistas como un orden estricto por módulo subido:
- Subir JSON →
QuestionnaireModule - Extraer esquema (
schema_extractor.ColecticaSchemaExtractor) →NormalizedQuestionfilas - Extraer enrutamiento (
routing_extractor.ColecticaRoutingExtractor) →RoutingEdgefilas (condicional / secuencial / bucle) - Construir grafo (
graph_builder.py+graph_enrichment.py) →QuestionnaireGraph(JSON de nodos/aristas + texto Mermaid) - Ejecutar revisión de Flowise (opcional) →
ModuleAIReview
Todo se ejecuta de forma síncrona en el ciclo petición/respuesta — no hay cola de tareas Celery/async.
Diff de enrutamiento Colectica vs Forsta+
Un segundo pipeline independiente se ejecuta contra un segundo QuestionnaireModule (source_format auto-detectado como forsta_xml a partir de la extensión .xml en la subida — el mismo formulario de subida que para Colectica), validando de forma cruzada la exportación XML de Forsta+ (Confirmit Horizons) de una agencia de campo contra el enrutamiento derivado de Colectica para la misma oleada:
- Subir XML de Forsta+ →
QuestionnaireModule - Extraer esquema (
forsta_xml_schema_extractor.ForstaXmlSchemaExtractor) →NormalizedQuestionfilas - Extraer enrutamiento (
forsta_xml_routing_extractor.ForstaXmlRoutingExtractor) →RoutingEdgefilas - Emparejar preguntas (
question_matcher.build_question_matches) →QuestionMatchfilas, emparejando cada pregunta de Colectica con su mejor contraparte de Forsta+ en tres pasadas: coincidencia exacta de texto normalizado, luego respaldo difuso (difflib, umbral 0.75), y luego un paso de reconciliación desempate por nombre — si la coincidencia actual de una pregunta tiene un nombre diferente al suyo, y existe una pregunta no utilizada con el mismo nombre en el otro lado cuyo propio texto también supera el umbral difuso (o es una coincidencia limpia de prefijo/subcadena — el texto fuente de Forsta+ a veces pliega las instrucciones del entrevistador en línea donde Colectica las mantiene separadas), la del mismo nombre se hace cargo. El nombre es un desempate, nunca una anulación: un "falso amigo" con el mismo nombre pero contenido no relacionado se deja en paz. - Comparar enrutamiento (
routing_comparator.compare_routing_for_modules) →RoutingDiscrepancyfilas — un diff estructural (solo presencia del destino de la arista, no semántica de condiciones). Tanto la pregunta fuente como la destino de cada arista se resuelven medianteQuestionMatchantes de comparar, no se comparan como cadenas de nombre crudas, de modo que un destino presente en ambos lados bajo un nombre diferente (mayúsculas, un sufijo de Forsta+, etc.) no se reporte erróneamente como faltante.
Navegable en /questionnaires/routing-diff/<colectica_module_id>/<forsta_module_id>/, con una página de detalle por discrepancia que muestra los grafos de enrutamiento de ambos sistemas lado a lado.
Servidor de herramientas MCP
Junto a la aplicación Django principal, mcp_server expone un subconjunto curado y de solo lectura de los mismos datos como herramientas MCP (Model Context Protocol) sobre streamable-HTTP, para clientes MCP como Claude Desktop — su propia aplicación Django, su propio proceso independiente, su propio puerto, nunca el runserver principal.
python manage.py runmcp # own process, port 8765 by default
Cada petición debe llevar un token de acceso por persona en su ruta URL (https://<host>/t/<token>/mcp) en lugar de una cabecera, ya que las UIs de conectores de clientes MCP generalmente solo aceptan una URL. Los usuarios staff generan/revocan tokens en /questionnaires/mcp-tokens/ — sin secreto compartido, sin necesidad de comando de terminal para incorporar a una nueva persona, y revocar el token de una persona no afecta a nadie más.
Solicitar acceso: no hay registro de autoservicio por diseño. Abre un issue en este repositorio o contacta al mantenedor para solicitar un token.
Herramientas (mcp_server/tools.py), cada una con un prompt MCP correspondiente (mcp_server/prompts.py) que los clientes MCP pueden mostrar como un atajo estilo comando de barra:
| Tool | Prompt | Notes |
|---|---|---|
list_modules | listModules | Solo Colectica |
get_module_summary | showModuleSummary | Solo Colectica |
list_questions | listQuestions | Solo Colectica |
get_question | showQuestion | Solo Colectica |
get_routing_edges | listRoutingEdges | Solo Colectica |
trace_variable | traceVariable | Solo Colectica |
get_module_graph | showModuleGraph | Colectica + Forsta+; también devuelve sintaxis de diagrama de flujo Mermaid para que un cliente MCP pueda renderizar un diagrama real; los módulos grandes se auto-resumen en lugar de devolver un grafo enorme |
evaluate_edge_condition | evaluateCondition | Colectica + Forsta+; evalúa cualquier cadena de condición contra respuestas hipotéticas |
get_routing_diff_report | showRoutingDiffReport | Par Colectica + Forsta+; replica la página de informe de diff de enrutamiento |
get_routing_discrepancy_detail | showColecticaForstaDiscrepancy | Par Colectica + Forsta+; replica la página de detalle por discrepancia, con los grafos de ambos sistemas incluidos |
get_routing_simulation | showRoutingSimulation | Solo Colectica |
Nunca escribe en la base de datos y nunca dispara un paso del pipeline computacionalmente pesado (extracción, construcción de grafos, emparejamiento/comparación, revisión de IA) por sí mismo — cada herramienta lee datos que otra parte de la aplicación ya calculó y persistió.
Stack tecnológico
- Django 6.0 (proyecto
config/; dos apps,flowise_questionnaireymcp_server) - PostgreSQL (
flowise_questionnaire_db) - Flowise (externo, autoalojado o en la nube) para revisión/redacción consultiva de IA
- Sin framework de frontend — plantillas Django renderizadas en servidor (grafos de enrutamiento renderizados en el cliente mediante vis-network, cargado desde un CDN)
Primeros pasos
Requisitos previos
- Python 3.12+
- PostgreSQL, con una base de datos
flowise_questionnaire_dbdisponible - Una instancia de Flowise en ejecución (opcional — solo necesaria para las funciones de revisión de IA / redacción de entrevista; el resto de la aplicación funciona sin ella)
Configuración
git clone https://github.com/amiravarzamani/colectica-forsta-routing-toolkit.git
cd flowise-questionnaire-system
python3 -m venv venv
source venv/bin/activate # venv\Scripts\activate on Windows
pip install -r requirements.txt
Copia .env.example a .env y completa SECRET_KEY/DB_PASSWORD/DB_HOST — config/settings.py no tiene valores predeterminados para estos y fallará de forma ruidosa al inicio si faltan. Ajusta los ajustes DATABASES y FLOWISE_* en config/settings.py para que coincidan con tu entorno antes de ejecutar las migraciones.
python manage.py migrate
python manage.py createsuperuser # first user, since login is required app-wide
python manage.py runserver
La aplicación está montada en /questionnaires/ y requiere inicio de sesión (LOGIN_URL = /questionnaires/login/).
Ejecutar pruebas
python manage.py test
Estructura del proyecto
config/ Django project settings, URLs, WSGI/ASGI
flowise_questionnaire/
models.py QuestionnaireModule, NormalizedQuestion, RoutingEdge,
QuestionnaireGraph, ModuleAIReview, InterviewSimulatorSession/Turn,
QuestionMatch, RoutingDiscrepancy
services/ Pipeline logic, in order:
schema_extractor.py parse questions out of the Colectica JSON
routing_extractor.py parse conditional/sequential/loop routing (Colectica)
forsta_xml_schema_extractor.py parse questions out of the Forsta+ XML
forsta_xml_routing_extractor.py parse conditional/sequential/loop routing (Forsta+)
graph_builder.py build the routing graph
graph_enrichment.py annotate the graph
condition_evaluator.py evaluate Colectica-syntax routing conditions against answers
forsta_condition_evaluator.py evaluate Forsta+-syntax routing conditions against answers
coverage_intent_builder.py generate deterministic test-case seed inputs
routing_simulator.py check routing coverage
question_matcher.py pair Colectica and Forsta+ questions (exact + fuzzy + name-tiebreak)
routing_comparator.py structural diff of matched questions' routing edges (source + target resolved via QuestionMatch)
routing_diff_explainer.py plain-language explanation text for the routing-diff GUI
agentflow_payload_builder.py build the Module Review Flowise payload
flowise_client.py send/receive the Module Review agentflow
interview_router.py deterministic routing engine for the simulator
interview_simulator_service.py orchestrate simulator sessions
answer_validation.py validate respondent A/B/C input
question_presentation.py convert questions to respondent-facing text
flowise_interview_wording.py Interview Wording agentflow client + caching/fallback
interview_simulator_contracts.py shared dataclasses
views/
module_views.py upload / extract / build-graph / review / graph
interview_simulator_views.py start / state / answer / abandon
routing_simulation_views.py
routing_diff_views.py Colectica-vs-Forsta+ report / run / discrepancy-detail
auth_views.py
mcp_server/
models.py McpAccessToken (per-person access token)
auth_middleware.py TokenAuthMiddleware -- validates /t/<token>/mcp on every request
tools.py the MCP tools (see "MCP tool server" above)
prompts.py matching MCP prompts (slash-command shortcuts)
server.py MCPServer instance, tool/prompt registration
views.py / urls.py staff-only token management UI (/questionnaires/mcp-tokens/)
management/commands/runmcp.py standalone streamable-HTTP server command
Grafo de conocimiento (graphify)
El código fuente se puede explorar mediante graphify, una herramienta que convierte el repositorio en un grafo de conocimiento consultable (god nodes, estructura de comunidades, relaciones entre archivos) en lugar de depender de grep/navegación cruda. La salida se escribe en graphify-out/ (gitignored — es un artefacto local regenerable, no código fuente commiteado).
pip install graphifyy
graphify . # build the graph (AST + semantic extraction)
graphify query "<question>" # BFS/DFS traversal, answers from the graph
graphify path "<A>" "<B>" # shortest path between two concepts/symbols
graphify explain "<concept>" # plain-language explanation of a node
graphify update . # incremental re-extract after code changes
graphify-out/graph.html se abre como una visualización interactiva independiente; GRAPH_REPORT.md es una auditoría en lenguaje sencillo de god nodes, conexiones sorprendentes y preguntas sugeridas.
Estado / trabajo en curso
- Los modelos
AgentRun,SyntheticProfile,SimulationRun,SimulationCase,ValidationIssueestán definidos pero aún no conectados a ninguna vista. - El pipeline de importación XML de Forsta+ (Confirmit Horizons) y de diff de enrutamiento Colectica-vs-Forsta+ (ver arriba) está implementado y en uso activo. Consulta
forsta_xml_routing_validation_plan.mdpara el documento de investigación original y la justificación del diseño (ahora también incluye una sección de notas "post-build" que documenta dónde divergió la implementación real del diseño inicial). RoutingDiscrepancy.DiscrepancyType.CONDITION_MISMATCHestá definido en el modelo (para un futuro diff semántico/de evaluación de condiciones, a diferencia del diff estructural actual) pero actualmente no es producido porrouting_comparator.py— reservado, no es un bug.- Una herramienta
mcp_serverpara el resultado más reciente deModuleAIReviewestá diseñada pero aún no construida — intencionalmente en espera pendiente de una aprobación separada, no es un descuido. - Limitación conocida de
question_matcher.py: dos preguntas de Colectica con redacción genérica reutilizada byte-idéntica (p. ej., un seguimiento tipo carta modelo como "¿Y en qué pueblo es eso?" preguntado en más de un contexto de enrutamiento) no se pueden desambiguar solo por similitud de texto, por lo que la incorrecta puede ganar un emparejamiento. El desempate por nombre no ayuda aquí ya que los nombres de las preguntas no colisionan, solo su texto. Actualmente no corregido — necesitaría una señal diferente (p. ej., posición en el grafo de enrutamiento) que la similitud de texto.
Licencia
Aún no hay archivo de licencia — todos los derechos reservados por defecto hasta que se añada uno.