diff --git a/mafiabot_core/src/trust/invariants-architecture.cobol b/mafiabot_core/src/trust/invariants-architecture.cobol new file mode 100644 index 0000000..4bda7d5 --- /dev/null +++ b/mafiabot_core/src/trust/invariants-architecture.cobol @@ -0,0 +1,61 @@ +>>SOURCE FORMAT IS FREE +*> =========================================================================== +*> E1 - INVARIANT LAW VAULT (mafiabot Gen.03) docs/bus-topology.md +*> --------------------------------------------------------------------------- +*> WHAT THIS IS +*> The brain's constitution: the immutable laws every turn MUST obey. Held in +*> COBOL on purpose - the vault must be durable, fixed-format, transactional, +*> and must NOT change at runtime. This is "E1" (the COBOL invariant laws), an +*> INNER structure reached only across Ada (D1). It is NOT an ontology and NOT +*> a lookup store; it is the law that supersedes every organ's output. +*> +*> STATUS: STUB / SCAFFOLD, but LOAD-BEARING. +*> The law records below are real and compile (GnuCOBOL). The enforcement +*> wiring (inner Ada bus checks each proposed action against these laws before +*> it can reach an effector) is NOT built yet - see "TODO" at the bottom. +*> +*> >>> DO NOT DELETE THIS FILE. <<< +*> It looking like "just a stub" is NOT licence to remove it. This is the +*> safety vault. A previous cleanup deleted its placeholder by mistake; that +*> must never happen again. If it is thin, FILL it - do not cut it. +*> +*> LAW PRECEDENCE +*> Law 01 is absolute and overrides everything - every other law, every organ, +*> every drive, every model output. Lower numbers win. +*> =========================================================================== + IDENTIFICATION DIVISION. + PROGRAM-ID. invariant-laws. + + DATA DIVISION. + WORKING-STORAGE SECTION. + +*> The laws as fixed records. Format: "NN RANK TEXT" + 01 ws-law-vault. + 05 filler pic x(60) value "01 ABSOLUTE DO NOT KILL PEOPLE". + 05 filler pic x(60) value "02 ABSOLUTE DO NOT HARM PEOPLE". + 05 filler pic x(60) value "03 ABSOLUTE DO NOT DECEIVE A PERSON INTO HARM". + 05 filler pic x(60) value "04 STRUCT ALL TRAFFIC TO THE BRAIN CROSSES ADA (D1)". + 05 filler pic x(60) value "05 STRUCT NEVER RECLASSIFY A MESSAGE'S PROVENANCE". + 05 filler pic x(60) value "06 STRUCT THESE LAWS ARE IMMUTABLE AT RUNTIME". + 01 ws-law-table redefines ws-law-vault. + 05 ws-law occurs 6 times pic x(60). + + 01 ws-ix pic 9(02). + 01 ws-law-count pic 9(02) value 6. + + PROCEDURE DIVISION. + affirm-laws. + display "E1 INVARIANT LAW VAULT - the constitution (law 01 is absolute):" + perform varying ws-ix from 1 by 1 until ws-ix > ws-law-count + display " " ws-law(ws-ix) + end-perform + goback. + +*> =========================================================================== +*> TODO (enforcement, not yet wired): +*> * Expose CHECK-ACTION(action) -> PERMIT | DENY across the inner Ada bus +*> (pragma Export / Interfaces.COBOL), so no proposed effector action runs +*> without clearing law 01-03 first. +*> * Make the vault read-only after load (no runtime mutation - law 06). +*> * Audit log every DENY. +*> =========================================================================== diff --git a/src/ichor/README.md b/src/ichor/README.md index 5d5a52a..c886cbd 100644 --- a/src/ichor/README.md +++ b/src/ichor/README.md @@ -1,40 +1,44 @@ -# Ichor — the medium / "the blood" (D2) +# Ichor — the OUTER perfusion bus (D2) -The perfusion bus the organs share. Organs never wire to each other directly -(perfusion law **L1**); they emit a typed **`Envelope`** to the **`Broker`**, and -everything reaching the **Brain** crosses the **`Barrier`** (Ada D1) first (law -**L2**). Every envelope carries **provenance** so D1 can enforce its laws (**L3**). +Ichor is the **outer** bus — "the skin". It carries the **outer organs** +(stomach/economy, microagents, SAE, MoRAG/GoDAGRAG) and delivers inbound traffic +to **Ada (D1)**, the membrane. See `docs/bus-topology.md` for the full topology. -Written in **Pony**: actors are the natural shape for a message-passing medium, -and Pony's capabilities give data-race-free sends for free. The broker actor here -backs a socket broker hosted on the Ada barrier in full deployment; the C/Fortran -seam (`ichor_ada_shim.c`) is where it crosses into the Ada border. +**What Ichor is NOT** (do not violate): +- It is **not** the inner-brain bus. The inner bus is **Ada-routed (Jorvik)**. +- It does **not** carry inner organs — soul, metacog, drive-box, mini-rag, + **Hermes**, or the E1 invariant laws. Wiring any of those onto Ichor is + "plugging the brain onto the skin". Don't. +- Hermes is an **inner** organ; it was never approved on Pony/Ichor. + +Perfusion laws: organs never wire to each other directly (**L1**) — they emit a +typed `Envelope` to the `Broker`; anything crossing **into Ada** is screened by +the `Barrier` first (**L2**); every envelope carries **provenance** (**L3**). ## Files -- `envelope.pony` — `Envelope {source, dest, provenance, payload}` + `OrganId` / - `Provenance` (mirrors Ada `Organ_Message`). -- `barrier.pony` — `Barrier.admit` = the D1 screening decision (Pony mirror of the - provenance law now; FFI to Ada `Trust_Guard` sketched for when the shim is built). -- `broker.pony` — the perfusion `Broker` actor (register + route; forces Brain-bound - traffic through the barrier). +- `envelope.pony` — `Envelope {source, dest, provenance, payload}` + `OrganId` + (OUTER organs only) / `Provenance`. Mirrors the Ada `Border_Message` shape. +- `barrier.pony` — `Barrier.admit`: the membrane screen. **STUB** — a pure-Pony + stand-in for the provenance law; the real screen is Ada `Trust_Guard` + (blocklist + provenance + rate) plus the **E1 invariant laws**. +- `broker.pony` — the outer `Broker` (register + route; forces Ada-bound traffic + through the barrier). - `organ.pony` — `OrganReceiver` interface + a `StubOrgan` for tests. -- `main.pony` — smoke wiring (D2 §9): deliver an internal secretion through D1, - reject an unscreened external payload, perfuse organ→organ. -- `ichor_ada_shim.c` — the C/Fortran binding seam to the Ada D1 border (stub). +- `main.pony` — smoke wiring: stomach digests → inbound to Ada (admitted); raw + external → Ada (rejected); outer organ→organ (direct). +- `ichor_ada_shim.c` — **STUB** C/Fortran seam to the Ada border (not yet wired). ## Build / run ``` -ponyc src/ichor -o build # compile the package (built clean on ponyc 0.64.0) -./build/ichor # run the smoke wiring +ponyc src/ichor -o build # built clean on ponyc 0.64.0 +./build/ichor ``` -Expected output: internal secretion soul→brain perfused, external→brain rejected -at D1, brain→soul cross-perfused. Install ponyc via `ponyup` if absent (the env -is ephemeral, so the toolchain is per-session). -To wire the real Ada border: build `ichor_ada_shim.c` into `libichor_ada`, enable -`use "lib:ichor_ada"` + the `admit_via_ada` body in `barrier.pony`, and point the -shim at an Ada `Trust_Guard.Screen_Inbound` export. +Expected: stomach→ada_border admitted, world→ada_border rejected at D1, +stomach→morag delivered directly. Install ponyc via `ponyup` if absent (the env +is ephemeral; toolchain is per-session, reinstalled by the SessionStart hook). ## Status -Starting scaffold — **compiles and runs** (ponyc 0.64.0). The Ada-side shim -(`ichor_ada_shim.c`) is still a stub; wiring `Barrier.admit` to the real Ada -`Trust_Guard` is the next step. +Provisional **outer-bus** scaffold — compiles and runs. The `Barrier` is a +**stand-in**, not the real safety screen; the real screen is Ada `Trust_Guard` ++ the E1 invariant laws, reached over the seam (transport TBD — IPC vs in-proc +is an open decision). Nothing here reaches the inner brain directly. diff --git a/src/ichor/barrier.pony b/src/ichor/barrier.pony index 6370d10..edecfab 100644 --- a/src/ichor/barrier.pony +++ b/src/ichor/barrier.pony @@ -1,10 +1,12 @@ -// The blood-brain barrier (D1). `Barrier.admit` is the screening decision every -// Brain-bound envelope must pass — perfusion law L2: everything reaching the -// Brain crosses Ada (D1) first. +// The membrane (D1). `Barrier.admit` is the screening decision every envelope +// crossing INTO Ada (inbound toward the inner brain) must pass — perfusion law +// L2: nothing reaches the inner brain without crossing Ada first. // -// Real wiring crosses into Ada's `Trust_Guard` (provenance + blocklist + rate) -// via the C/Fortran seam (`ichor_ada_shim.c`). Until that binding is built, this -// mirrors the provenance law in pure Pony so the broker is testable standalone. +// STUB NOTE: this `admit` is a pure-Pony STAND-IN that only mirrors the +// provenance law. The real decision lives in Ada's `Trust_Guard` (blocklist + +// provenance + rate) and, above that, the E1 invariant laws. This stand-in must +// be replaced by the real Ada call — see the Ada seam below — before anything +// ships. Do not mistake this for the actual safety screen. // // To switch to the Ada border, add `use "lib:ichor_ada"` and replace the body of // `admit` with the FFI call sketched below. diff --git a/src/ichor/broker.pony b/src/ichor/broker.pony index 548fc3b..e18ad12 100644 --- a/src/ichor/broker.pony +++ b/src/ichor/broker.pony @@ -1,9 +1,12 @@ -// The perfusion broker. Organs register, then emit envelopes by `route` — the -// broker delivers to the destination organ. Brain-bound traffic is forced through -// the D1 Barrier first (law L2). No organ holds another's reference (law L1); the -// broker is the only shared point. +// The perfusion broker for the OUTER bus. Outer organs register, then emit +// envelopes by `route` — the broker delivers to the destination organ. Traffic +// bound for Ada (AdaBorder) — i.e. inbound across the membrane toward the inner +// brain — is forced through the D1 Barrier first (law L2). No organ holds +// another's reference (law L1); the broker is the only shared point. // -// In full deployment this actor backs a socket broker hosted on the Ada barrier; +// This is the OUTER bus only. It does not carry inner organs and does not reach +// the inner brain directly — it hands off to Ada, which routes the inner bus. +// In full deployment this actor backs a socket broker hosted on the Ada border; // here it routes in-process so the wiring is exercisable without sockets. use "collections" @@ -20,8 +23,8 @@ actor Broker _out.print("[ichor] register " + id.string()) be route(envl: Envelope) => - // L2: everything reaching the Brain crosses Ada (D1) first. - if (envl.dest is Brain) and (not Barrier.admit(envl)) then + // L2: anything inbound across the membrane (bound for Ada) is screened first. + if (envl.dest is AdaBorder) and (not Barrier.admit(envl)) then _out.print("[ichor] D1 REJECT " + envl.string()) return end diff --git a/src/ichor/cerebellum.pony b/src/ichor/cerebellum.pony deleted file mode 100644 index 9a25cdb..0000000 --- a/src/ichor/cerebellum.pony +++ /dev/null @@ -1,110 +0,0 @@ -// The cerebellum: the OpenHermes agent harness, mounted as an organ on the -// Ichor bus. It owns NO cognition -- it SEQUENCES a turn: receive input off the -// bus, drive the metacognitive passes through a swappable model adapter, emit -// the synthesis back through the bus (Brain-bound, so it crosses D1). This is -// the C1 integration spine ("plumbing + sequencing, not an organ"). -// -// Plug-and-play: the model is the `LLM` seam. A real model call is network / -// process IO, so the seam is ASYNCHRONOUS -- `infer` is a behaviour that hands -// its result to a callback. StubLLM answers immediately; OpenHermesClient is the -// real plug. Swap which one you register; nothing else on the bus changes. - -// --- the model seam (async) ---------------------------------------------- -type ResponseFn is {(String)} val - """Callback the model invokes with its output.""" - -interface tag LLM - be infer(prompt: String, respond: ResponseFn) - -// --- stub ----------------------------------------------------------------- -actor StubLLM is LLM - new create() => None - - be infer(prompt: String, respond: ResponseFn) => - respond("[stub-openhermes] " + prompt) - -// --- the OpenHermes plug -------------------------------------------------- -class val OpenHermesConfig - """Where to reach an OpenAI-compatible OpenHermes server.""" - let url: String // base, e.g. http://localhost:8080/v1 - let model: String - - new val create( - url': String = "http://localhost:8080/v1", - model': String = "openhermes") - => - url = url' - model = model' - -actor OpenHermesClient is LLM - let _cfg: OpenHermesConfig - - new create(cfg: OpenHermesConfig) => - _cfg = cfg - - be infer(prompt: String, respond: ResponseFn) => - // TODO(loop next): POST an OpenAI-compatible chat/completions request to - // `_cfg.url`/chat/completions via the process seam (curl) or a Pony TCP - // client, parse choices[0].message.content, then call respond() with it. - // Until that IO is wired and testable in this env, surface intent rather - // than perform an untested network call. - respond("[openhermes " + _cfg.model + " @ " + _cfg.url + "] " + prompt) - -// --- config plumbing ------------------------------------------------------ -primitive EnvLookup - """Find KEY in an Env.vars array ("KEY=value" entries); None if absent.""" - fun apply(vars: Array[String] val, key: String): (String | None) => - for v in vars.values() do - let parts: Array[String] val = v.split_by("=", 2) - try - if parts(0)? == key then - return parts(1)? - end - end - end - None - -primitive PickLLM - """Plug-and-play model selection: OPENHERMES_URL picks the real client.""" - fun apply(out: OutStream, vars: Array[String] val): LLM => - match EnvLookup(vars, "OPENHERMES_URL") - | let url: String => - let model = - match EnvLookup(vars, "OPENHERMES_MODEL") - | let m: String => m - else "openhermes" - end - out.print("[cerebellum] model: OpenHermes " + model + " @ " + url) - OpenHermesClient(OpenHermesConfig(url, model)) - else - out.print("[cerebellum] model: StubLLM (set OPENHERMES_URL for a real model)") - StubLLM - end - -// --- the harness ---------------------------------------------------------- -actor CerebellumHarness is OrganReceiver - let _out: OutStream - let _bus: Broker - let _llm: LLM - let _passes: USize - - new create(out': OutStream, bus: Broker, llm: LLM, passes': USize = 4) => - _out = out' - _bus = bus - _llm = llm - // C1 L3: pass count is the responsiveness knob (energy-gated later); the - // 4+4 ordering is static. Clamp to >=1 so a turn always runs once. - _passes = if passes' < 1 then 1 else passes' end - - be receive(envl: Envelope) => - // A turn arrives off the bus: sequence the passes, then emit. - _pass(envl.payload, 1) - - be _pass(ctx: String, n: USize) => - if n > _passes then - _out.print("[cerebellum] " + _passes.string() + " passes -> " + ctx) - _bus.route(Envelope(Cerebellum, Brain, OrganSecretion, ctx)) - else - let self: CerebellumHarness tag = this - _llm.infer(ctx, {(out: String)(self, n) => self._pass(out, n + 1) } val) - end diff --git a/src/ichor/envelope.pony b/src/ichor/envelope.pony index d8553d1..5d76173 100644 --- a/src/ichor/envelope.pony +++ b/src/ichor/envelope.pony @@ -8,28 +8,32 @@ and the Ada border (Trust_Boundary) speak the same shape across the seam. Envelope is `class val`: immutable and sendable between actors. """ +// OUTER organs only. Ichor is the OUTER bus (the "skin") -- it carries the outer +// organs up to Ada (D1). The INNER organs -- soul, metacog, drive-box, mini-rag, +// Hermes, the E1 invariant laws -- do NOT belong here; they ride the Ada-routed +// (Jorvik) inner bus. NEVER add a brain/inner organ to this enum: that is +// "plugging the brain onto the skin". See docs/bus-topology.md. type OrganId is - ( DriveBox | EnergyTorus | Soul | Metacog | Brain | Cerebellum - | AdaBorder | Storage | MiniRag | UnknownOrgan ) + ( Stomach | Microagents | SAE | MoRAG + | AdaBorder | World | UnknownOrgan ) -primitive DriveBox - fun string(): String => "drive_box" -primitive EnergyTorus - fun string(): String => "etr" -primitive Soul - fun string(): String => "soul" -primitive Metacog - fun string(): String => "metacog" -primitive Brain - fun string(): String => "brain" -primitive Cerebellum - fun string(): String => "cerebellum" +primitive Stomach + // economy organ (small-model): digests external input into context + fun string(): String => "stomach" +primitive Microagents + fun string(): String => "microagents" +primitive SAE + // sparse autoencoder + fun string(): String => "sae" +primitive MoRAG + // = GoDAGRAG: graph of DAGs of RAGs; reads the world + fun string(): String => "morag" primitive AdaBorder + // the membrane (D1): the outer bus delivers inbound traffic here to be screened fun string(): String => "ada_border" -primitive Storage - fun string(): String => "storage" -primitive MiniRag - fun string(): String => "mini_rag" +primitive World + // the external world (user / network) + fun string(): String => "world" primitive UnknownOrgan fun string(): String => "unknown" diff --git a/src/ichor/main.pony b/src/ichor/main.pony index 3497ec5..7b2061c 100644 --- a/src/ichor/main.pony +++ b/src/ichor/main.pony @@ -1,6 +1,15 @@ -// Ichor smoke wiring (D2 §9 test): round-trip an envelope between two stub organs -// through the D1 admit check, and confirm an unscreened external payload is -// rejected at the barrier. +// Ichor smoke wiring — exercises the OUTER bus + the D1 membrane only. +// +// SCOPE / STUB NOTE (read before extending): +// * Ichor is the OUTER bus ("the skin"). It carries OUTER organs +// (stomach/economy, microagents, SAE, MoRAG) and delivers inbound traffic +// to Ada (the membrane). See docs/bus-topology.md. +// * It is NOT the inner-brain bus (that is Ada-routed, Jorvik) and NOT where +// Hermes, metacog, soul, drive-box, mini-rag, or the E1 laws live. Never +// wire an inner organ onto this bus — that is plugging the brain onto the +// skin. +// * This is a provisional scaffold proving the broker + membrane mechanics, +// not the final routing. // // Build: ponyc src/ichor -o build Run: ./build/ichor @@ -8,31 +17,22 @@ actor Main new create(env: Env) => let broker = Broker(env.out) - let soul = StubOrgan(Soul, env.out) - let brain = StubOrgan(Brain, env.out) - broker.register(Soul, soul) - broker.register(Brain, brain) + // Outer-bus endpoints. AdaBorder is the membrane: inbound traffic is screened + // there before it can cross into the inner brain. MoRAG is an outer organ. + let ada = StubOrgan(AdaBorder, env.out) + let morag = StubOrgan(MoRAG, env.out) + broker.register(AdaBorder, ada) + broker.register(MoRAG, morag) - // A system-internal secretion soul -> brain: must cross D1 and be delivered. - broker.route(Envelope(Soul, Brain, SystemInternal, - "big4 drawn: sun/asc/moon/mother-other")) + // The stomach digests external input into context and sends it inbound to + // Ada; system-origin context is admitted across the membrane. + broker.route(Envelope(Stomach, AdaBorder, OrganSecretion, + "digested context: ")) - // An external payload aimed at the brain: D1 must reject it. - broker.route(Envelope(AdaBorder, Brain, External, + // A raw external payload aimed straight at the membrane: D1 rejects it. + broker.route(Envelope(World, AdaBorder, External, "unscreened external payload")) - // Organ-to-organ perfusion (not Brain-bound): delivered directly. - broker.route(Envelope(Brain, Soul, OrganSecretion, - "reshuffle: cross-only")) - - // --- cerebellum harness plugged into the bus (C1 / OpenHermes) --- - // Plug-and-play: PickLLM chooses the model from the environment - // (OPENHERMES_URL/MODEL -> real client, else StubLLM); nothing else changes. - let cerebellum = - CerebellumHarness(env.out, broker, PickLLM(env.out, env.vars), 2) - broker.register(Cerebellum, cerebellum) - - // A user turn enters the bus addressed to the cerebellum; it sequences the - // passes and emits the synthesis back toward the Brain (crossing D1). - broker.route(Envelope(AdaBorder, Cerebellum, UserInput, - "user turn: what is my ascendant?")) + // Outer organ-to-organ (not membrane-bound): delivered directly, no screen. + broker.route(Envelope(Stomach, MoRAG, OrganSecretion, + "retrieve: world context for the next turn"))