From 786d4662c9d831b9dc2d8550dfb3abe23ae69352 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 18 Jun 2026 14:09:33 +0000 Subject: [PATCH] =?UTF-8?q?ichor(D2):=20start=20the=20Pony=20wiring=20?= =?UTF-8?q?=E2=80=94=20broker=20+=20D1=20barrier=20+=20envelope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Name the medium Ichor and scaffold it in Pony at src/ichor: - Envelope {source,dest,provenance,payload} mirroring Ada Organ_Message - Broker actor: register + perfusion route; Brain-bound traffic crosses D1 - Barrier (D1) admit: Pony provenance-law mirror + Ada FFI seam sketched - StubOrgan + main smoke wiring (deliver internal, reject external) - ichor_ada_shim.c: C/Fortran binding seam to Ada Trust_Guard (stub) Not compiled in-env (no ponyc). Updates D2 spec to SCAFFOLD/Pony. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_015hmgREHNsxYCuim33yUF2c --- docs/plans/D2-medium.md | 12 ++++--- src/ichor/README.md | 36 +++++++++++++++++++++ src/ichor/barrier.pony | 39 +++++++++++++++++++++++ src/ichor/broker.pony | 36 +++++++++++++++++++++ src/ichor/envelope.pony | 64 ++++++++++++++++++++++++++++++++++++++ src/ichor/ichor_ada_shim.c | 30 ++++++++++++++++++ src/ichor/main.pony | 29 +++++++++++++++++ src/ichor/organ.pony | 19 +++++++++++ 8 files changed, 261 insertions(+), 4 deletions(-) create mode 100644 src/ichor/README.md create mode 100644 src/ichor/barrier.pony create mode 100644 src/ichor/broker.pony create mode 100644 src/ichor/envelope.pony create mode 100644 src/ichor/ichor_ada_shim.c create mode 100644 src/ichor/main.pony create mode 100644 src/ichor/organ.pony diff --git a/docs/plans/D2-medium.md b/docs/plans/D2-medium.md index 6980aaa..55802f0 100644 --- a/docs/plans/D2-medium.md +++ b/docs/plans/D2-medium.md @@ -6,11 +6,13 @@ explicit that organs communicate by **perfusion, not direct wiring**; this is th **unnamed and unimplemented**. ## 2. Status / certainty -DESIGN-FIRST · **C1** (named structurally only; no backing, no name). +SCAFFOLD · named **Ichor**, Pony starting scaffold at `src/ichor/` (envelope + broker + D1 barrier + +C seam). Not yet compiled here (no `ponyc` in-env). Backing/transport now C3. ## 3. Language & location -TBD. Likely a message/IPC substrate (the R↔Octave↔Ada↔Guile organs must interoperate across languages), -so a language-neutral transport (e.g. line-delimited JSON, or a small broker) is the leading shape. +**Pony** (`src/ichor/`) — actor-model broker; capabilities give data-race-free sends. Transport split: +Pony actors = the broker (hosted on the D1 barrier) + **C/Fortran** for the Ada-side binding +(`ichor_ada_shim.c`). Cross-language organs (R/Octave/Ada/Guile) connect to the broker. ## 4. Does / does-not - **Does:** carry organ secretions/injections between organs, always *through* Ada (D1) before reaching the Brain. @@ -38,4 +40,6 @@ Everything rides it; nothing it depends on. *Stub today:* in-process function ca Round-trip an envelope between two stub organs; assert it passes through a D1 `admit` check; provenance preserved. ## 10. Open items -- **The name.** The transport choice. Whether RDE drives idle-perfusion. (All C1.) +- ~~The name~~ (**Ichor**). ~~Transport choice~~ (**Pony broker + C/Fortran Ada seam**). +- Build `ichor_ada_shim.c` into `libichor_ada` + wire `Barrier.admit` to Ada `Trust_Guard` (needs ponyc). +- Socket layer for out-of-process organs (in-process routing works today). Whether RDE drives idle-perfusion (C1). diff --git a/src/ichor/README.md b/src/ichor/README.md new file mode 100644 index 0000000..5a3ad38 --- /dev/null +++ b/src/ichor/README.md @@ -0,0 +1,36 @@ +# Ichor — the medium / "the blood" (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**). + +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. + +## 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). +- `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). + +## Build / run (needs ponyc — NOT installed in this env) +``` +ponyc src/ichor -o build # compile the package +./build/ichor # run the smoke wiring +``` +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. + +## Status +Starting scaffold. Pony + Fortran toolchains are absent in this environment, so +this is design-complete source to build where Pony exists — not yet compiled here. diff --git a/src/ichor/barrier.pony b/src/ichor/barrier.pony new file mode 100644 index 0000000..ea4bc24 --- /dev/null +++ b/src/ichor/barrier.pony @@ -0,0 +1,39 @@ +""" +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. + +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. + +To switch to the Ada border, add `use "lib:ichor_ada"` and replace the body of +`admit` with the FFI call sketched below. +""" + +primitive Barrier + fun admit(envl: Envelope): Bool => + // Pony-side mirror of D1's provenance law (stand-in for Trust_Guard). + match envl.provenance + | SystemInternal => true + | External => false // external never free-passes the barrier; D1 must screen + else + true + end + + // --- Ada seam (enable once the C shim + ponyc are present) ----------------- + // use "lib:ichor_ada" + // + // fun admit_via_ada(envl: Envelope): Bool => + // @ichor_ada_admit[Bool]( + // _provenance_code(envl.provenance), + // envl.payload.cpointer(), + // envl.payload.size()) + // + // fun _provenance_code(p: Provenance): U8 => + // match p + // | SystemInternal => 0 + // | UserInput => 1 + // | OrganSecretion => 2 + // | External => 3 + // end diff --git a/src/ichor/broker.pony b/src/ichor/broker.pony new file mode 100644 index 0000000..2c7891d --- /dev/null +++ b/src/ichor/broker.pony @@ -0,0 +1,36 @@ +""" +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. + +In full deployment this actor backs a socket broker hosted on the Ada barrier; +here it routes in-process so the wiring is exercisable without sockets. +""" + +use "collections" + +actor Broker + let _out: OutStream + let _organs: Map[String, OrganReceiver tag] = Map[String, OrganReceiver tag] + + new create(out': OutStream) => + _out = out' + + be register(id: OrganId, organ: OrganReceiver tag) => + _organs(id.string()) = organ + _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 + _out.print("[ichor] D1 REJECT " + envl.string()) + return + end + + try + _organs(envl.dest.string())?.receive(envl) + _out.print("[ichor] perfuse " + envl.string()) + else + _out.print("[ichor] no organ registered at " + envl.dest.string()) + end diff --git a/src/ichor/envelope.pony b/src/ichor/envelope.pony new file mode 100644 index 0000000..78098dd --- /dev/null +++ b/src/ichor/envelope.pony @@ -0,0 +1,64 @@ +""" +Ichor — the perfusion medium ("the blood"). D2. + +The one envelope every organ emits and consumes. Mirrors the Ada D1 +`Organ_Message {Source, Destination, Provenance, Payload}` so the Pony broker +and the Ada border (Trust_Boundary) speak the same shape across the seam. + +Envelope is `class val`: immutable and sendable between actors. +""" + +type OrganId is + ( DriveBox | EnergyTorus | Soul | Metacog | Brain + | AdaBorder | Storage | MiniRag | 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 AdaBorder + fun string(): String => "ada_border" +primitive Storage + fun string(): String => "storage" +primitive MiniRag + fun string(): String => "mini_rag" +primitive UnknownOrgan + fun string(): String => "unknown" + +type Provenance is ( SystemInternal | UserInput | OrganSecretion | External ) + +primitive SystemInternal + fun string(): String => "system_internal" +primitive UserInput + fun string(): String => "user_input" +primitive OrganSecretion + fun string(): String => "organ_secretion" +primitive External + fun string(): String => "external" + +class val Envelope + let source: OrganId + let dest: OrganId + let provenance: Provenance + let payload: String + + new val create( + source': OrganId, + dest': OrganId, + provenance': Provenance, + payload': String) + => + source = source' + dest = dest' + provenance = provenance' + payload = payload' + + fun string(): String => + source.string() + " -> " + dest.string() + + " [" + provenance.string() + "] " + payload diff --git a/src/ichor/ichor_ada_shim.c b/src/ichor/ichor_ada_shim.c new file mode 100644 index 0000000..1edee13 --- /dev/null +++ b/src/ichor/ichor_ada_shim.c @@ -0,0 +1,30 @@ +/* ichor_ada_shim.c + * + * The C/Fortran binding seam between Ichor (Pony) and the Ada D1 border + * (Trust_Boundary.Trust_Guard). Pony's FFI calls `ichor_ada_admit`; this shim + * is where the call crosses into Ada. + * + * Stub: returns admit=true. Replace the body with a call into an Ada export of + * Trust_Guard.Screen_Inbound (provenance + blocklist + rate), e.g. via a + * `pragma Export (C, ...)` wrapper on the Ada side. + * + * Build into a lib so Pony's `use "lib:ichor_ada"` can link it. + */ +#include +#include + +/* provenance codes mirror Ichor's Provenance: + * 0 system_internal, 1 user_input, 2 organ_secretion, 3 external */ +bool ichor_ada_admit(unsigned char provenance, + const char *payload, + size_t len) +{ + (void)payload; + (void)len; + + /* TODO: cross into Ada Trust_Guard.Screen_Inbound and return its verdict. */ + if (provenance == 3 /* external */) { + return false; + } + return true; +} diff --git a/src/ichor/main.pony b/src/ichor/main.pony new file mode 100644 index 0000000..5100cac --- /dev/null +++ b/src/ichor/main.pony @@ -0,0 +1,29 @@ +""" +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. + +Build (where ponyc exists): ponyc src/ichor -o build +Run: ./build/ichor +""" + +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) + + // 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")) + + // An external payload aimed at the brain: D1 must reject it. + broker.route(Envelope(AdaBorder, Brain, External, + "unscreened external payload")) + + // Organ-to-organ perfusion (not Brain-bound): delivered directly. + broker.route(Envelope(Brain, Soul, OrganSecretion, + "reshuffle: cross-only")) diff --git a/src/ichor/organ.pony b/src/ichor/organ.pony new file mode 100644 index 0000000..6c7cce7 --- /dev/null +++ b/src/ichor/organ.pony @@ -0,0 +1,19 @@ +""" +What an organ is, to Ichor: anything that can receive a perfused envelope. +Organs hold no hard reference to each other (perfusion law L1) — they only know +the Broker. `StubOrgan` is a canned receiver for standalone tests. +""" + +interface tag OrganReceiver + be receive(envl: Envelope) + +actor StubOrgan is OrganReceiver + let _id: OrganId + let _out: OutStream + + new create(id': OrganId, out': OutStream) => + _id = id' + _out = out' + + be receive(envl: Envelope) => + _out.print(" [" + _id.string() + "] received: " + envl.payload)