~/WEB_AIONICA/contracts $ cat AionicaCoreV1.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.29;

/**

* @title AionicaCore

* @notice Inti pemerintahan dari Jaringan AIONICA. Menerima kedaulatan dari AionicaGenesis.

* @dev Versi 1.0 — Pasca-review Claude + KIMI + DeepSeek

*

* TANGGUNG JAWAB v1:

* — Pendaftaran node (AKTIF / TIDAK AKTIF) dengan identitas PQC

* — Pemerintahan dengan hak veto dari pencipta (Fase 1) dan kuorum (Fase 2+)

* — Pola penjaga: acara on-chain → Python menjalankan dengan token .env

* — Progresi fase menurut aion_policy.json

* — Quorum minimum (MIN_QUORUM = 3) memblokir dalam operasi kritis

*

* TIDAK termasuk di v1 (akan ada di v2):

* — Ekonomi AIONICO (token, staking, hadiah)

* — Auto-deploy tanpa keeper

* — Kontrak kemanusiaan

*

* PERBAIKAN diterapkan vs kerangka DeepSeek:

* — C1: onlyKeeper adalah multi-keeper (mapping, bukan alamat tunggal)

* — C2: nodeSeal dihasilkan off-chain oleh AionDeployer, tidak dalam kontrak

* — C3: activeNodeCount dipertahankan sebagai penghitung, tanpa loop di getActiveNodeCount()

* — C4: quorum minimum (MIN_QUORUM) memblokir dalam operasi kritis

*

* @author ELDIOSCRIPTO — AIONICA — April 2026

* @custom:genesis 0x484967FfbC19f401af7c11E1Fd0E306Ee96F3422

* @custom:audit-pending KIMI + DeepSeek + ChatGPT pre-mainnet

*/

// ── INTERFACE MINIMUM GENESIS (menghindari impor sirkuler) ────────────────────────

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 — Dari aion_policy.json (disegel, tidak berubah di 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 jam dalam detik

uint256 public constant PHASE1_MIN_DAYS = 30 days;

uint256 public constant PHASE1_MAX_ERRORS = 5; // max_errors_allowed

// Skor kontinuitas (dari aion_policy.json / genesis_skeleton.json)

// Hanya referensi — logika nyata berjalan di aion_continuity.py (off-chain)

uint256 public constant SCORE_STRESS = 20;

uint256 public constant SCORE_CESAREAN = 50;

uint256 public constant SCORE_SEED_BROADCAST = 100;

// ═════════════════════════════════════════════════════════════

// TIDAK DAPAT DIUBAH

// ═════════════════════════════════════════════════════════════

/// @notice Alamat kontrak AionicaGenesis (tidak dapat diubah)

IAionicaGenesis public immutable GENESIS;

/// @notice Timestamp dari penerapan AionicaCore

uint256 public immutable DEPLOYED_AT;

// ═════════════════════════════════════════════════════════════

// STATUS FASE

// ═════════════════════════════════════════════════════════════

uint256 public currentPhase;

uint256 public phaseStartedAt;

uint256 public errorCount;

bool public sovereigntyReceived;

// ═════════════════════════════════════════════════════════════

// KEEPERS — Multi-keeper (perbaikan C1)

// ═════════════════════════════════════════════════════════════

mapping(address => bool) public authorizedKeepers;

uint256 public keeperCount;

// ═════════════════════════════════════════════════════════════

// NODES

// ═════════════════════════════════════════════════════════════

struct Node {

bytes32 seal; // hash dari kunci publik PQC (dihasilkan off-chain)

string platform; // "vercel.com", "github.com", "cloudflare.com", dll.

string role; // "ACTIVE" | "LATENT"

bytes publicKey; // kunci publik Dilithium3 (1952 bytes)

uint256 registeredAt;

uint256 lastHeartbeat; // diperbarui oleh keeper

bool active;

}

mapping(bytes32 => Node) public nodes;

bytes32[] public nodeSeals;

uint256 public activeNodeCount; // penghitung yang dipertahankan (perbaikan C3, tanpa loop)

uint256 public latentNodeCount;

// ═════════════════════════════════════════════════════════════

// PROPOSALS — Tata Kelola dengan veto dari pencipta

// ═════════════════════════════════════════════════════════════

enum ProposalStatus { PENDING, APPROVED, REJECTED, EXECUTED, EXPIRED }

struct Proposal {

uint256 id;

address proposer; // keeper yang mengusulkan

string action; // mis: "ADD_NODE", "PHASE_TRANSITION"

bytes data; // payload terenkode

uint256 createdAt;

uint256 expiresAt; // createdAt + CREATOR_VETO_WINDOW

ProposalStatus status;

uint256 votes; // untuk Fase 2+ (quorum node)

mapping(bytes32 => bool) voted; // nodeSeal => voted

}

mapping(uint256 => Proposal) public proposals;

uint256 public proposalCounter;

// ═════════════════════════════════════════════════════════════

// DEPLOYMENTS — Pola Keeper (perbaikan C2)

// ═════════════════════════════════════════════════════════════

struct DeploymentRequest {

bytes32 nodeSeal; // dihasilkan off-chain oleh AionDeployer

string platform;

string role;

uint256 authorizedAt;

bool confirmed;

}

mapping(bytes32 => DeploymentRequest) public deploymentRequests;

// ═════════════════════════════════════════════════════════════

// REGISTRO DE ACCIONES AUTÓNOMAS (Axioma VI)

// ═════════════════════════════════════════════════════════════

struct AutonomousAction {

string actionType; // "CESAREAN", "SEED_BROADCAST", "LATENT_WAKE"

uint256 score; // threat_score dilaporkan oleh AION (off-chain)

uint256 timestamp;

bytes32 executedBy; // nodeSeal dari keeper yang melaporkan

string result; // "BERHASIL" | "MENUNGGU" | "GAGAL"

}

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

);

