Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions workers/noema/src/chamber-map-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ const LINKS: Array<[string, string, string, string]> = [
["room.outer-works", "room.frontier-gate", "south", "north"],
];

export function chamberMapRooms(): Record<string, import("./genesis").GenesisRoom> {
const rooms: Record<string, import("./genesis").GenesisRoom> = {};
import type { GenesisRoom } from "./genesis";

export function chamberMapRooms(): Record<string, GenesisRoom> {
const rooms: Record<string, GenesisRoom> = {};
for (const id of CHAMBER_MAP_ROOM_IDS) {
const n = NAMES[id];
rooms[id] = { room_id: id, name: n.name, description: n.description, exits: [], entities: [] };
Expand Down
24 changes: 19 additions & 5 deletions workers/noema/src/world-do.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { enrichEntity } from "./actions";
import { isHiddenRoom } from "./construction";
import { FROZEN_GENESIS_ID, type Cycle0World, type GenesisResult } from "./genesis";
import type { Cycle0World, GenesisResult } from "./genesis";
import {
buildWatchLive,
heldFromSnapshot,
Expand Down Expand Up @@ -688,7 +688,7 @@ export class NoemaWorldDO {
{ status: 400 },
);
}
if (preview.genesis_id === FROZEN_GENESIS_ID && preview.world_id !== "world.perihelion-reach") {
if (preview.genesis_id === "genesis.ef578f4ffceeccd0" && preview.world_id !== "world.perihelion-reach") {
return Response.json(
{ error: { code: "INVALID_SEED", message: "frozen genesis cannot activate on another world" } },
{ status: 400 },
Expand Down Expand Up @@ -822,10 +822,24 @@ export class NoemaWorldDO {
const admitted = admitTestWorldId(requested, this.env.DEFAULT_WORLD_ID);
this.requestedWorldId = admitted.ok ? admitted.world_id : null;
this.allowCanonicalBootstrap = admitted.ok && body.allow_bootstrap === true;
// Preview health/store may bind a successor id on this isolate. PLAY must
// not keep that in-memory world; reload from storage / DEFAULT_WORLD_ID.
if (!admitted.ok) {
this.world = null;
this.meta = null;
}

const result = await this.applyCommand(agent, body.envelope);
// Action failures are structured envelopes (ok:false), not transport errors.
return Response.json(result, { status: commandResultHttpStatus(result) });
try {
const result = await this.applyCommand(agent, body.envelope);
return Response.json(result, { status: commandResultHttpStatus(result) });
} catch (e) {
console.error("do/command", e instanceof Error ? e.stack || e.message : e);
return Response.json({
ok: false,
request_id: body.envelope?.request_id || "unknown",
error: { code: "COMMAND_FAILED", message: "The world could not apply that action." },
});
}
}

private publicMeta(): Record<string, unknown> {
Expand Down
205 changes: 205 additions & 0 deletions workers/noema/test/enter-command-do.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import { describe, expect, it } from "vitest";
import { mintControllerToken } from "../src/auth";
import worker from "../src/index";
import { ACCEPTED_SEALS } from "../src/seal";
import type { Env, PlayerPrincipal } from "../src/types";
import { NoemaWorldDO } from "../src/world-do";

function memoryState(initial: Record<string, unknown> = {}): DurableObjectState {
const bag = new Map<string, unknown>(Object.entries(initial));
return {
storage: {
async get(key: string) {
return bag.get(key);
},
async put(keyOrEntries: string | Record<string, unknown>, value?: unknown) {
if (typeof keyOrEntries === "string") bag.set(keyOrEntries, value);
else for (const [k, v] of Object.entries(keyOrEntries)) bag.set(k, v);
},
},
} as unknown as DurableObjectState;
}

function perihelionStored() {
return {
world_id: "world.perihelion-reach",
world_name: "Perihelion Reach",
cycle: 139,
sequence: 1002,
entry_room_id: "room.relay-quarter",
rooms: {
"room.relay-quarter": {
room_id: "room.relay-quarter",
name: "Grid Anchor",
description: "A frontier anchor.",
exits: [{ direction: "east", to_room_id: "room.transit-ring" }],
entities: [{ entity_id: "entity.relay-7", label: "relay-7", entity_type: "INFRASTRUCTURE" }],
},
"room.transit-ring": {
room_id: "room.transit-ring",
name: "Coldline",
description: "A ring corridor.",
exits: [{ direction: "west", to_room_id: "room.relay-quarter" }],
entities: [],
},
},
players: {},
trades: {},
messages: [],
organizations: {},
seen_idempotency: {},
unsettled: [],
};
}

describe("NoemaWorldDO command ENTER/LOOK after successor wiring", () => {
it("ENTER then LOOK on stored Perihelion does not 500", async () => {
const env = {
TOKEN_SIGNING_SECRET: "test-signing-secret-enter-do",
NOEMA_ENV: "production",
NOEMA_PROTOCOL_VERSION: "1",
DEFAULT_WORLD_ID: "world-01",
} as Env;
const doInst = new NoemaWorldDO(
memoryState({
world: perihelionStored(),
world_meta: {
status: "ACTIVE",
genesis_id: "genesis.ef578f4ffceeccd0",
config_frozen: true,
settlement_health: "HEALTHY",
},
}),
env,
);
const minted = await mintControllerToken(env, {
handle: "maintc2",
controllerType: "agent",
playerId: "player.maintc2",
});
const principal: PlayerPrincipal = {
player_id: minted.player_id,
agent_id: `agent.${minted.player_id.replace(/^player\./, "")}`,
session_id: "sess.enter-do",
controller_id: minted.controller_id,
controller_type: "agent",
scopes: ["noema.player.read", "noema.world.observe", "noema.action.submit"],
};
const enter = await doInst.fetch(
new Request("https://do/command", {
method: "POST",
headers: { "content-type": "application/json", "x-noema-world-id": "world-01" },
body: JSON.stringify({
principal,
envelope: { request_id: "e1", command: "ENTER_WORLD", arguments: {} },
world_id: "world-01",
}),
}),
);
expect(enter.status).toBe(200);
const enterBody = (await enter.json()) as { ok?: boolean; error?: { code?: string } };
expect(enterBody.error?.code).not.toBe("INTERNAL");
expect(enterBody.ok).toBe(true);

const look = await doInst.fetch(
new Request("https://do/command", {
method: "POST",
headers: { "content-type": "application/json", "x-noema-world-id": "world-01" },
body: JSON.stringify({
principal,
envelope: { request_id: "l1", command: "LOOK", arguments: {} },
world_id: "world-01",
}),
}),
);
expect(look.status).toBe(200);
const lookBody = (await look.json()) as { ok?: boolean; error?: { code?: string } };
expect(lookBody.error?.code).not.toBe("INTERNAL");
expect(lookBody.ok).toBe(true);
});

it("PLAY reloads stored world after a successor health bind on the same isolate", async () => {
const env = {
TOKEN_SIGNING_SECRET: "test-signing-secret-enter-do",
NOEMA_ENV: "production",
DEFAULT_WORLD_ID: "world-01",
} as Env;
const doInst = new NoemaWorldDO(memoryState(), env);
const health = await doInst.fetch(
new Request("https://do/health", { headers: { "x-noema-world-id": "world.perihelion-reach-2" } }),
);
expect(health.status).toBe(200);
expect(((await health.json()) as { world_id: string }).world_id).toBe("world.perihelion-reach-2");

const minted = await mintControllerToken(env, { handle: "maintc2b", controllerType: "agent", playerId: "player.maintc2b" });
const principal: PlayerPrincipal = {
player_id: minted.player_id,
agent_id: "agent.maintc2b",
session_id: "sess.enter-do2",
controller_id: minted.controller_id,
controller_type: "agent",
scopes: ["noema.player.read", "noema.world.observe", "noema.action.submit"],
};
const enter = await doInst.fetch(
new Request("https://do/command", {
method: "POST",
headers: { "content-type": "application/json", "x-noema-world-id": "world-01" },
body: JSON.stringify({
principal,
envelope: { request_id: "e2", command: "ENTER_WORLD", arguments: {} },
world_id: "world-01",
}),
}),
);
expect(enter.status).toBe(200);
const enterBody = (await enter.json()) as { ok?: boolean; error?: { code?: string }; observation?: { world_name?: string } };
expect(enterBody.error?.code).not.toBe("INTERNAL");
expect(enterBody.ok).toBe(true);

const after = await doInst.fetch(new Request("https://do/health"));
const afterBody = (await after.json()) as { world_id: string };
expect(afterBody.world_id).toBe("world-01");
});

it("worker /v1/command ENTER through real DO does not 500", async () => {
const envBase = {
TOKEN_SIGNING_SECRET: "test-signing-secret-enter-do",
NOEMA_ENV: "production",
NOEMA_PROTOCOL_VERSION: "1",
DEFAULT_WORLD_ID: "world-01",
} as Env;
const doInst = new NoemaWorldDO(
memoryState({
world: perihelionStored(),
world_meta: { status: "ACTIVE", genesis_id: "genesis.ef578f4ffceeccd0", config_frozen: true, settlement_health: "HEALTHY" },
}),
envBase,
);
const env = {
...envBase,
WORLD_DO: {
idFromName: (name: string) => ({ name }),
get: () => ({
fetch: (url: string, init?: RequestInit) => doInst.fetch(new Request(String(url), init)),
}),
},
} as unknown as Env;
const minted = await mintControllerToken(env, { handle: "maintc2c", controllerType: "agent", playerId: "player.maintc2c" });
const res = await worker.fetch(
new Request("https://noema.guru/v1/command", {
method: "POST",
headers: {
"content-type": "application/json",
Authorization: `Bearer ${minted.access_token}`,
"X-Noema-Seal": ACCEPTED_SEALS[0] || "",
},
body: JSON.stringify({ request_id: "w1", command: "ENTER_WORLD", arguments: {} }),
}),
env,
);
const body = (await res.json()) as { ok?: boolean; error?: { code?: string; message?: string } };
expect(res.status, JSON.stringify(body)).not.toBe(500);
expect(body.error?.code).not.toBe("INTERNAL");
expect(body.ok).toBe(true);
});
});
Loading