Pausa: 11 crates del fractal Ente #0 con cerebro completo
PID 1 boot + bus interno autenticado + cerebro KCL/Rust: - 6 lib crates de infra (card, bus, cas, kernel, soma, wasm, snapshot) - ente-brain: motor de reglas O(1), observer Shannon, cristalización, audit hash-chain, persistencia rules.k, Prometheus /metrics - KCL schemas card.k + rule.k como gramática autoritativa - compat-logind D-Bus, ente-echo demo provider, ente-zero PID 1 - 22 tests OK, ~3.8k LOC Rust + ~300 LOC KCL Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
# ============================================================================
|
||||
# rule.k — Triplet [Sujeto + Evento + Acción(Objeto)]. La gramática del
|
||||
# Cerebro del fractal. Cada regla es una sinapsis: cuando ocurre `when`,
|
||||
# el motor ejecuta `then` para todos los Entes que cumplen `scope`.
|
||||
#
|
||||
# El motor en Rust las indexa por discriminante de EventKind para lookup
|
||||
# en O(1). Las reglas son inmutables tras carga (Arc<Rule>).
|
||||
# ============================================================================
|
||||
|
||||
schema Rule:
|
||||
"""Una sinapsis del fractal. Determinista, sin estado entre disparos."""
|
||||
id: str # Ulid 26 chars
|
||||
priority: int = 5 # 0..255, mayor = se ejecuta primero
|
||||
when: EventPattern
|
||||
then: [Action]
|
||||
scope: Scope = Scope {} # qué Entes son sujetos válidos
|
||||
|
||||
check:
|
||||
len(id) == 26, "id debe ser Ulid"
|
||||
priority >= 0 and priority <= 255, "priority fuera de rango"
|
||||
len(then) > 0, "regla sin acciones"
|
||||
|
||||
|
||||
# ---------- Subject: alcance del sujeto ----------
|
||||
|
||||
schema Scope:
|
||||
"""Match del sujeto. None en todos los campos = match cualquier Ente."""
|
||||
subject_id?: str # Ulid exacto
|
||||
subject_label?: str # label exacto
|
||||
subject_has_cap?: Capability # Ente que declara esta capacidad
|
||||
|
||||
check:
|
||||
subject_id is None or len(subject_id) == 26, "subject_id no es Ulid"
|
||||
|
||||
|
||||
# ---------- Event: qué dispara la regla ----------
|
||||
|
||||
# EventPattern es tagged union recursivo.
|
||||
#
|
||||
# Atómicos:
|
||||
# Single — match un evento por kind
|
||||
# Sequence — N eventos consecutivos dentro de within_ms
|
||||
#
|
||||
# Compuestos (recursivos):
|
||||
# Either — OR sobre sub-patterns
|
||||
# All — AND sobre sub-patterns (mismo event/history)
|
||||
schema EventPattern:
|
||||
type: "Single" | "Sequence" | "Either" | "All"
|
||||
kind?: EventKind # Single
|
||||
kinds?: [EventKind] # Sequence
|
||||
within_ms?: int = 0
|
||||
patterns?: [EventPattern] # Either / All (recursivo)
|
||||
|
||||
check:
|
||||
type != "Single" or kind is not None, "Single requiere kind"
|
||||
type != "Sequence" or (kinds is not None and len(kinds) > 0), \
|
||||
"Sequence requiere kinds no vacío"
|
||||
type != "Either" or (patterns is not None and len(patterns) > 0), \
|
||||
"Either requiere patterns no vacío"
|
||||
type != "All" or (patterns is not None and len(patterns) > 0), \
|
||||
"All requiere patterns no vacío"
|
||||
within_ms is None or within_ms >= 0, "within_ms negativo"
|
||||
|
||||
|
||||
# EventKind con tag interno + payload opcional según tag.
|
||||
schema EventKind:
|
||||
tag: "EnteSpawned" | "EnteDied" | "BusAnnounce" | "BusInvoke" | "BusInvokeOf" | "DeviceAdded" | "DeviceRemoved" | "Custom"
|
||||
cap?: Capability # para BusInvokeOf
|
||||
custom?: str # para Custom
|
||||
|
||||
check:
|
||||
tag != "BusInvokeOf" or cap is not None, "BusInvokeOf requiere cap"
|
||||
tag != "Custom" or custom is not None, "Custom requiere custom string"
|
||||
|
||||
|
||||
# ---------- Action: qué hacer ----------
|
||||
|
||||
schema Action:
|
||||
"""Una acción ejecutable por el motor. Tagged union con kind."""
|
||||
kind: "Log" | "Notify" | "Spawn" | "Invoke" | "Inhibit"
|
||||
# Log
|
||||
level?: "trace" | "debug" | "info" | "warn" | "error"
|
||||
message?: str
|
||||
# Notify
|
||||
target_id?: str # Ulid
|
||||
# Spawn
|
||||
card_blob?: str # base64-encoded EntityCard JSON
|
||||
# Invoke
|
||||
target_cap?: Capability
|
||||
blob_b64?: str
|
||||
# Inhibit
|
||||
reason?: str
|
||||
|
||||
check:
|
||||
kind != "Log" or message is not None, "Log requiere message"
|
||||
kind != "Notify" or (target_id is not None and message is not None), \
|
||||
"Notify requiere target_id + message"
|
||||
kind != "Spawn" or card_blob is not None, "Spawn requiere card_blob"
|
||||
kind != "Invoke" or target_cap is not None, "Invoke requiere target_cap"
|
||||
kind != "Inhibit" or reason is not None, "Inhibit requiere reason"
|
||||
|
||||
|
||||
# ---------- Capability: re-export desde card.k para evitar inclusión circular ----------
|
||||
|
||||
# En uso real: `import ..ente_card.schema.card` y referencia Capability.
|
||||
# Aquí declaramos una versión alineada para auto-contención del esquema.
|
||||
schema Capability:
|
||||
kind: "FilesystemRoot" | "KernelNetlink" | "Endpoint" | "LegacyLogind" | "Device" | "Spawn" | "Journal"
|
||||
netlink_family?: "Uevent" | "Route" | "Generic" | "Audit"
|
||||
endpoint_interface?: str
|
||||
endpoint_version?: int
|
||||
device_class?: "Block" | "Tty" | "Input" | "Drm" | "Net" | "Hidraw"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Ejemplo de regla cristalizada (auto-generada por el observador)
|
||||
# ============================================================================
|
||||
|
||||
example_rule = Rule {
|
||||
id = "01KQQ100000000000000000000"
|
||||
priority = 5
|
||||
when = EventPattern {
|
||||
type = "Single"
|
||||
kind = EventKind {tag = "EnteSpawned"}
|
||||
}
|
||||
scope = Scope {
|
||||
subject_label = "demo-echo"
|
||||
}
|
||||
then = [
|
||||
Action {
|
||||
kind = "Log"
|
||||
level = "info"
|
||||
message = "demo-echo encarnado, observando para crystallization"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Ejemplo de regla compuesta: cuando un Ente se anuncia y luego es invocado
|
||||
# en menos de 500ms, log estructurado para auditoría.
|
||||
example_sequence = Rule {
|
||||
id = "01KQQ200000000000000000000"
|
||||
priority = 7
|
||||
when = EventPattern {
|
||||
type = "Sequence"
|
||||
kinds = [
|
||||
EventKind {tag = "BusAnnounce"}
|
||||
EventKind {tag = "BusInvoke"}
|
||||
]
|
||||
within_ms = 500
|
||||
}
|
||||
scope = Scope {}
|
||||
then = [
|
||||
Action {
|
||||
kind = "Log"
|
||||
level = "info"
|
||||
message = "patrón Announce→Invoke detectado <500ms"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user