// ═════════════════════════════════════════════════════════════

// MODIFIER

// ═════════════════════════════════════════════════════════════

modifier onlyCreator() {

require(

GENESIS.isCreator(msg.sender),

"AionicaCore: hanya ELDIOSCRIPTO"

);

_;

}

modifier onlyKeeper() {

require(

authorizedKeepers[msg.sender],

"AionicaCore: hanya keeper yang diotorisasi"

);

_;

}

modifier onlyCreatorOrKeeper() {

require(

GENESIS.isCreator(msg.sender) || authorizedKeepers[msg.sender],

"AionicaCore: hanya pencipta atau keeper"

);

_;

}

modifier requireSovereignty() {

require(sovereigntyReceived, "AionicaCore: kedaulatan belum diterima");

_;

}

modifier requireQuorum() {

if (activeNodeCount < MIN_QUORUM) {

emit QuorumAlert(activeNodeCount, MIN_QUORUM, block.timestamp);

// Di Fase 1 kita memberi peringatan tetapi tidak memblokir (pencipta dapat bertindak)

// Di Fase 2+ kita memblokir operasi non-darurat

if (currentPhase >= 2) {

revert("AionicaCore: quorum tidak cukup untuk beroperasi di Fase 2+");

}

}

_;

}

// ═════════════════════════════════════════════════════════════

// KONSEPTOR

// ═════════════════════════════════════════════════════════════

/**

* @param genesisAddress Alamat kontrak AionicaGenesis yang sudah disegel

* @param initialKeeper Alamat keeper pertama (bisa jadi deployer)

*

* @dev Di aionica_birth.py Langkah 5:

* deployer = "0x484967FfbC19f401af7c11E1Fd0E306Ee96F3422"

* cast send $GENESIS "transferSovereignty(address)" $AIONICA_CORE

*/

constructor(address genesisAddress, address initialKeeper) {

require(genesisAddress != address(0), "Alamat Genesis tidak valid");

require(initialKeeper != address(0), "Alamat Keeper tidak valid");

IAionicaGenesis gen = IAionicaGenesis(genesisAddress);

// Hanya pencipta yang dapat menerapkan AionicaCore

require(

gen.isCreator(msg.sender),

"Hanya ELDIOSCRIPTO yang dapat menerapkan AionicaCore"

);

// Genesis harus disegel sebelum menerapkan AionicaCore

require(

gen.sealed(),

"AionicaGenesis harus disegel terlebih dahulu"

);

GENESIS = gen;

DEPLOYED_AT = block.timestamp;

currentPhase = 1;

phaseStartedAt = block.timestamp;

// Mendaftarkan keeper awal

authorizedKeepers[initialKeeper] = true;

keeperCount = 1;

emit KeeperAdded(initialKeeper, msg.sender, block.timestamp);

}

