Release Healer Man 0.1.27

This commit is contained in:
phenom committed 2026-09-10 09:54:12 -04:00
1 parent 147c2804d4
commit ed8b9e3719
6 files changed
+86 -6

No files matched your search

+23
View File
@@ -1992,3 +1992,26 @@ Vite's existing large-chunk advisory remains informational.
eight-heading pixel comparisons, profiles, before/after timing JSON, and eight-heading pixel comparisons, profiles, before/after timing JSON, and
screenshots. Measurements use the same desktop Edge/RX 9070 XT setup as the screenshots. Measurements use the same desktop Edge/RX 9070 XT setup as the
preceding audit. These CPU improvements do not certify Thor performance. preceding audit. These CPU improvements do not certify Thor performance.
# 2026-09-09 — bundled arena assets blocked by the browser content worker
- Reproduced the reported collision-matched fallback in the production build
with the content worker active. Warnorken's `visual.glb?arena-runtime=1`
returned 404 even though the file was bundled and directly served with 200.
The worker omitted `/assets/game/arenas/` from its bundled asset prefixes and
incorrectly rejected these files as uninstalled optional content.
- Added the arena prefix to the worker. Installed updates still take priority;
missing optional dungeon content still returns 404. Behavioral worker tests
failed for all eight arenas before the fix and now cover visual, collision,
and navigation requests with the runtime query parameter.
- The production build passed. Reloading the same browser session activated
the fixed worker without clearing storage or downloading content. Warnorken
rendered textured stone geometry and Nagrand rendered its authored arena
geometry; neither showed the loading/fallback banner after loading, and no
new console errors were recorded. Checks used offline practice in the Codex
browser at `http://127.0.0.1:4174/`, backed by a local test server on port 4173.
- All 22 content tests and the eight-arena asset validator passed. Screenshots,
before/after error logs, asset validation, and build output are saved under
`playtest-artifacts/2026-09-09-arena-loading/`. The existing large-bundle
advisory remains. This verifies the local browser build, not a deployment
or an Android package.
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "healer-man", "name": "healer-man",
"version": "0.1.26", "version": "0.1.27",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "healer-man", "name": "healer-man",
"version": "0.1.26", "version": "0.1.27",
"dependencies": { "dependencies": {
"@capacitor/android": "8.4.1", "@capacitor/android": "8.4.1",
"@capacitor/core": "8.4.1", "@capacitor/core": "8.4.1",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "healer-man", "name": "healer-man",
"private": true, "private": true,
"version": "0.1.26", "version": "0.1.27",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 0.0.0.0", "dev": "vite --host 0.0.0.0",
+1
View File
@@ -12,6 +12,7 @@ const BUNDLED_ASSET_PREFIXES = [
"/assets/characters/wow335a-v1/manifest.json", "/assets/characters/wow335a-v1/manifest.json",
"/assets/characters/wow335a-v1/human/", "/assets/characters/wow335a-v1/human/",
"/assets/creatures/wailing-caverns/", "/assets/creatures/wailing-caverns/",
"/assets/game/arenas/",
"/assets/game/dungeons/wailing-caverns/", "/assets/game/dungeons/wailing-caverns/",
]; ];
const BUNDLED_ASSET_PATHS = new Set([ const BUNDLED_ASSET_PATHS = new Set([
+2 -2
View File
@@ -1,4 +1,4 @@
{ {
"versionName": "0.1.26", "versionName": "0.1.27",
"versionCode": 1026 "versionCode": 1027
} }
+57 -1
View File
@@ -1,5 +1,7 @@
import { readFileSync } from "node:fs"; import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest"; import { runInNewContext } from "node:vm";
import { describe, expect, it, vi } from "vitest";
import { ARENA_STAGES } from "../game/arenaStages";
import { BROWSER_CONTENT_CACHE_NAME } from "./contentManager"; import { BROWSER_CONTENT_CACHE_NAME } from "./contentManager";
const workerSource = readFileSync( const workerSource = readFileSync(
@@ -7,7 +9,61 @@ const workerSource = readFileSync(
"utf8", "utf8",
); );
function contentWorker(cached?: Response) {
const handlers = new Map<string, (event: unknown) => void>();
const fetch = vi.fn(async () => new Response("bundled arena", { status: 200 }));
const match = vi.fn(async () => cached);
runInNewContext(workerSource, {
self: {
location: { origin: "https://healer.test" },
addEventListener: (type: string, handler: (event: unknown) => void) => handlers.set(type, handler),
},
caches: { open: async () => ({ match }) },
fetch,
URL,
Response,
});
return {
fetch,
match,
request: (path: string) => {
let response: Promise<Response> | undefined;
handlers.get("fetch")!({
request: new Request(new URL(path, "https://healer.test")),
respondWith: (value: Promise<Response>) => { response = value; },
});
return response;
},
};
}
describe("browser content cache worker", () => { describe("browser content cache worker", () => {
it.each(ARENA_STAGES)("loads bundled $name assets without an optional content install", async (stage) => {
const worker = contentWorker();
for (const asset of stage.assets) {
const response = await worker.request(`${asset.url}?arena-runtime=1`);
expect(response?.status).toBe(200);
expect(await response?.text()).toBe("bundled arena");
}
expect(worker.fetch).toHaveBeenCalledTimes(stage.assets.length);
});
it("prefers installed arena updates over bundled files, ignoring the runtime query", async () => {
const worker = contentWorker(new Response("updated arena"));
const response = await worker.request(`${ARENA_STAGES[0].assets[0].url}?arena-runtime=1`);
expect(await response?.text()).toBe("updated arena");
expect(worker.match).toHaveBeenCalledWith(expect.any(Request), { ignoreSearch: true });
expect(worker.fetch).not.toHaveBeenCalled();
});
it("still blocks optional dungeon assets that have not been installed", async () => {
const worker = contentWorker();
const response = await worker.request("/assets/game/manastorm/optional/visual.glb");
expect(response?.status).toBe(404);
expect(await response?.text()).toBe("Optional content is not installed.");
expect(worker.fetch).not.toHaveBeenCalled();
});
it("serves only cached same-origin asset requests from the active content cache", () => { it("serves only cached same-origin asset requests from the active content cache", () => {
expect(workerSource).toContain(`const CONTENT_CACHE_NAME = "${BROWSER_CONTENT_CACHE_NAME}";`); expect(workerSource).toContain(`const CONTENT_CACHE_NAME = "${BROWSER_CONTENT_CACHE_NAME}";`);
expect(workerSource).toContain('request.method !== "GET"'); expect(workerSource).toContain('request.method !== "GET"');