@wenathlan/saddle 2.0.167 → 2.0.170
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +36 -16
- package/README.md +1 -1
- package/docker.config +1 -1
- package/docs/architecture.md +4 -4
- package/docs/e2ughengine.md +4 -4
- package/modalities.ts +99 -22
- package/package.json +55 -56
- package/vmcore.ts +581 -0
- package/workloadlaw.ts +337 -38
package/Dockerfile
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# saddle 2.0.
|
|
1
|
+
# saddle 2.0.170 — THE ENGINE CONTAINER FILE
|
|
2
2
|
#
|
|
3
3
|
# THE FAMILY CONTAINER DOCTRINE, THE SADDLE SHAPE: one versioned container
|
|
4
4
|
# per engine, built like the site homes (argan, cadria) build theirs — a
|
|
@@ -158,7 +158,7 @@ ARG NODE_BASE_DIGEST=5adad64f9a1fca2d51972caa65983634c8a774eb300d72b20f7f2a0f603
|
|
|
158
158
|
# ===== stage: solbuild — the locked npm tree and the console spa =====
|
|
159
159
|
FROM --platform=$BUILDPLATFORM ${NODE_BASE_TAG}@sha256:${NODE_BASE_DIGEST} AS solbuild
|
|
160
160
|
|
|
161
|
-
ARG SADDLE_VERSION=2.0.
|
|
161
|
+
ARG SADDLE_VERSION=2.0.170
|
|
162
162
|
|
|
163
163
|
WORKDIR /app
|
|
164
164
|
|
|
@@ -172,6 +172,12 @@ COPY saddle/ .
|
|
|
172
172
|
# so the vault sources ride the context beside the saddle and land at
|
|
173
173
|
# /vault where the import resolves (the family context fix).
|
|
174
174
|
COPY vault/ /vault
|
|
175
|
+
# the routerbase sibling of the family law: saddle/routerbase.ts
|
|
176
|
+
# re-exports the family routerBase from ../devthink/routerbase.ts, so
|
|
177
|
+
# the devthink sources land at /devthink where the sol build resolves
|
|
178
|
+
# the re-export (sources only - the same never-installed law the vault
|
|
179
|
+
# sibling above rides, the family context fix the lanes carry).
|
|
180
|
+
COPY devthink/ /devthink
|
|
175
181
|
RUN npm run web:build:pages \
|
|
176
182
|
# the theme build emits the hashed SPA bundles straight at the app
|
|
177
183
|
# root (the family static-first vite contract): stage them into a
|
|
@@ -186,7 +192,7 @@ RUN npm run web:build:pages \
|
|
|
186
192
|
# ===== stage: base — the hardened runtime floor every profile shares =====
|
|
187
193
|
FROM ${NODE_BASE_TAG}@sha256:${NODE_BASE_DIGEST} AS base
|
|
188
194
|
|
|
189
|
-
ARG SADDLE_VERSION=2.0.
|
|
195
|
+
ARG SADDLE_VERSION=2.0.170
|
|
190
196
|
# the revision stamp the devthink container carries (DEVTHINK_REVISION
|
|
191
197
|
# there): the publish legs pass the release sha at build time and the
|
|
192
198
|
# revision label below declares the default-unknown local shape.
|
|
@@ -255,6 +261,20 @@ RUN case "${TARGETARCH:-}" in \
|
|
|
255
261
|
esac
|
|
256
262
|
|
|
257
263
|
COPY --from=solbuild /app/package.json /app/package-lock.json ./
|
|
264
|
+
# the both-blocks grammar heal (the saddle container law): the family
|
|
265
|
+
# manifest carries the same seats inside dependencies and
|
|
266
|
+
# devDependencies, and every npm tested (11.19.1 and 12.0.2) answers
|
|
267
|
+
# that duplicate seat by planting dev:true over the whole lock tree -
|
|
268
|
+
# so a plain `npm ci --omit=dev` installs nothing and the runtime stage
|
|
269
|
+
# dies at the cleanup walk with no node_modules to sweep. The derived
|
|
270
|
+
# prod-only manifest (the dependencies block alone, byte-identical
|
|
271
|
+
# specs) restores the honest production install: the lock the
|
|
272
|
+
# foundry/lockprod.ts heal stamped walks beside it and the --omit=dev
|
|
273
|
+
# lane lands the full production closure (the 1372-package install the
|
|
274
|
+
# local verification measured). Nothing is removed - the dev seats stay
|
|
275
|
+
# in the lock for the full-install lanes, only the runtime's own view
|
|
276
|
+
# of the manifest narrows.
|
|
277
|
+
RUN node -e "const fs=require('node:fs');const m=JSON.parse(fs.readFileSync('package.json','utf8'));delete m.devDependencies;fs.writeFileSync('package.json',JSON.stringify(m,null,2)+'\n')"
|
|
258
278
|
RUN apt-get update \
|
|
259
279
|
&& apt-get upgrade -y \
|
|
260
280
|
&& rm -rf /var/lib/apt/lists/* \
|
|
@@ -489,7 +509,7 @@ LABEL org.opencontainers.image.title="saddle (the android os-distribution lane)"
|
|
|
489
509
|
# docker build --target osv -t saddle:2.0.165-v .
|
|
490
510
|
# docker build --target oswindows -t saddle:2.0.165-windows .
|
|
491
511
|
FROM scratch AS osgrapheneos
|
|
492
|
-
ARG SADDLE_VERSION=2.0.
|
|
512
|
+
ARG SADDLE_VERSION=2.0.170
|
|
493
513
|
ARG SADDLE_OS_PROFILE="grapheneos"
|
|
494
514
|
ENV SADDLE_OS_PROFILE=grapheneos
|
|
495
515
|
LABEL org.opencontainers.image.title="saddle (the grapheneos os-distribution catalog lane)" \
|
|
@@ -500,7 +520,7 @@ LABEL org.opencontainers.image.title="saddle (the grapheneos os-distribution cat
|
|
|
500
520
|
COPY osprofiles/grapheneos.json /saddle/osprofile.json
|
|
501
521
|
|
|
502
522
|
FROM scratch AS osmaruos
|
|
503
|
-
ARG SADDLE_VERSION=2.0.
|
|
523
|
+
ARG SADDLE_VERSION=2.0.170
|
|
504
524
|
ARG SADDLE_OS_PROFILE="maruos"
|
|
505
525
|
ENV SADDLE_OS_PROFILE=maruos
|
|
506
526
|
LABEL org.opencontainers.image.title="saddle (the maru os os-distribution catalog lane)" \
|
|
@@ -511,7 +531,7 @@ LABEL org.opencontainers.image.title="saddle (the maru os os-distribution catalo
|
|
|
511
531
|
COPY osprofiles/maruos.json /saddle/osprofile.json
|
|
512
532
|
|
|
513
533
|
FROM scratch AS osv
|
|
514
|
-
ARG SADDLE_VERSION=2.0.
|
|
534
|
+
ARG SADDLE_VERSION=2.0.170
|
|
515
535
|
ARG SADDLE_OS_PROFILE="v"
|
|
516
536
|
ENV SADDLE_OS_PROFILE=v
|
|
517
537
|
LABEL org.opencontainers.image.title="saddle (the v os-distribution catalog lane)" \
|
|
@@ -522,7 +542,7 @@ LABEL org.opencontainers.image.title="saddle (the v os-distribution catalog lane
|
|
|
522
542
|
COPY osprofiles/v.json /saddle/osprofile.json
|
|
523
543
|
|
|
524
544
|
FROM scratch AS oswindows
|
|
525
|
-
ARG SADDLE_VERSION=2.0.
|
|
545
|
+
ARG SADDLE_VERSION=2.0.170
|
|
526
546
|
ARG SADDLE_OS_PROFILE="windows"
|
|
527
547
|
ENV SADDLE_OS_PROFILE=windows
|
|
528
548
|
LABEL org.opencontainers.image.title="saddle (the windows os-distribution catalog lane)" \
|
|
@@ -533,7 +553,7 @@ LABEL org.opencontainers.image.title="saddle (the windows os-distribution catalo
|
|
|
533
553
|
COPY osprofiles/windows.json /saddle/osprofile.json
|
|
534
554
|
|
|
535
555
|
FROM scratch AS ospostmarketos
|
|
536
|
-
ARG SADDLE_VERSION=2.0.
|
|
556
|
+
ARG SADDLE_VERSION=2.0.170
|
|
537
557
|
ARG SADDLE_OS_PROFILE="postmarketos"
|
|
538
558
|
ENV SADDLE_OS_PROFILE=postmarketos
|
|
539
559
|
LABEL org.opencontainers.image.title="saddle (the postmarketos os-distribution catalog lane)" \
|
|
@@ -544,7 +564,7 @@ LABEL org.opencontainers.image.title="saddle (the postmarketos os-distribution c
|
|
|
544
564
|
COPY osprofiles/postmarketos.json /saddle/osprofile.json
|
|
545
565
|
|
|
546
566
|
FROM scratch AS oslineageos
|
|
547
|
-
ARG SADDLE_VERSION=2.0.
|
|
567
|
+
ARG SADDLE_VERSION=2.0.170
|
|
548
568
|
ARG SADDLE_OS_PROFILE="lineageos"
|
|
549
569
|
ENV SADDLE_OS_PROFILE=lineageos
|
|
550
570
|
LABEL org.opencontainers.image.title="saddle (the lineageos os-distribution catalog lane)" \
|
|
@@ -555,7 +575,7 @@ LABEL org.opencontainers.image.title="saddle (the lineageos os-distribution cata
|
|
|
555
575
|
COPY osprofiles/lineageos.json /saddle/osprofile.json
|
|
556
576
|
|
|
557
577
|
FROM scratch AS oscalyxos
|
|
558
|
-
ARG SADDLE_VERSION=2.0.
|
|
578
|
+
ARG SADDLE_VERSION=2.0.170
|
|
559
579
|
ARG SADDLE_OS_PROFILE="calyxos"
|
|
560
580
|
ENV SADDLE_OS_PROFILE=calyxos
|
|
561
581
|
LABEL org.opencontainers.image.title="saddle (the calyxos os-distribution catalog lane)" \
|
|
@@ -566,7 +586,7 @@ LABEL org.opencontainers.image.title="saddle (the calyxos os-distribution catalo
|
|
|
566
586
|
COPY osprofiles/calyxos.json /saddle/osprofile.json
|
|
567
587
|
|
|
568
588
|
FROM scratch AS osarchlinux
|
|
569
|
-
ARG SADDLE_VERSION=2.0.
|
|
589
|
+
ARG SADDLE_VERSION=2.0.170
|
|
570
590
|
ARG SADDLE_OS_PROFILE="archlinux"
|
|
571
591
|
ENV SADDLE_OS_PROFILE=archlinux
|
|
572
592
|
LABEL org.opencontainers.image.title="saddle (the archlinux os-distribution catalog lane)" \
|
|
@@ -577,7 +597,7 @@ LABEL org.opencontainers.image.title="saddle (the archlinux os-distribution cata
|
|
|
577
597
|
COPY osprofiles/archlinux.json /saddle/osprofile.json
|
|
578
598
|
|
|
579
599
|
FROM scratch AS osalpine
|
|
580
|
-
ARG SADDLE_VERSION=2.0.
|
|
600
|
+
ARG SADDLE_VERSION=2.0.170
|
|
581
601
|
ARG SADDLE_OS_PROFILE="alpine"
|
|
582
602
|
ENV SADDLE_OS_PROFILE=alpine
|
|
583
603
|
LABEL org.opencontainers.image.title="saddle (the alpine os-distribution catalog lane)" \
|
|
@@ -588,7 +608,7 @@ LABEL org.opencontainers.image.title="saddle (the alpine os-distribution catalog
|
|
|
588
608
|
COPY osprofiles/alpine.json /saddle/osprofile.json
|
|
589
609
|
|
|
590
610
|
FROM scratch AS osdebian
|
|
591
|
-
ARG SADDLE_VERSION=2.0.
|
|
611
|
+
ARG SADDLE_VERSION=2.0.170
|
|
592
612
|
ARG SADDLE_OS_PROFILE="debian"
|
|
593
613
|
ENV SADDLE_OS_PROFILE=debian
|
|
594
614
|
LABEL org.opencontainers.image.title="saddle (the debian os-distribution catalog lane)" \
|
|
@@ -599,7 +619,7 @@ LABEL org.opencontainers.image.title="saddle (the debian os-distribution catalog
|
|
|
599
619
|
COPY osprofiles/debian.json /saddle/osprofile.json
|
|
600
620
|
|
|
601
621
|
FROM scratch AS osfedora
|
|
602
|
-
ARG SADDLE_VERSION=2.0.
|
|
622
|
+
ARG SADDLE_VERSION=2.0.170
|
|
603
623
|
ARG SADDLE_OS_PROFILE="fedora"
|
|
604
624
|
ENV SADDLE_OS_PROFILE=fedora
|
|
605
625
|
LABEL org.opencontainers.image.title="saddle (the fedora os-distribution catalog lane)" \
|
|
@@ -610,7 +630,7 @@ LABEL org.opencontainers.image.title="saddle (the fedora os-distribution catalog
|
|
|
610
630
|
COPY osprofiles/fedora.json /saddle/osprofile.json
|
|
611
631
|
|
|
612
632
|
FROM scratch AS osnixos
|
|
613
|
-
ARG SADDLE_VERSION=2.0.
|
|
633
|
+
ARG SADDLE_VERSION=2.0.170
|
|
614
634
|
ARG SADDLE_OS_PROFILE="nixos"
|
|
615
635
|
ENV SADDLE_OS_PROFILE=nixos
|
|
616
636
|
LABEL org.opencontainers.image.title="saddle (the nixos os-distribution catalog lane)" \
|
|
@@ -621,7 +641,7 @@ LABEL org.opencontainers.image.title="saddle (the nixos os-distribution catalog
|
|
|
621
641
|
COPY osprofiles/nixos.json /saddle/osprofile.json
|
|
622
642
|
|
|
623
643
|
FROM scratch AS osvoid
|
|
624
|
-
ARG SADDLE_VERSION=2.0.
|
|
644
|
+
ARG SADDLE_VERSION=2.0.170
|
|
625
645
|
ARG SADDLE_OS_PROFILE="void"
|
|
626
646
|
ENV SADDLE_OS_PROFILE=void
|
|
627
647
|
LABEL org.opencontainers.image.title="saddle (the void os-distribution catalog lane)" \
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ domain modules land beside the saddle domains:
|
|
|
31
31
|
| `media.ts`, `render.ts`, `quantum.ts`, `tiers.ts` | media pipeline, GPU registry, quantum simulation, tier policy |
|
|
32
32
|
| `security.ts`, `alternatives.ts` | hardening gates and the alternative-stack catalog |
|
|
33
33
|
| `index.html`, `App.tsx`, `sol/` | the single SPA shell and the Sol theme (one tsx app with one stylesheet per theme) |
|
|
34
|
-
| `server.ts`, `sandbox.ts` | the zero-dependency self-hosted API of the 2.0.
|
|
34
|
+
| `server.ts`, `sandbox.ts` | the zero-dependency self-hosted API of the 2.0.170 grand-merge envelope (`node server.ts`; the api answers its version at `/api/v1/health`) and the browser-pure engine port |
|
|
35
35
|
| `vercel.json`, `netlify.toml` | the platform deploy adapters beside the surface they publish (the caddy ghost stays out of the tree) |
|
|
36
36
|
| `specs/*` package exports | processors, gpus, cores, boards and the qemu/mttg/passage/docker envelopes |
|
|
37
37
|
|
package/docker.config
CHANGED
package/docs/architecture.md
CHANGED
|
@@ -121,9 +121,9 @@ The remaining categories of the old file were already domain-owned: kernel featu
|
|
|
121
121
|
|
|
122
122
|
## 3b. Test patterns
|
|
123
123
|
|
|
124
|
-
Tests live in the `test/` directory (one of the five allowed directories) and run
|
|
124
|
+
Tests live in the `test/` directory (one of the five allowed directories) and run on vitest: `vitest run` reads `test/*.test.ts` (153 tests across eleven files - engine, features, media, render, simulation, specs, virtualcpu, virtualgpu, virtualmemory, web, workflow), the same runner the ci.yml family suite executes through the app's `npm test`. Patterns:
|
|
125
125
|
|
|
126
|
-
-
|
|
126
|
+
- vitest (`describe`/`it`) plus `node:assert/strict`; no Jest, no node:test (vitest is the only CI runner), no install step beyond the dev tooling (the engine has zero runtime dependencies).
|
|
127
127
|
- One test file per area under test (planner and lint rules, cpuinfo/meminfo generators, MIG density validator, QEMU argv builder); assertions target public exports, never module internals.
|
|
128
128
|
- Doc-tests remain `@example` blocks in JSDoc (the planner asserts in `index.ts`), and every test stays deterministic: ports use the 30000-59999 random band or explicit ephemeral allocation, no network, no timing-dependent assertions.
|
|
129
129
|
|
|
@@ -266,7 +266,7 @@ Supporting subsystems: warm pool (prewarm/acquire/release/refill/drain, MAP_PRIV
|
|
|
266
266
|
| TypeScript | 7.0.2 (Go-native port); `strict`, `verbatimModuleSyntax`, `isolatedModules`, `erasableSyntaxOnly`, `exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`; ES2025 target with `lib ES2025+ESNext.Disposable` |
|
|
267
267
|
| Erasable modern syntax | `using`/`await using` (modellease, MetricsStore, sandboxhandle), `satisfies` (`engineversions as const satisfies Record<string,string>`), const type parameters (`validateSpec<const T>`), `#private` fields and accessors, `import.meta.filename` for CLI detection |
|
|
268
268
|
| ESM | `"type": "module"`; relative imports carry the `.ts` extension; no CommonJS `require` |
|
|
269
|
-
| Tests |
|
|
269
|
+
| Tests | vitest + `node:assert/strict` executed with `vitest run` over `test/*.test.ts`; the dedicated `test/` directory holds eleven test files (148 cases: 86 planner/generator originals, 24 workflow/simulation gates, 18 feature-audit builders, 4 media pipeline, 1 snapshot regression, 9 web edition), ci.yml runs them through the app's `npm test`; no Jest; no node:test; doc-tests as `@example` blocks (the planner asserts live in `index.ts` planner docs) |
|
|
270
270
|
| C++26 | `import std;` permitted, `std::expected` as the error channel, `std::mdspan` with the p2662r3 fallback guard, `std::print`/`std::format`, `enum class`, `[[nodiscard]]` on validate/argv/topology, RAII for every fd/socket (no exceptions in happy paths) |
|
|
271
271
|
| C | C11 with `_GNU_SOURCE`, `dlsym(RTLD_NEXT)` resolution, xorshift32 deterministic drift, constructor priority 101 |
|
|
272
272
|
| Python | 3.14 floor; stdlib only (socket, json, logging); try/except logging on every operation |
|
|
@@ -318,7 +318,7 @@ The old pins survive only inside `legacyCatalog` provenance blocks in `virtualha
|
|
|
318
318
|
|
|
319
319
|
## 15. CI graph (summary)
|
|
320
320
|
|
|
321
|
-
Five workflows gate the tree: ci.yml (lint, typecheck matrix Node 24/26, the
|
|
321
|
+
Five workflows gate the tree: ci.yml (lint, typecheck matrix Node 24/26, the vitest suite in `test/`, build, flat-structure md5 guard, JSON schema validation of the ten data files), publishghcr.yml (the combined container pipeline: per-arch validation legs on push - clinfo/vulkaninfo/glxinfo probes inside the image - and the four-arch GHCR publication with provenance+SBOM on release), release.yml (GHCR + npm provenance + level-9 zip with SHA-256), pages.yml (the merged web pipeline: module syntax gate, boot smoke on port 37810, html lint, the webapi auth/mesh suite with a throwaway `E2UGH_DB`, the zip -9 static bundle and the GitHub Pages deployment of the web tree) and security.yml (CodeQL C/C++/TS, dependency review, Dockle/Trivy SARIF, gitleaks, Scorecard, Biome security group, license allowlist). Full descriptions and pins are in `readme.md`; the workflows themselves are the executable contract.
|
|
322
322
|
|
|
323
323
|
## 16. Compliance checklist
|
|
324
324
|
|
package/docs/e2ughengine.md
CHANGED
|
@@ -220,7 +220,7 @@ The CI pipeline enforces the flat contract: one concern per file with 20-25 rela
|
|
|
220
220
|
| 42 | `docs/viability.md` | the proof, research methodology, 145-entry bibliography and roadmap appendices A-C |
|
|
221
221
|
| 43 | `docs/alternatives.md` | ten alternative sandbox families compared against the engine |
|
|
222
222
|
| 43b | `docs/optimization.md` | the build-pipeline optimization roadmap (cross-compilation, prebuilt QEMU/Mesa layers, runner strategy) for the slow multi-arch grid |
|
|
223
|
-
| 44 | `test/` |
|
|
223
|
+
| 44 | `test/` | vitest suite executed by ci.yml (`npm test`, `vitest run` over `test/*.test.ts`; 153 cases, including CI-gate replay and end-to-end simulation suites) |
|
|
224
224
|
| 45 | `web/` | the web node (v7): `index.html` terminal sandbox, `login.html`/`register.html`/`dashboard.html` auth pages, `sandbox.js` browser-pure engine port (20 commands), `localauth.js` static-edge browser accounts (login/register/dashboard keep working on github pages with no api; accounts are mirrored to IndexedDB so partial clears never lose them, the dashboard carries backup/restore keyfile buttons, and the CODEOWNERS admins iakadion + akadion are seeded automatically with the shared bootstrap password - surviving any storage reset), `server.js` self-hosted node:http API (`/api/v1` sandboxes and exec), `db.js` sqlite persistence layer, `auth.js` scrypt password hashing with cookie sessions, `mesh.js` HMAC-signed node-to-node calls, `package.json`/`Dockerfile` (image `ghcr.io/wenathlan/e2ugh`; node pinned by the root `.nvmrc`), `schema.prisma`/`init.sql` database definition kept flat per the two-level contract, `mime.types`, `vercel.json`/`netlify.toml` static deploy without functions, `caddyfile` self-host proxy for devthink.pro, `readme.md` web docs |
|
|
225
225
|
| 46 | `LICENSE` | full MIT text (Copyright (c) 2026 wenathlan) |
|
|
226
226
|
|
|
@@ -327,7 +327,7 @@ docker run --rm -p 37810:37810 -e E2UGH_DB=/data/e2ugh.db -v e2ughdata:/data \
|
|
|
327
327
|
|
|
328
328
|
Five workflows gate the repository, all pinned to action releases verified on 2026-08-22:
|
|
329
329
|
|
|
330
|
-
- **ci.yml** (every push and pull request) - six gates: Biome 2.5.11 lint and format; `tsc --noEmit` with TypeScript 7.0.2 on a Node 24/26 matrix; the
|
|
330
|
+
- **ci.yml** (every push and pull request) - six gates: Biome 2.5.11 lint and format; `tsc --noEmit` with TypeScript 7.0.2 on a Node 24/26 matrix; the vitest runner over the dedicated `test/` suite (153 test cases); a build gate; the flat-structure contract (flat tree, no deep nesting, no duplicated content via md5); strict JSON schema validation of every tracked data file.
|
|
331
331
|
- **hardware variants** (publishghcr.yml matrix) - one dockerfile, three curated profiles baked at build time so operators pull exactly the flavor they need: `ghcr.io/wenathlan/e2ugh:latest` (max: EPYC 9965 192c/384t, 1 TiB plan, 8x B200), `:balanced` (Threadripper PRO 9995WX 96c/192t, 512 GiB, 2x B200) and `:lite` (Ryzen 9 9950X3D 16c/32t, 128 GiB, 1x RTX 5090); every profile tag also carries semver and sha suffixes, and the runtime overlay (`VHE_TOTALRAM_GB`, `VHE_CPUS`, `VHE_GPU_PROFILE` environment variables) still lets any variant report any catalog identity up to 18 TiB at run time - the baked profile is the default identity, never a ceiling.
|
|
332
332
|
- **publishghcr.yml** (the combined container pipeline; main, tags and releases) - per-architecture validation legs (`linux/amd64` native; `linux/arm64`, `linux/ppc64le` and `linux/s390x` under QEMU user emulation) that validate the live stack inside the built image: `clinfo` must report Rusticl OpenCL 3.1 on llvmpipe, `vulkaninfo --summary` must find lavapipe Vulkan 1.4, and Xvfb + `glxinfo` must report llvmpipe OpenGL 4.6, executed with `--memory-swap=-1 --shm-size=2g`. On releases, production builds push per-arch images by digest (the max profile ships the four-arch registry surface: amd64, arm64, ppc64le, s390x) with provenance `mode=max` and SBOM attestations before `docker buildx imagetools` assembles the per-profile manifest indexes.
|
|
333
333
|
- **release.yml** (version tags and releases) - three publications: the multi-arch GHCR image, the npm package with `--provenance --access public` (zero runtime dependencies), and a maximum-compression (level 9) source zip with SHA-256 checksums.
|
|
@@ -384,7 +384,7 @@ The test contract is the Node built-in runner: no Jest, no third-party harness,
|
|
|
384
384
|
# from a checkout (Node 24+)
|
|
385
385
|
npm run typecheck # tsc --noEmit, the TypeScript 7.0.2 gate
|
|
386
386
|
npm run lint # Biome 2.5.11
|
|
387
|
-
|
|
387
|
+
npm test # the vitest suite (153 tests) - vitest run over test/*.test.ts, the form ci.yml uses
|
|
388
388
|
|
|
389
389
|
# from the published image (GHCR, linux/amd64 and linux/arm64)
|
|
390
390
|
docker run --rm --memory-swap=-1 --shm-size=2g \
|
|
@@ -424,7 +424,7 @@ The `test/` suite (Node 26.7.0 in CI, Node 24+ locally, `node:assert/strict`, 15
|
|
|
424
424
|
| SADDLE v5 / v6 (Meta TS) | 2026-08-22 wave | `src_core_orchestrator.ts` (2080 lines) and `coreorchestrator.ts` (1283 lines): RBAC, NUMA scheduler, balloon, SR-IOV, passage protocols, quotas, preemption, leader election, OTel exporter; plus `pipelinememorypassage.ts` host-aware memory planning | Unique subsystems absorbed into `orchestrator.ts` (5238 lines) and `virtualmemory.ts`; duplicated buses/state machines/metrics collapsed into one of each |
|
|
425
425
|
| Virtual Hardware Engine v5 (e2ugh) | 2026-08-22, English | The 44-file public repo generation: 9 TS modules, 11 JSONs, 4 workflows, 10 English docs with ~120 cited sources | Baseline of the v2 code tree; modules renamed and extended (hardware -> virtualcpu, memory -> virtualmemory) |
|
|
426
426
|
| e2ugh v2 | 2026-08-22+ | The merge: 57 CPUs, 19 GPUs + APUs, one event bus (51 typed topics), one 15-state lifecycle, one metrics store | Baseline of the v3 redistribution |
|
|
427
|
-
| e2ugh v3-v9 (this repo) | 2026-08-23+ | The rebrand and redistribution: github.com/wenathlan/e2ugh, package 1.2.1, `future.ts` decomposed into `scheduler.ts` and `compute.ts` (checkpoint plans into `virtualization.ts`, post-quantum into `security.ts`), a `test/`
|
|
427
|
+
| e2ugh v3-v9 (this repo) | 2026-08-23+ | The rebrand and redistribution: github.com/wenathlan/e2ugh, package 1.2.1, `future.ts` decomposed into `scheduler.ts` and `compute.ts` (checkpoint plans into `virtualization.ts`, post-quantum into `security.ts`), a `test/` vitest suite, and the corrected version ledger (kernel 7.1.9/6.18.45, edk2-stable202605, wgpu 30.x, Spin 3.6.0, containerd 2.3.4, WireGuard via kernel mainline) | Current |
|
|
428
428
|
|
|
429
429
|
Full per-generation detail, including the verification reports for each wave, is preserved in `docs/viability.md`.
|
|
430
430
|
|
package/modalities.ts
CHANGED
|
@@ -2492,7 +2492,7 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
|
|
|
2492
2492
|
slug: "runnerdeno",
|
|
2493
2493
|
lane: "runner",
|
|
2494
2494
|
isolation: "process",
|
|
2495
|
-
state: "
|
|
2495
|
+
state: "live",
|
|
2496
2496
|
drivers: ["deno"],
|
|
2497
2497
|
hardening: ["permission-map"],
|
|
2498
2498
|
boot: "hot",
|
|
@@ -2508,10 +2508,18 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
|
|
|
2508
2508
|
num: 19,
|
|
2509
2509
|
lane: "runner",
|
|
2510
2510
|
binary: "deno",
|
|
2511
|
-
// the payload rides the staged program file —
|
|
2512
|
-
// the sandbox alone, the
|
|
2511
|
+
// the real deno runner: the payload rides the staged program file —
|
|
2512
|
+
// the read permission maps the sandbox alone, the module cache rides
|
|
2513
|
+
// the sandbox tree (DENO_DIR never touches the host home — the same
|
|
2514
|
+
// seat the edge lane carries), the stdin dash never rides (no pipe
|
|
2515
|
+
// is written). the runtime detection rides the spawner's own absence
|
|
2516
|
+
// grammar — the same probehostbinary seat the edge lane table
|
|
2517
|
+
// carries — and a host without the deno binary answers the honest
|
|
2518
|
+
// coded absence, never a faked run (the seat never fakes a runtime).
|
|
2513
2519
|
argv: ({ file }) => ["deno", "run", "--allow-read=/sandbox", file],
|
|
2520
|
+
env: { DENO_DIR: "/sandbox/denodir" },
|
|
2514
2521
|
hardening: ["permission-map"],
|
|
2522
|
+
probe: "the host must carry the deno runtime (the runner-deno seat the owner's law 268 charges)",
|
|
2515
2523
|
}),
|
|
2516
2524
|
},
|
|
2517
2525
|
{
|
|
@@ -4191,7 +4199,7 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
|
|
|
4191
4199
|
slug: "storagesqlite",
|
|
4192
4200
|
lane: "sandbox",
|
|
4193
4201
|
isolation: "process",
|
|
4194
|
-
state: "
|
|
4202
|
+
state: "live",
|
|
4195
4203
|
drivers: ["sqlite"],
|
|
4196
4204
|
hardening: ["file-quota"],
|
|
4197
4205
|
boot: "hot",
|
|
@@ -4207,27 +4215,60 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
|
|
|
4207
4215
|
num: 72,
|
|
4208
4216
|
lane: "sandbox",
|
|
4209
4217
|
operate: async (request) => {
|
|
4218
|
+
// the real vault roundtrip: the node:sqlite runtime the engine host
|
|
4219
|
+
// carries — without it the seat answers the honest coded absence, and
|
|
4220
|
+
// with it one full roundtrip (create, insert, select, drop) on a
|
|
4221
|
+
// private in-memory table, the readback compared against the payload
|
|
4222
|
+
// character for character (the seat never fakes a database and never
|
|
4223
|
+
// opens a file — the store rides :memory: alone, the caller values
|
|
4224
|
+
// ride parameterized statements, only the seat's own generated table
|
|
4225
|
+
// name rides the statement text).
|
|
4226
|
+
let sqlite: typeof import("node:sqlite");
|
|
4210
4227
|
try {
|
|
4211
|
-
|
|
4212
|
-
const database = new sqlite.DatabaseSync(":memory:");
|
|
4213
|
-
try {
|
|
4214
|
-
database.exec("CREATE TABLE sandbox_artifacts (id INTEGER PRIMARY KEY, payload TEXT)");
|
|
4215
|
-
const statement = database.prepare("INSERT INTO sandbox_artifacts (payload) VALUES (?)");
|
|
4216
|
-
statement.run(request.code.slice(0, 1024));
|
|
4217
|
-
const rows = database.prepare("SELECT id, payload FROM sandbox_artifacts").all();
|
|
4218
|
-
return {
|
|
4219
|
-
stdout: `sqlite vault: ${rows.length} row(s) answered by the in-memory store (node:sqlite, :memory:)`,
|
|
4220
|
-
artifact: { rows: rows.length, engine: "node:sqlite" },
|
|
4221
|
-
};
|
|
4222
|
-
} finally {
|
|
4223
|
-
database.close();
|
|
4224
|
-
}
|
|
4228
|
+
sqlite = (await import("node:sqlite")) as typeof import("node:sqlite");
|
|
4225
4229
|
} catch (error) {
|
|
4226
4230
|
throw Object.assign(
|
|
4227
4231
|
new Error(`the sqlite runtime is absent from this host: ${error instanceof Error ? error.message : String(error)}`),
|
|
4228
4232
|
{ code: "HOST_RUNTIME_ABSENT" },
|
|
4229
4233
|
);
|
|
4230
4234
|
}
|
|
4235
|
+
const table = `saddle_sqlite_${Date.now().toString(36)}${Math.floor(Math.random() * 1679616).toString(36)}`;
|
|
4236
|
+
const payload = request.code;
|
|
4237
|
+
let readback = "";
|
|
4238
|
+
const database = new sqlite.DatabaseSync(":memory:");
|
|
4239
|
+
try {
|
|
4240
|
+
database.exec(`CREATE TABLE ${table} (k TEXT PRIMARY KEY, v TEXT)`);
|
|
4241
|
+
database.prepare(`INSERT INTO ${table} (k, v) VALUES (?, ?)`).run("saddle-payload", payload);
|
|
4242
|
+
readback = String(
|
|
4243
|
+
(database.prepare(`SELECT v FROM ${table} WHERE k = ?`).get("saddle-payload") as { v?: unknown } | undefined)?.v ?? "",
|
|
4244
|
+
);
|
|
4245
|
+
} catch (error) {
|
|
4246
|
+
throw Object.assign(
|
|
4247
|
+
new Error(`the sqlite vault refused the roundtrip: ${error instanceof Error ? error.message : String(error)}`),
|
|
4248
|
+
{ code: "SQLITE_ROUNDTRIP_FAILED" },
|
|
4249
|
+
);
|
|
4250
|
+
} finally {
|
|
4251
|
+
try {
|
|
4252
|
+
database.exec(`DROP TABLE IF EXISTS ${table}`);
|
|
4253
|
+
} catch {
|
|
4254
|
+
/* the roundtrip already answered; the drop is best effort */
|
|
4255
|
+
}
|
|
4256
|
+
try {
|
|
4257
|
+
database.close();
|
|
4258
|
+
} catch {
|
|
4259
|
+
/* the close is best effort */
|
|
4260
|
+
}
|
|
4261
|
+
}
|
|
4262
|
+
if (readback !== payload) {
|
|
4263
|
+
throw Object.assign(
|
|
4264
|
+
new Error(`the sqlite roundtrip answered ${readback.length} characters for ${payload.length} written`),
|
|
4265
|
+
{ code: "SQLITE_ROUNDTRIP_FAILED" },
|
|
4266
|
+
);
|
|
4267
|
+
}
|
|
4268
|
+
return {
|
|
4269
|
+
stdout: `sqlite vault: ${payload.length} characters roundtripped through the node:sqlite in-memory store`,
|
|
4270
|
+
artifact: { rows: 1, engine: "node:sqlite", roundtrip: true, store: ":memory:" },
|
|
4271
|
+
};
|
|
4231
4272
|
},
|
|
4232
4273
|
}),
|
|
4233
4274
|
},
|
|
@@ -4427,7 +4468,7 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
|
|
|
4427
4468
|
slug: "networkdns",
|
|
4428
4469
|
lane: "sandbox",
|
|
4429
4470
|
isolation: "process",
|
|
4430
|
-
state: "
|
|
4471
|
+
state: "live",
|
|
4431
4472
|
drivers: ["dns"],
|
|
4432
4473
|
hardening: ["resolver-allowlist"],
|
|
4433
4474
|
boot: "hot",
|
|
@@ -4443,11 +4484,47 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
|
|
|
4443
4484
|
num: 77,
|
|
4444
4485
|
lane: "sandbox",
|
|
4445
4486
|
operate: async (request) => {
|
|
4487
|
+
// the real resolution roundtrip: the node:dns resolver the engine
|
|
4488
|
+
// host carries — one lookup of the pinned well-known name
|
|
4489
|
+
// ("localhost", the name every host resolver answers; the caller
|
|
4490
|
+
// may name another, the roundtrip rides the same resolver call)
|
|
4491
|
+
// with the answered records verified as the honest result (the
|
|
4492
|
+
// non-empty answer, the address, the address family). the seat
|
|
4493
|
+
// never fakes a response and never opens a socket beyond the
|
|
4494
|
+
// resolver call — a host without a working resolver path answers
|
|
4495
|
+
// the honest coded refusal, never a canned answer (the wire
|
|
4496
|
+
// question the builddnsquery builder frames rides the artifact
|
|
4497
|
+
// beside the records the resolver actually answered — the same
|
|
4498
|
+
// grammar the sqlite vault roundtrip carries).
|
|
4499
|
+
const dns = await import("node:dns");
|
|
4446
4500
|
const inputs = (request.inputs ?? {}) as { domain?: string; qtype?: string };
|
|
4447
|
-
const
|
|
4501
|
+
const domain = inputs.domain ?? "localhost";
|
|
4502
|
+
const qtype = (inputs.qtype ?? "a").toLowerCase();
|
|
4503
|
+
const packet = builddnsquery(domain, qtype);
|
|
4504
|
+
const family = qtype === "a" ? 4 : qtype === "aaaa" ? 6 : 0;
|
|
4505
|
+
let records: import("node:dns").LookupAddress[];
|
|
4506
|
+
try {
|
|
4507
|
+
records = await dns.promises.lookup(domain, { all: true, family });
|
|
4508
|
+
} catch (error) {
|
|
4509
|
+
throw Object.assign(
|
|
4510
|
+
new Error(
|
|
4511
|
+
`the host resolver refused the ${qtype} roundtrip for ${domain}: ${error instanceof Error ? error.message : String(error)}`,
|
|
4512
|
+
),
|
|
4513
|
+
{ code: "DNS_RESOLUTION_REFUSED" },
|
|
4514
|
+
);
|
|
4515
|
+
}
|
|
4516
|
+
if (
|
|
4517
|
+
records.length === 0 ||
|
|
4518
|
+
records.some((record) => record.address.length === 0 || (record.family !== 4 && record.family !== 6))
|
|
4519
|
+
) {
|
|
4520
|
+
throw Object.assign(
|
|
4521
|
+
new Error(`the dns roundtrip answered ${records.length} records for ${domain} — the honest result never rides a malformed answer`),
|
|
4522
|
+
{ code: "DNS_ROUNDTRIP_FAILED" },
|
|
4523
|
+
);
|
|
4524
|
+
}
|
|
4448
4525
|
return {
|
|
4449
|
-
stdout: `dns:
|
|
4450
|
-
artifact: { packet, domain
|
|
4526
|
+
stdout: `dns resolver: ${domain} resolved ${records.length} records through the node:dns host resolver (the ${qtype} question, the honest roundtrip)`,
|
|
4527
|
+
artifact: { packet, domain, qtype, records, resolved: true, resolver: "node:dns" },
|
|
4451
4528
|
};
|
|
4452
4529
|
},
|
|
4453
4530
|
}),
|