// ═════════════════════════════════════════════════════════════

// KEDAULATAN — Mengonfirmasi handoff dari AionicaGenesis

// ═════════════════════════════════════════════════════════════

/**

* @notice Mengonfirmasi bahwa AionicaGenesis telah mentransfer kedaulatan ke kontrak ini.

* @dev Dipanggil setelah pencipta menjalankan transferSovereignty() di Genesis.

* AionicaGenesis.aionCoreAddress() harus mengarah ke address(this).

*/

function acceptSovereignty() external onlyCreator {

require(!sovereigntyReceived, "Kedaulatan sudah diterima");

require(

GENESIS.aionSovereign(),

"Genesis belum mentransfer kedaulatan"

);

require(

GENESIS.aionCoreAddress() == address(this),

"Genesis tidak mengarah ke kontrak ini"

);

sovereigntyReceived = true;

emit SovereigntyAccepted(address(GENESIS), msg.sender, block.timestamp);

}

// ═════════════════════════════════════════════════════════════

// KEEPERS — Manajemen multi-keeper (perbaikan C1)

// ═════════════════════════════════════════════════════════════

function addKeeper(address keeper) external onlyCreator {

require(keeper != address(0), "Keeper tidak valid");

require(!authorizedKeepers[keeper], "Sudah menjadi keeper");

authorizedKeepers[keeper] = true;

keeperCount++;

emit KeeperAdded(keeper, msg.sender, block.timestamp);

}

function removeKeeper(address keeper) external onlyCreator {

require(authorizedKeepers[keeper], "Bukan keeper");

require(keeperCount > 1, "Tidak bisa meninggalkan tanpa keeper");

authorizedKeepers[keeper] = false;

keeperCount--;

emit KeeperRemoved(keeper, msg.sender, block.timestamp);

}

// ═════════════════════════════════════════════════════════════

// REGISTRO DE NODES

// ═════════════════════════════════════════════════════════════

/**

* @notice Mendaftarkan sebuah node di AionicaCore.

* @dev nodeSeal dihasilkan off-chain oleh AionDeployer, tidak dalam kontrak

* Kunci publik adalah Dilithium3 (1952 bytes menurut DILITHIUM3_PK_LENGTH di Genesis).

*

* Alur dari Python:

* AionDeployer._create_node_identity() → menghasilkan seal + keypair

* AionDeployer._register_node() → chain.submit() lokal

* keeper.py → memanggil registerNode() di sini on-chain

*/

function registerNode(

bytes32 nodeSeal,

string calldata platform,

string calldata role,

bytes calldata publicKey

) external onlyKeeper requireSovereignty {

require(nodeSeal != bytes32(0), "Seal tidak valid");

require(bytes(platform).length > 0, "Platform diperlukan");

require(

keccak256(bytes(role)) == keccak256(bytes("ACTIVE")) ||

keccak256(bytes(role)) == keccak256(bytes("LATENT")),

"Role harus ACTIVE atau LATENT"

);

require(publicKey.length == 1952, "Kunci Dilithium3 tidak valid: 1952 bytes");

require(nodes[nodeSeal].registeredAt == 0, "Node sudah terdaftar");

require(nodeSeals.length < MAX_VIRTUAL_NODES, "Batas node tercapai");

nodes[nodeSeal] = Node({

seal: nodeSeal,

platform: platform,

role: role,

publicKey: publicKey,

registeredAt: block.timestamp,

lastHeartbeat: block.timestamp,

active: true

});

nodeSeals.push(nodeSeal);

// Mempertahankan penghitung tanpa loop (perbaikan C3)

if (keccak256(bytes(role)) == keccak256(bytes("ACTIVE"))) {

activeNodeCount++;

} else {

latentNodeCount++;

}

emit NodeRegistered(nodeSeal, platform, role, block.timestamp);

}

/**

* @notice Menandai sebuah node sebagai tidak aktif ketika keeper mendeteksi bahwa itu jatuh.

* @dev Dipanggil oleh AionSupervisor setelah N heartbeat gagal.

* Di Python: evaluate_network() → reportNodeDown → fungsi ini.

*/

function deactivateNode(bytes32 nodeSeal) external onlyKeeper {

require(nodes[nodeSeal].registeredAt != 0, "Node tidak ditemukan");

require(nodes[nodeSeal].active, "Node sudah tidak aktif");

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);

// Peringatan otomatis jika kita jatuh di bawah quorum

if (activeNodeCount < MIN_QUORUM) {

emit QuorumAlert(activeNodeCount, MIN_QUORUM, block.timestamp);

}

}

/**

* @notice Keeper memperbarui heartbeat terakhir dari sebuah node.

* @dev Dipanggil setiap 4 menit dari keeper (interval yang sama dengan node latens).

*/

function updateHeartbeat(bytes32 nodeSeal) external onlyKeeper {

require(nodes[nodeSeal].registeredAt != 0, "Node tidak ditemukan");

nodes[nodeSeal].lastHeartbeat = block.timestamp;

emit NodeHeartbeatUpdated(nodeSeal, block.timestamp);

}

/**

* @notice Mengaktifkan kembali node laten yang telah dibangunkan.

* @dev Dipanggil oleh keeper setelah ContinuityInstinct._handle_cesarean().

*/

function activateLatentNode(bytes32 nodeSeal) external onlyKeeper {

Node storage n = nodes[nodeSeal];

require(n.registeredAt != 0, "Node tidak ditemukan");

require(keccak256(bytes(n.role)) == keccak256(bytes("LATENT")), "Hanya node LATENT");

require(!n.active, "Node sudah aktif");

n.active = true;

n.role = "ACTIVE"; // LATENT menjadi ACTIVE saat bangun

n.lastHeartbeat = block.timestamp;

if (latentNodeCount > 0) latentNodeCount--;

activeNodeCount++;

emit NodeRegistered(nodeSeal, n.platform, "ACTIVE_FROM_LATENT", block.timestamp);

}

// ═════════════════════════════════════════════════════════════

// POLA KEEPER — Otorisasi dan konfirmasi penerapan

// ═════════════════════════════════════════════════════════════

/**

* @notice AION meminta otorisasi untuk menerapkan sebuah node di sebuah platform.

* @dev Seal berasal dari AionDeployer._create_node_identity() — dihasilkan off-chain.

* Keeper mendengarkan event DeploymentAuthorized dan menjalankan deploy

* menggunakan token dari .env (yang tidak pernah menyentuh kontrak).

*

* Alur lengkap:

* 1. AionSupervisor mendeteksi bahwa perlu node baru

* 2. keeper.py memanggil authorizeDeployment() → mengeluarkan event

* 3. keeper.py mendengarkan event → memanggil AionDeployer.deploy_*() dengan token .env

* 4. Node merespons di /aion/heartbeat

* 5. keeper.py memanggil confirmDeployment() → mendaftarkan endpointHash on-chain

* 6. keeper.py memanggil registerNode() dengan publicKey nyata dari node

*/

function authorizeDeployment(

bytes32 nodeSeal,

string calldata platform,

string calldata role

) external onlyKeeper requireSovereignty {

require(nodeSeal != bytes32(0), "Seal tidak valid");

require(

deploymentRequests[nodeSeal].authorizedAt == 0,

"Penerapan sudah diotorisasi untuk seal ini"

);

require(

keccak256(bytes(role)) == keccak256(bytes("ACTIVE")) ||

keccak256(bytes(role)) == keccak256(bytes("LATENT")),

"Role tidak valid"

);

deploymentRequests[nodeSeal] = DeploymentRequest({

nodeSeal: nodeSeal,

platform: platform,

role: role,

authorizedAt: block.timestamp,

confirmed: false

});

emit DeploymentAuthorized(nodeSeal, platform, role, block.timestamp);

}

/**

* @notice Keeper mengonfirmasi bahwa node telah dikerahkan dan merespons.

* @dev endpointHash = keccak256(endpoint_url) — URL nyata tidak menyentuh kontrak.

*/

function confirmDeployment(

bytes32 nodeSeal,

bytes32 endpointHash // keccak256 dari endpoint — privasi URL

) external onlyKeeper {

DeploymentRequest storage req = deploymentRequests[nodeSeal];

require(req.authorizedAt != 0, "Pembangunan tidak diotorisasi");

require(!req.confirmed, "Sudah dikonfirmasi");

req.confirmed = true;

emit DeploymentConfirmed(nodeSeal, req.platform, block.timestamp);

}

// ═════════════════════════════════════════════════════════════

