# SPDX-License-Identifier: LUL-1.0 # Copyright (c) 2026 Markus Maiwald # Stewardship: Self Sovereign Society Foundation # # This file is part of the Nexus Sovereign Core. # See legal/LICENSE_SOVEREIGN.md for license terms. ## Nexus Membrane: Configuration Ledger (SPEC-140) ## Implements Event Sourcing for System State. import strutils, times, options import kdl # Local NPK/NipBox KDL type OpType* = enum OpAdd, OpSet, OpDel, OpMerge, OpRollback ConfigTx* = object id*: uint64 timestamp*: uint64 author*: string op*: OpType path*: string value*: Node # KDL Node for complex values ConfigLedger* = object head_tx*: uint64 ledger_path*: string # --- Internal: Serialization --- proc serialize_tx*(tx: ConfigTx): string = ## Converts a transaction to a KDL block for the log file. result = "tx id=" & $tx.id & " ts=" & $tx.timestamp & " author=\"" & tx.author & "\" {\n" result.add " op \"" & ($tx.op).replace("Op", "").toUpperAscii() & "\"\n" result.add " path \"" & tx.path & "\"\n" if tx.value != nil: result.add tx.value.render(indent = 2) result.add "}\n" # --- Primary API --- proc ledger_append*(ledger: var ConfigLedger, op: OpType, path: string, value: Node, author: string = "root") = ## Appends a new transaction to the ledger. ledger.head_tx += 1 let tx = ConfigTx( id: ledger.head_tx, timestamp: uint64(epochTime()), author: author, op: op, path: path, value: value ) # TODO: SFS-backed atomic write to /Data/ledger.sfs let entry = serialize_tx(tx) echo "[LEDGER] TX Commit: ", tx.id, " (", tx.path, ")" # writeToFile(ledger.ledger_path, entry, append=true) proc ledger_replay*(ledger: ConfigLedger): Node = ## Replays the entire log to project the current state tree. ## Returns the root KDL Node of the current world state. result = newNode("root") echo "[LEDGER] Replaying from 1 to ", ledger.head_tx # 1. Read ledger.sfs # 2. Parse into seq[ConfigTx] # 3. Apply operations sequentially to result tree # TODO: Implement state projection logic proc ledger_rollback*(ledger: var ConfigLedger, target_tx: uint64) = ## Rolls back the system state. ## Note: This appends a ROLLBACK tx rather than truncating (SPEC-140 Doctrine). let rb_node = newNode("rollback_target") rb_node.addArg(newVal(int(target_tx))) ledger.ledger_append(OpRollback, "system.rollback", rb_node)