feat: XNet ↔ Unreal Engine 6 interop — game schema pack + governed connector (0200) - #186
Merged
Conversation
Add the PlayerIdentity / Inventory / GameItem / Achievement / MatchSession / GameEconomyEntry / GameAsset schemas — the durable, save-file-grade vocabulary that flows between a game engine (Unreal Engine 6) and XNet. Every node is space-scoped (spaceCascadeAuthorization) so a title sees only its own game/* space; assets are glTF/USD file refs (XNet stores the CID, never the mesh); economy is money() minor units (a ledger fact, not a payment rail). Registered in builtInSchemas + the 3-layer barrel; passes authorization-coverage. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…on 0200)
New package implementing the XNet ↔ Unreal Engine 6 bridge's XNet half:
- buildUnrealConnector — a @xnetjs/plugins ConnectorDefinition that pulls a
title's normalized event stream into governed, space-scoped nodes (a game is
"just another external service", per exploration 0196). Capability-scoped:
secrets held by the hub broker, schemaWrite limited to the game pack, network
limited to the title's host.
- granularity guardrail — assertDurableCadence/assertDurableSchemas enforce the
central rule of 0200: save-file-grade data may sync, netcode-packet state may
not. Rejects any cadence below a 1s floor and any non-durable schema target.
- mapGameEventToNode — pure event → node translation; soft currencies map to a
money() value with ISO 'XXX' (name kept in the text field).
Tests run in the integration project; includes a real defineConnector
compatibility check so there is no structural drift from the connector primitive.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nector, granularity guard) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
✓ Changelog fragment found — thanks! |
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Preview removed for PR #186. |
crs48
added a commit
that referenced
this pull request
Jun 18, 2026
## Summary Implements exploration **0202** — makes changelog PR-number resolution **robust and visible** without adding a second commit. (Supersedes the doc-only PR #190, which is folded in here.) The investigation found PR linking *wasn't* actually broken — the deploy-time `resolve-prs.mjs` works — but it was fragile (regex over merge-commit subjects), silent on failure, and entries without screenshots looked bare. This hardens all three. ### Robustness — `resolve-prs.mjs` + deploy - **Authoritative API fallback:** when the git-subject parse misses, resolve via the GitHub `commits/{addSha}/pulls` API (keyed by the fragment's adding commit) — **merge-method-proof**, so rebase-merges resolve too. Verified live: `commits/4f413f61/pulls → #187`. - **Fail-loud:** unresolved fragments now emit a `::warning` annotation + summary line instead of silently shipping numberless. Never blocks the deploy (entries still render). - `deploy-site.yml` passes `GITHUB_TOKEN` to the step. ### Authoring — `new.mjs` - **`--pr auto`** (default) bakes the PR number via `gh pr view` when the branch already has a PR — one commit, visible in the repo/previews/local. Omitted when no PR exists yet → the deploy resolves it. (`--pr <N>` / `--pr none` override.) **This fragment was added that way.** - Fixes the **UTC-tomorrow date drift** (stamps the local day). ### UI — `index.astro` - A **"View PR #N →"** affordance for entries that have a PR but no gallery, so server/docs changes don't read as broken. (Built HTML shows it for #187/#186/#184…) ### Notably *not* done (a finding, not a gap) - The exploration suggested running resolve in the preview workflows. They build only `apps/web`, **not** the Astro `site/`, so the changelog page is never in previews — running resolve there would be dead code. Skipped to avoid useless pipeline surface. ## Testing - `resolve-prs.mjs` resolves all current slug entries via git; API fallback verified live against the real endpoint. - `new.mjs`: local-date + graceful no-PR + bake-on-`--pr` all smoke-tested. - `site/` builds (70 pages); "View PR #187" affordance present in the built changelog HTML. - Not eslint/prettier-gated (lint covers `packages apps`; `format:check` skips `scripts/site`), but formatted and syntax-checked anyway. Exploration: `docs/explorations/0202_..._CHANGELOG_PR_NUMBER_RESOLUTION_ROBUSTNESS.md` (items checked off). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the keystone (Phase 2) of exploration 0200: the XNet half of the XNet ↔ Unreal Engine 6 bridge — the governed, user-owned, cross-game data plane UE6's portability vision implies but doesn't itself supply.
What ships
1. Game-interop schema pack (
@xnetjs/data,packages/data/src/schema/schemas/game.ts)The durable, save-file-grade vocabulary that flows between an engine and XNet:
PlayerIdentity(keyed to the player's portabledid),Inventory,GameItem,Achievement,MatchSession,GameEconomyEntry,GameAsset. Every node is space-scoped (spaceCascadeAuthorization()) so a title sees only its owngame/*space — never the player's finance/CRM/notes. Assets are glTF/USDfile()refs (XNet stores the CID, never the mesh); economy ismoney()minor units (a ledger fact, not a payment rail). Registered through the 3-layer barrel; passesauthorization-coverage.test.ts.2.
@xnetjs/unrealconnector package (new, server-side)buildUnrealConnector→ a realdefineConnector-validConnectorDefinition(fyi.xnet.connector.unreal): a game is "just another external service" (per 0196). Capability-scoped secrets/schemaWrite/network, opt-inagentTools, apullthat maps events → nodes. A test wraps it with the realdefineConnectorto prove zero structural drift.assertDurableCadencerejects any cadence below a 1s floor;assertDurableSchemasrejects non-durable targets — at build time.mapGameEventToNode— pure event → node translation; soft currencies map to amoney()value with ISOXXX.Tests
packages/dataunit: 1476 pass (incl. newgame.test.ts+authorization-coverage).@xnetjs/unrealintegration: 27 pass (granularity, event mapping, connector incl. real-defineConnectorcompatibility).tsc --noEmitclean; eslint +format:checkclean.Deferred (tracked as unchecked in the 0200 doc)
Hub
connectorSyncFeaturemount, the "Games"/guild-manager UI surfaces, the UE-side client SDK (separate repo), Phase-3 runtime UCAN auth, and Phase-4 DID-login. The connector ships unmounted — exactly like the 0196 connectors — to be wired when a real title API exists. No 3D engine or heavy dependency lands in the web/desktop bundles.🤖 Generated with Claude Code