Make Eve onboarding one executable path

This commit is contained in:
Meta Vens 2026-08-18 03:17:52 +02:00
commit 3c19e54d91
8 changed files with 157 additions and 29 deletions

View file

@ -9,6 +9,42 @@ on:
workflow_dispatch:
jobs:
getting-started:
name: ${{ matrix.os }} one-command multiplayer onboarding
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest]
steps:
- name: Check out CultLib
uses: actions/checkout@v4
with:
path: CultLib
- name: Check out the matching Eve contract
uses: actions/checkout@v4
with:
repository: GameCult/Eve
ref: ${{ vars.EVE_INTEGRATION_REF || 'codex/eve-browser-host-isolation' }}
path: Eve
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24
- name: Run the documented one-command checkpoint
shell: pwsh
run: ./CultLib/scripts/verify-eve-getting-started.ps1 -EveRoot ./Eve
reactive-and-resource-lifetime:
name: ${{ matrix.os }} reactive semantics and leases
runs-on: ${{ matrix.os }}

View file

@ -70,8 +70,14 @@ series. Its first executable package-consumer checkpoint is
[`samples/eve-two-runtime`](samples/eve-two-runtime/README.md).
The real-process browser continuation is
[`samples/eve-browser-network`](samples/eve-browser-network/README.md).
The implemented browser client boundary and remaining real-network gate are
mapped explicitly in
One documented command runs both layers:
```powershell
pwsh -File ./scripts/verify-eve-getting-started.ps1
```
The implemented browser client boundary and remaining deployed-infrastructure
gates are mapped explicitly in
[`browser-verse-transport.md`](src/GameCult.Mesh/docs/browser-verse-transport.md).
If you want only the smallest durable "open node -> put typed doc -> get typed doc"

View file

@ -15,9 +15,15 @@ This is the real-process continuation of `samples/eve-two-runtime`:
Run the proof from the CultLib repository:
```powershell
node scripts/verify-eve-browser-network.mjs --eve-root ..\Eve
pwsh -File ./scripts/verify-eve-getting-started.ps1
```
The wrapper first proves clean package consumption, then runs this real-process
checkpoint. Run `node scripts/verify-eve-browser-network.mjs --eve-root ../Eve`
directly only to diagnose the network layer. Browser discovery is portable:
`CHROME_PATH` wins when configured, then common Chrome/Chromium/Edge locations
and Playwright's installed Chromium are checked.
The verifier clicks the Eve button twice with one idempotency key, requires one
state transition, restarts the provider on a different physical port, updates
the local Odin fixture, and requires the still-open browser to rediscover the

View file

@ -12,9 +12,13 @@ Eve. It intentionally has one owner for each decision:
Run it from the CultLib repository:
```powershell
pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve
pwsh -File ./scripts/verify-eve-getting-started.ps1
```
That command continues into the real Chromium/C# network checkpoint after this
artifact layer passes. Run `verify-eve-two-runtime-sample.ps1` directly only to
diagnose clean package consumption in isolation.
From clean CultLib and Eve checkouts, the verifier installs missing build
dependencies, builds package artifacts, installs them into a new empty
temporary consumer, and runs `sample.mjs`. Success proves:

View file

