def _block_read(file):
    try:
        with open(file) as f:
            content = f.read().strip()
        if not content:
            return None  # empty file = no block data
        try:
            return json.loads(content)
        except json.JSONDecodeError:
            # Old format — migrate
            lines = content.split('\n')
def _subnet_read(file):
    """Read subnets.json, return dict or empty dict"""
    try:
        if not os.path.exists(file):
            return {}
        with open(file) as f:
            content = f.read().strip()
        if not content:
            return {}
        return json.loads(content)
    except Exception:
def _identity_read(file):
    """Read an identity file, return dict or None"""
    try:
        if not os.path.exists(file):
            return None
        with open(file) as f:
            content = f.read().strip()
        if not content:
            return None
        return json.loads(content)
    except Exception:
def _policy_read(file):
    try:
        if not os.path.exists(file):
            return {}
        with open(file) as f:
            content = f.read().strip()
        if not content:
            return {}
        return json.loads(content)
    except Exception:
        return {}
def _hosts_read(file):
    if not os.path.exists(file):
        return {"hosts": {}, "subnets": {}, "ports": {}}
    try:
        with open(file) as f:
            data = json.load(f)
        # Ensure all sections exist
        data.setdefault("hosts", {})
        data.setdefault("subnets", {})
        data.setdefault("ports", {})
        return data
def _net_read(file):
    try:
        if not os.path.exists(file): return {}
        with open(file) as f:
            content = f.read().strip()
        if not content: return {}
        return json.loads(content)
    except Exception:
        return {}

def _net_write(file, data):
