zcatconfig/CLAUDE.md
reugenio 9b1d85c8c3 docs: CLAUDE.md v0.2.3 - initDeferred() y rangos negativos
Documentación añadida:
- initDeferred(): control manual sin auto-crear archivo
- Arquitectura 3 fuentes (File > BD > Defaults)
- Validación rangos negativos: "-100-100" soportado
- Historial con commits 0ef5efd y 957767d

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 19:05:06 +01:00

11 KiB

ZCATCONFIG - Sistema de Configuracion Declarativo

IMPORTANTE PARA CLAUDE: Lee la seccion "PROTOCOLO DE INICIO" antes de hacer cualquier cosa.


PROTOCOLO DE INICIO (LEER PRIMERO)

Paso 1: Leer normas del equipo

/mnt/cello2/arno/re/recode/teamdocs/LAST_UPDATE.md

Paso 2: Verificar estado del proyecto

cd /mnt/cello2/arno/re/recode/zig/zcatconfig
git status
git log --oneline -5
PATH=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2:$PATH zig build test

INFORMACION DEL PROYECTO

Campo Valor
Nombre zcatconfig
Version v0.2.3
Fecha inicio 2025-12-17
Estado FUNCIONAL - Integrado en zsimifactu (arquitectura 3 fuentes)
Lenguaje Zig 0.15.2
Dependencias Ninguna (Zig puro)

Descripcion

zcatconfig es una libreria para gestion de configuracion declarativa:

  • Definicion de variables con metadatos (tipo, default, descripcion, categoria)
  • Persistencia a archivo de texto legible con comentarios
  • Validacion de valores (rangos, enums, tipos)
  • Sistema Get/Set generico con inline for + @field
  • ConfigManager: Gestor autonomo con observers y auto-save
  • FileWatcher: Detecta cambios en archivo via mtime (hot-reload)
  • loadFromString: Carga config desde string embebido

ORIGEN: zsimifactu config/

Esta libreria extrae y generaliza el sistema de configuracion implementado en zsimifactu.

Archivos originales en zsimifactu:

src/config/
├── config.zig        # Re-exports publicos
├── types.zig         # ConfigVariable, ConfigVarType, Color
├── variables.zig     # Definiciones declarativas (proyecto-especifico)
├── structures.zig    # Config struct (proyecto-especifico)
├── engine.zig        # Meta-engine Get/Set con validacion
└── persistence.zig   # Load/Save archivo texto

Que se extrae a zcatconfig:

  • types.zig (completo)
  • engine.zig (generalizado)
  • persistence.zig (generalizado)

Que queda en el proyecto consumidor:

  • variables.zig (definiciones especificas del proyecto)
  • structures.zig (struct Config especifico)

ARQUITECTURA

┌─────────────────────────────────────────────────────────────────┐
│                      PROYECTO CONSUMIDOR                        │
│                                                                 │
│  variables.zig:                                                 │
│    pub const config_variables = [_]ConfigVariable{              │
│        .{ .name = "auto_save", .var_type = .boolean, ... },     │
│        .{ .name = "font_size", .var_type = .integer, ... },     │
│    };                                                           │
│                                                                 │
│  structures.zig:                                                │
│    pub const Config = struct {                                  │
│        auto_save: bool = true,                                  │
│        font_size: i32 = 14,                                     │
│    };                                                           │
├─────────────────────────────────────────────────────────────────┤
│                         ZCATCONFIG                              │
│                                                                 │
│  types.zig:                                                     │
│    ConfigVariable, ConfigVarType, ConfigResult, Color           │
│                                                                 │
│  engine.zig:                                                    │
│    Engine(comptime variables, comptime ConfigStruct)            │
│    - get(), set(), getByName(), setByName()                     │
│    - Validacion automatica                                      │
│                                                                 │
│  persistence.zig:                                               │
│    - load(config, path, variables)                              │
│    - save(config, path, variables)                              │
│    - Formato: @variable_name: valor  # comentario               │
└─────────────────────────────────────────────────────────────────┘

API PROPUESTA

Uso basico

const zcatconfig = @import("zcatconfig");

// En el proyecto consumidor:
const variables = @import("config/variables.zig");
const Config = @import("config/structures.zig").Config;

// Crear engine tipado
const Engine = zcatconfig.Engine(variables.config_variables, Config);

// Uso
var config = Config{};
Engine.load(&config, "app_config.txt") catch {};
config.font_size = 16;
try Engine.save(&config, "app_config.txt");

Tipos de variables soportados

Tipo Zig Type Formato archivo
boolean bool Si/No
integer i32 123
float f32 1.5
string []const u8 texto libre
color Color RGB(r,g,b)
enum_tipo enum NombreVariante

COMANDOS

# Compilar
PATH=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2:$PATH zig build

# Tests
PATH=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2:$PATH zig build test

RUTAS

# Este proyecto
/mnt/cello2/arno/re/recode/zig/zcatconfig/

# Proyecto origen (referencia)
/mnt/cello2/arno/re/recode/zig/zsimifactu/src/config/

# Documentacion equipo
/mnt/cello2/arno/re/recode/teamdocs/