@ -1,5 +1,6 @@
import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import { createServer as createHttpServer } from "node:http";
import { mkdtemp, readFile, rm } from "node:fs/promises";
import { createServer as createNetServer } from "node:net";
@ -45,7 +46,12 @@ try {
const bundle = await readFile(bundlePath, "utf8");
assert.doesNotMatch(bundle, /(?:from\s*["']node:|require\(["']node:)/u, "browser bundle contains a Node builtin import");
await run("dotnet", ["build", join(sampleRoot, "EveBrowserNetworkSample.csproj"), "--verbosity", "quiet"]);
await run("dotnet", [
"build",
join(sampleRoot, "EveBrowserNetworkSample.csproj"),
"--verbosity", "quiet",
"-p:NoWarn=1591%3BCS8632",
]);
const providerPort = await freePort();
const replacementProviderPort = await freePort();
const odinPort = await freePort();
@ -58,8 +64,7 @@ try {
await headless.waitFor("HEADLESS_READY ");
httpServer = await serve(httpPort, sampleRoot, bundlePath);
const executablePath = process.env.CHROME_PATH || "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
browser = await chromium.launch({ executablePath, headless: true });
browser = await chromium.launch({ executablePath: resolveChromiumExecutable(), headless: true });
let page = await browser.newPage();
const url = `http://127.0.0.1:${httpPort}/?odin=${encodeURIComponent(odinEndpoint)}&token=${token}`;
await page.goto(url);
@ -221,3 +226,36 @@ async function stop(process) {
]);
if (process.exitCode === null) process.kill("SIGKILL");
}
function resolveChromiumExecutable() {
const candidates = [process.env.CHROME_PATH];
if (process.platform === "win32") {
for (const root of [process.env.ProgramFiles, process.env["ProgramFiles(x86)"], process.env.LOCALAPPDATA]) {
if (!root) continue;
candidates.push(
join(root, "Google", "Chrome", "Application", "chrome.exe"),
join(root, "Microsoft", "Edge", "Application", "msedge.exe"),
);
}
} else if (process.platform === "darwin") {
candidates.push(
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
);
} else {
candidates.push(
"/usr/bin/google-chrome",
"/usr/bin/google-chrome-stable",
"/usr/bin/chromium",
"/usr/bin/chromium-browser",
"/opt/google/chrome/chrome",
);
}
candidates.push(chromium.executablePath());
const executablePath = candidates.find(candidate => candidate && existsSync(candidate));
if (executablePath) return executablePath;
throw new Error(
"No Chromium-family browser was found. Set CHROME_PATH or run "
+ "'node node_modules/playwright-core/cli.js install chromium'.",
);
}

View file

@ -0,0 +1,29 @@
param(
[string] $EveRoot = (Join-Path (Split-Path -Parent $PSScriptRoot) "..\Eve"),
[switch] $SkipDependencyInstall
)
$ErrorActionPreference = "Stop"
$cultLibRoot = Split-Path -Parent $PSScriptRoot
$EveRoot = [IO.Path]::GetFullPath($EveRoot)
& (Join-Path $PSScriptRoot "verify-eve-two-runtime-sample.ps1") `
-EveRoot $EveRoot `
-SkipDependencyInstall:$SkipDependencyInstall
if ($LASTEXITCODE -ne 0) {
throw "The clean package-consumer checkpoint failed."
}
$nodeCommand = Get-Command node -ErrorAction Stop
$playwrightCli = Join-Path $cultLibRoot "node_modules\playwright-core\cli.js"
if (-not (Test-Path -LiteralPath $playwrightCli -PathType Leaf)) {
throw "playwright-core is missing after dependency setup: $playwrightCli"
}
& $nodeCommand.Source (Join-Path $PSScriptRoot "verify-eve-browser-network.mjs") `
--eve-root $EveRoot
if ($LASTEXITCODE -ne 0) {
throw "The real browser/C# network checkpoint failed."
}
Write-Host "Eve getting-started verification passed: clean artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, receipts, persistence, and route replacement."

View file

@ -35,14 +35,18 @@ Run the same provider and connect at least two lowerers. Both must report the
same provider id, surface id, surface version, and command receipt ids. Native
pixels may differ; provider truth may not.
The package-artifact DOM-lowerer/headless checkpoint is executable from CultLib:
The complete checkpoint is executable from CultLib:
```powershell
cd CultLib
pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve
pwsh -File ./scripts/verify-eve-getting-started.ps1
```
The verifier builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`,
This one command runs the clean package-artifact checkpoint and then the real
browser/C# network checkpoint. They remain separate programs because they prove
different boundaries; the developer should not have to orchestrate them.
The first layer builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`,
`@gamecult/eve-contracts`, and `@gamecult/eve-browser-lowering`, installs the
tarballs into an empty temporary consumer, and runs
`samples/eve-two-runtime/sample.mjs`. Eve's generated runtime validators reject
@ -53,6 +57,12 @@ both consumers converge on the same state and canonical receipt identity, a
duplicate idempotency key is not applied twice, and the state plus receipt
survive reopening the `.cc` store.
The second layer runs a durable C# provider, a separate local Odin fixture, a
real Chromium Eve lowerer, and an independent C# headless observer over binary
CultNet WebSocket lanes. The open browser resolves provider identity through
the canonical Verse catalog, survives a provider restart on a different route,
resubscribes, and commits another canonical receipt.
Current verification for the Unity consumer remains:
```powershell
@ -60,19 +70,14 @@ cd ../EveUnity
pwsh -File ./scripts/run-release-consumer-tests.ps1
```
This first checkpoint proves clean package consumption, canonical Eve contract
The artifact layer proves clean package consumption, canonical Eve contract
validation, and two independent lowering/observation consumers inside Node. It
does **not** claim a real browser process, an Odin-discovered network hop, or
cross-language command execution. Do not cite it as evidence for those layers.
does **not** prove the network layer; the second program owns that evidence.
The next executable checkpoint is
The network program is
[`samples/eve-browser-network`](../../../../samples/eve-browser-network/README.md).
It runs a durable C# provider, a separate local Odin fixture, a real Chromium
Eve lowerer, and an independent C# headless observer over authenticated binary
CultNet WebSocket lanes. The still-open browser resolves stable identity through
the canonical Verse catalog, survives a provider restart on a different
physical route, resubscribes, and commits another canonical receipt. A smoke
against the deployed Odin daemon and retained C# lease reconnection remain
separate infrastructure gates. Their owner map and full acceptance contract are recorded in
Run it separately only while diagnosing that layer. A smoke against the
deployed Odin daemon and retained C# lease reconnection remain separate
infrastructure gates. Their owner map and full acceptance contract are recorded in
[`browser-verse-transport.md`](../browser-verse-transport.md).

View file

@ -4,18 +4,22 @@ This series builds one typed application state and presents it through multiple
Eve runtimes. It is maintained as an API acceptance test: examples use public
APIs, name the owner of each decision, and include a verification checkpoint.
Run the current clean-consumer checkpoint first:
Run the complete getting-started checkpoint:
```powershell
pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve
pwsh -File ./scripts/verify-eve-getting-started.ps1
```
From clean CultLib and Eve checkouts, the command installs the package build
dependencies when absent, packs the five TypeScript packages, installs only
those artifacts into an empty temporary project, validates the Eve
surface and receipt, executes one idempotent counter command, proves two local
consumers converge, and reopens the durable `.cc` store. It is deliberately not
called a networked-browser proof; chapter 3 names that remaining boundary.
With clean sibling CultLib and Eve checkouts, the command installs missing build
dependencies and runs two explicit evidence layers. First it packs the five
TypeScript packages into an empty temporary consumer, validates the Eve surface
and receipt, executes one idempotent counter command, proves a DOM lowerer and
headless observer converge, and reopens the durable `.cc` store. Then it boots a
durable C# provider, local Odin fixture, real Chromium lowerer, and independent
C# observer; it proves discovery by identity, commands, canonical receipts,
provider restart on another route, resubscription, and durable convergence.
Set `CHROME_PATH` only when no installed Chrome, Chromium, Edge, or Playwright
Chromium can be found automatically.
Follow the chapters in order: