@wenathlan/saddle 2.0.154 → 2.0.159
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 +167 -1334
- package/README.md +59 -60
- package/biome.jsonc +3 -3
- package/browser.ts +482 -0
- package/cli.ts +274 -0
- package/distribution.ts +731 -0
- package/docker.config +29 -8
- package/docs/{architecture.1.8.19.mmd → architecture1819.md} +6 -0
- package/docs/artifactavailability.md +2 -2
- package/docs/browser.md +18 -1
- package/docs/{containerplatforms.2.1.0.md → containerplatforms210.md} +1 -1
- package/docs/{documentmap.1.8.12.md → documentmap1812.md} +1 -1
- package/docs/extension.md +13 -2
- package/docs/features.md +5 -0
- package/docs/libraryapi.md +1 -1
- package/docs/{ninety.modalities.md → ninetymodalities.md} +87 -4
- package/docs/{planning.ninety.md → planningninety.md} +6 -6
- package/docs/{releasenotes.1.8.13.md → releasenotes1813.md} +2 -2
- package/docs/{releasenotes.1.8.14.md → releasenotes1814.md} +1 -1
- package/docs/{repo.synthesis.1.8.16.md → reposynthesis1816.md} +1 -1
- package/docs/todo.md +2 -2
- package/docs/{todo.1.8.15.md → todo1815.md} +1 -1
- package/docs/{todo.1.8.16.md → todo1816.md} +5 -5
- package/execution.ts +677 -0
- package/foundation.ts +314 -0
- package/index.ts +36 -34
- package/isolation.ts +84 -0
- package/modalityregistry.ts +189 -145
- package/modes.ts +170 -0
- package/mttg.config +1 -1
- package/orchestrator.ts +49 -15
- package/package.json +105 -89
- package/qemu.config +2 -2
- package/sandbox.ts +3279 -0
- package/scheduler.ts +1 -1
- package/server.ts +52 -0
- package/tsconfig.json +12 -13
- package/virtual.ts +7528 -0
- package/workloadlaw.ts +293 -0
- package/dist/App.d.ts +0 -5
- package/dist/App.js +0 -52
- package/dist/Sol/Sol.d.ts +0 -3
- package/dist/Sol/Sol.js +0 -46
- package/dist/Sol/agentbrowser/agentbrowser.d.ts +0 -9
- package/dist/Sol/agentbrowser/agentbrowser.js +0 -121
- package/dist/Sol/architecture/architecture.d.ts +0 -9
- package/dist/Sol/architecture/architecture.js +0 -93
- package/dist/Sol/compute/compute.d.ts +0 -9
- package/dist/Sol/compute/compute.js +0 -22
- package/dist/Sol/console/console.d.ts +0 -15
- package/dist/Sol/console/console.js +0 -292
- package/dist/Sol/dashboard/dashboard.d.ts +0 -10
- package/dist/Sol/dashboard/dashboard.js +0 -181
- package/dist/Sol/docs/docs.d.ts +0 -9
- package/dist/Sol/docs/docs.js +0 -28
- package/dist/Sol/home/home.d.ts +0 -35
- package/dist/Sol/home/home.js +0 -239
- package/dist/Sol/integrations/integrations.d.ts +0 -9
- package/dist/Sol/integrations/integrations.js +0 -83
- package/dist/Sol/intro/intro.d.ts +0 -7
- package/dist/Sol/intro/intro.js +0 -102
- package/dist/Sol/login/login.d.ts +0 -16
- package/dist/Sol/login/login.js +0 -49
- package/dist/Sol/notfound/notfound.d.ts +0 -9
- package/dist/Sol/notfound/notfound.js +0 -15
- package/dist/Sol/onboarding/onboarding.d.ts +0 -25
- package/dist/Sol/onboarding/onboarding.js +0 -60
- package/dist/Sol/playground/playground.d.ts +0 -9
- package/dist/Sol/playground/playground.js +0 -127
- package/dist/Sol/register/register.d.ts +0 -16
- package/dist/Sol/register/register.js +0 -193
- package/dist/Sol/shell/Shell.d.ts +0 -124
- package/dist/Sol/shell/Shell.js +0 -335
- package/dist/Sol/wingets/ComputeBootladder.d.ts +0 -6
- package/dist/Sol/wingets/ComputeBootladder.js +0 -71
- package/dist/Sol/wingets/ComputeModalitycatalog.d.ts +0 -7
- package/dist/Sol/wingets/ComputeModalitycatalog.js +0 -71
- package/dist/Sol/wingets/ConsoleApibadge.d.ts +0 -7
- package/dist/Sol/wingets/ConsoleApibadge.js +0 -5
- package/dist/Sol/wingets/ConsoleEdgelaw.d.ts +0 -6
- package/dist/Sol/wingets/ConsoleEdgelaw.js +0 -36
- package/dist/Sol/wingets/ConsoleEventstimeline.d.ts +0 -19
- package/dist/Sol/wingets/ConsoleEventstimeline.js +0 -12
- package/dist/Sol/wingets/ConsoleSnapshotcontrols.d.ts +0 -8
- package/dist/Sol/wingets/ConsoleSnapshotcontrols.js +0 -8
- package/dist/Sol/wingets/ConsoleSpecpanel.d.ts +0 -21
- package/dist/Sol/wingets/ConsoleSpecpanel.js +0 -75
- package/dist/Sol/wingets/ConsoleTerminal.d.ts +0 -22
- package/dist/Sol/wingets/ConsoleTerminal.js +0 -77
- package/dist/Sol/wingets/DashboardAccountpanel.d.ts +0 -18
- package/dist/Sol/wingets/DashboardAccountpanel.js +0 -65
- package/dist/Sol/wingets/DashboardAdminpanel.d.ts +0 -6
- package/dist/Sol/wingets/DashboardAdminpanel.js +0 -90
- package/dist/Sol/wingets/DashboardAuditlog.d.ts +0 -8
- package/dist/Sol/wingets/DashboardAuditlog.js +0 -50
- package/dist/Sol/wingets/DashboardCreatesandboxform.d.ts +0 -10
- package/dist/Sol/wingets/DashboardCreatesandboxform.js +0 -71
- package/dist/Sol/wingets/DashboardEventstimeline.d.ts +0 -8
- package/dist/Sol/wingets/DashboardEventstimeline.js +0 -83
- package/dist/Sol/wingets/DashboardGlobalsandboxestable.d.ts +0 -8
- package/dist/Sol/wingets/DashboardGlobalsandboxestable.js +0 -57
- package/dist/Sol/wingets/DashboardMeshnodestable.d.ts +0 -8
- package/dist/Sol/wingets/DashboardMeshnodestable.js +0 -103
- package/dist/Sol/wingets/DashboardSandboxlist.d.ts +0 -10
- package/dist/Sol/wingets/DashboardSandboxlist.js +0 -163
- package/dist/Sol/wingets/DashboardUserstable.d.ts +0 -8
- package/dist/Sol/wingets/DashboardUserstable.js +0 -78
- package/dist/Sol/wingets/HomeEntrygate.d.ts +0 -23
- package/dist/Sol/wingets/HomeEntrygate.js +0 -73
- package/dist/Sol/wingets/HomeMetricstrip.d.ts +0 -9
- package/dist/Sol/wingets/HomeMetricstrip.js +0 -4
- package/dist/Sol/wingets/HomeRuntimediagram.d.ts +0 -1
- package/dist/Sol/wingets/HomeRuntimediagram.js +0 -22
- package/dist/Sol/wingets/LoginForm.d.ts +0 -19
- package/dist/Sol/wingets/LoginForm.js +0 -141
- package/dist/Sol/wingets/RegisterPasswordconfirm.d.ts +0 -13
- package/dist/Sol/wingets/RegisterPasswordconfirm.js +0 -16
- package/dist/Sol/wingets/RegisterPasswordmeter.d.ts +0 -19
- package/dist/Sol/wingets/RegisterPasswordmeter.js +0 -65
- package/dist/Sol/wingets/RegisterUsernamerules.d.ts +0 -11
- package/dist/Sol/wingets/RegisterUsernamerules.js +0 -16
- package/dist/Sol/wingets/index.d.ts +0 -39
- package/dist/Sol/wingets/index.js +0 -39
- package/dist/alternatives.d.ts +0 -508
- package/dist/alternatives.js +0 -950
- package/dist/api.d.ts +0 -154
- package/dist/api.js +0 -174
- package/dist/auth.d.ts +0 -268
- package/dist/auth.js +0 -476
- package/dist/automation.d.ts +0 -425
- package/dist/automation.js +0 -566
- package/dist/browser.d.ts +0 -561
- package/dist/browser.js +0 -1058
- package/dist/capacitor.config.d.ts +0 -45
- package/dist/capacitor.config.js +0 -48
- package/dist/catalog.d.ts +0 -43
- package/dist/catalog.js +0 -44
- package/dist/cli.d.ts +0 -16
- package/dist/cli.js +0 -168
- package/dist/communication.d.ts +0 -181
- package/dist/communication.js +0 -376
- package/dist/compute.d.ts +0 -1160
- package/dist/compute.js +0 -2272
- package/dist/dashboardlib.d.ts +0 -58
- package/dist/dashboardlib.js +0 -161
- package/dist/db.d.ts +0 -569
- package/dist/db.js +0 -1080
- package/dist/distribution.d.ts +0 -528
- package/dist/distribution.js +0 -810
- package/dist/drizzle.config.d.ts +0 -20
- package/dist/drizzle.config.js +0 -18
- package/dist/edgelandes.d.ts +0 -70
- package/dist/edgelandes.host.d.ts +0 -26
- package/dist/edgelandes.host.js +0 -1089
- package/dist/edgelandes.inproc.d.ts +0 -27
- package/dist/edgelandes.inproc.js +0 -952
- package/dist/edgelandes.js +0 -1133
- package/dist/edgelandes.ninety.d.ts +0 -31
- package/dist/edgelandes.ninety.js +0 -174
- package/dist/edgelandes.virtual.d.ts +0 -25
- package/dist/edgelandes.virtual.js +0 -629
- package/dist/edgeplane.d.ts +0 -121
- package/dist/edgeplane.js +0 -341
- package/dist/examplelocaljob.d.ts +0 -1
- package/dist/examplelocaljob.js +0 -14
- package/dist/execution.d.ts +0 -529
- package/dist/execution.js +0 -760
- package/dist/family.d.ts +0 -16
- package/dist/family.js +0 -42
- package/dist/familyurl.d.ts +0 -21
- package/dist/familyurl.js +0 -24
- package/dist/format.d.ts +0 -18
- package/dist/format.js +0 -59
- package/dist/foundation.d.ts +0 -172
- package/dist/foundation.js +0 -312
- package/dist/index.d.ts +0 -735
- package/dist/index.js +0 -1020
- package/dist/integration.d.ts +0 -235
- package/dist/integration.js +0 -228
- package/dist/intelligence.d.ts +0 -93
- package/dist/intelligence.js +0 -144
- package/dist/isolation.d.ts +0 -128
- package/dist/isolation.js +0 -95
- package/dist/labels.d.ts +0 -665
- package/dist/labels.js +0 -707
- package/dist/localauth.d.ts +0 -127
- package/dist/localauth.js +0 -413
- package/dist/media.d.ts +0 -343
- package/dist/media.js +0 -985
- package/dist/mesh.d.ts +0 -177
- package/dist/mesh.js +0 -468
- package/dist/modalityregistry.d.ts +0 -109
- package/dist/modalityregistry.js +0 -1386
- package/dist/modes.d.ts +0 -358
- package/dist/modes.js +0 -133
- package/dist/onboardingstate.d.ts +0 -79
- package/dist/onboardingstate.js +0 -282
- package/dist/orchestrator.d.ts +0 -1338
- package/dist/orchestrator.js +0 -4310
- package/dist/packager/targetcli.js +0 -4
- package/dist/paths.d.ts +0 -2
- package/dist/paths.js +0 -14
- package/dist/performance.d.ts +0 -415
- package/dist/performance.js +0 -826
- package/dist/quantum.d.ts +0 -809
- package/dist/quantum.js +0 -2072
- package/dist/render.d.ts +0 -380
- package/dist/render.js +0 -1072
- package/dist/runall.d.ts +0 -2
- package/dist/runall.js +0 -39
- package/dist/runtimeprobe.d.ts +0 -4
- package/dist/runtimeprobe.js +0 -8
- package/dist/sandbox.d.ts +0 -355
- package/dist/sandbox.js +0 -1721
- package/dist/sandboxenvprofile.d.ts +0 -29
- package/dist/sandboxenvprofile.js +0 -89
- package/dist/sandboxprofile.d.ts +0 -137
- package/dist/sandboxprofile.js +0 -241
- package/dist/sandboxqueue.d.ts +0 -108
- package/dist/sandboxqueue.js +0 -201
- package/dist/sandboxquota.d.ts +0 -121
- package/dist/sandboxquota.js +0 -236
- package/dist/scheduler.d.ts +0 -595
- package/dist/scheduler.js +0 -1258
- package/dist/scriptlanes.d.ts +0 -182
- package/dist/scriptlanes.js +0 -660
- package/dist/scripts.buildengine.d.ts +0 -1
- package/dist/scripts.buildengine.js +0 -39
- package/dist/scripts.securitygate.d.ts +0 -1
- package/dist/scripts.securitygate.js +0 -68
- package/dist/scripts.validateflatnative.d.ts +0 -1
- package/dist/scripts.validateflatnative.js +0 -72
- package/dist/security.d.ts +0 -500
- package/dist/security.js +0 -1169
- package/dist/seedcatalog.d.ts +0 -13
- package/dist/seedcatalog.js +0 -46
- package/dist/server.d.ts +0 -20
- package/dist/server.js +0 -53
- package/dist/speccatalog.d.ts +0 -31
- package/dist/speccatalog.js +0 -163
- package/dist/tiers.d.ts +0 -1001
- package/dist/tiers.js +0 -2169
- package/dist/utils.d.ts +0 -2
- package/dist/utils.js +0 -5
- package/dist/vaulthandoff.d.ts +0 -141
- package/dist/vaulthandoff.js +0 -444
- package/dist/virtual.d.ts +0 -640
- package/dist/virtual.js +0 -1284
- package/dist/virtualcpu.d.ts +0 -315
- package/dist/virtualcpu.js +0 -1180
- package/dist/virtualgpu.d.ts +0 -344
- package/dist/virtualgpu.js +0 -1000
- package/dist/virtualization.d.ts +0 -606
- package/dist/virtualization.js +0 -1186
- package/dist/virtualmemory.d.ts +0 -817
- package/dist/virtualmemory.js +0 -1795
- package/dist/vite.config.d.ts +0 -3
- package/dist/vite.config.js +0 -48
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -25
- package/dist/webserver.d.ts +0 -166
- package/dist/webserver.js +0 -2226
- package/dist/workloadlaw.d.ts +0 -133
- package/dist/workloadlaw.js +0 -193
- package/docs/.gitkeep +0 -0
- package/docs/architecture.1.8.19.md +0 -76
- package/docs/logs/examplesession.json +0 -54
- package/docs/repo.analysis.1.8.21.json +0 -2617
- package/docs/repo.candidates.1.8.21.jsonl +0 -666
- package/docs/repo.selected.1.8.21.json +0 -786
- package/manifest.json +0 -20
- package/media.ts +0 -1337
- package/virtualcpu.ts +0 -1274
- package/virtualgpu.ts +0 -1182
- package/virtualization.ts +0 -1628
- package/virtualmemory.ts +0 -2303
- /package/docs/{artifactresearch.1.8.9.md → artifactresearch189.md} +0 -0
- /package/docs/{batches.1816.to.1820.md → batches1816to1820.md} +0 -0
- /package/docs/{brancharchive.2026.08.18.md → brancharchive20260818.md} +0 -0
- /package/docs/{containerplatforms.1.8.17.md → containerplatforms1817.md} +0 -0
- /package/docs/{e2ugh.engine.md → e2ughengine.md} +0 -0
- /package/docs/{flatbuildresearch.1.8.11.md → flatbuildresearch1811.md} +0 -0
- /package/docs/{licenseaudit.1.8.12.md → licenseaudit1812.md} +0 -0
- /package/docs/{mobileconversionresearch.1.8.10.md → mobileconversionresearch1810.md} +0 -0
- /package/docs/{nativeidentityresearch.1.8.11.md → nativeidentityresearch1811.md} +0 -0
- /package/docs/{native.wrappers.md → nativewrappers.md} +0 -0
- /package/docs/{planning.1.8.18.md → planning1818.md} +0 -0
- /package/docs/{planning.1.8.19.md → planning1819.md} +0 -0
- /package/docs/{planning.engine.md → planningengine.md} +0 -0
- /package/docs/{releasenotes.1.8.12.md → releasenotes1812.md} +0 -0
- /package/docs/{releasenotes.1.8.15.md → releasenotes1815.md} +0 -0
- /package/docs/{releasenotes.1.8.16.md → releasenotes1816.md} +0 -0
- /package/docs/{releasenotes.1.8.17.md → releasenotes1817.md} +0 -0
- /package/docs/{releasenotes.1.8.18.md → releasenotes1818.md} +0 -0
- /package/docs/{releasenotes.1.8.19.md → releasenotes1819.md} +0 -0
- /package/docs/{reorganization.1.8.8.md → reorganization188.md} +0 -0
- /package/docs/{reorganization.1.8.9.md → reorganization189.md} +0 -0
- /package/docs/{repo.research.1.8.16.md → reporesearch1816.md} +0 -0
- /package/docs/{repo.research.1.8.21.md → reporesearch1821.md} +0 -0
- /package/docs/{repo.synthesis.1.8.21.md → reposynthesis1821.md} +0 -0
- /package/docs/{research.1.8.18.isolation.md → research1818isolation.md} +0 -0
- /package/docs/{research.1.8.19.virtual.browser.md → research1819virtualbrowser.md} +0 -0
- /package/docs/{scanningresearch.1.8.11.md → scanningresearch1811.md} +0 -0
- /package/docs/{securityaudit.1.8.7.md → securityaudit187.md} +0 -0
- /package/docs/{securityreferences.1.8.11.md → securityreferences1811.md} +0 -0
- /package/docs/{securityresearch.1.8.11.md → securityresearch1811.md} +0 -0
- /package/docs/{signingresearch.1.8.12.md → signingresearch1812.md} +0 -0
- /package/docs/{tauri.glib.risk.1.8.11.md → tauriglibrisk1811.md} +0 -0
- /package/docs/{todo.1.8.18.md → todo1818.md} +0 -0
- /package/docs/{todo.1.8.19.md → todo1819.md} +0 -0
- /package/docs/{toolchainresearch.1.8.9.md → toolchainresearch189.md} +0 -0
- /package/docs/{web.duplicatecleanup.md → webduplicatecleanup.md} +0 -0
- /package/docs/{web.ideas.md → webideas.md} +0 -0
- /package/docs/{workflowimprovements.2026.08.19.md → workflowimprovements20260819.md} +0 -0
|
@@ -1,629 +0,0 @@
|
|
|
1
|
-
// # edgelandes.virtual.ts — the virtual hardware composition lanes of
|
|
2
|
-
// the edge plane (the ninety modalities wave, group c, task wa-2c: the
|
|
3
|
-
// seven planned virtual-hardware modalities wired as honest composition
|
|
4
|
-
// lanes). every lane rides the engine's own virtual hardware payloads —
|
|
5
|
-
// sandbox.ts generates the procfs, smi, dmesg and mesa surfaces,
|
|
6
|
-
// virtualization.ts carries the qemu/kvm plan surface — and composes the
|
|
7
|
-
// per-modality machine report from them: a lane never boots anything on
|
|
8
|
-
// the host, the report says composed, never booted. the code field of
|
|
9
|
-
// every executor is the machine manifest (json: model, gpu, ramgb, boot
|
|
10
|
-
// with the optional vcpus and mig); an unparsable manifest answers
|
|
11
|
-
// invalid-machine-manifest, a catalog reference the engine does not
|
|
12
|
-
// carry answers catalog-entry-absent, a plan the recipe cannot compose
|
|
13
|
-
// answers kvm-composition-failed and a blown deadline answers
|
|
14
|
-
// run-deadline-exceeded. determinism is the lane law: the engine samples
|
|
15
|
-
// some payload values per run (crypto-random memory fractions, the smi
|
|
16
|
-
// timestamp and counters, the state token), so the lanes pin those
|
|
17
|
-
// ranges at their midpoints and keep only the run-invariant smi lines —
|
|
18
|
-
// the same manifest always composes the same report bytes.
|
|
19
|
-
import { edgelaneerror } from "./edgelandes.ts";
|
|
20
|
-
import { bootSequence, clinfoSummary, cpudata, freeh, getcpu, getcpubyid, getgpu, getmig, glxinfoSummary, gpudata, lscpu, mesaenv, migprofiles, nvidiaSmiTable, pagealign, solvetopology, vulkanSummary, } from "./sandbox.ts";
|
|
21
|
-
/* the virtualization domain (virtualization.ts) re-exports virtualgpu
|
|
22
|
-
* through a .js specifier — the webserver's plain node host resolves only
|
|
23
|
-
* .ts specifiers, so the kvm lane loads the domain lazily inside the
|
|
24
|
-
* executor (the family law: a domain the host cannot resolve degrades
|
|
25
|
-
* that one lane honestly, never the engine boot). */
|
|
26
|
-
async function loadvirtualization() {
|
|
27
|
-
try {
|
|
28
|
-
return await import("./virtualization.ts");
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
throw edgelaneerror("KVM_MODULE_UNAVAILABLE", `the virtualization domain cannot load under this host (the .js specifier graph needs a full resolver): ${error instanceof Error ? error.message : String(error)}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/** the engine's virtual memory ceiling createSandboxState clamps under;
|
|
35
|
-
* the lane law refuses a manifest above it instead of silently
|
|
36
|
-
* rewriting the caller's machine. */
|
|
37
|
-
const ENGINERAMCEILINGGB = 18432;
|
|
38
|
-
/** parses the code field as the machine manifest: a json object carrying
|
|
39
|
-
* the optional model, gpu, ramgb, vcpus, boot and mig fields, every
|
|
40
|
-
* present field type-checked and bounded — anything else answers
|
|
41
|
-
* invalid-machine-manifest with the reason. */
|
|
42
|
-
function parsemanifest(code) {
|
|
43
|
-
const invalid = (detail) => {
|
|
44
|
-
throw edgelaneerror("INVALID_MACHINE_MANIFEST", detail);
|
|
45
|
-
};
|
|
46
|
-
let parsed;
|
|
47
|
-
try {
|
|
48
|
-
parsed = JSON.parse(code);
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
invalid(`the code field is not parsable json (the machine manifest law): ${error instanceof Error ? error.message : String(error)}`);
|
|
52
|
-
}
|
|
53
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
54
|
-
invalid("the machine manifest must be a json object carrying the machine fields");
|
|
55
|
-
}
|
|
56
|
-
const raw = parsed;
|
|
57
|
-
if (raw.model !== undefined && typeof raw.model !== "string") {
|
|
58
|
-
invalid("the model field must be a string when present");
|
|
59
|
-
}
|
|
60
|
-
if (raw.gpu !== undefined && typeof raw.gpu !== "string") {
|
|
61
|
-
invalid("the gpu field must be a string when present");
|
|
62
|
-
}
|
|
63
|
-
if (raw.mig !== undefined && typeof raw.mig !== "string") {
|
|
64
|
-
invalid("the mig field must be a string when present (a mig profile id or off)");
|
|
65
|
-
}
|
|
66
|
-
if (raw.boot !== undefined && typeof raw.boot !== "boolean") {
|
|
67
|
-
invalid("the boot field must be a boolean when present");
|
|
68
|
-
}
|
|
69
|
-
if (raw.ramgb !== undefined) {
|
|
70
|
-
if (typeof raw.ramgb !== "number" || !Number.isFinite(raw.ramgb)) {
|
|
71
|
-
invalid("the ramgb field must be a finite number when present");
|
|
72
|
-
}
|
|
73
|
-
if (raw.ramgb <= 0) {
|
|
74
|
-
invalid("the ramgb field must be a positive number of gigabytes");
|
|
75
|
-
}
|
|
76
|
-
if (raw.ramgb > ENGINERAMCEILINGGB) {
|
|
77
|
-
invalid(`the ramgb field must stay under the engine's ${ENGINERAMCEILINGGB} gb virtual ceiling (createSandboxState clamps there; the lane refuses instead of rewriting the manifest)`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (raw.vcpus !== undefined) {
|
|
81
|
-
if (typeof raw.vcpus !== "number" || !Number.isFinite(raw.vcpus)) {
|
|
82
|
-
invalid("the vcpus field must be a finite number when present");
|
|
83
|
-
}
|
|
84
|
-
if (raw.vcpus < 1) {
|
|
85
|
-
invalid("the vcpus field must be at least 1");
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return { model: raw.model, gpu: raw.gpu, ramgb: raw.ramgb, vcpus: raw.vcpus, boot: raw.boot, mig: raw.mig };
|
|
89
|
-
}
|
|
90
|
-
/** resolves the manifest against the engine catalogs: the model lookup
|
|
91
|
-
* accepts the catalog model name or its slug id (getcpu then
|
|
92
|
-
* getcpubyid), the gpu lookup accepts the id or the name, the mig
|
|
93
|
-
* lookup accepts a mig profile id or off; an entry the catalog does not
|
|
94
|
-
* carry answers catalog-entry-absent naming the known ids. the defaults
|
|
95
|
-
* mirror the engine's own laws: the first catalog entry for model and
|
|
96
|
-
* gpu (the vgpu lane overrides the gpu default with the first
|
|
97
|
-
* mig-capable device), 32 gb ram and 8 vcpus (the SandboxSpec defaults
|
|
98
|
-
* createSandboxState rides), the vcpus clamped by the engine's own
|
|
99
|
-
* solvetopology. */
|
|
100
|
-
function composemachine(raw, defaultgpu) {
|
|
101
|
-
const modelwanted = raw.model ?? cpudata[0].model;
|
|
102
|
-
const cpuspec = getcpu(modelwanted) ?? getcpubyid(modelwanted);
|
|
103
|
-
if (cpuspec === undefined) {
|
|
104
|
-
throw edgelaneerror("CATALOG_ENTRY_ABSENT", `the cpu catalog carries no model "${modelwanted}"; known models: ${cpudata.map((entry) => entry.model).join(", ")}`);
|
|
105
|
-
}
|
|
106
|
-
const gpuwanted = raw.gpu ?? defaultgpu ?? gpudata[0].id;
|
|
107
|
-
const gpuspec = getgpu(gpuwanted);
|
|
108
|
-
if (gpuspec === undefined) {
|
|
109
|
-
throw edgelaneerror("CATALOG_ENTRY_ABSENT", `the gpu catalog carries no device "${gpuwanted}"; known ids: ${gpudata.map((entry) => entry.id).join(", ")}`);
|
|
110
|
-
}
|
|
111
|
-
const migwanted = raw.mig ?? "off";
|
|
112
|
-
if (migwanted !== "off" && !migprofiles.some((profile) => profile.id === migwanted)) {
|
|
113
|
-
throw edgelaneerror("CATALOG_ENTRY_ABSENT", `the mig catalog carries no profile "${migwanted}"; known profiles: off, ${migprofiles.map((profile) => profile.id).join(", ")}`);
|
|
114
|
-
}
|
|
115
|
-
const topology = solvetopology(cpuspec, raw.vcpus ?? 8);
|
|
116
|
-
const manifest = {
|
|
117
|
-
model: cpuspec.model,
|
|
118
|
-
gpu: gpuspec.id,
|
|
119
|
-
ramgb: raw.ramgb ?? 32,
|
|
120
|
-
vcpus: topology.vcpus,
|
|
121
|
-
boot: raw.boot ?? false,
|
|
122
|
-
mig: migwanted,
|
|
123
|
-
};
|
|
124
|
-
return { manifest, cpuspec, gpuspec, topology };
|
|
125
|
-
}
|
|
126
|
-
/** renders the canonical manifest json (fixed key order): the bytes the
|
|
127
|
-
* session-otp gate hashes and the manifest the artifacts carry. */
|
|
128
|
-
function canonicalmanifest(manifest) {
|
|
129
|
-
return JSON.stringify({
|
|
130
|
-
model: manifest.model,
|
|
131
|
-
gpu: manifest.gpu,
|
|
132
|
-
ramgb: manifest.ramgb,
|
|
133
|
-
vcpus: manifest.vcpus,
|
|
134
|
-
boot: manifest.boot,
|
|
135
|
-
mig: manifest.mig,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
/** hashes one text with 64-bit fnv-1a and renders 16 lowercase hex
|
|
139
|
-
* characters: the deterministic digest the session-otp gate and the
|
|
140
|
-
* sandbox id ride — the engine's token() samples crypto randomness per
|
|
141
|
-
* run, the lane hashes the manifest instead so identical manifests
|
|
142
|
-
* compose identical ids. */
|
|
143
|
-
function fnv1a64(text) {
|
|
144
|
-
let hash = 0xcbf29ce484222325n;
|
|
145
|
-
for (let index = 0; index < text.length; index += 1) {
|
|
146
|
-
hash ^= BigInt(text.charCodeAt(index));
|
|
147
|
-
hash = (hash * 0x100000001b3n) & 0xffffffffffffffffn;
|
|
148
|
-
}
|
|
149
|
-
return hash.toString(16).padStart(16, "0");
|
|
150
|
-
}
|
|
151
|
-
/** honors the deadline after the composition (the boot budget law: the
|
|
152
|
-
* compositions are fast, a blown budget answers run-deadline-exceeded
|
|
153
|
-
* instead of a report the caller never paid for). */
|
|
154
|
-
function guarddeadline(startedat, deadline) {
|
|
155
|
-
const budget = Number.isFinite(deadline) ? Math.max(0, deadline) : Number.POSITIVE_INFINITY;
|
|
156
|
-
if (Date.now() - startedat > budget) {
|
|
157
|
-
throw edgelaneerror("RUN_DEADLINE_EXCEEDED", `the composition exceeded its ${deadline} ms deadline (the boot budget law)`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
/** composes the memory plan from the engine's own formulas: pagealign
|
|
161
|
-
* and the MemTotal and swap laws meminfo/createSandboxState ride, with
|
|
162
|
-
* every per-run sampled fraction pinned at the midpoint of the engine's
|
|
163
|
-
* rnd range (the engine samples free, buffers, cached, shmem and
|
|
164
|
-
* swapfree per run; the lane pins the midpoints so the same manifest
|
|
165
|
-
* composes the same bytes) — the free -h table still renders through
|
|
166
|
-
* the engine's own freeh over the pinned snapshot. */
|
|
167
|
-
function composememoryplan(ramgb, vcpus) {
|
|
168
|
-
const memtotalkb = pagealign(ramgb * 1024 * 1024 - 131072);
|
|
169
|
-
const swapgb = Math.min(Math.max(Math.round(ramgb / 8), 2), 128);
|
|
170
|
-
const swaptotalkb = swapgb * 1024 * 1024;
|
|
171
|
-
const row = (key, kb) => `${key}:${String(kb).padStart(24 - key.length - 1)} kB`;
|
|
172
|
-
const rows = [
|
|
173
|
-
row("MemTotal", memtotalkb),
|
|
174
|
-
row("MemFree", pagealign(memtotalkb * 0.053)),
|
|
175
|
-
row("MemAvailable", pagealign(memtotalkb * 0.895)),
|
|
176
|
-
row("Buffers", pagealign(memtotalkb * 0.0065)),
|
|
177
|
-
row("Cached", pagealign(memtotalkb * 0.36)),
|
|
178
|
-
row("SReclaimable", 0),
|
|
179
|
-
row("Shmem", pagealign(memtotalkb * 0.0085)),
|
|
180
|
-
row("SwapTotal", swaptotalkb),
|
|
181
|
-
row("SwapFree", pagealign(swaptotalkb * 0.915)),
|
|
182
|
-
row("KernelStack", pagealign(vcpus * 320)),
|
|
183
|
-
];
|
|
184
|
-
return { memtotalkb, swapgb, rows, free: freeh(rows.join("\n")) };
|
|
185
|
-
}
|
|
186
|
-
/** keeps the run-invariant lines of the engine's 89-char smi table: the
|
|
187
|
-
* composer stamps a per-run timestamp and samples the fan, temperature,
|
|
188
|
-
* memory and utilization counters, so the surface drops the timestamp
|
|
189
|
-
* line, the sampled perf row and the mig-worker process rows and keeps
|
|
190
|
-
* every deterministic line (the borders, the headers, the device row,
|
|
191
|
-
* the mig line, the no-running-processes line). */
|
|
192
|
-
function smilines(gpu, mig) {
|
|
193
|
-
return nvidiaSmiTable(gpu, mig)
|
|
194
|
-
.split("\n")
|
|
195
|
-
.filter((line) => !/^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat) /.test(line))
|
|
196
|
-
.filter((line) => !/P0\s+\d+W \//.test(line))
|
|
197
|
-
.filter((line) => !line.includes("mig-worker"));
|
|
198
|
-
}
|
|
199
|
-
/** the session law of the virtual display (the lane pins it; the
|
|
200
|
-
* registry record charges the virtual-screen modality under the xvfb
|
|
201
|
-
* and looking-glass drivers with the session-otp hardening gate):
|
|
202
|
-
* display :0, geometry 1280x800x24 and the vnc endpoint on the symbolic
|
|
203
|
-
* saddle-display host — the lane composes the tree, it never binds a
|
|
204
|
-
* socket. */
|
|
205
|
-
const displaylaw = {
|
|
206
|
-
display: ":0",
|
|
207
|
-
screen: 0,
|
|
208
|
-
geometry: "1280x800x24",
|
|
209
|
-
vnc: "vnc://saddle-display:5900",
|
|
210
|
-
driver: "looking-glass b7 (kvmfr ivshmem 128m, the guest-to-host frame bridge)",
|
|
211
|
-
};
|
|
212
|
-
/** reads the driver-quota bound from the lane inputs: inputs.quota with
|
|
213
|
-
* the default of 4 devices, clamped to 1-16 (the registry record's
|
|
214
|
-
* driver-quota hardening gate — the nvml surface never answers more
|
|
215
|
-
* devices than the quota bounds). */
|
|
216
|
-
function driverquota(inputs) {
|
|
217
|
-
const wanted = typeof inputs === "object" && inputs !== null ? inputs.quota : undefined;
|
|
218
|
-
if (typeof wanted !== "number" || !Number.isFinite(wanted)) {
|
|
219
|
-
return 4;
|
|
220
|
-
}
|
|
221
|
-
return Math.max(1, Math.min(16, Math.round(wanted)));
|
|
222
|
-
}
|
|
223
|
-
/** reads the context-quota bound from the lane inputs: inputs.contexts
|
|
224
|
-
* with the default of 8 contexts, clamped to 1-64 (the registry record's
|
|
225
|
-
* context-quota hardening gate). */
|
|
226
|
-
function contextquota(inputs) {
|
|
227
|
-
const wanted = typeof inputs === "object" && inputs !== null ? inputs.contexts : undefined;
|
|
228
|
-
if (typeof wanted !== "number" || !Number.isFinite(wanted)) {
|
|
229
|
-
return 8;
|
|
230
|
-
}
|
|
231
|
-
return Math.max(1, Math.min(64, Math.round(wanted)));
|
|
232
|
-
}
|
|
233
|
-
/** extracts the driver version strings from the engine's boot payload:
|
|
234
|
-
* the kernel banner of the first line rides virtualcpu and the engine's
|
|
235
|
-
* own version line rides virtualmemory (the boot sequence is
|
|
236
|
-
* deterministic, so the driver table composes identical bytes). */
|
|
237
|
-
function driverversions(manifest) {
|
|
238
|
-
const boot = bootSequence(manifest.model, manifest.vcpus, manifest.ramgb, manifest.gpu);
|
|
239
|
-
return {
|
|
240
|
-
kernel: /Linux version (\S+) /.exec(boot[0])?.[1] ?? "6.12.0-saddle",
|
|
241
|
-
engine: /virtual hardware engine v([0-9.]+)/.exec(boot.join("\n"))?.[1] ?? "2.0.127",
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
/* ════════════════════════════════════════════════════════════════════ */
|
|
245
|
-
/* Section 3: the seven lane executors — one per planned modality. */
|
|
246
|
-
/* ════════════════════════════════════════════════════════════════════ */
|
|
247
|
-
/** the artifact encoder shared by the lanes. */
|
|
248
|
-
const textencoder = new TextEncoder();
|
|
249
|
-
/** virtual-full: the complete machine. composes the cpu (the catalog by
|
|
250
|
-
* model, default the first entry), the gpu (by id, default the first),
|
|
251
|
-
* the memory (the engine's meminfo/freeh formulas), the boot dmesg
|
|
252
|
-
* sequence (when the manifest asks boot), the topology (solvetopology)
|
|
253
|
-
* and the sandbox state facts; the report answers the model, the
|
|
254
|
-
* cores/threads, the smi summary, the memory report, the state line and
|
|
255
|
-
* the boot dmesg head, and the artifact carries the complete manifest. */
|
|
256
|
-
async function virtualfulllane(code, _inputs, deadline) {
|
|
257
|
-
const startedat = Date.now();
|
|
258
|
-
const { manifest, cpuspec, gpuspec, topology } = composemachine(parsemanifest(code));
|
|
259
|
-
const memory = composememoryplan(manifest.ramgb, manifest.vcpus);
|
|
260
|
-
const smi = smilines(manifest.gpu, "off");
|
|
261
|
-
const digest = fnv1a64(canonicalmanifest(manifest));
|
|
262
|
-
const sandboxid = `sb-${digest.slice(0, 8)}`;
|
|
263
|
-
const hostname = `saddle-${digest.slice(0, 8)}`;
|
|
264
|
-
const kernel = cpuspec.arch === "arm64" ? "6.12.0-saddle-aarch64" : "6.12.0-saddle";
|
|
265
|
-
const boot = manifest.boot ? bootSequence(manifest.model, manifest.vcpus, manifest.ramgb, manifest.gpu) : [];
|
|
266
|
-
const stdout = [
|
|
267
|
-
"saddle virtual-full: composed machine report (composed, never booted)",
|
|
268
|
-
` model: ${cpuspec.displayname} — ${cpuspec.cores} cores / ${cpuspec.threads} threads (${cpuspec.microarch}, ${cpuspec.socket})`,
|
|
269
|
-
` topology: ${topology.vcpus} vcpus, ${topology.coresonline} cores online, ${topology.threadspercore} threads per core, ${topology.sockets} socket (solved by the engine's solvetopology)`,
|
|
270
|
-
` gpu: ${gpuspec.name} (${gpuspec.id}) — ${gpuspec.memtype} ${gpuspec.vrammib / 1024} gb, driver ${gpuspec.driver}${gpuspec.cuda === null ? "" : `, cuda ${gpuspec.cuda}`}`,
|
|
271
|
-
" smi (the engine's 89-char table, the run-invariant lines):",
|
|
272
|
-
...smi.map((line) => ` ${line}`),
|
|
273
|
-
" memory (the engine's formulas, the sampled fractions pinned at their midpoints):",
|
|
274
|
-
...memory.rows.map((line) => ` ${line}`),
|
|
275
|
-
" free -h (the engine's free table over the pinned plan):",
|
|
276
|
-
...memory.free.split("\n").map((line) => ` ${line}`),
|
|
277
|
-
` state: hostname ${hostname}, kernel ${kernel}, sandbox ${sandboxid} (the id pinned from the manifest hash — the engine's state composer samples a per-run token and meminfo snapshot instead)`,
|
|
278
|
-
...(manifest.boot
|
|
279
|
-
? [
|
|
280
|
-
` boot dmesg head (${Math.min(8, boot.length)} of ${boot.length} lines):`,
|
|
281
|
-
...boot.slice(0, 8).map((line) => ` ${line}`),
|
|
282
|
-
]
|
|
283
|
-
: [" boot: the manifest asks for no boot sequence (boot false)"]),
|
|
284
|
-
].join("\n");
|
|
285
|
-
guarddeadline(startedat, deadline);
|
|
286
|
-
const artifact = {
|
|
287
|
-
modality: "virtual-full",
|
|
288
|
-
verdict: "composed",
|
|
289
|
-
manifest,
|
|
290
|
-
machine: {
|
|
291
|
-
cpumodel: cpuspec.model,
|
|
292
|
-
cores: cpuspec.cores,
|
|
293
|
-
threads: cpuspec.threads,
|
|
294
|
-
gpuid: gpuspec.id,
|
|
295
|
-
gpuname: gpuspec.name,
|
|
296
|
-
vrammib: gpuspec.vrammib,
|
|
297
|
-
memtotalkb: memory.memtotalkb,
|
|
298
|
-
swapgb: memory.swapgb,
|
|
299
|
-
},
|
|
300
|
-
topology,
|
|
301
|
-
smi,
|
|
302
|
-
memory: { rows: memory.rows, free: memory.free },
|
|
303
|
-
state: { id: sandboxid, hostname, kernel },
|
|
304
|
-
boot,
|
|
305
|
-
lscpu: lscpu(manifest.model, manifest.vcpus),
|
|
306
|
-
};
|
|
307
|
-
return {
|
|
308
|
-
stdout,
|
|
309
|
-
artifact: { mime: "application/vnd.devthink.sandbox+json", bytes: textencoder.encode(JSON.stringify(artifact)) },
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
/** virtual-vgpu: the vgpu slice. composes the mig-capable device (the
|
|
313
|
-
* manifest's gpu selects it, default the first mig-capable entry), the
|
|
314
|
-
* mig slicing (the engine's migprofiles catalog), the smi table for the
|
|
315
|
-
* sliced device and the nvml shim surface (FAKE_MODEL/FAKE_VRAM under
|
|
316
|
-
* the profile, the engine's env law); a non-mig device answers
|
|
317
|
-
* catalog-entry-absent — the lane composes slices of the mig-class
|
|
318
|
-
* devices only, it never pretends a gaming card slices. */
|
|
319
|
-
async function virtualvgpulane(code, _inputs, deadline) {
|
|
320
|
-
const startedat = Date.now();
|
|
321
|
-
const defaultvgpu = gpudata.find((entry) => entry.mig) ?? gpudata[0];
|
|
322
|
-
const { manifest, gpuspec } = composemachine(parsemanifest(code), defaultvgpu.id);
|
|
323
|
-
if (!gpuspec.mig) {
|
|
324
|
-
throw edgelaneerror("CATALOG_ENTRY_ABSENT", `the gpu catalog carries no mig-capable entry for "${manifest.gpu}" (${gpuspec.name}); the vgpu lane composes slices of the mig-class devices only: ${gpudata
|
|
325
|
-
.filter((entry) => entry.mig)
|
|
326
|
-
.map((entry) => entry.id)
|
|
327
|
-
.join(", ")}`);
|
|
328
|
-
}
|
|
329
|
-
const profile = getmig(manifest.mig) ?? migprofiles[0];
|
|
330
|
-
const smi = smilines(manifest.gpu, profile.id);
|
|
331
|
-
const stdout = [
|
|
332
|
-
"saddle virtual-vgpu: composed vgpu slice report (composed, never booted)",
|
|
333
|
-
` device: ${gpuspec.name} (${gpuspec.id}) — ${gpuspec.memtype} ${gpuspec.vrammib / 1024} gb class, mig capable (driver ${gpuspec.driver})`,
|
|
334
|
-
` profile: ${profile.id} — ${profile.slicegb} gb slices, up to ${profile.maxinstances} instances`,
|
|
335
|
-
" slice table (the engine's mig catalog for the 96 gb-class device):",
|
|
336
|
-
...migprofiles.map((entry) => ` ${entry.id} ${entry.slicegb} gb max ${entry.maxinstances} instances`),
|
|
337
|
-
" smi (the sliced device, the run-invariant lines):",
|
|
338
|
-
...smi.map((line) => ` ${line}`),
|
|
339
|
-
" nvml shim (the engine's FAKE_* law under mig, the env surface of the sandbox state):",
|
|
340
|
-
` FAKE_MODEL=${gpuspec.name}`,
|
|
341
|
-
` FAKE_VRAM=${profile.slicegb * 1024}`,
|
|
342
|
-
].join("\n");
|
|
343
|
-
guarddeadline(startedat, deadline);
|
|
344
|
-
const artifact = {
|
|
345
|
-
modality: "virtual-vgpu",
|
|
346
|
-
verdict: "composed",
|
|
347
|
-
manifest,
|
|
348
|
-
device: { id: gpuspec.id, name: gpuspec.name, vrammib: gpuspec.vrammib, mig: gpuspec.mig },
|
|
349
|
-
profile,
|
|
350
|
-
slicetable: migprofiles,
|
|
351
|
-
nvmlshim: { FAKE_MODEL: gpuspec.name, FAKE_VRAM: profile.slicegb * 1024 },
|
|
352
|
-
smi,
|
|
353
|
-
};
|
|
354
|
-
return {
|
|
355
|
-
stdout,
|
|
356
|
-
artifact: { mime: "application/vnd.devthink.sandbox+json", bytes: textencoder.encode(JSON.stringify(artifact)) },
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
/** virtual-screen: the vm plus vnc. composes the machine (cpu, gpu,
|
|
360
|
-
* memory) plus the virtual display tree (xvfb :0 at 1280x800x24, the
|
|
361
|
-
* looking-glass driver line, the vnc endpoint the session law pins) and
|
|
362
|
-
* the session-otp hardening gate: the 64-bit fnv-1a digest of the
|
|
363
|
-
* canonical manifest, deterministic per manifest (the same manifest
|
|
364
|
-
* always answers the same otp); the lane composes the tree, it never
|
|
365
|
-
* binds the endpoint. */
|
|
366
|
-
async function virtualscreenlane(code, _inputs, deadline) {
|
|
367
|
-
const startedat = Date.now();
|
|
368
|
-
const { manifest, cpuspec, gpuspec } = composemachine(parsemanifest(code));
|
|
369
|
-
const memory = composememoryplan(manifest.ramgb, manifest.vcpus);
|
|
370
|
-
const otp = fnv1a64(canonicalmanifest(manifest));
|
|
371
|
-
const stdout = [
|
|
372
|
-
"saddle virtual-screen: composed display report (composed, never booted)",
|
|
373
|
-
` machine: ${cpuspec.displayname} + ${gpuspec.name} + ${manifest.ramgb} gb (the composed machine beneath the display)`,
|
|
374
|
-
` memory: memtotal ${memory.memtotalkb} kb, swap ${memory.swapgb} gb (the engine's formulas)`,
|
|
375
|
-
" display tree (the session law the lane pins):",
|
|
376
|
-
` ${displaylaw.display} xvfb virtual display, screen ${displaylaw.screen}, geometry ${displaylaw.geometry}, nolisten tcp`,
|
|
377
|
-
` driver ${displaylaw.driver}`,
|
|
378
|
-
` vnc ${displaylaw.vnc} (the endpoint the session law pins; the lane composes, never binds)`,
|
|
379
|
-
" session otp hardening gate (fnv-1a 64 over the canonical manifest):",
|
|
380
|
-
` otp: ${otp}`,
|
|
381
|
-
].join("\n");
|
|
382
|
-
guarddeadline(startedat, deadline);
|
|
383
|
-
const artifact = {
|
|
384
|
-
modality: "virtual-screen",
|
|
385
|
-
verdict: "composed",
|
|
386
|
-
manifest,
|
|
387
|
-
display: {
|
|
388
|
-
display: displaylaw.display,
|
|
389
|
-
screen: displaylaw.screen,
|
|
390
|
-
geometry: displaylaw.geometry,
|
|
391
|
-
vnc: displaylaw.vnc,
|
|
392
|
-
},
|
|
393
|
-
otp,
|
|
394
|
-
machine: { model: cpuspec.model, gpu: gpuspec.id, ramgb: manifest.ramgb, memtotalkb: memory.memtotalkb },
|
|
395
|
-
};
|
|
396
|
-
return {
|
|
397
|
-
stdout,
|
|
398
|
-
artifact: { mime: "application/vnd.devthink.screen+json", bytes: textencoder.encode(JSON.stringify(artifact)) },
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
/** virtual-drivers: the virtual driver surface. composes the driver
|
|
402
|
-
* table from the engine's own version strings (the kernel banner of the
|
|
403
|
-
* boot payload rides virtualcpu, the gpu catalog's driver string rides
|
|
404
|
-
* virtualgpu, the engine's own version line rides virtualmemory) and the
|
|
405
|
-
* nvml shim answers under the driver-quota gate: inputs.quota devices
|
|
406
|
-
* (default 4, clamped 1-16), each carrying the selected gpu identity
|
|
407
|
-
* through FAKE_MODEL/FAKE_VRAM. */
|
|
408
|
-
async function virtualdriverslane(code, inputs, deadline) {
|
|
409
|
-
const startedat = Date.now();
|
|
410
|
-
const { manifest, gpuspec } = composemachine(parsemanifest(code));
|
|
411
|
-
const quota = driverquota(inputs);
|
|
412
|
-
const versions = driverversions(manifest);
|
|
413
|
-
const stdout = [
|
|
414
|
-
"saddle virtual-drivers: composed driver report (composed, never booted)",
|
|
415
|
-
" driver table (the engine's own version strings):",
|
|
416
|
-
` virtualcpu ${versions.kernel} (the kernel banner of the engine's boot sequence)`,
|
|
417
|
-
` virtualgpu ${gpuspec.driver} (the driver string of the gpu catalog entry)`,
|
|
418
|
-
` virtualmemory ${versions.engine} (the engine version line of the boot sequence)`,
|
|
419
|
-
` nvml shim (the driver-quota gate, quota ${quota}, clamped 1-16):`,
|
|
420
|
-
...Array.from({ length: quota }, (_, index) => ` device ${index}: FAKE_MODEL=${gpuspec.name} FAKE_VRAM=${gpuspec.smireportedmib}`),
|
|
421
|
-
].join("\n");
|
|
422
|
-
guarddeadline(startedat, deadline);
|
|
423
|
-
const artifact = {
|
|
424
|
-
modality: "virtual-drivers",
|
|
425
|
-
verdict: "composed",
|
|
426
|
-
manifest,
|
|
427
|
-
drivers: { virtualcpu: versions.kernel, virtualgpu: gpuspec.driver, virtualmemory: versions.engine },
|
|
428
|
-
quota,
|
|
429
|
-
nvmlshim: Array.from({ length: quota }, (_, index) => ({
|
|
430
|
-
device: index,
|
|
431
|
-
FAKE_MODEL: gpuspec.name,
|
|
432
|
-
FAKE_VRAM: gpuspec.smireportedmib,
|
|
433
|
-
})),
|
|
434
|
-
};
|
|
435
|
-
return {
|
|
436
|
-
stdout,
|
|
437
|
-
artifact: { mime: "application/vnd.devthink.sandbox+json", bytes: textencoder.encode(JSON.stringify(artifact)) },
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
/** virtual-kvm: the kvm machine planner. composes the qemu argv from the
|
|
441
|
-
* engine's turbo builder (buildqemucmd over the manifest's ramgb and the
|
|
442
|
-
* topology-resolved vcpus — the cpu model rides the recipe's own
|
|
443
|
-
* DiamondRapids default, the qemu cpu model space is the recipe's law),
|
|
444
|
-
* the kvm capability names and the clean-rootfs law; the report answers
|
|
445
|
-
* the composed plan, never a booted machine — the actual boot rides the
|
|
446
|
-
* firecracker/qemu host lanes. a manifest asking for more memory than
|
|
447
|
-
* the model's catalog ceiling answers kvm-composition-failed (the
|
|
448
|
-
* recipe cannot compose hardware the model cannot address). */
|
|
449
|
-
async function virtualkvmlane(code, _inputs, deadline) {
|
|
450
|
-
const startedat = Date.now();
|
|
451
|
-
const { manifest, cpuspec } = composemachine(parsemanifest(code));
|
|
452
|
-
if (manifest.ramgb > cpuspec.maxmemorygb) {
|
|
453
|
-
throw edgelaneerror("KVM_COMPOSITION_FAILED", `the manifest asks for ${manifest.ramgb} gb on ${cpuspec.model} whose catalog ceiling is ${cpuspec.maxmemorygb} gb — the recipe cannot compose hardware the model cannot address`);
|
|
454
|
-
}
|
|
455
|
-
const domain = await loadvirtualization();
|
|
456
|
-
const argv = domain.buildqemucmd({ vcpu: manifest.vcpus, memMB: manifest.ramgb * 1024 });
|
|
457
|
-
const stdout = [
|
|
458
|
-
"saddle virtual-kvm: composed kvm plan (the planner — the boot rides the host lanes, never this one)",
|
|
459
|
-
` manifest: model ${manifest.model} (validated against the cpu catalog), gpu ${manifest.gpu} (validated; the plan carries no display device, vga none), ${manifest.ramgb} gb, ${manifest.vcpus} vcpus`,
|
|
460
|
-
` qemu (the engine's turbo builder, qemu ${domain.qemuversioncheck().split(" ")[0]}):`,
|
|
461
|
-
...argv.map((arg, index) => (index === 0 ? ` ${arg}` : ` ${arg}`)),
|
|
462
|
-
` kvm caps: ${domain.kvmcapnames.length} (${domain.kvmcapnames.join(", ")})`,
|
|
463
|
-
" rootfs law: clean-rootfs — the plan ships a pristine rootfs image; this lane composes the plan, it never boots",
|
|
464
|
-
].join("\n");
|
|
465
|
-
guarddeadline(startedat, deadline);
|
|
466
|
-
const artifact = {
|
|
467
|
-
modality: "virtual-kvm",
|
|
468
|
-
verdict: "composed-plan",
|
|
469
|
-
manifest,
|
|
470
|
-
qemu: { version: domain.qemuversioncheck(), argv },
|
|
471
|
-
kvmcaps: domain.kvmcapnames,
|
|
472
|
-
rootfslaw: "clean-rootfs",
|
|
473
|
-
};
|
|
474
|
-
return {
|
|
475
|
-
stdout,
|
|
476
|
-
artifact: { mime: "application/vnd.devthink.sandbox+json", bytes: textencoder.encode(JSON.stringify(artifact)) },
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
/** microvm-gpuless: the gpuless render. composes the mesa software stack
|
|
480
|
-
* (the engine's pinned summaries: llvmpipe opengl 4.6 through glxinfo,
|
|
481
|
-
* lavapipe vulkan 1.4 through vulkaninfo, rusticl opencl 3.1 through
|
|
482
|
-
* clinfo, the validated mesaenv record), the cpu and the memory, and
|
|
483
|
-
* the xvfb display — the full software-render machine with no gpu
|
|
484
|
-
* device in the composition (the render rides the cpu). */
|
|
485
|
-
async function microvmgpulesslane(code, _inputs, deadline) {
|
|
486
|
-
const startedat = Date.now();
|
|
487
|
-
const { manifest, cpuspec } = composemachine(parsemanifest(code));
|
|
488
|
-
const memory = composememoryplan(manifest.ramgb, manifest.vcpus);
|
|
489
|
-
const env = mesaenv(manifest.vcpus);
|
|
490
|
-
const glxinfo = glxinfoSummary();
|
|
491
|
-
const vulkan = vulkanSummary();
|
|
492
|
-
const clinfo = clinfoSummary(manifest.vcpus);
|
|
493
|
-
const stdout = [
|
|
494
|
-
"saddle microvm-gpuless: composed software-render machine (composed, never booted)",
|
|
495
|
-
` cpu: ${cpuspec.displayname} — ${manifest.vcpus} vcpus (${cpuspec.microarch})`,
|
|
496
|
-
` memory: ${manifest.ramgb} gb (memtotal ${memory.memtotalkb} kb, swap ${memory.swapgb} gb, the engine's formulas)`,
|
|
497
|
-
" mesa software stack (the engine's pinned summaries):",
|
|
498
|
-
" glxinfo (llvmpipe — opengl 4.6 core):",
|
|
499
|
-
...glxinfo.split("\n").map((line) => ` ${line}`),
|
|
500
|
-
" vulkaninfo (lavapipe — vulkan 1.4):",
|
|
501
|
-
...vulkan.split("\n").map((line) => ` ${line}`),
|
|
502
|
-
" clinfo (rusticl — opencl 3.1):",
|
|
503
|
-
...clinfo.split("\n").map((line) => ` ${line}`),
|
|
504
|
-
" env (the engine's mesaenv record):",
|
|
505
|
-
...Object.keys(env)
|
|
506
|
-
.sort()
|
|
507
|
-
.map((key) => ` ${key}=${env[key]}`),
|
|
508
|
-
" display (the gpuless virtual display):",
|
|
509
|
-
` ${displaylaw.display} xvfb, screen ${displaylaw.screen}, geometry ${displaylaw.geometry} (the software-render display, nolisten tcp)`,
|
|
510
|
-
].join("\n");
|
|
511
|
-
guarddeadline(startedat, deadline);
|
|
512
|
-
const artifact = {
|
|
513
|
-
modality: "microvm-gpuless",
|
|
514
|
-
verdict: "composed",
|
|
515
|
-
manifest,
|
|
516
|
-
memory: { memtotalkb: memory.memtotalkb, swapgb: memory.swapgb, free: memory.free },
|
|
517
|
-
mesa: { glxinfo, vulkan, clinfo, env },
|
|
518
|
-
display: { display: displaylaw.display, geometry: displaylaw.geometry },
|
|
519
|
-
};
|
|
520
|
-
return {
|
|
521
|
-
stdout,
|
|
522
|
-
artifact: { mime: "application/vnd.devthink.microvm+json", bytes: textencoder.encode(JSON.stringify(artifact)) },
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
/** gpu-virgl: the virgl render slice. composes the gpu catalog entry for
|
|
526
|
-
* the virtual device, the context-quota law (inputs.contexts, default
|
|
527
|
-
* 8, clamped 1-64) and the 3d capability report — the virtio-gpu virgl
|
|
528
|
-
* bridge carrying the device identity; the report never claims a host
|
|
529
|
-
* gpu, the composition rides the catalog entry. */
|
|
530
|
-
async function gpuvirgllane(code, inputs, deadline) {
|
|
531
|
-
const startedat = Date.now();
|
|
532
|
-
const { manifest, gpuspec } = composemachine(parsemanifest(code));
|
|
533
|
-
const contexts = contextquota(inputs);
|
|
534
|
-
const stdout = [
|
|
535
|
-
"saddle gpu-virgl: composed virgl render slice (composed, never booted)",
|
|
536
|
-
` device: ${gpuspec.name} (${gpuspec.id}) — ${gpuspec.arch}, ${gpuspec.smarch}, ${gpuspec.smcount} sms`,
|
|
537
|
-
` vram: ${gpuspec.vrammib} MiB ${gpuspec.memtype} (the smi surface reports ${gpuspec.smireportedmib} MiB)`,
|
|
538
|
-
` driver: ${gpuspec.driver}${gpuspec.cuda === null ? "" : ` (cuda ${gpuspec.cuda})`}`,
|
|
539
|
-
` context quota: ${contexts} (the context-quota law; inputs.contexts overrides, clamped 1-64)`,
|
|
540
|
-
" 3d capability report (the virtual device's catalog entry through the virtio-gpu virgl bridge):",
|
|
541
|
-
" virtio-gpu virgl 3d acceleration on (the venus native context stays off — the virgl bridge is the composed path)",
|
|
542
|
-
` contexts ${contexts} concurrent render contexts (ctx 0-${contexts - 1})`,
|
|
543
|
-
" render the guest contexts render through the composed device identity above; the lane never claims a host gpu",
|
|
544
|
-
].join("\n");
|
|
545
|
-
guarddeadline(startedat, deadline);
|
|
546
|
-
const artifact = {
|
|
547
|
-
modality: "gpu-virgl",
|
|
548
|
-
verdict: "composed",
|
|
549
|
-
manifest,
|
|
550
|
-
device: {
|
|
551
|
-
id: gpuspec.id,
|
|
552
|
-
name: gpuspec.name,
|
|
553
|
-
arch: gpuspec.arch,
|
|
554
|
-
smarch: gpuspec.smarch,
|
|
555
|
-
smcount: gpuspec.smcount,
|
|
556
|
-
vrammib: gpuspec.vrammib,
|
|
557
|
-
driver: gpuspec.driver,
|
|
558
|
-
},
|
|
559
|
-
contexts,
|
|
560
|
-
caps: { virgl: true, venus: false, contexts: `ctx 0-${contexts - 1}` },
|
|
561
|
-
};
|
|
562
|
-
return {
|
|
563
|
-
stdout,
|
|
564
|
-
artifact: { mime: "application/vnd.devthink.gpu+json", bytes: textencoder.encode(JSON.stringify(artifact)) },
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
/** the seven virtual lane specs (kind live — the lanes compose the
|
|
568
|
-
* engine's own payloads in process; the present probes guard the
|
|
569
|
-
* imported surfaces by typeof so a module graph that cannot load one
|
|
570
|
-
* surface answers absent for that lane, never a fake presence). */
|
|
571
|
-
export const virtuallanespecs = Object.freeze([
|
|
572
|
-
{
|
|
573
|
-
modality: "virtual-full",
|
|
574
|
-
kind: "live",
|
|
575
|
-
runtime: "sandbox-hardware",
|
|
576
|
-
present: () => typeof getcpu === "function" && typeof bootSequence === "function",
|
|
577
|
-
},
|
|
578
|
-
{
|
|
579
|
-
modality: "virtual-vgpu",
|
|
580
|
-
kind: "live",
|
|
581
|
-
runtime: "sandbox-mig",
|
|
582
|
-
present: () => typeof nvidiaSmiTable === "function" && migprofiles.length > 0,
|
|
583
|
-
},
|
|
584
|
-
{
|
|
585
|
-
modality: "virtual-screen",
|
|
586
|
-
kind: "live",
|
|
587
|
-
runtime: "sandbox-display",
|
|
588
|
-
present: () => typeof getgpu === "function" && typeof freeh === "function",
|
|
589
|
-
},
|
|
590
|
-
{
|
|
591
|
-
modality: "virtual-drivers",
|
|
592
|
-
kind: "live",
|
|
593
|
-
runtime: "sandbox-drivers",
|
|
594
|
-
present: () => typeof bootSequence === "function" && typeof getgpu === "function",
|
|
595
|
-
},
|
|
596
|
-
{
|
|
597
|
-
modality: "virtual-kvm",
|
|
598
|
-
kind: "live",
|
|
599
|
-
runtime: "qemu-planner",
|
|
600
|
-
present: () => true /* the kvm lane composes from the lazy domain: the probe answers the engine ships the composition seat */,
|
|
601
|
-
},
|
|
602
|
-
{
|
|
603
|
-
modality: "microvm-gpuless",
|
|
604
|
-
kind: "live",
|
|
605
|
-
runtime: "mesa-llvmpipe",
|
|
606
|
-
present: () => typeof glxinfoSummary === "function" && typeof mesaenv === "function",
|
|
607
|
-
},
|
|
608
|
-
{
|
|
609
|
-
modality: "gpu-virgl",
|
|
610
|
-
kind: "live",
|
|
611
|
-
runtime: "virgl-virtio-gpu",
|
|
612
|
-
present: () => typeof getgpu === "function" && typeof solvetopology === "function",
|
|
613
|
-
},
|
|
614
|
-
]);
|
|
615
|
-
/** the lane executor table of the virtual lanes, keyed by modality id:
|
|
616
|
-
* the dispatch plane refuses to boot over a lane it cannot wire. */
|
|
617
|
-
export const edgelaneexecutorsvirtual = Object.freeze({
|
|
618
|
-
"virtual-full": virtualfulllane,
|
|
619
|
-
"virtual-vgpu": virtualvgpulane,
|
|
620
|
-
"virtual-screen": virtualscreenlane,
|
|
621
|
-
"virtual-drivers": virtualdriverslane,
|
|
622
|
-
"virtual-kvm": virtualkvmlane,
|
|
623
|
-
"microvm-gpuless": microvmgpulesslane,
|
|
624
|
-
"gpu-virgl": gpuvirgllane,
|
|
625
|
-
});
|
|
626
|
-
/** the seven virtual lane ids derived from the spec table (the order is
|
|
627
|
-
* the spec order; the ids are pinned — the orchestrator's edge plane and
|
|
628
|
-
* the api routes read them exactly). */
|
|
629
|
-
export const virtuallaneids = Object.freeze(virtuallanespecs.map((spec) => spec.modality));
|