PLAN DE TRABAJO

Fase 1: Estructura base

  • Crear proyecto (build.zig, CLAUDE.md)
  • Extraer types.zig de zsimifactu
  • Adaptar engine.zig (parametrizar variables y Config)
  • Adaptar persistence.zig

Fase 2: Generalizacion

  • Engine generico con comptime
  • Tests unitarios
  • Documentacion API

Fase 3: Integracion

  • Integrar en zsimifactu como dependencia
  • Verificar que zsimifactu funciona igual

Fase 4: ConfigManager

  • ConfigManager con loadOrCreate, auto-save, observers
  • Sistema de observers con contexto
  • isDirty tracking

Fase 5: FileWatcher + Utils

  • FileWatcher para hot-reload (mtime polling)
  • loadFromString para defaults embebidos
  • updateMtime para evitar auto-detectar cambios propios

API PRINCIPAL

ConfigManager (gestor autonomo)

const zcatconfig = @import("zcatconfig");

// Crear ConfigManager tipado
const MyConfigManager = zcatconfig.ConfigManager(&variables, MyConfig, "mi_app");

// Opcion 1: init() - Carga o crea archivo automaticamente
var manager = try MyConfigManager.init(allocator, "config.txt");
defer manager.deinit();  // Auto-save si dirty

// Opcion 2: initDeferred() - NO carga/crea archivo (control manual)
var manager = MyConfigManager.initDeferred(allocator, "config.txt");
// Luego cargar manualmente cuando sea necesario:
try manager.load();  // o manager.save() para crear

// Acceso
const cfg = manager.getConfig();
try manager.set("@mi_variable", "nuevo_valor");

// Observers
manager.addObserver(myCallback, my_context);

initDeferred() - Control manual de archivo (v0.2.3)

Cuando necesitas controlar cuándo se crea/carga el archivo (ej: arquitectura 3 fuentes):

// Caso de uso: File > BD > Defaults
// 1. Crear manager SIN cargar archivo
var manager = MyConfigManager.initDeferred(allocator, "config.txt");

// 2. Verificar si existe archivo
const archivo_existe = std.fs.cwd().access("config.txt", .{}) catch false;

// 3. Verificar si BD tiene config
const bd_tiene_config = checkDatabase();

// 4. Aplicar prioridad
if (archivo_existe) {
    try manager.load();           // Cargar de archivo
    syncToBd(&manager);           // Sync a BD
} else if (bd_tiene_config) {
    loadFromBd(&manager);         // Cargar de BD
    try manager.save();           // Crear archivo
} else {
    try manager.save();           // Crear con defaults
    syncToBd(&manager);           // Sync defaults a BD
}

Por qué initDeferred()?

  • init() llama loadOrCreate() que crea el archivo con defaults
  • Si BD tiene valores, el archivo ya existe antes de poder verificar
  • initDeferred() permite verificar BD primero, luego decidir

FileWatcher (hot-reload)

var watcher = zcatconfig.FileWatcher.init("config.txt", 1000);  // check cada 1s

// En main loop:
if (watcher.checkForChanges()) {
    // Recargar configuracion
}

// Despues de guardar:
watcher.updateMtime();  // Evitar detectar nuestro propio cambio

loadFromString (defaults embebidos)

const defaults = @embedFile("defaults.txt");
zcatconfig.loadFromString(&variables, Config, &config, defaults);

VALIDACION DE RANGOS (v0.2.3)

Rangos negativos soportados

La validación de rangos ahora soporta valores mínimos negativos:

// Definición de variable con rango negativo
.{ .name = "offset_x", .var_type = .integer, .range = "-100-100", ... }
.{ .name = "offset_y", .var_type = .integer, .range = "-50-50", ... }
.{ .name = "temperature", .var_type = .float, .range = "-40.0-85.0", ... }

Bug corregido (commit 957767d)

Problema: splitScalar('-') dividía "-100-100" como ["", "100", "100"]

Solución: Buscar el separador '-' excluyendo el primer carácter si es negativo:

const separator_pos = blk: {
    const start: usize = if (range.len > 0 and range[0] == '-') 1 else 0;
    for (range[start..], start..) |c, i| {
        if (c == '-') break :blk i;
    }
    return false;
};

Formatos de rango válidos

Rango Mínimo Máximo Notas
"0-100" 0 100 Positivo simple
"-100-100" -100 100 Negativo a positivo
"-50-50" -50 50 Centrado en cero
"-100-0" -100 0 Solo negativos

EQUIPO

  • Usuario (R.Eugenio): Desarrollador principal
  • Claude: Asistente de programacion (Claude Code / Opus 4.5)

HISTORIAL

Fecha Version Commit Cambios
2025-12-18 v0.2.3 957767d validateIntRange/Float fix: rangos negativos "-100-100"
2025-12-18 v0.2.2 0ef5efd initDeferred(): control manual sin auto-crear archivo
2025-12-18 v0.2.1 - FileWatcher, loadFromString, updateMtime
2025-12-17 v0.2.0 - ConfigManager con observers, auto-save, isDirty
2025-12-17 v0.1.0 - Proyecto creado, Engine + persistence