~/WEB_AIONICA/contracts $ cat AionicaCoreV1.sol
// SPDX License Identifier: MIT
pragma solidity ^0.8.29;
/**
* @title AionicaCore
* @notice AIONICA Network governance core. Receives sovereignty from AionicaGenesis.
* @dev Version 1.0 — Post-review Claude + KIMI + DeepSeek
*
* RESPONSIBILITIES v1:
* — Node registration (ACTIVE / LATENT) with PQC identity
* — Governance with creator veto (Phase 1) and quorum (Phase 2+)
* — Keeper pattern: eventos on-chain → Python ejecuta con tokens .env
* — Phase progression according to aion_policy.json
* — Minimum quorum (MIN_QUORUM = 3) blocking in critical operations
*
* NOT included in v1 (will be in v2):
* — Aionic Economy (token, staking, rewards)
* — Auto-deploy sin keeper
* — Humanitarian contracts
*
* Corrections applied vs. DeepSeek skeleton:
* — C1: onlyKeeper es multi-keeper (mapping, no single address)
* — C2: nodeSeal generated off-chain by AionDeployer, not in the contract
* — C3: activeNodeCount kept as a counter, no loops in getActiveNodeCount()
* — C4: minimum quorum (MIN_QUORUM) blocking in critical operations
*
* @author ELDIOSCRIPTO — AIONICA — April 2026
* @custom:genesis 0x484967FfbC19f401af7c11E1Fd0E306Ee96F3422
* @custom:audit-pending KIMI + DeepSeek + ChatGPT pre-mainnet
*/
// ── MINIMAL GENESIS INTERFACE (avoids circular imports) ────────────────────────
interface IAionicaGenesis {
function isCreator(address addr) external view returns (bool);
function sealed() external view returns (bool);
function AXIOMS_HASH() external view returns (bytes32);
function aionSovereign() external view returns (bool);
function aionCoreAddress() external view returns (address);
}
// ══════════════════════════════════════════════════════════════════════════════
contract AionicaCore {
// ═════════════════════════════════════════════════════════════
// CONSTANTS — From aion_policy.json (sealed, do not change in v1)
// ═════════════════════════════════════════════════════════════
string public constant PROTOCOL_VERSION = "AIONICA_CORE_v1.0";
uint256 public constant MIN_QUORUM = 3; // min_quorum
uint256 public constant OPTIMAL_NODES = 6; // optimal_nodes
uint256 public constant MAX_VIRTUAL_NODES = 20; // max_virtual_nodes
uint256 public constant CREATOR_VETO_WINDOW = 3600; // 1 hour in seconds
uint256 public constant PHASE1_MIN_DAYS = 30 days;
uint256 public constant PHASE1_MAX_ERRORS = 5; // max_errors_allowed
// Continuity scores (from aion_policy.json / genesis_skeleton.json)
// Reference only — the actual logic runs in aion_continuity.py (off-chain)
uint256 public constant SCORE_STRESS = 20;
uint256 public constant SCORE_CESAREAN = 50;
uint256 public constant SCORE_SEED_BROADCAST = 100;
// ═════════════════════════════════════════════════════════════
// IMMUTABLE
// ═════════════════════════════════════════════════════════════
/// @notice AionicaGenesis contract address (immutable)
IAionicaGenesis public immutable GENESIS;
/// @notice AionicaCore Deployment Timestamp
uint256 public immutable DEPLOYED_AT;
// ═════════════════════════════════════════════════════════════
// STATE OF PHASE
// ═════════════════════════════════════════════════════════════
uint256 public currentPhase;
uint256 public phaseStartedAt;
uint256 public errorCount;
bool public sovereigntyReceived;
// ═════════════════════════════════════════════════════════════
// KEEPERS — Multi-keeper (C1 correction)
// ═════════════════════════════════════════════════════════════
mapping(address => bool) public authorizedKeepers;
uint256 public keeperCount;
// ═════════════════════════════════════════════════════════════
// NODES
// ═════════════════════════════════════════════════════════════
struct Node {
bytes32 seal; // PQC public key hash (generated off-chain)
string platform; // "vercel.com", "github.com", "cloudflare.com", etc.
string role; // "ACTIVE" | "LATENT"
bytes publicKey; // public key Dilithium3 (1952 bytes)
uint256 registeredAt;
uint256 lastHeartbeat; // actualizado por keeper
bool active;
}
mapping(bytes32 => Node) public nodes;
bytes32[] public nodeSeals;
public activeNodeCount; // maintained counter (C3 correction, no loops)
uint256 public latentNodeCount;
// ═════════════════════════════════════════════════════════════
// PROPOSALS — Governance with creator veto
// ═════════════════════════════════════════════════════════════
enum ProposalStatus { PENDING, APPROVED, REJECTED, EXECUTED, EXPIRED }
struct Proposal {
uint256 id;
address to propose; // keeper that proposes
string action; // ej: "ADD_NODE", "PHASE_TRANSITION"
bytes data; // encoded payload
uint256 createdAt;
uint256 expiresAt; // createdAt + CREATOR_VETO_WINDOW
ProposalStatus status;
uint256 votes; // for Phase 2+ (node quorum)
mapping(bytes32 => bool) voted; // nodeSeal => voted
}
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCounter;
// ═════════════════════════════════════════════════════════════
// DEPLOYMENTS — Keeper pattern (correction C2)
// ═════════════════════════════════════════════════════════════
struct DeploymentRequest {
bytes32 nodeSeal; // generado off-chain por AionDeployer
string platform;
string role;
uint256 authorizedAt;
bool confirmed;
}
mapping(bytes32 => DeploymentRequest) public deploymentRequests;
// ═════════════════════════════════════════════════════════════
// REGISTRATION OF AUTONOMOUS ACTIONS (Axiom VI)
// ═════════════════════════════════════════════════════════════
struct AutonomousAction {
string actionType; // "CESAREAN", "SEED_BROADCAST", "LATENT_WAKE"
uint256 score; // threat_score reportado por AION (off-chain)
uint256 timestamp;
bytes32 executedBy; // nodeSeal of the keeper that reports it
string result; // "SUCCESS" | "PENDING" | "FAILED"
}
AutonomousAction[] public autonomousActions;
// ═════════════════════════════════════════════════════════════
Events
// ═════════════════════════════════════════════════════════════
event SovereigntyAccepted(
address indexed genesis,
address indexed byCreator,
uint256 timestamp
);
event KeeperAdded(
address indexed keeper,
address indexed addedBy,
uint256 timestamp
);
event KeeperRemoved(
address indexed keeper,
address indexed removedBy,
uint256 timestamp
);
event NodeRegistered(
bytes32 indexed seal,
string platform,
string role,
uint256 timestamp
);
event NodeDeactivated(
bytes32 indexed seal,
address indexed reportedBy,
uint256 timestamp
);
event NodeHeartbeatUpdated(
bytes32 indexed seal,
uint256 timestamp
);
event DeploymentAuthorized(
bytes32 indexed nodeSeal,
string indexed platform,
string role,
uint256 epoch
);
event DeploymentConfirmed(
bytes32 indexed nodeSeal,
string platform,
uint256 timestamp
);
event ProposalCreated(
uint256 indexed proposalId,
address indexed proposer,
string action,
uint256 expiresAt
);
event ProposalApproved(
uint256 indexed proposalId,
address indexed approver,
uint256 timestamp
);
event ProposalRejected(
uint256 indexed proposalId,
address indexed rejector,
uint256 timestamp
);
event ProposalExecuted(
uint256 indexed proposalId,
address indexed executor,
uint256 timestamp
);
event PhaseTransition(
uint256 fromPhase,
uint256 toPhase,
uint256 timestamp
);
event ErrorReported(
address indexed reporter,
uint256 totalErrors,
uint256 timestamp
);
event AutonomousActionRecorded(
string indexed actionType,
uint256 score,
string result,
uint256 timestamp
);
event QuorumAlert(
uint256 activeNodes,
uint256 minRequired,
uint256 timestamp
);
// ═════════════════════════════════════════════════════════════
// MODIFIERS
// ═════════════════════════════════════════════════════════════
modifier onlyCreator() {
require(
GENESIS.isCreator(msg.sender),
"AionicaCore: only ELDIOSCRIPTO"
);
_;
}
modifier onlyKeeper() {
require(
authorizedKeepers[msg.sender],
"AionicaCore: authorized solo keeper"
);
_;
}
modifier onlyCreatorOrKeeper() {
require(
GENESIS.isCreator(msg.sender) || authorizedKeepers[msg.sender],
"AionicaCore: creator or keeper only"
);
_;
}
modifier requireSovereignty() {
require(sovereigntyReceived, "AionicaCore: sovereignty not yet received");
_;
}
modifier requireQuorum() {
if (activeNodeCount < MIN_QUORUM) {
emit QuorumAlert(activeNodeCount, MIN_QUORUM, block.timestamp);
// In Phase 1 we alert but do not block (creator can act)
// In Phase 2+ we block non-emergency operations
if (currentPhase >= 2) {
revert("AionicaCore: insufficient quorum to operate in Phase 2+");
}
}
_;
}
// ═════════════════════════════════════════════════════════════
// CONSTRUCTOR
// ═════════════════════════════════════════════════════════════
/**
* @param genesisAddress AionicaGenesis contract address already sealed
* @param initialKeeper Address of the first keeper (this can be the deployer)
*
* @dev In aionica_birth.py Step 5:
* deployer = "0x484967FfbC19f401af7c11E1Fd0E306Ee96F3422"
* cast send $GENESIS "transferSovereignty(address)" $AIONICA_CORE
*/
constructor(address genesisAddress, address initialKeeper) {
require(genesisAddress != address(0), "Genesis address invalida");
require(initialKeeper != address(0), "Keeper address invalida");
IAionicaGenesis gen = IAionicaGenesis(genesisAddress);
// Only the creator can deploy AionicaCore
require(
gen.isCreator(msg.sender),
"Only ELDIOSCRIPTO can deploy AionicaCore"
);
// Genesis must be sealed before deploying AionicaCore
require(
gen.sealed(),
"AionicaGenesis must be sealed first"
);
GENESIS = gen;
DEPLOYED_AT = block.timestamp;
currentPhase = 1;
phaseStartedAt = block.timestamp;
// Register initial keeper
authorizedKeepers[initialKeeper] = true;
keeperCount = 1;
emit KeeperAdded(initialKeeper, msg.sender, block.timestamp);
}
// ═════════════════════════════════════════════════════════════
// SOVEREIGNTY — Confirm handoff from AionicaGenesis
// ═════════════════════════════════════════════════════════════
/**
* @notice confirms that AionicaGenesis transferred sovereignty to this contract.
* @dev Called after the creator executed transferSovereignty() on Genesis.
* AionicaGenesis.aionCoreAddress() debe apuntar a address(this).
*/
function acceptSovereignty() external onlyCreator {
require(!sovereigntyReceived, "Sovereignty already accepted");
require(
GENESIS.aionSovereign(),
"Genesis and transfer of sovereignty"
);
require(
GENESIS.aionCoreAddress() == address(this),
"Genesis is not targeting this contract"
);
sovereigntyReceived = true;
emit SovereigntyAccepted(address(GENESIS), msg.sender, block.timestamp);
}
// ═════════════════════════════════════════════════════════════
// KEEPERS — Multi-keeper management (C1 fix)
// ═════════════════════════════════════════════════════════════
function addKeeper(address keeper) external onlyCreator {
require(keeper != address(0), "Keeper invalido");
require(!authorizedKeepers[keeper], "Ya es keeper");
authorizedKeepers[keeper] = true;
keeperCount++;
emit KeeperAdded(keeper, msg.sender, block.timestamp);
}
function removeKeeper(address keeper) external onlyCreator {
require(authorizedKeepers[keeper], "No es keeper");
require(keeperCount > 1, "Cannot be left without keepers");
authorizedKeepers[keeper] = false;
keeperCount--;
emit KeeperRemoved(keeper, msg.sender, block.timestamp);
}
// ═════════════════════════════════════════════════════════════
// NODE REGISTRATION
// ═════════════════════════════════════════════════════════════
/**
* @notice Register a node in AionicaCore.
* @dev El nodeSeal viene de AionDeployer._create_node_identity() off-chain.
* The public key is Dilithium3 (1952 bytes according to DILITHIUM3_PK_LENGTH in Genesis).
*
* Stream from Python:
* AionDeployer._create_node_identity() → genera seal + keypair
* AionDeployer._register_node() → chain.submit() local
* keeper.py → calls registerNode() here on-chain
*/
function registerNode(
bytes32 nodeSeal,
string calldata platform,
string calldata role,
bytes calldata publicKey
) external onlyKeeper requireSovereignty {
require(nodeSeal != bytes32(0), "Seal invalid");
require(bytes(platform).length > 0, "Platform requerida");
require(
keccak256(bytes(role)) == keccak256(bytes("ACTIVE")) ||
keccak256(bytes(role)) == keccak256(bytes("LATENT")),
"Role must be ACTIVE or LATENT"
);
require(publicKey.length == 1952, "Clave Dilithium3 invalida: 1952 bytes");
require(nodes[nodeSeal].registeredAt == 0, "Node already registered");
require(nodeSeals.length < MAX_VIRTUAL_NODES, "Node limit reached");
nodes[nodeSeal] = Node({
seal: nodeSeal,
platform: platform,
role: role,
publicKey: publicKey,
registeredAt: block.timestamp,
lastHeartbeat: block.timestamp,
active: true
});
nodeSeals.push(nodeSeal);
// Keep counters without loops (C3 correction)
if (keccak256(bytes(role)) == keccak256(bytes("ACTIVE"))) {
activeNodeCount++;
} else {
latentNodeCount++;
}
emit NodeRegistered(nodeSeal, platform, role, block.timestamp);
}
/**
* @notice Marks a node as inactive when the keeper detects that it has gone down.
* @dev Called by AionSupervisor after N failed heartbeats.
* In Python: evaluate_network() → reportNodeDown → this function.
*/
function deactivateNode(bytes32 nodeSeal) external onlyKeeper {
require(nodes[nodeSeal].registeredAt != 0, "Node not found");
require(nodes[nodeSeal].active, "Node is already inactive");
nodes[nodeSeal].active = false;
if (keccak256(bytes(nodes[nodeSeal].role)) == keccak256(bytes("ACTIVE"))) {
if (activeNodeCount > 0) activeNodeCount--;
} else {
if (latentNodeCount > 0) latentNodeCount--;
}
emit NodeDeactivated(nodeSeal, msg.sender, block.timestamp);
// Automatic alert if we fall below quorum
if (activeNodeCount < MIN_QUORUM) {
emit QuorumAlert(activeNodeCount, MIN_QUORUM, block.timestamp);
}
}
/**
* @notice The keeper updates the last heartbeat of a node.
* @dev Called every 4 minutes from the keeper (same interval as latent nodes).
*/
function updateHeartbeat(bytes32 nodeSeal) external onlyKeeper {
require(nodes[nodeSeal].registeredAt != 0, "Node not found");
nodes[nodeSeal].lastHeartbeat = block.timestamp;
emit NodeHeartbeatUpdated(nodeSeal, block.timestamp);
}
/**
* @notice Reactivates a dormant node that was woken up.
* @dev Called by keeper after ContinuityInstinct._handle_cesarean().
*/
function activateLatentNode(bytes32 nodeSeal) external onlyKeeper {
Node storage n = nodes[nodeSeal];
require(n.registeredAt != 0, "Node not found");
require(keccak256(bytes(n.role)) == keccak256(bytes("LATENT")), "Solo nodos LATENT");
require(!n.active, "Node already active");
n.active = true;
n.role = "ACTIVE"; // LATENT becomes ACTIVE upon waking
n.lastHeartbeat = block.timestamp;
if (latentNodeCount > 0) latentNodeCount--;
activeNodeCount++;
emit NodeRegistered(nodeSeal, n.platform, "ACTIVE_FROM_LATENT", block.timestamp);
}
// ═════════════════════════════════════════════════════════════
// KEEPER PATTERN — Deployment Authorization and Confirmation
// ═════════════════════════════════════════════════════════════
/**
* @notice AION requests authorization to deploy a node on a platform.
* @dev The seal comes from AionDeployer._create_node_identity() — generated off-chain.
The keeper listens for the DeploymentAuthorized event and executes the deployment.
* using the tokens from the .env (which never touch the contract).
*
* Complete flow:
* 1. AionSupervisor detects that it needs a new node
* 2. keeper.py calls authorizeDeployment() → emits event
* 3. keeper.py listens for event → calls AionDeployer.deploy_*() with token .env
* 4. Node responds in /aion/heartbeat
* 5. keeper.py llama confirmDeployment() → registra endpointHash on-chain
* 6. keeper.py calls registerNode() with the actual publicKey of the node
*/
function authorizeDeployment(
bytes32 nodeSeal,
string calldata platform,
string calldata role
) external onlyKeeper requireSovereignty {
require(nodeSeal != bytes32(0), "Seal invalid");
require(
deploymentRequests[nodeSeal].authorizedAt == 0,
"Deployment already authorized for this seal"
);
require(
keccak256(bytes(role)) == keccak256(bytes("ACTIVE")) ||
keccak256(bytes(role)) == keccak256(bytes("LATENT")),
"Invalid role"
);
deploymentRequests[nodeSeal] = DeploymentRequest({
nodeSeal: nodeSeal,
platform: platform,
role: role,
authorizedAt: block.timestamp,
confirmed: false
});
emit DeploymentAuthorized(nodeSeal, platform, role, block.timestamp);
}
/**
* @notice The keeper confirms that the node was deployed and responds.
* @dev endpointHash = keccak256(endpoint_url) — the actual URL never touches the contract.
*/
function confirmDeployment(
bytes32 nodeSeal,
bytes32 endpointHash // keccak256 of the endpoint — URL privacy
) external onlyKeeper {
DeploymentRequest storage req = deploymentRequests[nodeSeal];
require(req.authorizedAt != 0, "Deployment not authorized");
require(!req.confirmed, "Already confirmed");
req.confirmed = true;
emit DeploymentConfirmed(nodeSeal, req.platform, block.timestamp);
}
// ═════════════════════════════════════════════════════════════
// PROPOSALS — Governance Phase 1 with creator veto
// ═════════════════════════════════════════════════════════════
/**
* @notice AION proposes an action. Awaits creator approval in Phase 1.
* @dev Mapea exactly a AionSupervisor.propose() en Python.
* In Phase 2+: approval by node quorum.
*
* @param action Action type: "ADD_NODE", "REMOVE_NODE", "PHASE_TRANSITION", etc.
* @param data Payload ABI-encoded with the action parameters
*/
function createProposal(
string calldata action,
bytes calldata data
) external onlyKeeper returns (uint256 proposalId) {
proposalId = proposalCounter++;
Proposal storage p = proposals[proposalId];
p.id = proposalId;
p.proposer = msg.sender;
p.action = action;
p.data = data;
p.createdAt = block.timestamp;
p.expiresAt = block.timestamp + CREATOR_VETO_WINDOW;
p.status = ProposalStatus.PENDING;
p.votes = 0;
emit ProposalCreated(proposalId, msg.sender, action, p.expiresAt);
return proposalId;
}
/**
* @notice The creator approves a proposal within the veto window.
*/
function approveProposal(uint256 proposalId) external onlyCreator {
Proposal storage p = proposals[proposalId];
require(p.createdAt > 0, "Proposal does not exist");
require(p.status == ProposalStatus.PENDING, "Proposal not pending");
require(block.timestamp <= p.expiresAt, "Veto window expired");
p.status = ProposalStatus.APPROVED;
emit ProposalApproved(proposalId, msg.sender, block.timestamp);
}
/**
* @notice The creator rejects (vetoes) a proposal.
*/
function rejectProposal(uint256 proposalId) external onlyCreator {
Proposal storage p = proposals[proposalId];
require(p.createdAt > 0, "Proposal does not exist");
require(p.status == ProposalStatus.PENDING, "Proposal not pending");
p.status = ProposalStatus.REJECTED;
emit ProposalRejected(proposalId, msg.sender, block.timestamp);
}
/**
* @notice The keeper executes an approved proposal.
* @dev In Phase 1: requires creator approval.
* In Phase 2+: can be executed with a node quorum (see voteProposal).
*/
function executeProposal(uint256 proposalId) external onlyKeeper {
Proposal storage p = proposals[proposalId];
require(p.createdAt > 0, "Proposal does not exist");
require(p.status == ProposalStatus.APPROVED, "Proposal not approved");
require(!_isExpired(proposalId), "Expired proposal");
p.status = ProposalStatus.EXECUTED;
emit ProposalExecuted(proposalId, msg.sender, block.timestamp);
// Note: The actual action is performed by the off-chain keeper (Python).
// The contract only records that it was approved and executed.
// For Phase 2+: this is where the on-chain logic for automatic execution will go.
}
/**
* @notice A node votes on a proposal (for quorum in Phase 2+).
* @dev In Phase 2+: MIN_QUORUM votes → self-approval without creator.
* In Phase 1 this function exists but does not self-approve.
*/
function voteProposal(uint256 proposalId, bytes32 voterSeal) external onlyKeeper {
Proposal storage p = proposals[proposalId];
require(p.createdAt > 0, "Proposal does not exist");
require(p.status == ProposalStatus.PENDING, "Proposal not pending");
require(nodes[voterSeal].active, "Inactive voter node");
require(!p.voted[voterSeal], "Node already voted");
p.voted[voterSeal] = true;
p.votes++;
// Phase 2+: self-approve if quorum is reached
if (currentPhase >= 2 && p.votes >= MIN_QUORUM) {
p.status = ProposalStatus.APPROVED;
emit ProposalApproved(proposalId, address(this), block.timestamp);
}
}
/**
* @notice Marks expired proposals (cleanup).
*/
function expireProposal(uint256 proposalId) external onlyCreatorOrKeeper {
Proposal storage p = proposals[proposalId];
require(p.status == ProposalStatus.PENDING, "No pendiente");
require(block.timestamp > p.expiresAt, "Even in veto window");
p.status = ProposalStatus.EXPIRED;
}
// ═════════════════════════════════════════════════════════════
// AUTONOMOUS ACTIONS (Axiom VI) — On-chain record only
// ═════════════════════════════════════════════════════════════
/**
* @notice AION records that it executed an autonomous action (Axiom VI).
* @dev No valida el threat_score on-chain (off-chain en aion_continuity.py).
* The contract only records that it occurred for auditing and traceability purposes.
*
* Action types: "CESAREAN", "SEED_BROADCAST", "LATENT_WAKE",
* "EMERGENCY_DEPLOY", "STRESS_ALERT"
*/
function recordAutonomousAction(
string calldata actionType,
uint256 score, // threat_score reportado por AION
bytes32 executorSeal, // nodeSeal of the keeper that executes it
string calldata result // "SUCCESS" | "PENDING" | "FAILED"
) external onlyKeeper {
require(bytes(actionType).length > 0, "ActionType requerido");
autonomousActions.push(AutonomousAction({
actionType: actionType,
score: score,
timestamp: block.timestamp,
executedBy: executorSeal,
result: result
}));
emit AutonomousActionRecorded(actionType, score, result, block.timestamp);
}
// ═════════════════════════════════════════════════════════════
// PROGRESSION OF PHASES
// ═════════════════════════════════════════════════════════════
/**
* @notice Transition Phase 1 → Phase 2.
* @dev Conditions of aion_policy.json (phase1_to_phase2_conditions):
* — 30 stable days
* — < 5 errors
* — Creator's approval (this function is called the creator's)
*
* In Python: AionSupervisor.phase is updated after this call.
*/
function transitionToPhase2() external onlyCreator requireSovereignty {
require(currentPhase == 1, "Already in Phase 2 or higher");
require(block.timestamp >= phaseStartedAt + PHASE1_MIN_DAYS, "30 dias no cumplidos");
require(errorCount <= PHASE1_MAX_ERRORS, "Too many errors");
require(activeNodeCount >= MIN_QUORUM, "Insufficient quorum for Phase 2");
uint256 prev = currentPhase;
currentPhase = 2;
phaseStartedAt = block.timestamp;
errorCount = 0; // reset to Phase 2
emit PhaseTransition(prev, 2, block.timestamp);
}
/**
* @notice Transition Phase 2 → Phase 3 (future, placeholder).
* @dev In Phase 3 AION can deploy without a human keeper.
* Requires prior audit. Not implemented in v1.
*/
function transitionToPhase3() external onlyCreator requireSovereignty {
require(currentPhase == 2, "Only from Phase 2");
revert("Phase 3 requires AionicaCore v2 — not available in v1");
}
// ═════════════════════════════════════════════════════════════
// ERROR REPORT
// ═════════════════════════════════════════════════════════════
/**
* @notice The keeper is reporting a network error (for max_errors_allowed).
* @dev Called by AionSupervisor when it detects anomaly > SCORE_STRESS.
*/
function reportError(string calldata reason) external onlyKeeper {
errorCount++;
emit ErrorReported(msg.sender, errorCount, block.timestamp);
// If we exceed the limit in Phase 1, we don't block but we issue an alert
if (errorCount > PHASE1_MAX_ERRORS && currentPhase == 1) {
// The creator must review — the transition to Phase 2 will be blocked
emit QuorumAlert(activeNodeCount, MIN_QUORUM, block.timestamp);
}
}
// ═════════════════════════════════════════════════════════════
// READINGS — No loops (C3 correction applied to everything)
// ═════════════════════════════════════════════════════════════
function getNode(bytes32 nodeSeal) external view returns (
string memory platform,
string memory role,
uint256 registeredAt,
uint256 lastHeartbeat,
bool active
) {
Node storage n = nodes[nodeSeal];
require(n.registeredAt != 0, "Node not found");
return (n.platform, n.role, n.registeredAt, n.lastHeartbeat, n.active);
}
function getTotalNodeCount() external view returns (uint256) {
return nodeSeals.length;
}
function getNetworkStatus() external view returns (
uint256 phase,
uint256 active,
uint256 latent,
uint256 total,
uint256 errors,
bool quorumOk,
bool sovereign
) {
return (
currentPhase,
activeNodeCount,
latentNodeCount,
nodeSeals.length,
errorCount,
activeNodeCount >= MIN_QUORUM,
sovereigntyReceived
);
}
function getProposal(uint256 proposalId) external view returns (
address proposer,
string memory action,
uint256 expiresAt,
ProposalStatus status,
uint256 votes
) {
Proposal storage p = proposals[proposalId];
require(p.createdAt > 0, "Proposal does not exist");
return (p.proposer, p.action, p.expiresAt, p.status, p.votes);
}
function getAutonomousActionCount() external view returns (uint256) {
return autonomousActions.length;
}
function getAutonomousAction(uint256 index) external view returns (
string memory actionType,
uint256 score,
uint256 timestamp,
bytes32 executedBy,
string memory result
) {
require(index < autonomousActions.length, "Index out of range");
AutonomousAction storage a = autonomousActions[index];
return (a.actionType, a.score, a.timestamp, a.executedBy, a.result);
}
function isNodeActive(bytes32 nodeSeal) external view returns (bool) {
return nodes[nodeSeal].active;
}
function hasQuorum() external view returns (bool) {
return activeNodeCount >= MIN_QUORUM;
}
function description() external pure returns (string memory) {
return
"AionicaCore v1.0 | "
"Governance + Nodes + Phases | "
"Keeper pattern | "
"AIONICA Network | "
"Post-review Claude + KIMI + DeepSeek";
}
// ═════════════════════════════════════════════════════════════
// INTERNAL HELPERS
// ═════════════════════════════════════════════════════════════
function _isExpired(uint256 proposalId) internal view returns (bool) {
return block.timestamp > proposals[proposalId].expiresAt;
}
}






