Skip to content

Commit b6dcc83

Browse files
authored
Merge pull request #90 from halcyonic-systems/feature/bert-core
feat: bert-core kernel extraction + bert-compose live-circuit thread (#88)
2 parents 4eeff7b + 4b6be1c commit b6dcc83

72 files changed

Lines changed: 14503 additions & 2245 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 1120 additions & 252 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
bert-core = { path = "bert-core", features = ["reflect"] }
910
bevy = { version = "0.17", features = [
1011
"bevy_picking",
1112
"bevy_mesh_picking_backend",
@@ -53,7 +54,7 @@ web-sys = { version = "0.3", features = [
5354
uuid = { version = "1.12.1", features = ["v4"] }
5455

5556
[workspace]
56-
members = ["src-tauri", "tools/bert-typedb"]
57+
members = ["src-tauri", "tools/bert-typedb", "bert-core", "bert-compose"]
5758

5859

5960
[profile.dev]

bert-compose/ARCHITECTURE.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# BERT Compose — Architecture
2+
3+
One spine, layers on top. The whole thing exists to make one claim *tactile*: that the common core of systems science is small, behaves the same across domains, and conserves. Everything here serves that.
4+
5+
```
6+
┌─────────────────────────────────────────────┐
7+
UI (ui/*) │ top_bar · palette · inspector · canvas · │ panels only,
8+
│ charts · status_bar · hal_window · about │ no physics
9+
└───────────────────────┬─────────────────────┘
10+
│ reads/writes
11+
state (app.rs) ──────────────────────┤ App: selection, run loop, persistence
12+
13+
┌─────────────────────┬───────────────┴───────────┬───────────────────┐
14+
│ engine (circuit.rs) │ content (ladder, examples,│ io (export.rs) │
15+
│ primitives, step, │ lens, docs) │ ↔ BERT JSON │
16+
│ conservation ledger│ │ (save + load) │
17+
└─────────────────────┴───────────────────────────┴───────────────────┘
18+
19+
verification (sweep.rs, #[cfg(test)]) │ drives ladder, asserts the LPs,
20+
│ emits troncale-sweep/
21+
```
22+
23+
## The engine — `circuit.rs`
24+
25+
A `Circuit` is `nodes: Vec<Node>` + `wires: Vec<Wire>`. One synchronous discrete `step()`: every transfer function reads the *previous* tick's wire amounts and writes the next, so feedback loops are ordinary dynamics with no special cases. Transfer functions are ports of BERT's verified `python/agents.py` (39 tests there).
26+
27+
**Substance trichotomy.** Energy and Material are conserved (split across fanouts, stored, never duplicated); Message is information (copies freely, gates, is manufactured by Inverting — never conserved). Every node has an `out_substance: DeclaredSubstance { name, base, unit }` — a human name over one of the three conserved `base` kinds. Dynamics read `.base` only; the name/unit are presentation and ride into the JSON.
28+
29+
**Flow modes.** A `Wire` is `pushed` (rate = a set parameter) or `gradient` (rate = `conductance · (level_from − level_to)`). Gradient is how Potential Fields enter — a field is a flow *mode*, not a node (Mobus Ch.4: forces/fields are generalized flows). Gradient flows only run from nodes with a *potential* (Sources, stocks); elsewhere they're inert.
30+
31+
### The conservation contract
32+
33+
The engine's central invariant. Per node, per tick:
34+
35+
```
36+
dissipated += physical_in − physical_out − Δstorage
37+
```
38+
39+
which makes the ledger hold **by construction**:
40+
41+
```
42+
emitted + initial stocks == stored + sunk + in-flight + dissipated
43+
```
44+
45+
`balance()` returns the residual; ≈0 means every unit of physical mass is accounted, and any *unintended* leak is a nonzero residual the property tests catch. `dissipated` is not a fudge factor — it's the sum of the **declared** loss channels: Propelling/Impeding friction, Amplifying power draw, Modulating shed, Sensing consumption, substance-mismatch shed, dead ends. Message is never ledgered (information doesn't conserve).
46+
47+
The property tests in `circuit.rs` build hundreds of random circuits and assert `balance() ≈ 0` every tick; they are mutation-tested (reverting any one leak fix makes them fail). This is why a curve out of bert-compose is *evidence*.
48+
49+
## Content layers
50+
51+
- **`ladder.rs`** — Troncale's systems processes as primitive circuits, the single source of truth shared by the palette macros (you *stamp* a process and its bricks appear) and the sweep tests. A `Rung` carries the builder plus its provenance, sweep bucket, and whether it's palette-stampable.
52+
- **`examples.rs`** — the friendly on-ramp library (leaky bucket, thermostat, battery, the universal homeostat…).
53+
- **`lens.rs`** — four domain vocabularies aligned to the halcyonic.systems pillars (Political Economy / Neuromorphics / Protocol Science / Ecology) + the Systems identity, each a 12-name relabeling (plus per-slot glosses) over the primitive slots. A lens is **pure presentation**: it never enters `circuit.rs`, which is asserted by the lens-invariance test (the universal homeostat's CSV is byte-identical under every lens).
54+
- **`examples.rs`** — categorized to mirror the pillars: Foundations (concepts, neutral lens), the four domain examples (each loads in its lens), and the cross-domain Universal homeostat. A leaky bucket is never relabeled with crypto words — lenses apply only where they mean something.
55+
- **`docs.rs`** — per-primitive teaching cards (plain English → math → substance → theory → transfer function).
56+
57+
## IO — `export.rs`
58+
59+
The only path to/from JSON, both directions:
60+
- `to_world_model` — circuit → a BERT `WorldModel` (composite root + atomic subsystems carrying `AgentModel.primitives`; wires → flows; Source/Sink → environment externals).
61+
- `from_world_model` — the inverse; Load and drag-a-`.json` both use it. Compose-only knobs ride in extensible fields (buffer `release_rate` in `cognitive_params`, gradient `conductance` as a flow `Parameter`) so the round-trip is lossless. Non-compose-shaped models error with a reason rather than dropping structure.
62+
63+
A round-trip test asserts behavioral identity (same physics over 30 ticks), not just structural equality.
64+
65+
## Verification — `sweep.rs` (the Troncale sweep)
66+
67+
The empirical instrument. It climbs Troncale's own dependency ladder and, per process, asks: does the signature behavior emerge from a primitive circuit? Each constructible process is a **passing test whose assertion is the demonstration** — "coupled feedback → oscillation" becomes a circuit whose CSV oscillates, proven by his own criteria (sustainability + influence-richness).
68+
69+
Four buckets sort every process and the boundary is the finding:
70+
- **(a) constructible** — emerges from a primitive circuit
71+
- **(b) is-a-primitive** — already atomic (Storage = Buffering)
72+
- **(c) out-of-scope** — structural/relational, not flow-dynamical (Hierarchy → #75)
73+
- **(d) needs-agent-layer** — individuated/selective (Evolution → Mesa)
74+
75+
`cargo test sweep` proves the LPs. `cargo test emit_sweep_artifacts -- --ignored` writes the circuit+CSV evidence bundle + outcome table to `troncale-sweep/`. The sweep's headline findings (two routes to stability; cycling is automatic; zeroth-order release is a hard floor) live in [troncale-sweep/README.md](troncale-sweep/README.md).
76+
77+
## Roadmap (open issues)
78+
79+
| # | what |
80+
|---|---|
81+
| [#82](https://github.com/halcyonic-systems/bert/issues/82) | "signal costs power" mode — messages aren't free, carriers cost Energy |
82+
| [#83](https://github.com/halcyonic-systems/bert/issues/83) | export the four-lens homeostat as a publishable artifact bundle |
83+
| [#84](https://github.com/halcyonic-systems/bert/issues/84) | lenses auto-apply domain substances (suggest / override) |
84+
| [#85](https://github.com/halcyonic-systems/bert/issues/85) | proportional-release buffer mode → unlocks first-order decay + Lotka-Volterra |
85+
| [#86](https://github.com/halcyonic-systems/bert/issues/86) | "Troncale mode" — processes as first-class collapsible composite components (with #75 nesting) |
86+
87+
## Conventions
88+
89+
- The engine has no UI; the UI has no physics; `export.rs` is the only JSON. Keep it that way.
90+
- New behavior goes in `circuit.rs` with a property/regression test; the conservation invariant must keep holding.
91+
- Rebuild the app with `./make-app.sh` after changes, and **kill stale instances first**`open` re-focuses a running instance and serves the old binary.

bert-compose/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "bert-compose"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
bert-core = { path = "../bert-core" }
8+
serde_json = "1"
9+
eframe = "0.31"
10+
egui = "0.31"
11+
egui_plot = "=0.31.0"
12+
ureq = { version = "2.10", features = ["json"] }
13+
rfd = "0.15"

bert-compose/DESIGN-VISION.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# BERT Compose — UI/UX vision
2+
3+
What would make Stella, Vensim, NetLogo, and Mesa jealous? Not more features —
4+
a different *relationship* between the modeler and the model. Those tools all
5+
share one flaw: a gap between describing a system and being in causal contact
6+
with it. You draw/code, then compile/run/debug as a separate act, and errors
7+
live in the gap. Compose has no gap and no error states — both are theory, not
8+
polish. The design job is to protect and deepen that, never to bury it under
9+
chrome.
10+
11+
Principle: **every pixel either shows the live system or gets out of the way.**
12+
Calm warm-paper canvas (the Halcyonic shell), color reserved for meaning
13+
(substance identity, state level, the one amber warning), motion reserved for
14+
truth (flow only moves when flow is real).
15+
16+
## The five things that win
17+
18+
### 1. Flow you can read at a glance — make conservation visible, not just true
19+
Today: a number and a moving dot per wire. Jealousy-grade:
20+
- **Wire thickness = magnitude** (log-scaled), so a glance reads the whole
21+
circuit's balance — fat in, thin out means something's accumulating.
22+
- **Pulse density = rate**, color = substance. A conserved split *looks*
23+
conserved: one fat wire becoming two half-width wires.
24+
- **Stock as a filling vessel**, not a bar — buffers visibly hold, and a
25+
buffer near overflow or empty pulses at its rim. The state of the system is
26+
legible from across the room. Stella draws stocks; none of them *breathe*.
27+
28+
### 2. The inline sparkline — every node carries its own history
29+
Mesa/NetLogo make you wire up a separate plot window. Compose should paint a
30+
**tiny live sparkline under each node** (the last ~40 ticks of its activity or
31+
storage), so the dynamics are *on the diagram*, not in a side panel. The whole
32+
canvas becomes a dashboard of itself. Click a node → the sparkline expands into
33+
the right panel with axes. This is the single highest-jealousy feature: the
34+
model and its behavior are the same picture.
35+
36+
### 3. Direct-manipulation parameters — drag the system, watch it respond live
37+
Vensim has sliders in a separate "SyntheSim" mode. Compose should let you drag
38+
a parameter *while it runs* and watch the loop respond in real time — pull the
39+
source rate up and see the homeostat fight back, live. Even better: **drag on
40+
the node itself** (vertical drag on a buffer = release rate; on a source =
41+
emission). The parameter space becomes something you *play* like an
42+
instrument, not a form you fill.
43+
44+
### 4. The lens switch — one model, every domain (nobody else has this)
45+
The killer differentiator, straight from K≅2. A **lens selector** aligned to
46+
the halcyonic.systems pillars (Systems / Political Economy / Neuromorphics /
47+
Protocol Science / Ecology) that *renames and re-skins* the same running
48+
circuit without touching its dynamics: Sensing→"monitor"/"oracle"/"receptor",
49+
Buffering→"registry"/"mempool"/"membrane". Switch lenses mid-run and watch the
50+
*same regulation* become a quorum throttle, a difficulty adjustment, a
51+
spiking neuron. No other modeling tool can show you that two domains are the
52+
same system because no other tool has the proof underneath. This is the
53+
"jealous" moment — it's not a better SD tool, it's a category they don't have.
54+
55+
### 5. Provenance on demand — the proof is one hover away
56+
Every primitive, every bond, every "no error" can cite its license. Hover a
57+
node → "Buffering: conservative stock, transfer fn verified
58+
(python/agents.py), Mobus Ch.3." Hover the canvas → "valid by construction:
59+
composition is unconditional, Systems/Mobus/Composition.lean." Nobody trusts a
60+
black-box simulator; Compose can make rigor *ambient* — always available,
61+
never in the way. The honesty is the brand.
62+
63+
## Smaller touches that compound
64+
- **Snap-to-grid + auto-route wires** (orthogonal, not straight-through-nodes).
65+
- **Palette items show their I/O substance** as little colored ports, so you
66+
pre-see what connects to what.
67+
- **Drag-from-port creates a node** ("drag into empty space → pick primitive"),
68+
so building is one gesture, not add-then-wire.
69+
- **Time scrubber** on the recorded run — drag back through ticks, the canvas
70+
reconstructs that moment's state (the CSV already holds it).
71+
- **Equilibrium glow**: when a regulated loop settles, it gets a soft steady
72+
halo — the system *telling you* it found homeostasis.
73+
- **"Why is this amber?"** — the substance/unit warnings already shipped;
74+
make them one-click-fixable ("change source to Message" / "insert
75+
transducer").
76+
77+
## What to deliberately NOT do (the discipline)
78+
- No code panel, no equation editor as the *primary* surface — the diagram IS
79+
the model. (Equations available on hover for the curious; never required.)
80+
- No modal config dialogs — everything inline, everything live.
81+
- No individuated-agent simulation here — that's Mesa's job; Compose is
82+
aggregate flow. Resisting this keeps the tool honest and the canvas calm.
83+
- No error states. Ever. Composition is unconditional; the worst that happens
84+
is an amber "this flow is ignored, here's why."
85+
86+
## The one-sentence pitch
87+
Stella shows you a diagram, Vensim shows you a model, Mesa shows you a program —
88+
**Compose lets you reach in and hold the system while it runs, in any domain,
89+
with the proof one hover away.**

bert-compose/MOBUS.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Grounding in Mobus
2+
3+
What in bert-compose comes straight from Mobus, what's our extension, and what's a known gap — sourced from the actual text, not general knowledge.
4+
5+
**Sources.** The vault `operations/systems-science/mobus/` is **Mobus 2022** (*Systems Science: Theory, Analysis, Modeling, and Design*). Mobus & Kalton 2015 (*Principles of Systems Science*) is the earlier, separate work (Zotero). The **8-tuple is Mobus's post-2022 "book-revisions,"** formalized and machine-checked in `systems-science-foundations/Systems/Mobus/Tuple.lean`; the BERT element table is `bert/docs/mobus-reference.md`.
6+
7+
## The primitives ARE Mobus's atomic work processes
8+
9+
The palette is Mobus 2022 **Figs 3.18–3.19** verbatim:
10+
11+
- **Fig 3.18** (four simple): **Combining** (two substances → a product + waste), **Splitting** (one flow → two products + loss), **Impeding** (slow a flow *"with a consequent back-pressure"*), **Buffering** (*"smooth out the flow volumes over time"*).
12+
- **Fig 3.19** (additional): **Copying** (template + blank → original + copy + waste), **Propelling** (*"push a substance against a gradient, like a pump"*), **Sensing** (responds to a modulated force, emits a low-power modulated signal), **Amplifying** (adds power to a weak modulated input), **Modulating** (applies a signal to a substance flow).
13+
14+
Source: *"All system components recapitulate the fundamental work processes depicted in Figs 3.18 and 3.19"* (Ch. 3 conclusion).
15+
16+
## The conservation ledger IS Mobus's waste heat (Fig 3.17)
17+
18+
Our `dissipated` is not an artifact — it's the Second Law. Fig 3.17: *"Work processes require high-potential energy… some of the energy… is transformed to waste heat. Material transformations involve some material waste; energy transformations produce a greater proportion of waste heat."*
19+
20+
That is exactly why the domain examples differ on the **conservation chart**: a Material/value system (budget, tokens) loses little; an Energy system (neuron, meadow) loses most. The energy-vs-value distinction is Mobus, made runnable — see the substance trichotomy (Energy/Material conserve and degrade; Message copies, never ledgered), also Mobus (Ch. 3, "Three Substance Types").
21+
22+
## The 8-tuple and the parameter license
23+
24+
`S = ⟨C, N, E, G, B, T, H, Δt⟩` (`Tuple.lean`, "Book-revisions Eq. 1"):
25+
C components · N internal network · E = ⟨O,M⟩ environment · G external (boundary-crossing) flows · B = ⟨P,I⟩ boundary · T transforms · H history/knowledge · Δt time scale.
26+
27+
The Lean DESIGN note is load-bearing for *this tool's design*: **T, H, Δt are parametric / domain-specific by intent** — the structural constraints live only in C/N/E/G/B. So **there is no Mobus-canonical per-primitive parameter set**; bert-compose choosing transfer-function parameters (a Source's rate, a Sensing gain, an efficiency) fills the slot Mobus deliberately leaves open. It's licensed by the ontology, not a deviation.
28+
29+
## What's faithful · what's ours · what's a gap
30+
31+
- **Faithful:** the primitives (Figs 3.18–3.19), conservation/waste heat (Fig 3.17), the substance trichotomy, the error-sensing homeostat (Fig 4.12: sensing → inverter → modulator → comparator, computing reference − measured), composition as ontogenic linkage of work processes (Ch. 4 Fig 4.12).
32+
- **Ours (extensions):** the lenses (presentation functors over the same model), the named-substance dictionary, the conservation chart, the gradient flow-mode (grounded separately in Mobus Ch. 4 "fields are generalized flows").
33+
- **Known gaps (roadmap, [bert#87](https://github.com/halcyonic-systems/bert/issues/87)):** the push model has **no back-pressure**, yet Mobus's *Impeding is defined with* back-pressure — so a throttled valve sheds blocked flow instead of backing it up (this is why a budget can appear to "lose" money). Plus **maintenance energy** (Fig 3.17's upkeep cost), and Buffering **time-constant** smoothing. **Threshold** is a candidate too but is neuroscience, *not* Mobus — don't attribute it to him.
34+
35+
## Don't
36+
37+
- Don't "correct" the 8-tuple to a 7-tuple from the 2022 book chapters — the 8-tuple is the authoritative revision (`Tuple.lean`).
38+
- Don't attribute the **threshold** parameter to Mobus.
39+
- Don't treat ledger `dissipated` as a leak to eliminate — for Energy it's the physics (Fig 3.17).

0 commit comments

Comments
 (0)