# Modelo experimental y trazabilidad Este programa representa un diseño conceptual. No se han validado resistencia, montaje, microclima, independencia experimental ni condiciones agronómicas para *Pleurotus*. El croquis original no estaba disponible al crear esta versión; el inventario y la envolvente descritos por el usuario conservan su estado preliminar o pendiente. No se interpreta el porcentaje de polisombra como humedad relativa. ## Entidades y nivel de aplicación | Entidad | Registro | Significado y límite | |---|---|---| | Estructura | `structure.id`, inicialmente E01 | Recinto físico; sus dimensiones son una envolvente, no separaciones entre ejes de tubos. | | Unidad de cultivo | `cultivation_units`, U01–U20 | Objeto de cultivo; su existencia en el inventario no demuestra independencia experimental. | | Tratamiento | `experiment.treatments` | Definición del investigador con `id`, `label` y `application_level`. | | Bloque | `experiment.blocks`, referencia `block_id` | Agrupación opcional definida por el investigador; la aplicación no inventa bloques. | | Réplica | `experiment.replicates`, referencia `replicate_id` | Identificador declarado por el investigador; el software no certifica independencia. | | Sensor | `sensors`, S01–Sn | Instrumento asociado a coordenadas, variables y calibración. | | Medición | CSV importado | Observación con tiempo, instrumento, calibración y origen explícitos. | `application_level` y `assignment_scope` aceptan `cultivation_unit` o `structure`. El nivel de aplicación determina la unidad experimental. Con un tratamiento aplicado a toda E01, E01 es la única unidad experimental de ese tratamiento en este archivo. Las veinte bolsas son submuestras de E01. Veinte registros de bolsas, o muchas lecturas temporales, no crean veinte réplicas independientes del tratamiento estructural. El modo `structure` admite exactamente un tratamiento por campaña y genera una sola asignación a E01. La comparación de tratamientos estructurales requiere ampliar el diseño a estructuras independientes o a campañas justificadas por un protocolo; el programa no convierte automáticamente campañas en réplicas ni controla efectos temporales. El modo `cultivation_unit` permite asignar tratamientos a bolsas cuando el investigador haya justificado que ese es su nivel de aplicación. No establece por sí solo independencia, ausencia de interferencia o un análisis estadístico apropiado. Esta separación sigue el tratamiento de NIST de las unidades experimentales anidadas y de los distintos niveles de aplicación. NIST distingue unidades de mayor y menor escala y sus términos de error; usar un único error puede producir inferencias inválidas. La aplicación concreta a E01 y a sus bolsas es una decisión de diseño conservadora para evitar atribuir independencia sin evidencia. Fuente: [NIST/SEMATECH, variación anidada y aleatorización restringida](https://www.itl.nist.gov/div898/handbook/pri/section5/pri55.htm), consultada el 29 de octubre de 2026. ## Aleatorización reproducible `randomize_design(design, seed, scope, treatment_ids)` devuelve una copia profunda y conserva el JSON de entrada. Requiere una semilla entera explícita, tratamientos existentes y niveles de aplicación compatibles. No crea tratamientos, bloques ni réplicas. En `cultivation_unit` ordena los IDs de bloques y unidades; dentro de cada bloque mezcla el orden de tratamientos, construye una asignación con frecuencias que difieren como máximo en uno y mezcla sus etiquetas con `random.Random(seed)`. Un bloque incompleto puede omitir tratamientos; el investigador debe comprobar su pertinencia. Las unidades sin bloque forman su propio grupo. Se guardan algoritmo `python-random-fisher-yates-v1`, semilla, versión de Python, generador, hash del diseño de entrada y la lista completa de asignaciones en `experiment.randomization_snapshot`. El identificador del algoritmo, la versión de ejecución y las asignaciones permiten auditar la salida aunque una implementación futura de Python cambie. La semilla sola no sustituye la instantánea. La función no afirma realizar una prueba de hipótesis ni selecciona un tamaño muestral. La aleatorización es una operación planificada sobre unidades experimentales, como describe [NIST/SEMATECH, diseños completamente aleatorizados](https://www.itl.nist.gov/div898/handbook/pri/section3/pri331.htm), consultada el 29 de octubre de 2026. El balance por bloque implementado aquí es una regla de asignación del programa y debe ajustarse al protocolo del investigador. ## Campañas y exportaciones `campaign_snapshot(design, campaign_id)` devuelve el diseño completo, su `design_version`, un SHA-256 de JSON canónico con claves ordenadas y una fecha de creación UTC. El hash cubre también supuestos, posiciones, tratamientos y estado de verificación. La fecha describe la creación del registro y queda fuera del diseño que se firma. La misma configuración genera el mismo `design_hash`; la fecha de creación de dos instantáneas será diferente. El usuario debe guardar el resultado antes de iniciar cada campaña y usarlo para importar sus mediciones. Cambiar posiciones exige una nueva versión o instantánea de campaña. `export_units_csv(design)` genera las columnas `id,treatment_id,x_m,y_m,z_m,structure_id,block_id,replicate_id,experimental_unit_id,role,design_version,design_hash`. Las coordenadas son las del centro del cilindro de la unidad de cultivo. Un dato desconocido se exporta vacío. En `structure`, el tratamiento se hereda de E01 y `experimental_unit_id=E01`, `role=subsample`; el CSV conserva así el nivel de aplicación. Con alcance todavía no definido, el rol es `pending` y la unidad experimental permanece vacía. ## Geometría y validación Todas las coordenadas y longitudes están en metros. El sistema es derecho, Z arriba; este MVP exige el origen explícito y fijo `[0,0,0]` en la esquina inferior frontal izquierda. Los extremos de tubos y las posiciones son coordenadas absolutas en ese sistema. Los tres tamaños de envolvente deben ser positivos para generar el MVP; sus valores preliminares no constituyen medidas verificadas. Un cambio de origen requiere ampliar de forma coordinada el CAD, las proyecciones y el visor y queda fuera de esta versión. Los tubos usan `start,end,outer_diameter_m,wall_thickness_m`. Los codos usan `center,axis_u,axis_v,bend_radius_m,angle_deg,outer_diameter_m,wall_thickness_m`: el eje central comienza en `axis_u` y gira hacia `axis_v`, ambos vectores unitarios ortogonales; el arco debe cumplir `0 < angle_deg < 360`. La malla lateral usa `vertices` coplanares. Las unidades son cilindros verticales definidos por centro, diámetro y altura explícitos. Las futuras instalaciones usan cajas con `position` central y `size_m=[X,Y,Z]`. Estos tipos son convenciones del modelo; sus tamaños y posiciones no se rellenan automáticamente. `validate_design(design)` devuelve `errors,warnings,collisions,out_of_bounds,pendientes`. Los `null` son pendientes válidos; no producen objetos físicos ni cotas ficticias. Se rechazan NaN, infinito, IDs duplicados, referencias desconocidas, dimensiones no positivas, ejes inválidos y espesores incompatibles. El diámetro exterior y la pared deben declararse cuando corresponda; con pared pendiente, la envolvente exterior puede inspeccionarse, pero no se infiere una sección constructiva. La detección de interferencias utiliza AABB conservadoras: extremos de tubo más radio, eje de codo muestreado más extremos analíticos y radio, vértices de malla, cilindros de cultivo y cajas de instalaciones. Es una fase amplia aproximada: puede producir falsos positivos y no calcula penetraciones exactas. Los contactos entre tubos y codos se clasifican como `possible_connection`, sin llamarlos defecto constructivo. Los sensores sin tamaño son puntos, se comprueba si quedan dentro de límites y se excluyen de colisiones físicas. La malla sin espesor no representa volumen de material. Esta revisión no certifica ensamblajes, holguras, ventilación ni desempeño agronómico. ## Pruebas Ejecutar desde la raíz del proyecto: ```sh python3 -m unittest discover -s tests -p 'test_domain.py' -v ``` Los valores numéricos de las fixtures de pruebas son datos sintéticos exclusivos de pruebas; no se escriben en el maestro ni se exportan como mediciones del cultivo. Las pruebas cubren pendientes, unidades, límites por radio y altura, codos, malla, IDs, semilla, bloques, nivel estructural, CSV estricto e instantáneas.