Skip to content

Philosophy

Germán Luis Aracil Boned edited this page Apr 6, 2026 · 1 revision

The 14 Laws of Top Level System

These are non-negotiable design rules. Every line of code, every module, every decision must obey them. They are not guidelines — they are laws.

Law 1 — Everything is a Path

Every resource, service, device, and configuration is addressed by a path. No exceptions. No special APIs. No hidden channels. If it exists in the system, it has a path.

/health              → system health check
/iot/devices         → list IoT devices
/node/peer1/health   → health check on remote peer
/cache/session:abc   → cached session data
/logic/apps          → list running applications

Law 2 — Every Interaction is a Message

All communication uses one structure: portal_msg_t. No direct function calls between modules. No shared memory tricks. No callbacks. One message in, one response out.

typedef struct {
    char     path[512];        // target path
    int      method;           // GET, SET, CREATE, DELETE, ACTION, EVENT, SUBSCRIBE
    char     headers[4096];    // key:value pairs
    char     body[65536];      // payload
    portal_context_t context;  // auth + trace
} portal_msg_t;

Law 3 — Modules Do One Thing

Each module is an expert at exactly one domain. mod_cache caches. mod_dns resolves names. mod_iot controls devices. No module does two things. No god-modules. If you need combined behavior, compose via messages.

Law 4 — The Core Routes, Modules Act

The core is a router, not a doer. It receives messages, finds the owning module via path lookup, checks ACL, delivers the message. The core never implements business logic. Zero. It routes.

Law 5 — Labels Control Access

No role-based access. No permission matrices. Users have groups. Paths have labels. Access = intersection of user groups and path labels. If the intersection is non-empty, access is granted.

User "operator" groups: ["ops", "monitoring"]
Path "/metrics" labels: ["monitoring"]
→ intersection: ["monitoring"] → ACCESS GRANTED

Path "/admin/users" labels: ["admin"]
→ intersection: [] → ACCESS DENIED

Law 6 — Hot-Load Everything

Modules load, unload, and reload at runtime. No restart required. The core tracks reference counts — unload waits for active handlers to finish. Config changes: reload. Bug fix: reload. New feature: load.

portal:/> module load mod_iot       # load at runtime
portal:/> module reload mod_web     # zero-downtime update
portal:/> module unload mod_hello   # clean removal

Law 7 — Crash Isolation

A module crash (segfault, SIGFPE, stack overflow) must never bring down the core. The core wraps every handler call in setjmp/longjmp. If a module crashes, the core logs the fault, returns 500 to the caller, increments the crash counter, and continues serving.

if (setjmp(crash_buf) == 0) {
    rc = handler->handle(core, msg, resp);  // module code
} else {
    resp->status = 500;                     // module crashed
    snprintf(resp->body, sizeof(resp->body),
             "Module %s crashed (signal %d)", mod->name, crash_signal);
    mod->stats.crashes++;
}

Law 8 — Trace Everything

Every message carries a trace context: trace_id (UUID), timestamp (µs), hops counter. When a message crosses a federation link, hops increment. When it passes through modules, the trace follows. Full distributed tracing with zero configuration.

Law 9 — Three Storage Backends, One API

Configuration and data persist through three simultaneous backends: file (always), SQLite (optional), PostgreSQL (optional). The core writes to all enabled backends. Reads try PostgreSQL first, then SQLite, then file. Modules never know which backend served the data.

Law 10 — Federation is Transparent

Remote nodes appear as local paths. /node/peer1/health routes to the health path on peer1 transparently. The wire protocol (PORTAL02) handles TLS encryption, key authentication, and message serialization. Modules don't know (or care) if a message is local or remote.

Law 11 — Events are First-Class

Modules declare events. Other modules subscribe. The event system is ACL-controlled — you can only subscribe to events whose labels intersect with your groups. Pattern matching supports exact (/events/iot/device_added), wildcard (/events/iot/*), and global (*).

Law 12 — No External Dependencies (Core)

The core and every module compile with standard C libraries only. Embedded: libev (event loop), sha256, cJSON. No boost, no glib, no external frameworks. Optional: libsqlite3, libpq, liblzma, libz, libssh, libldap — but the core runs without them.

Law 13 — Four Scripting Engines, One API

Lua (embedded, in-process), Python (forked subprocess, JSON pipe), C (gcc compile + dlopen), Pascal (fpc compile + dlopen). All four expose the same API: portal.get(), portal.set(), portal.call(), portal.route(), portal.on(), portal.log().

Law 14 — Configuration is a Path

All configuration is accessible via /config/* paths. Read config with GET, modify with SET. Changes persist to all storage backends. Modules watch for config changes via events. No config files are read directly after startup — everything goes through the path system.


Summary

# Law Core Principle
1 Everything is a Path Universal addressing
2 Every Interaction is a Message Single communication primitive
3 Modules Do One Thing Single responsibility
4 The Core Routes, Modules Act Separation of concerns
5 Labels Control Access Set-intersection ACL
6 Hot-Load Everything Zero-downtime operations
7 Crash Isolation Fault tolerance
8 Trace Everything Observability built-in
9 Three Storage Backends Redundant persistence
10 Federation is Transparent Location-transparent networking
11 Events are First-Class Reactive architecture
12 No External Dependencies Self-contained core
13 Four Scripting Engines Polyglot with unified API
14 Configuration is a Path Config as data

Clone this wiki locally