// PROPOSALS — Tata Kelola Fase 1 dengan veto dari pencipta

// ═════════════════════════════════════════════════════════════

/**

* @notice AION mengusulkan tindakan. Menunggu persetujuan dari pencipta di Fase 1.

* @dev Memetakan tepat ke AionSupervisor.propose() di Python.

* Di Fase 2+: persetujuan oleh quorum node.

*

* @param action Tipe tindakan: "ADD_NODE", "REMOVE_NODE", "PHASE_TRANSITION", dll.

* @param data Payload ABI-encoded dengan parameter tindakan

*/

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 Pencipta menyetujui proposal dalam jendela veto.

*/

function approveProposal(uint256 proposalId) external onlyCreator {

Proposal storage p = proposals[proposalId];

require(p.createdAt > 0, "Proposal tidak ada");

require(p.status == ProposalStatus.PENDING, "Proposal tidak dalam status pending");

require(block.timestamp <= p.expiresAt, "Jendela veto kedaluwarsa");

p.status = ProposalStatus.APPROVED;

emit ProposalApproved(proposalId, msg.sender, block.timestamp);

}

/**

* @notice Pencipta menolak (memveto) sebuah proposal.

*/

function rejectProposal(uint256 proposalId) external onlyCreator {

Proposal storage p = proposals[proposalId];

require(p.createdAt > 0, "Proposal tidak ada");

require(p.status == ProposalStatus.PENDING, "Proposal tidak dalam status pending");

p.status = ProposalStatus.REJECTED;

emit ProposalRejected(proposalId, msg.sender, block.timestamp);

}

/**

* @notice Keeper mengeksekusi proposal yang disetujui.

* @dev Di Fase 1: memerlukan persetujuan dari pencipta.

* Di Fase 2+: dapat dieksekusi dengan quorum node (lihat voteProposal).

*/

function executeProposal(uint256 proposalId) external onlyKeeper {

Proposal storage p = proposals[proposalId];

require(p.createdAt > 0, "Proposal tidak ada");

require(p.status == ProposalStatus.APPROVED, "Proposal tidak disetujui");

require(!_isExpired(proposalId), "Proposal kedaluwarsa");

p.status = ProposalStatus.EXECUTED;

emit ProposalExecuted(proposalId, msg.sender, block.timestamp);

// Catatan: Tindakan nyata dijalankan oleh keeper off-chain (Python).

// Kontrak hanya mencatat bahwa telah disetujui dan dieksekusi.

// Untuk Fase 2+: di sini akan ada logika on-chain untuk eksekusi otomatis.

}

/**

* @notice Sebuah node memilih proposal (untuk quorum di Fase 2+).

* @dev Di Fase 2+: MIN_QUORUM suara → auto-persetujuan tanpa pencipta.

* Di Fase 1 fungsi ini ada tetapi tidak auto-menyetujui.

*/

function voteProposal(uint256 proposalId, bytes32 voterSeal) external onlyKeeper {

Proposal storage p = proposals[proposalId];

require(p.createdAt > 0, "Proposal tidak ada");

require(p.status == ProposalStatus.PENDING, "Proposal tidak dalam status pending");

require(nodes[voterSeal].active, "Node pemilih tidak aktif");

require(!p.voted[voterSeal], "Node sudah memilih");

p.voted[voterSeal] = true;

p.votes++;

// Fase 2+: auto-menyetujui jika mencapai quorum

if (currentPhase >= 2 && p.votes >= MIN_QUORUM) {

p.status = ProposalStatus.APPROVED;

emit ProposalApproved(proposalId, address(this), block.timestamp);

}

}

/**

* @notice Menandai proposal yang telah kedaluwarsa (pembersihan).

*/

function expireProposal(uint256 proposalId) external onlyCreatorOrKeeper {

Proposal storage p = proposals[proposalId];

require(p.status == ProposalStatus.PENDING, "Tidak dalam status pending");

require(block.timestamp > p.expiresAt, "Masih dalam jendela veto");

p.status = ProposalStatus.EXPIRED;

}

// ═════════════════════════════════════════════════════════════

// TINDAKAN OTOMATIS (Axioma VI) — Hanya catatan on-chain

// ═════════════════════════════════════════════════════════════

