Make Eve onboarding one executable path
This commit is contained in:
parent
44abedfc9f
commit
3c19e54d91
8 changed files with 157 additions and 29 deletions
36
.github/workflows/cultmesh-portability.yml
vendored
36
.github/workflows/cultmesh-portability.yml
vendored
|
|
@ -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 }}
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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'.",
|
||||
);
|
||||
}
|
||||
|
|
|
|||
29
scripts/verify-eve-getting-started.ps1
Normal file
29
scripts/verify-eve-getting-started.ps1
Normal 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."
|
||||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue