Visión general
Coclico está arquitecturado alrededor de un bucle autónomo: Observar → Analizar → Actuar → Validar
- Observar:
DynamicTracerServicerecopila telemetría CPU/RAM/red - Analizar:
OptimizationEngineService+SourceAnalyzerService(Roslyn AST) - Actuar:
AutoPatcherServiceaplica parches validados - Validar:
DigitalTwinServiceasegura que la complejidad ciclomática no aumenta
Framework: .NET 10 / C# (LangVersion: preview), UI en WPF + WPF-UI 4.x, DI via Microsoft.Extensions.DependencyInjection.
Arranque & DI
Punto de entrada: App.xaml.cs. Secuencia de arranque:
// App.xaml.cs — secuencia de arranque simplificada
protected override async void OnStartup(StartupEventArgs e)
{
// 1. Elevación UAC obligatoria
if (!ElevationHelper.IsElevated())
ElevationHelper.RestartAsAdmin();
// 2. Construcción del contenedor DI
ServiceContainer.Build(services =>
{
services.AddSingleton<ICacheService, CacheService>();
services.AddSingleton<IDynamicTracer, DynamicTracerService>();
services.AddSingleton<IRollbackService, RollbackService>();
services.AddSingleton<AiChatService>();
services.AddTransient<CleaningService>();
}, validateOnBuild: true);
// 3. SplashWindow durante el calentamiento de servicios
var splash = new SplashWindow();
splash.Show();
await Task.Delay(2000).ConfigureAwait(false);
// 4. Apertura de MainWindow
new MainWindow().Show();
splash.Close();
} ServiceContainer
Un wrapper estático thread-safe alrededor de IServiceProvider. Dos métodos principales:
public static class ServiceContainer
{
/// Resolución obligatoria — lanza excepción si falta
public static T GetRequired<T>() where T : notnull
=> _provider!.GetRequiredService<T>();
/// Resolución opcional — devuelve null si falta
public static T? GetOptional<T>() where T : class
=> _provider!.GetService<T>();
}
Prefiere la inyección por constructor en código nuevo. ServiceContainer.GetRequired<T>() está reservado para casos donde la inyección es imposible (handlers estáticos, convertidores WPF, etc.).
Patrón MVVM
Coclico sigue estrictamente el MVVM con CommunityToolkit.Mvvm 8.4:
- Vistas (
Views/*.xaml) — XAML puro, sin lógica de negocio - ViewModels (
ViewModels/*ViewModel.cs) —[ObservableProperty],[RelayCommand] - Servicios (
Services/*.cs) — lógica de negocio, acceso al sistema, IA
// ViewModels/DashboardViewModel.cs
public partial class DashboardViewModel : ObservableObject
{
[ObservableProperty] private double _cpuUsage;
[ObservableProperty] private long _ramUsedMb;
[RelayCommand]
private async Task RefreshAsync()
{
var snap = await _tracer.GetSnapshotAsync().ConfigureAwait(false);
// Siempre Dispatcher.InvokeAsync para actualizaciones de UI
await Application.Current.Dispatcher
.InvokeAsync(() => { CpuUsage = snap.CpuPercent; });
}
} Dual LLM Executor
AiChatService mantiene dos pares de contexto/executor LLamaSharp completamente aislados para evitar contención entre el chat de usuario y el motor de optimización:
public sealed class AiChatService
{
// Contexto dedicado al chat de usuario (AiChatView)
private LLamaContext _chatCtx;
private readonly SemaphoreSlim _chatSem = new(1, 1);
// Contexto dedicado al OptimizationEngine (segundo plano)
private LLamaContext _engineCtx;
private readonly SemaphoreSlim _engineSem = new(1, 1);
// Immutable Context Swap — reset sin bloquear consumidores
public async Task ResetChatContextAsync()
{
var old = Interlocked.Exchange(ref _chatCtx, await BuildContextAsync());
old?.Dispose();
}
} FeatureExecutionEngine
Todas las acciones de larga duración deben pasar por FeatureExecutionEngine.RunFeatureAsync, que añade automáticamente protección circuit-breaker, telemetría y soporte de cancelación.
RollbackService
Cada operación de escritura disparada por la IA debe ir precedida de un snapshot de rollback:
// Patrón obligatorio antes de File.WriteAllText
var snapshotId = await _rollback
.CreateSnapshotAsync(targetFilePath)
.ConfigureAwait(false);
try
{
File.WriteAllText(targetFilePath, newContent, Encoding.UTF8);
}
catch
{
await _rollback.RestoreAsync(snapshotId).ConfigureAwait(false);
throw;
} Sistema Flow Chains
Tres servicios gestionan el ciclo de vida del pipeline de automatización:
WorkflowPipelineService— CRUD para definiciones de pipeline (JSON en%APPDATA%\Coclico\flow-chains\)WorkflowPipelineExecutionService— ejecución secuencial con circuit-breaker y aplicación de política de seguridadWorkflowExecutionService— orquestación de alto nivel y planificación
Modelo WorkflowPipeline
public record WorkflowPipeline
{
public Guid Id { get; init; } = Guid.NewGuid();
public string Name { get; init; } = string.Empty;
public List<PipelineNode> Nodes { get; init; } = [];
}
// 28 valores NodeType, 10 valores ConditionOperator, 3 valores OnErrorAction
public enum NodeType
{
KillProcess, LaunchProcess, RestartService, StopService, StartService,
SetRegistryValue, DeleteRegistryKey, CreateDirectory, DeleteFile,
MoveFile, CopyFile, RunScript, CleanTemp, EmptyRecycleBin, FlushDns,
ClearBrowserCache, ClearEventLogs, ClearPrefetch, ClearThumbnailCache,
ClearWindowsErrorReports, FreeRam, SetWorkingSet, PingHost,
DisableNetworkAdapter, EnableNetworkAdapter, Wait, Condition, Log, Notification
} SourceAnalyzer (Roslyn AST) — Fase 3.3
SourceAnalyzerService usa Roslyn para analizar el propio código fuente C# de Coclico. Calcula por método: Complejidad Ciclomática (CC), métricas Halstead (V, D, E) e Índice de Mantenibilidad (MI).
Digital Twin Gate — Fase 3.3
Antes de aplicar cualquier parche generado por IA, DigitalTwinService valida que el parche no aumente la complejidad ciclomática. Si patchedCC > originalCC, el parche es rechazado.
AutoPatcher — Fase 3.4
Gestiona el ciclo de vida de los parches de IA con aprobación humana. Por defecto: AutoPatcherAuditOnly = true — los parches se registran en el log de auditoría pero nunca se aplican sin aprobación explícita vía ApproveAndApplyAsync(proposalId).
OptimizationEngine — Fase 2
Se ejecuta cada 30 segundos en segundo plano. Reglas críticas: usar ArrayPool<byte>.Shared para buffers de telemetría, nunca closures en el bucle principal, siempre ConfigureAwait(false).
Seguridad & Auditoría
SecurityPolicyService fusiona %APPDATA%\Coclico\security-policy.json con valores predeterminados codificados no suprimibles. AuditLogService escribe NDJSON de solo anexión incluyendo AiDecisionContext para trazabilidad completa de decisiones LLM.
Convenciones de código
- Nomenclatura:
PascalCasepara clases/interfaces,_camelCasepara campos privados, sufijoAsyncpara métodos async - Inyección: Solo por constructor — nunca service-locate dentro de un constructor
- Segundo plano:
ConfigureAwait(false)en cadaawaiten servicios - Logs:
LoggingService.LogInfo/LoggingService.LogException— nunca silenciar excepciones - DTOs: Usar
recordpara snapshots y resultados (inmutabilidad) - Secretos: Nunca codificar en duro — usar
SettingsServiceo variables de entorno - C# 12: Usar primary constructors y collection expressions (
[])