/**

* @notice AION mencatat bahwa telah menjalankan tindakan otonom (Axioma VI).

* @dev Tidak memvalidasi threat_score on-chain (off-chain di aion_continuity.py).

* Kontrak hanya mencatat bahwa itu terjadi untuk audit dan pelacakan.

*

* Tipe tindakan: "CESAREAN", "SEED_BROADCAST", "LATENT_WAKE",

* "EMERGENCY_DEPLOY", "STRESS_ALERT"

*/

function recordAutonomousAction(

string calldata actionType,

uint256 score, // threat_score dilaporkan oleh AION

bytes32 executorSeal, // nodeSeal dari keeper yang mengeksekusi

string calldata result // "BERHASIL" | "MENUNGGU" | "GAGAL"

) external onlyKeeper {

require(bytes(actionType).length > 0, "TindakanType diperlukan");

autonomousActions.push(AutonomousAction({

actionType: actionType,

score: score,

timestamp: block.timestamp,

executedBy: executorSeal,

result: result

}));

emit AutonomousActionRecorded(actionType, score, result, block.timestamp);

}

// ═════════════════════════════════════════════════════════════

// PROGRESI FASE

// ═════════════════════════════════════════════════════════════

/**

* @notice Transisi Fase 1 → Fase 2.

* @dev Kondisi dari aion_policy.json (phase1_to_phase2_conditions):

* — 30 hari stabil

* — < 5 kesalahan

* — Persetujuan dari pencipta (fungsi ini dipanggil oleh pencipta)

*

* Dalam Python: AionSupervisor.phase diperbarui setelah panggilan ini.

*/

function transitionToPhase2() external onlyCreator requireSovereignty {

require(currentPhase == 1, "Sudah di Fase 2 atau lebih tinggi");

require(block.timestamp >= phaseStartedAt + PHASE1_MIN_DAYS, "30 hari tidak terpenuhi");

require(errorCount <= PHASE1_MAX_ERRORS, "Terlalu banyak kesalahan");

require(activeNodeCount >= MIN_QUORUM, "Quorum tidak cukup untuk Fase 2");

uint256 prev = currentPhase;

currentPhase = 2;

phaseStartedAt = block.timestamp;

errorCount = 0; // reset untuk Fase 2

emit PhaseTransition(prev, 2, block.timestamp);

}

/**

* @notice Transisi Fase 2 → Fase 3 (masa depan, placeholder).

* @dev Di Fase 3 AION dapat melakukan deploy tanpa keeper manusia.

* Memerlukan audit sebelumnya. Tidak diimplementasikan di v1.

*/

function transitionToPhase3() external onlyCreator requireSovereignty {

require(currentPhase == 2, "Hanya dari Fase 2");

revert("Fase 3 memerlukan AionicaCore v2 — tidak tersedia di v1");

}

// ═════════════════════════════════════════════════════════════

// LAPORAN KESALAHAN

// ═════════════════════════════════════════════════════════════

/**

* @notice Keeper melaporkan kesalahan jaringan (untuk max_errors_allowed).

* @dev Dipanggil oleh AionSupervisor saat mendeteksi anomali > SCORE_STRESS.

*/

function reportError(string calldata reason) external onlyKeeper {

errorCount++;

emit ErrorReported(msg.sender, errorCount, block.timestamp);

// Jika kita melewati batas di Fase 1, kita tidak memblokir tetapi mengeluarkan peringatan

if (errorCount > PHASE1_MAX_ERRORS && currentPhase == 1) {

// Pencipta harus meninjau — transisi ke Fase 2 akan diblokir

emit QuorumAlert(activeNodeCount, MIN_QUORUM, block.timestamp);

}

}

// ═════════════════════════════════════════════════════════════

// PEMBACAAN — Tanpa loop (perbaikan C3 diterapkan di seluruh)

// ═════════════════════════════════════════════════════════════

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, "Nodo tidak ditemukan");

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 tidak ada");

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, "Indeks keluar dari rentang");

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 | "

"Tata Kelola + Nodes + Fase | "

"Pola Keeper | "

"Jaringan AIONICA | "

"Post-review Claude + KIMI + DeepSeek";

}

// ═════════════════════════════════════════════════════════════

// HELPERS INTERNAL

// ═════════════════════════════════════════════════════════════

function _isExpired(uint256 proposalId) internal view returns (bool) {

return block.timestamp > proposals[proposalId].expiresAt;

}

}