-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathengineering-record.html
More file actions
396 lines (329 loc) · 36 KB
/
Copy pathengineering-record.html
File metadata and controls
396 lines (329 loc) · 36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Engineering Record | Pisces Moon OS — ESP32-S3 Reference Architecture</title>
<meta name="description" content="The Pisces Moon OS Engineering Record — eight architectural patterns hardened into platform-level disciplines across three ESP32-S3 deployment targets including the no-PSRAM Cardputer ADV. Reference architecture document.">
<link rel="canonical" href="https://fluidfortune.com/engineering-record.html">
<meta property="og:type" content="article">
<meta property="og:url" content="https://fluidfortune.com/engineering-record.html">
<meta property="og:title" content="Engineering Record | Pisces Moon OS — ESP32-S3 Reference Architecture">
<meta property="og:description" content="Eight architectural patterns proven across three ESP32-S3 devices. The chip is more capable than the marketing implies — when the operating system is real.">
<meta property="og:image" content="https://fluidfortune.com/courtjester.jpg">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,600;0,900;1,400&family=Source+Serif+4:ital,opsz,wght@0,8..60,300;0,8..60,400;0,8..60,600;1,8..60,300&family=DM+Mono:wght@300;400;500&display=swap" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,600;0,900;1,400&family=Source+Serif+4:ital,opsz,wght@0,8..60,300;0,8..60,400;0,8..60,600;1,8..60,300&family=DM+Mono:wght@300;400;500&display=swap"></noscript>
<style>
:root {
--paper: #faf8f4;
--paper-dark: #f0ede6;
--ink: #1a1614;
--ink-mid: #4a4340;
--ink-light: #8a7f78;
--ink-faint: #c5bdb5;
--accent: #c17f3a;
--accent-dim: #9a6128;
--accent-pale: #f5ead8;
--rule: #ddd8d0;
--green: #2d5a3d;
--green-pale: #e8f0eb;
--font-disp: 'Playfair Display', Georgia, serif;
--font-body: 'Source Serif 4', Georgia, serif;
--font-mono: 'DM Mono', monospace;
--max-w: 760px;
--toc-w: 220px;
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{font-size:16px;scroll-behavior:smooth}
body{background:var(--paper);color:var(--ink);font-family:var(--font-body);line-height:1.75;-webkit-font-smoothing:antialiased}
nav.top{border-bottom:1px solid var(--rule);position:sticky;top:0;background:var(--paper);z-index:100}
nav.top .nav-inner{max-width:calc(var(--max-w) + var(--toc-w) + 4rem);margin:0 auto;padding:0 2rem;display:flex;gap:1.5rem;align-items:center}
nav.top a{font-family:var(--font-mono);font-size:.62rem;letter-spacing:.12em;color:var(--ink-light);text-decoration:none;padding:.9rem 0;border-bottom:2px solid transparent;transition:color .15s,border-color .15s;display:inline-block}
nav.top a:hover{color:var(--accent);border-bottom-color:var(--accent)}
nav.top .doc-label{margin-left:auto;font-family:var(--font-mono);font-size:.56rem;letter-spacing:.15em;color:var(--ink-light);border:1px solid var(--rule);padding:.25rem .65rem;background:var(--paper-dark)}
.layout{display:flex;max-width:calc(var(--max-w) + var(--toc-w) + 4rem);margin:0 auto;padding:0 2rem;gap:3rem;align-items:flex-start}
.toc{width:var(--toc-w);flex-shrink:0;position:sticky;top:50px;padding:2.5rem 0;max-height:calc(100vh - 50px);overflow-y:auto}
.toc-label{font-family:var(--font-mono);font-size:.55rem;letter-spacing:.2em;color:var(--ink-light);margin-bottom:.75rem;padding-bottom:.4rem;border-bottom:1px solid var(--rule);display:block;text-transform:uppercase}
.toc a{display:block;font-family:var(--font-mono);font-size:.62rem;color:var(--ink-mid);text-decoration:none;padding:.25rem 0 .25rem .5rem;letter-spacing:.04em;transition:color .15s,border-left-color .15s;border-left:2px solid transparent;margin-bottom:.1rem;line-height:1.5}
.toc a:hover{color:var(--accent);border-left-color:var(--accent)}
.toc a .num{color:var(--ink-faint);display:inline-block;width:1.5rem}
.toc-divider{border-top:1px solid var(--rule);margin:.85rem 0 .5rem}
.toc-divider-label{font-family:var(--font-mono);font-size:.5rem;letter-spacing:.18em;color:var(--ink-faint);text-transform:uppercase;padding:0 0 .35rem .5rem}
.toc a.ext{color:var(--accent-dim)}
::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background:var(--paper)}::-webkit-scrollbar-thumb{background:var(--rule)}
.content{flex:1;min-width:0;padding:3rem 0 6rem;max-width:var(--max-w)}
.masthead{border-bottom:2px solid var(--ink);padding-bottom:2rem;margin-bottom:2.5rem}
.masthead-eyebrow{font-family:var(--font-mono);font-size:.6rem;letter-spacing:.2em;color:var(--ink-light);margin-bottom:.5rem;text-transform:uppercase}
.masthead-title{font-family:var(--font-disp);font-size:clamp(2rem,5vw,2.75rem);font-weight:900;letter-spacing:-.02em;line-height:1.1;color:var(--ink);margin-bottom:.65rem}
.masthead-sub{font-family:var(--font-body);font-size:1.05rem;color:var(--accent-dim);font-style:italic;font-weight:300;line-height:1.5;margin-bottom:1.25rem}
.masthead-meta{font-family:var(--font-mono);font-size:.62rem;color:var(--ink-light);letter-spacing:.05em;line-height:1.95}
.masthead-meta span{display:inline-block;margin-right:1.25rem}
.masthead-meta .ver{color:var(--accent-dim);border:1px solid var(--accent-pale);background:var(--accent-pale);padding:.1rem .55rem}
.abstract{background:var(--paper-dark);border-left:3px solid var(--ink);padding:1.5rem 1.75rem;margin-bottom:3rem}
.abstract-label{font-family:var(--font-mono);font-size:.58rem;letter-spacing:.2em;color:var(--ink-light);margin-bottom:.85rem;text-transform:uppercase}
.abstract p{font-family:var(--font-body);font-size:.95rem;color:var(--ink-mid);line-height:1.75;margin-bottom:.85rem;font-weight:300}
.abstract p:last-child{margin-bottom:0}
.abstract strong{color:var(--ink);font-weight:600}
.abstract em{font-style:italic}
section.s{padding-top:3rem}
.s-header{display:flex;align-items:baseline;gap:.85rem;padding-bottom:.75rem;border-bottom:1.5px solid var(--ink);margin-bottom:1.5rem}
.s-num{font-family:var(--font-mono);font-size:.65rem;color:var(--ink-light);letter-spacing:.12em;flex-shrink:0}
.s-title{font-family:var(--font-disp);font-size:1.5rem;font-weight:700;color:var(--ink);letter-spacing:-.01em;line-height:1.2}
p{font-size:.95rem;color:var(--ink-mid);line-height:1.85;margin-bottom:1rem;font-weight:300}
strong{color:var(--ink);font-weight:600}
em{font-style:italic}
a{color:var(--accent-dim);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px;transition:color .15s}
a:hover{color:var(--accent)}
code{font-family:var(--font-mono);font-size:.82em;color:var(--accent-dim);background:var(--paper-dark);padding:.1em .35em;border:1px solid var(--rule);border-radius:2px}
ol,ul{margin:.85rem 0 1.25rem 1.5rem}
li{font-size:.93rem;color:var(--ink-mid);line-height:1.8;margin-bottom:.4rem;font-weight:300}
li strong{color:var(--ink)}
blockquote{border-left:3px solid var(--ink-faint);padding:.25rem 1.25rem;margin:1.5rem 0}
blockquote p{font-style:italic;font-size:.95rem;color:var(--ink-mid);margin-bottom:0}
h3.subhead{font-family:var(--font-disp);font-size:1.15rem;font-weight:600;color:var(--ink);letter-spacing:-.005em;margin:2.5rem 0 .85rem;padding-bottom:.35rem;border-bottom:1px solid var(--rule)}
.pattern{background:var(--paper);border:1px solid var(--rule);border-left:3px solid var(--ink);padding:1.25rem 1.5rem;margin:1.25rem 0}
.pattern-num{font-family:var(--font-mono);font-size:.6rem;letter-spacing:.15em;color:var(--ink-light);text-transform:uppercase;margin-bottom:.4rem}
.pattern-title{font-family:var(--font-disp);font-size:1.15rem;font-weight:600;color:var(--ink);letter-spacing:-.005em;line-height:1.3;margin-bottom:.85rem}
.pattern-text{font-size:.92rem;color:var(--ink-mid);line-height:1.8;font-weight:300}
.pattern-hero{border-left:4px solid var(--accent);background:var(--accent-pale)}
.pattern-hero .pattern-num{color:var(--accent-dim)}
.table-wrap{overflow-x:auto;margin:1.5rem 0;border:1px solid var(--rule)}
table{width:100%;border-collapse:collapse;font-family:var(--font-body);font-size:.88rem;background:var(--paper)}
th{background:var(--paper-dark);color:var(--ink);font-family:var(--font-mono);font-size:.6rem;letter-spacing:.1em;padding:.65rem .85rem;text-align:left;border-bottom:2px solid var(--ink);font-weight:500;text-transform:uppercase}
td{padding:.55rem .85rem;border-top:1px solid var(--rule);color:var(--ink-mid);vertical-align:top;line-height:1.65;font-weight:300}
td:first-child{color:var(--ink);font-weight:500;font-family:var(--font-mono);font-size:.83rem}
.callout{background:var(--paper-dark);border-left:3px solid var(--accent);padding:1.1rem 1.4rem;margin:1.5rem 0}
.callout .c-label{font-family:var(--font-mono);font-size:.58rem;letter-spacing:.15em;color:var(--accent-dim);margin-bottom:.55rem;text-transform:uppercase}
.callout p{font-size:.9rem;color:var(--ink-mid);line-height:1.8;margin-bottom:.65rem;font-weight:300}
.callout p:last-child{margin-bottom:0}
.callout strong{color:var(--ink)}
.callout-green{background:var(--green-pale);border-left-color:var(--green)}
.callout-green .c-label{color:var(--green)}
.closing{border-top:2px solid var(--ink);margin-top:3.5rem;padding-top:1.75rem}
.closing-quote{font-family:var(--font-disp);font-size:1.25rem;font-style:italic;font-weight:400;color:var(--ink);line-height:1.4;margin-bottom:1.25rem;letter-spacing:-.005em}
.closing p{font-family:var(--font-mono);font-size:.72rem;color:var(--ink-light);line-height:1.95;margin-bottom:.4rem;font-weight:400}
.closing strong{color:var(--ink)}
.closing a{color:var(--accent-dim)}
.site-footer{border-top:1px solid var(--rule);padding:1.5rem 0;text-align:center;font-family:var(--font-mono);font-size:.6rem;color:var(--ink-light);letter-spacing:.05em;margin-top:3rem}
.site-footer a{color:var(--ink-mid);text-decoration:none;margin:0 .5rem}
.site-footer a:hover{color:var(--accent)}
@media(max-width:900px){
.layout{flex-direction:column;padding:0 1.5rem}
.toc{width:100%;position:static;padding:2rem 0 0;max-height:none}
.content{padding:2rem 0 4rem}
nav.top .nav-inner{padding:0 1.5rem}
}
@media(max-width:600px){.masthead-meta span{display:block;margin-bottom:.25rem}}
</style>
</head>
<body>
<nav class="top">
<div class="nav-inner">
<a href="https://fluidfortune.com">FLUID FORTUNE</a>
<a href="sovereignty.html">WHITE PAPER</a>
<a href="engineering-record.html">ENGINEERING RECORD</a>
<a href="spi-bus-treaty.html">SPI BUS TREATY</a>
<a href="device-architecture.html">DEVICE ARCHITECTURE</a>
<a href="mesh-state.html">MESH STATE</a>
<span class="doc-label">TECHNICAL DOCUMENTATION</span>
</div>
</nav>
<div class="layout">
<aside class="toc">
<span class="toc-label">Contents</span>
<a href="#thesis"><span class="num">I.</span>Thesis</a>
<a href="#chip"><span class="num">II.</span>The Chip vs the Marketing</a>
<a href="#targets"><span class="num">III.</span>Three Deployment Targets</a>
<a href="#patterns"><span class="num">IV.</span>Eight Architectural Patterns</a>
<a href="#problems"><span class="num">V.</span>Eleven Engineering Problems</a>
<a href="#methodology"><span class="num">VI.</span>The Methodology</a>
<a href="#next"><span class="num">VII.</span>What's Next</a>
<div class="toc-divider"></div>
<div class="toc-divider-label">Companion Documents</div>
<a href="sovereignty.html" class="ext"><span class="num">↗</span>White Paper</a>
<a href="spi-bus-treaty.html" class="ext"><span class="num">↗</span>SPI Bus Treaty</a>
<a href="device-architecture.html" class="ext"><span class="num">↗</span>Device Architecture</a>
<a href="mesh-state.html" class="ext"><span class="num">↗</span>Mesh State</a>
<div class="toc-divider"></div>
<div class="toc-divider-label">Project</div>
<a href="pisces-moon.html" class="ext"><span class="num">↗</span>Pisces Moon OS</a>
<a href="https://github.com/FluidFortune/pisces-moon-os" class="ext"><span class="num">↗</span>GitHub</a>
</aside>
<main class="content">
<div class="masthead">
<div class="masthead-eyebrow">Pisces Moon OS · Engineering Record</div>
<h1 class="masthead-title">What the ESP32-S3 Is,<br>When the Operating System Is Real</h1>
<p class="masthead-sub">Reference architecture record for Pisces Moon OS v1.2.0 — eight patterns proven across three deployment targets spanning the entire memory tier of the chip class.</p>
<div class="masthead-meta">
<span>Eric Becker · Fluid Fortune</span>
<span>v1.2.0 · May 19, 2026</span>
<span class="ver">Reference Architecture</span>
</div>
</div>
<div class="abstract">
<div class="abstract-label">Abstract</div>
<p>Pisces Moon OS v1.2.0 ships a four-radio multi-app handheld operating system — preemptive multitasking, persistent dual-core background intelligence collection, runtime-loadable application modules, real-time SD logging, FAT32 file management — on a $50 microcontroller with <strong>320 KB of internal SRAM and no external memory of any kind</strong>. This is not a benchmark or a tech demo. It is a shipping operating system.</p>
<p>This engineering record documents how that became possible. Eleven engineering problems solved on the way — none of which had documented prior solutions on this hardware platform. Eight architectural patterns hardened into platform-level disciplines: the SPI Bus Treaty, the Ghost Engine task model, lazy app-state allocation, WiFi mode-locking with hard teardown, lazy boot initialization, runtime radio tuning, the three-layer ELF sandbox, and the three-tier memory architecture that allows the same OS to run from zero PSRAM through 8 MB PSRAM with a single codebase.</p>
<p>The deeper claim is in the methodology: <em>name the constraint, document the protocol, make it a platform contract.</em> The treaties this methodology produced — SPI Bus Treaty on the S3, UART Peripheral Map on the P4 — are the expressions. The methodology is the contribution. The Cardputer result is the proof that it generalizes to hardware the industry treats as incapable of running an OS at all.</p>
</div>
<!-- I. THESIS -->
<section class="s" id="thesis">
<div class="s-header"><div class="s-num">I.</div><h2 class="s-title">Thesis</h2></div>
<p>The Espressif ESP32-S3 is sold for single-purpose firmware. Smart-home endpoints. IoT modules. AI inference accelerators. The chip vendors target the customers who collectively ship hundreds of millions of devices and pay the bills. Nobody at Espressif is wrong about what their chip sells for.</p>
<p>The chip is also more capable than its marketing implies. Pisces Moon OS demonstrates this by shipping a multi-app operating system on three different ESP32-S3 deployment targets, including the no-PSRAM Cardputer ADV — concurrent four-radio operation, real-time logging, persistent multi-app state, and a documented sandbox for runtime third-party code. This document is the record of what that took.</p>
<p>The argument is not that mutexes are new, that PSRAM heap redirection is undocumented, or that the ESP-IDF is missing features. The argument is structural: no prior project on this hardware class assembled the available primitives into a multi-app OS that required all of them simultaneously, named the architectural protocols that made them coexist, and ported the result across three devices in the same chip family without breaking the protocols. Eight patterns generalized. Eleven problems solved. One methodology behind all of it.</p>
</section>
<!-- II. THE CHIP -->
<section class="s" id="chip">
<div class="s-header"><div class="s-num">II.</div><h2 class="s-title">The Chip vs the Marketing</h2></div>
<p>The clearest way to show what the marketing leaves unsaid is to compare the most resource-constrained Pisces Moon target — the Cardputer ADV with zero PSRAM — to its commercial framing as a single-purpose device.</p>
<div class="table-wrap">
<table>
<thead><tr><th>Property</th><th>Cardputer ADV — Marketing</th><th>Cardputer ADV — Running Pisces Moon</th></tr></thead>
<tbody>
<tr><td>Use case</td><td>Single-purpose IoT firmware</td><td>Multi-app operating system, 47 applications</td></tr>
<tr><td>Multitasking</td><td>Optional FreeRTOS task</td><td>Preemptive multitasking, dual-core split</td></tr>
<tr><td>Memory budget</td><td>320 KB shared across all uses</td><td>Static footprint 109 KB, app-lifetime heap 219 KB</td></tr>
<tr><td>Concurrent radios</td><td>One at a time, usually</td><td>WiFi STA + NimBLE observer + GPS + LoRa</td></tr>
<tr><td>Persistent background work</td><td>Not in the reference designs</td><td>Ghost Engine on Core 0, runs unconditionally</td></tr>
<tr><td>Runtime third-party code</td><td>Not supported</td><td>ELF sandbox with hardware-enforced isolation</td></tr>
<tr><td>Retail price (2026)</td><td>$50</td><td>$50</td></tr>
</tbody>
</table>
</div>
<p>The chip in the Cardputer is the same chip in both columns. The difference is what the operating system asked of it. Architecture was spent instead of memory — the SPI Bus Treaty for shared peripheral arbitration, lazy app-state allocation for memory headroom, WiFi mode-locking for radio mutual exclusion, the ELF sandbox for runtime application safety. Architecture written by hand, in C, against hardware primitives directly.</p>
<p>Pisces Moon's specialization is the source of its capability. The reference firmware ecosystem optimized for general-purpose flexibility at the cost of efficiency. Pisces Moon spends architecture on specialization — Treaty mutex for one specific bus, mode-locking for one specific radio, lazy init for one specific boot path — that gives radio-handheld capability at the cost of being unable to run unrelated workloads. Both are valid optimizations. They reach different ceilings on the same chip.</p>
</section>
<!-- III. TARGETS -->
<section class="s" id="targets">
<div class="s-header"><div class="s-num">III.</div><h2 class="s-title">Three Deployment Targets</h2></div>
<p>Pisces Moon OS v1.2.0 ships on three Tier 1 ESP32-S3 devices spanning the entire memory tier of the chip class. The same operating system, the same Treaty, the same Ghost Engine architecture, the same application contract — across all three.</p>
<div class="table-wrap">
<table>
<thead><tr><th>Device</th><th>Variant</th><th>PSRAM</th><th>Display</th><th>Radio Stack</th><th>Apps</th></tr></thead>
<tbody>
<tr><td>T-Deck Plus</td><td>ESP32-S3 (8M)</td><td>8 MB</td><td>ST7789 320×240</td><td>WiFi, BLE, SX1262 LoRa, ATGM336H GPS</td><td>49</td></tr>
<tr><td>T-LoRa Pager</td><td>ESP32-S3 (8M)</td><td>8 MB</td><td>ST7796U 480×222</td><td>WiFi, BLE, SX1262 LoRa, MIA-M10Q GPS, TCA8418 keyboard, DRV2605 haptic, XL9555 expander</td><td>52</td></tr>
<tr><td>Cardputer ADV</td><td>ESP32-S3FN8</td><td><strong>None</strong></td><td>ST7789 240×135</td><td>WiFi, NimBLE, AT6668 multi-constellation GPS; Cap LoRa-1262 adds SX1262 +27dBm</td><td>47</td></tr>
</tbody>
</table>
</div>
<p>The same Treaty mutex protects the SPI bus on all three. The same Ghost Engine model — Core 0 owns radios, never stops, releases the foreground to Core 1 — runs on all three. The same ELF sandbox enforces runtime isolation on all three. The user-facing application contract is identical. The hardware differences are absorbed in the architectural patterns documented below.</p>
<p>For full hardware comparison, including peripheral pin maps and radio-specific configuration notes, see the <a href="device-architecture.html">device architecture reference</a>.</p>
</section>
<!-- IV. EIGHT PATTERNS -->
<section class="s" id="patterns">
<div class="s-header"><div class="s-num">IV.</div><h2 class="s-title">Eight Architectural Patterns</h2></div>
<p>The patterns below are what the eleven engineering problems hardened into. Each is a discipline binding on first-party OS code, third-party ELF modules, and every future hardware target. The patterns generalized; the problems were how we learned them.</p>
<div class="pattern">
<div class="pattern-num">Pattern 1</div>
<div class="pattern-title">The SPI Bus Treaty</div>
<div class="pattern-text">Recursive mutex (<code>spi_mutex</code>) protecting all SD, LoRa, and display SPI traffic. Four rules: hit-and-run, no extended holds, radio-traffic mutual exclusion via shared boolean, destructive operations under Treaty discipline at boot. v1.2.0 audit: 54 take sites, 56 give sites verified across 12 files. The Treaty is the public contract every component and every ELF module must obey. Published as a standalone whitepaper at <a href="spi-bus-treaty.html">spi-bus-treaty.html</a>.</div>
</div>
<div class="pattern">
<div class="pattern-num">Pattern 2</div>
<div class="pattern-title">The Ghost Engine Task Model</div>
<div class="pattern-text">Core 0 owns the radios and runs the persistent background intelligence collection process. Core 1 owns the foreground application and the user interface. Ghost Engine task is FreeRTOS priority 7. ELF tasks are priority 5. Core 0 never stops. Core 1 freely changes state without endangering background collection. The model holds across all three deployment targets without modification.</div>
</div>
<div class="pattern pattern-hero">
<div class="pattern-num">Pattern 3 — The Turning Point</div>
<div class="pattern-title">Lazy App-State Allocation</div>
<div class="pattern-text">The moment the project stopped treating the chip as a microcontroller and started treating it as a computer that happened to be small. Every always-on app buffer was moved out of static memory and into app-lifetime allocations. The OS no longer reserves RAM for dormant apps. <strong>Result on the Cardputer: 81 KB of static memory returned to the heap before the user did anything.</strong> Static footprint 190 KB → 109 KB. Free heap at task-spawn 97 KB → 219 KB. The constraint was never the hardware. The constraint was an architectural assumption inherited from single-purpose firmware. <strong>Discipline:</strong> if an app's state is not in use, it does not belong in static memory.</div>
</div>
<div class="pattern">
<div class="pattern-num">Pattern 4</div>
<div class="pattern-title">WiFi Mode-Locking with Hard Teardown</div>
<div class="pattern-text">WiFi CLIENT mode (Gemini AI client) and SCANNER mode (Ghost Engine wardrive) are mutually exclusive at the OS level. Mode transitions perform full <code>esp_wifi_stop()</code> + <code>esp_wifi_deinit()</code> teardown before re-init in the new mode — hardware-honest arbitration, not software flag arbitration. The pattern is required on the no-PSRAM Cardputer ADV; on PSRAM-equipped targets it costs nothing and improves stability.</div>
</div>
<div class="pattern">
<div class="pattern-num">Pattern 5</div>
<div class="pattern-title">Lazy Boot Initialization</div>
<div class="pattern-text">SD mount, radio init, and peripheral configuration deferred out of the boot sequence into background FreeRTOS tasks that run after all other peripherals have completed init. Apps poll readiness flags with timeout before accessing the resource. Required on the T-LoRa Pager (where the boot sequence leaves SPI in a state SD CMD0 cannot complete); now the recommended pattern for any new ESP32-S3 hardware target.</div>
</div>
<div class="pattern">
<div class="pattern-num">Pattern 6</div>
<div class="pattern-title">Runtime Radio Tuning</div>
<div class="pattern-text">When build-flag tuning fails — because the Arduino-ESP32 stack ships with precompiled <code>libbt.a</code> that cannot be reconfigured at compile time — radio parameters are tuned at runtime via direct register writes and ESP-IDF API calls. BLE scan window/interval, WiFi PHY mode, LoRa coding rate, GPS baud rate. The pattern is required when the surface API doesn't expose what the silicon supports.</div>
</div>
<div class="pattern">
<div class="pattern-num">Pattern 7</div>
<div class="pattern-title">Three-Layer ELF Sandbox</div>
<div class="pattern-text">Hardware-enforced isolation for runtime-loadable ELF modules on a non-MMU SoC. Layer 1: custom Xtensa exception handler intercepts PMS violations before the ESP-IDF panic handler — kills the offending ELF task, returns to launcher, Ghost Engine never pauses. Layer 2: direct PMS register writes mark OS SRAM read-only during ELF execution. Layer 3: ELF runs in a dedicated FreeRTOS task at priority 5 with semaphore-based completion and configurable timeout. Buggy-resistant, not adversarial-proof. Honest limitation: PMS write-protects OS SRAM but cannot prevent an ELF from reading arbitrary addresses.</div>
</div>
<div class="pattern">
<div class="pattern-num">Pattern 8</div>
<div class="pattern-title">Three-Tier Memory Architecture from a Single Codebase</div>
<div class="pattern-text">The same source tree compiles to three memory configurations: 8 MB PSRAM (T-Deck Plus, T-LoRa Pager), 320 KB SRAM only (Cardputer ADV), and 32 MB HEX PSRAM (ESP32-P4, alpha). Memory-tier-specific behavior is gated behind <code>#ifdef DEVICE_*</code> defines that route allocations, set buffer sizes, and select initialization paths. The application contract is identical across tiers. The OS knows which tier it's running on; the apps do not need to.</div>
</div>
</section>
<!-- V. ELEVEN PROBLEMS — SUMMARY -->
<section class="s" id="problems">
<div class="s-header"><div class="s-num">V.</div><h2 class="s-title">Eleven Engineering Problems — Summary</h2></div>
<p>The eleven problems are documented in full detail in the <a href="sovereignty.html#problems">sovereignty white paper</a>. The summary below maps each problem to the architectural pattern it produced.</p>
<div class="table-wrap">
<table>
<thead><tr><th>#</th><th>Problem</th><th>Target</th><th>Pattern</th></tr></thead>
<tbody>
<tr><td>1</td><td>SPI bus conflict (SD vs LoRa)</td><td>T-Deck Plus</td><td>SPI Bus Treaty</td></tr>
<tr><td>2</td><td>Memory exhaustion under simultaneous workloads</td><td>T-Deck Plus</td><td>PSRAM heap redirect</td></tr>
<tr><td>3</td><td>Dual-core SD synchronization corruption</td><td>T-Deck Plus</td><td>SPI Bus Treaty + radio flag</td></tr>
<tr><td>4</td><td>Dense RF environment instability</td><td>T-Deck Plus</td><td>Buffer sizing + drain loops</td></tr>
<tr><td>5</td><td>Security architecture under Treaty constraints</td><td>T-Deck Plus</td><td>Sector-overwrite Nuke</td></tr>
<tr><td>6</td><td>GPS module variation across batches</td><td>T-Deck Plus</td><td>Baud auto-detection</td></tr>
<tr><td>7</td><td>GPIO 21 dual-function collision</td><td>T-LoRa Pager port</td><td>Conditional compilation</td></tr>
<tr><td>8</td><td>SPI bus state corruption at boot</td><td>T-LoRa Pager port</td><td>Lazy boot init + cold SPI restart</td></tr>
<tr><td>9</td><td>Ghost Engine silent failure (phantom file)</td><td>T-LoRa Pager port</td><td>Lazy session-file creation</td></tr>
<tr><td>10</td><td>ELF execution without HW isolation</td><td>Platform-wide</td><td>Three-layer PMS sandbox</td></tr>
<tr><td>11</td><td>Concurrent multi-radio on no-PSRAM S3</td><td>Cardputer ADV</td><td>Lazy app-state + WiFi mode-locking + PSRAM flag isolation</td></tr>
</tbody>
</table>
</div>
<div class="callout callout-green">
<div class="c-label">The Cardputer Result — Why Problem 11 Is Different</div>
<p>Problems 1 through 10 were engineering work on hardware with 8 MB of PSRAM. They prove the operating system works. <strong>Problem 11 was building the same operating system on hardware with 1/25th of that memory.</strong> It proves the architecture works.</p>
<p>The Cardputer ADV ships with 320 KB of internal SRAM and no external memory of any kind. The ESP32-S3FN8 variant simply does not include PSRAM. When the v1.2.0 port began, the honest read of the heap measurements at the moment the wardrive task spawned — 97 KB free, with WiFi requiring 54 KB and NimBLE requiring 48 KB — was that concurrent multi-radio operation on this hardware was impossible. The industry's expectation for a no-PSRAM ESP32-S3 is single-purpose firmware. The chip is sold for that workload.</p>
<p>Three architectural changes — lazy app-state allocation, WiFi mode-locking with hard teardown, and PlatformIO PSRAM flag isolation — reclaimed 81 KB of static memory before the user did anything, established hardware-honest WiFi mode arbitration, and removed false PSRAM expectations from the allocator. The result: <strong>219 KB free heap after WiFi STA init. 174 KB after NimBLE observer init. 125 KB free during active wardrive scanning with 24 BLE devices, 14 WiFi networks, and GPS lock at 27 satellites.</strong> Four concurrent radios. Real-time SD logging. Persistent multi-app state. 47 applications. On a chip with 320 KB total.</p>
<p><strong>Bench validation, May 20, 2026:</strong> Mesh Messenger send/receive confirmed between T-Deck Plus and Cardputer ADV with Cap LoRa-1262 on the LongFast channel, concurrent with active wardrive logging on both devices and SD transcripts written to <code>/mesh_logs/messages.csv</code>. The Mesh Messenger application, the LoRa protocol stack, and the SPI Bus Treaty discipline held across the 8 MB PSRAM and no-PSRAM ends of the chip tier simultaneously.</p>
<p>Eight patterns generalized from the PSRAM-equipped origin devices down to the no-PSRAM extreme of the same chip class, with no compromise on the application catalog, the Bridge protocol, or the Ghost Engine invariant. The Cardputer running Pisces Moon OS is the proof that the methodology generalizes. It is also, to the best of our knowledge, the most capable multi-radio handheld operating system shipping on a no-PSRAM microcontroller in the current market.</p>
</div>
</section>
<!-- VI. METHODOLOGY -->
<section class="s" id="methodology">
<div class="s-header"><div class="s-num">VI.</div><h2 class="s-title">The Methodology</h2></div>
<p>The eleven problems share a structure. Each involved a behavior the hardware permits but the documentation does not constrain. Each surfaced under conditions — sustained concurrency, dense RF, hardware-variant edge cases, no-PSRAM extremes — that prior projects on this hardware had not produced. Each was solved by writing down what the unconstrained behavior must become, and enforcing it as a contract.</p>
<p>Three steps:</p>
<ol>
<li><strong>Name the constraint.</strong> The hardware permits behavior X. The system requires behavior Y. The gap is named so it can be referenced in code, reviewed in commits, and enforced at module boundaries.</li>
<li><strong>Document the protocol.</strong> The constraint is written down as a finite set of rules every component must obey. The Treaty has four rules. WiFi mode-locking has three. Lazy app-state has one.</li>
<li><strong>Make it a platform contract.</strong> The rules are not best practice — they are obligations binding on first-party OS code, third-party ELF modules, and any future hardware target. Violation produces immediate crashes or test failures.</li>
</ol>
<p>The SPI Bus Treaty is one expression. The UART Peripheral Map (ESP32-P4) is another. Lazy app-state allocation (Cardputer ADV) is a third. Three protocols, three hardware contexts, one methodology. The protocols are deliverables. The methodology is the contribution.</p>
</section>
<!-- VII. WHAT'S NEXT -->
<section class="s" id="next">
<div class="s-header"><div class="s-num">VII.</div><h2 class="s-title">What's Next</h2></div>
<p><strong>ESP32-P4 (alpha).</strong> First boot May 13, 2026. RISC-V dual HP cores at 360MHz, LP Sentinel Core at 40MHz, 32MB HEX PSRAM, MIPI-DSI display, ESP32-C6 radio coprocessor via SDIO. The Ghost Engine moves to dedicated silicon. The UART Peripheral Map replaces the SPI Bus Treaty as the P4 shared-resource protocol. The methodology generalizes; the specific protocol changes to match the hardware. 57 apps registered. Launcher rendering. Touch navigation operational. Pisces Moon P4 v1.2.0-alpha.</p>
<p><strong>Heltec V4 (near-term).</strong> Heltec ESP32 LoRa V4 with touch screen case — ESP32-S3R2, 2 MB PSRAM, 16 MB flash, SX1262 +27dBm, multi-constellation GPS, 2800mAh battery, solar charging support. A stationary deployment variant; documentation forthcoming after firmware validation completes.</p>
<p><strong>Honest v1.2.0 nuke limitation.</strong> A v1.2.0 audit identified that the nuke's hardcoded target list in <code>security_config.h</code> does not match the wardrive's actual session-numbered output paths. v1.2.0 nuke covers Ghost Partition index files; wardrive CSVs survive. The right shape for the fix — dynamic discovery of sensitive files at SD root and under known directories rather than maintaining a hardcoded list — is identified; research on the cleanest implementation is ongoing.</p>
<p><strong>Honest v1.2.0 security limitations.</strong> v1.2.0 nuke, against the files it currently targets, defeats software file-recovery tools (PhotoRec, Recuva, TestDisk) — no sector structure remains to reconstruct from the targeted files. It does not defeat chip-off NAND forensics due to SD controller wear-leveling: an overwritten logical sector may leave its physical NAND block intact but unmapped. Additionally, the PIN compiled into <code>firmware.bin</code> is extractable via <code>esptool.py read_flash</code> on devices without Secure Boot v2 + Flash Encryption enabled. The architectural answer to both gaps points toward an encrypted Ghost Partition with key destruction (making data irrecoverable regardless of wear-leveling) and Secure Boot v2 + Flash Encryption for production deployments. Both are research-ongoing and will land when verified end-to-end, not on a fixed release timeline. A full MFA unlock-key flow is currently deferred in v1.2.0 source.</p>
<p><strong>Tier 2 deployment record.</strong> The Linux distribution (Pisces Moon Linux), Android APK, Luckfox Pico 86 Panel, and cross-platform Trojan Horse application runtime have their own engineering record. They will be documented separately when the work to consolidate them reaches the same level of formal architectural completeness as the ESP32-S3 work documented here.</p>
</section>
<!-- CLOSING -->
<div class="closing">
<p class="closing-quote">“This is what the chip is, when the operating system is real. The chip is the hero. The operating system is the proof.”</p>
<p><strong>Pisces Moon OS</strong> — Engineering Record v1.2.0 — May 19, 2026</p>
<p>Eric Becker · <a href="https://fluidfortune.com">Fluid Fortune</a> · <a href="mailto:forge@fluidfortune.com">forge@fluidfortune.com</a></p>
<p>Companion documents: <a href="sovereignty.html">white paper</a> · <a href="spi-bus-treaty.html">SPI Bus Treaty</a> · <a href="device-architecture.html">device architecture</a></p>
<p>Source: <a href="https://github.com/FluidFortune/pisces-moon-os">github.com/FluidFortune/pisces-moon-os</a></p>
</div>
</main>
</div>
<footer class="site-footer">
<a href="https://fluidfortune.com">Main Site</a> ·
<a href="pisces-moon.html">Pisces Moon OS</a> ·
<a href="sovereignty.html">White Paper</a> ·
<a href="https://github.com/FluidFortune">GitHub</a>
</footer>
</body>
</html>